commit 35e1f40abf408663d468038e22af2c6f2ec34659 from: Omar Polo date: Sun Mar 14 21:17:11 2021 UTC added fs process it's the only one that has file system access. For now it serves about:new (from memory) and about:bookmarks (from ~/.telescope/bookmarks.gmi if found) commit - f5ccf7ae3254e2e1ae090253ae13e21b16f8d50b commit + 35e1f40abf408663d468038e22af2c6f2ec34659 blob - 731893b48ab311b07be28cc9781bb004cec09e22 blob + e16501d2dcee4bd502a2a607fd995a5c7310903f --- Makefile.am +++ Makefile.am @@ -2,6 +2,7 @@ bin_PROGRAMS = telescope telescope_SOURCES = compat.h \ compat/*.[ch] \ + fs.c \ gemini.c \ gemtext.c \ hist.c \ blob - cab5f282060ec52b8f8eb22f0e0ad9a48f0a7523 blob + bd119ecb712192bbcc512815692a08ebb2db55fe --- gemini.c +++ gemini.c @@ -40,6 +40,7 @@ #include #include +static struct event imsgev; static struct tls_config *tlsconf; static struct imsgbuf *ibuf; blob - /dev/null blob + a5847c463c7f75320b500f978acd57640cbf2ba4 (mode 644) --- /dev/null +++ fs.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2021 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "telescope.h" + +#include +#include +#include +#include +#include +#include + +static void die(void) __attribute__((__noreturn__)); +static void serve_bookmarks(uint32_t); +static void handle_get(struct imsg*, size_t); +static void handle_quit(struct imsg*, size_t); +static void dispatch_imsg(int, short, void*); + +static struct event imsgev; +static struct imsgbuf *ibuf; + +static imsg_handlerfn *handlers[] = { + [IMSG_GET] = handle_get, + [IMSG_QUIT] = handle_quit, +}; + +static void __attribute__((__noreturn__)) +die(void) +{ + abort(); /* TODO */ +} + +static void +serve_bookmarks(uint32_t peerid) +{ + const char *t; + char path[PATH_MAX], buf[BUFSIZ]; + size_t r; + FILE *f; + + strlcpy(path, getenv("HOME"), sizeof(path)); + strlcat(path, "/.telescope/bookmarks.gmi", sizeof(path)); + + if ((f = fopen(path, "r")) == NULL) { + t = "# error\n\nCan't open ~/.telescope/bookmarks.gmi"; + imsg_compose(ibuf, IMSG_BUF, peerid, 0, -1, t, strlen(t)); + imsg_compose(ibuf, IMSG_EOF, peerid, 0, -1, NULL, 0); + imsg_flush(ibuf); + return; + } + + for (;;) { + r = fread(buf, 1, sizeof(buf), f); + imsg_compose(ibuf, IMSG_BUF, peerid, 0, -1, buf, r); + imsg_flush(ibuf); + if (r != sizeof(buf)) + break; + } + + imsg_compose(ibuf, IMSG_EOF, peerid, 0, -1, NULL, 0); + imsg_flush(ibuf); + + fclose(f); +} + +static void +handle_get(struct imsg *imsg, size_t datalen) +{ + char *data; + const char *p; + + data = imsg->data; + + if (data[datalen-1] != '\0') + die(); + + if (!strcmp(data, "about:new")) { + imsg_compose(ibuf, IMSG_BUF, imsg->hdr.peerid, 0, -1, + about_new, strlen(about_new)); + imsg_compose(ibuf, IMSG_EOF, imsg->hdr.peerid, 0, -1, NULL, 0); + imsg_flush(ibuf); + } else if (!strcmp(data, "about:bookmarks")) { + serve_bookmarks(imsg->hdr.peerid); + } else { + p = "# not found!\n"; + imsg_compose(ibuf, IMSG_BUF, imsg->hdr.peerid, 0, -1, p, strlen(p)); + imsg_compose(ibuf, IMSG_EOF, imsg->hdr.peerid, 0, -1, NULL, 0); + imsg_flush(ibuf); + } +} + +static void +handle_quit(struct imsg *imsg, size_t datalen) +{ + event_loopbreak(); +} + +static void +dispatch_imsg(int fd, short ev, void *d) +{ + struct imsgbuf *ibuf = d; + struct imsg imsg; + ssize_t n; + size_t datalen; + + if ((n = imsg_read(ibuf)) == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + _exit(1); + } + + if (n == 0) + _exit(1); + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + _exit(1); + if (n == 0) + return; + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + handlers[imsg.hdr.type](&imsg, datalen); + imsg_free(&imsg); + } +} + +int +fs_main(struct imsgbuf *b) +{ + ibuf = b; + + event_init(); + + event_set(&imsgev, ibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, ibuf); + event_add(&imsgev, NULL); + + sandbox_fs_process(); + + event_dispatch(); + return 0; +} blob - 550c6d1f6a2c846270a261c5c863b4f119ca6fcf blob + ce229f46156efda7fbd24c38fa125849669a5fd5 --- sandbox.c +++ sandbox.c @@ -19,7 +19,9 @@ #ifdef __OpenBSD__ # include -# include +# include +# include +# include # include void @@ -32,10 +34,32 @@ sandbox_network_process(void) void sandbox_ui_process(void) { - if (pledge("stdio tty", NULL)) + if (pledge("stdio tty", NULL) == -1) err(1, "pledge"); } +void +sandbox_fs_process(void) +{ + char path[PATH_MAX]; + + if (unveil("/tmp", "r") == -1) + err(1, "unveil"); + + strlcpy(path, getenv("HOME"), sizeof(path)); + strlcat(path, "/Downloads", sizeof(path)); + if (unveil(path, "r") == -1) + err(1, "unveil"); + + strlcpy(path, getenv("HOME"), sizeof(path)); + strlcat(path, "/.telescope", sizeof(path)); + if (unveil(path, "r") == -1) + err(1, "unveil"); + + if (pledge("stdio rpath", NULL) == -1) + err(1, "pledge"); +} + #else #warning "No sandbox for this OS" @@ -46,4 +70,16 @@ sandbox_network_process(void) return; } +void +sandbox_ui_process(void) +{ + return; +} + +void +sandbox_fs_process(void) +{ + return; +} + #endif blob - 9044a5f66221c0e8dafa303ace681e87d1de1a89 blob + 6d3c77320242a17abb3375bb5be608c085a67389 --- telescope.c +++ telescope.c @@ -10,7 +10,7 @@ #include #include -struct event imsgev; +struct event netev, fsev; struct tabshead tabshead; /* the first is also the fallback one */ @@ -20,7 +20,7 @@ static struct proto protos[] = { { NULL, NULL }, }; -static struct imsgbuf *netibuf; +static struct imsgbuf *netibuf, *fsibuf; static void die(void) __attribute__((__noreturn__)); static struct tab *tab_by_id(uint32_t); @@ -201,23 +201,22 @@ handle_imsg_eof(struct imsg *imsg, size_t datalen) static void dispatch_imsg(int fd, short ev, void *d) { - struct imsg imsg; - size_t datalen; - ssize_t n; + struct imsgbuf *ibuf = d; + struct imsg imsg; + size_t datalen; + ssize_t n; - if ((n = imsg_read(netibuf)) == -1) { + if ((n = imsg_read(ibuf)) == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) return; die(); } - if (n == 0) { - fprintf(stderr, "other side is dead\n"); - exit(0); - } + if (n == 0) + _exit(1); for (;;) { - if ((n = imsg_get(netibuf, &imsg)) == -1) + if ((n = imsg_get(ibuf, &imsg)) == -1) die(); if (n == 0) return; @@ -255,10 +254,11 @@ load_about_url(struct tab *tab, const char *url) len = sizeof(tab->hist_cur->h)-1; strlcpy(tab->hist_cur->h, url, len); - if (!strcmp(url, "about:new")) - load_page_from_str(tab, about_new); - else - load_page_from_str(tab, "# not found\n"); + gemtext_initparser(&tab->page); + + imsg_compose(fsibuf, IMSG_GET, tab->id, 0, -1, + tab->hist_cur->h, len+1); + imsg_flush(fsibuf); } void @@ -355,12 +355,15 @@ stop_tab(struct tab *tab) int main(void) { - struct imsgbuf main_ibuf, network_ibuf; - int imsg_fds[2]; + struct imsgbuf network_ibuf, fs_ibuf; + int net_fds[2], fs_fds[2]; + pid_t pid; + pid = getpid(); + signal(SIGCHLD, SIG_IGN); - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fs_fds) == -1) err(1, "socketpair"); switch (fork()) { @@ -368,25 +371,47 @@ main(void) err(1, "fork"); case 0: /* child */ - setproctitle("client"); - close(imsg_fds[0]); - imsg_init(&network_ibuf, imsg_fds[1]); - exit(client_main(&network_ibuf)); + setproctitle("(%d) fs", pid); + close(fs_fds[0]); + imsg_init(&fs_ibuf, fs_fds[1]); + exit(fs_main(&fs_ibuf)); + default: + close(fs_fds[1]); + imsg_init(&fs_ibuf, fs_fds[0]); + fsibuf = &fs_ibuf; } - setproctitle("ui"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, net_fds) == -1) + err(1, "socketpair"); - close(imsg_fds[1]); - imsg_init(&main_ibuf, imsg_fds[0]); - netibuf = &main_ibuf; + switch (fork()) { + case -1: + err(1, "fork"); + case 0: + /* child */ + setproctitle("(%d) client", pid); + close(net_fds[0]); + close(fs_fds[0]); + imsg_init(&network_ibuf, net_fds[1]); + exit(client_main(&network_ibuf)); + default: + close(net_fds[1]); + imsg_init(&network_ibuf, net_fds[0]); + netibuf = &network_ibuf; + } + setproctitle("(%d) ui", pid); + TAILQ_INIT(&tabshead); event_init(); - event_set(&imsgev, netibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, netibuf); - event_add(&imsgev, NULL); + event_set(&netev, netibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, netibuf); + event_add(&netev, NULL); + event_set(&fsev, fsibuf->fd, EV_READ | EV_PERSIST, dispatch_imsg, fsibuf); + event_add(&fsev, NULL); + ui_init(); sandbox_ui_process(); @@ -396,6 +421,9 @@ main(void) imsg_compose(netibuf, IMSG_QUIT, 0, 0, -1, NULL, 0); imsg_flush(netibuf); + imsg_compose(fsibuf, IMSG_QUIT, 0, 0, -1, NULL, 0); + imsg_flush(fsibuf); + ui_end(); return 0; blob - 382a95116c89beb11b4d9a2975dbe37d594463e4 blob + dbbcaa9440b78c25e03f3b714416d3349db6abcb --- telescope.h +++ telescope.h @@ -29,6 +29,7 @@ #define GEMINI_URL_LEN 1024 enum imsg_type { + /* ui <-> client */ IMSG_GET, /* data is URL, peerid the tab id */ IMSG_ERR, IMSG_CHECK_CERT, @@ -158,10 +159,11 @@ struct keymap { TAILQ_ENTRY(keymap) keymaps; }; -extern struct event imsgev; +/* fs.c */ +int fs_main(struct imsgbuf*); /* gemini.c */ -int client_main(struct imsgbuf *b); +int client_main(struct imsgbuf*); /* gemtext.c */ void gemtext_initparser(struct parser*); @@ -194,6 +196,7 @@ int parser_set_buf(struct parser*, const char*, size /* sandbox.c */ void sandbox_network_process(void); void sandbox_ui_process(void); +void sandbox_fs_process(void); /* telescope.c */ void load_about_url(struct tab*, const char*);