Download raw body.
gotwebd: get rid of proc.[ch]
proc.c really shines when there's a net of different kinds of processes with potentially many instances that needs to talk. gotwebd instead is just a main process for the privileged operations plus a bunch of unpriviled workers. using proc.c here only really caused some headaces, so here's a proposal to remove it. it needs some testing, but some preliminary testing locally promises good :) There's something regarding the verbose logging that I still need to figure out exactly, but otherwise seems to be working just as before. There are now two main routines that I expect will be used to send messages: - main_compose_sockets(): send an imsg (with optional fd) to the sockets processes. The file descriptor is dup'ed as needed. This alone semplifies most of the loops in config.c - sockets_compose_main(): to send messages the other ways. There is no iov variant since we don't need them so far, will be easy to add eventually. The imsgev structs now live in the main gotwebd struct. The parent allocates enough entries for the children it needs to run, while each child only initialize one to talk with the parent. Maybe my hands slipped and there's more fixing that strictly needed... I've omitted `got rm proc.[ch]' to keep the diff short, but I intend to do so before committing. diff /home/op/w/got commit - 5abbba2d467df0d641100b74fbe24428fbb1c2c6 path + /home/op/w/got blob - 8a18107cdc7ef357964ae5a8c38a6e1205874e12 file + gotwebd/Makefile --- gotwebd/Makefile +++ gotwebd/Makefile @@ -7,7 +7,7 @@ SUBDIR = libexec .include "Makefile.inc" PROG = gotwebd -SRCS = config.c sockets.c log.c gotwebd.c parse.y proc.c \ +SRCS = config.c sockets.c log.c gotwebd.c parse.y \ fcgi.c gotweb.c got_operations.c tmpl.c pages.c SRCS += blame.c commit_graph.c delta.c diff.c \ diffreg.c error.c object.c object_cache.c \ blob - 1c8057cb99a030e7a3b45871f35124b82101e918 file + gotwebd/config.c --- gotwebd/config.c +++ gotwebd/config.c @@ -39,31 +39,18 @@ #include "got_opentemp.h" #include "got_reference.h" -#include "proc.h" #include "gotwebd.h" int config_init(struct gotwebd *env) { - struct privsep *ps = env->gotwebd_ps; - unsigned int what; - strlcpy(env->httpd_chroot, D_HTTPD_CHROOT, sizeof(env->httpd_chroot)); - /* Global configuration. */ - if (privsep_process == PROC_GOTWEBD) - env->prefork_gotwebd = GOTWEBD_NUMPROC; + env->prefork_gotwebd = GOTWEBD_NUMPROC; + env->server_cnt = 0; + TAILQ_INIT(&env->servers); + TAILQ_INIT(&env->sockets); - ps->ps_what[PROC_GOTWEBD] = CONFIG_ALL; - ps->ps_what[PROC_SOCKS] = CONFIG_SOCKS; - - /* Other configuration. */ - what = ps->ps_what[privsep_process]; - if (what & CONFIG_SOCKS) { - env->server_cnt = 0; - TAILQ_INIT(&env->servers); - TAILQ_INIT(&env->sockets); - } return 0; } @@ -71,23 +58,17 @@ int config_getcfg(struct gotwebd *env, struct imsg *imsg) { /* nothing to do but tell gotwebd configuration is done */ - if (privsep_process != PROC_GOTWEBD) - proc_compose(env->gotwebd_ps, PROC_GOTWEBD, - IMSG_CFG_DONE, NULL, 0); - + if (sockets_compose_main(env, IMSG_CFG_DONE, NULL, 0) == -1) + fatal("sockets_compose_main IMSG_CFG_DONE"); return 0; } int config_setserver(struct gotwebd *env, struct server *srv) { - struct server ssrv; - struct privsep *ps = env->gotwebd_ps; - - memcpy(&ssrv, srv, sizeof(ssrv)); - if (proc_compose(ps, PROC_SOCKS, IMSG_CFG_SRV, &ssrv, sizeof(ssrv)) + if (main_compose_sockets(env, IMSG_CFG_SRV, -1, srv, sizeof(*srv)) == -1) - fatal("proc_compose"); + fatal("main_compose_sockets IMSG_CFG_SRV"); return 0; } @@ -97,17 +78,11 @@ config_getserver(struct gotwebd *env, struct imsg *ims struct server *srv; uint8_t *p = imsg->data; - IMSG_SIZE_CHECK(imsg, &srv); - srv = calloc(1, sizeof(*srv)); if (srv == NULL) fatalx("%s: calloc", __func__); - if (IMSG_DATA_SIZE(imsg) != sizeof(*srv)) { - log_debug("%s: imsg size error", __func__); - free(srv); - return 1; - } + IMSG_SIZE_CHECK(imsg, srv); memcpy(srv, p, sizeof(*srv)); srv->cached_repos = calloc(GOTWEBD_REPO_CACHESIZE, @@ -129,62 +104,15 @@ config_getserver(struct gotwebd *env, struct imsg *ims int config_setsock(struct gotwebd *env, struct socket *sock) { - struct privsep *ps = env->gotwebd_ps; - struct socket_conf s; - int id; - int fd = -1, n, m; - struct iovec iov[6]; - size_t c; - unsigned int what; - /* open listening sockets */ if (sockets_privinit(env, sock) == -1) return -1; - for (id = 0; id < PROC_MAX; id++) { - what = ps->ps_what[id]; + if (main_compose_sockets(env, IMSG_CFG_SOCK, sock->fd, + &sock->conf, sizeof(sock->conf)) == -1) + fatal("main_compose_sockets IMSG_CFG_SOCK"); - if ((what & CONFIG_SOCKS) == 0 || id == privsep_process) - continue; - - memcpy(&s, &sock->conf, sizeof(s)); - - c = 0; - iov[c].iov_base = &s; - iov[c++].iov_len = sizeof(s); - - if (id == PROC_SOCKS) { - /* XXX imsg code will close the fd after 1st call */ - n = -1; - proc_range(ps, id, &n, &m); - for (n = 0; n < m; n++) { - if (sock->fd == -1) - fd = -1; - else if ((fd = dup(sock->fd)) == -1) - return 1; - if (proc_composev_imsg(ps, id, n, IMSG_CFG_SOCK, - -1, fd, iov, c) != 0) { - log_warn("%s: failed to compose " - "IMSG_CFG_SOCK imsg", - __func__); - return 1; - } - if (proc_flush_imsg(ps, id, n) == -1) { - log_warn("%s: failed to flush " - "IMSG_CFG_SOCK imsg", - __func__); - return 1; - } - } - } - } - - /* Close socket early to prevent fd exhaustion in gotwebd. */ - if (sock->fd != -1) { - close(sock->fd); - sock->fd = -1; - } - + sock->fd = -1; return 0; } @@ -237,60 +165,20 @@ config_getsock(struct gotwebd *env, struct imsg *imsg) int config_setfd(struct gotwebd *env, struct socket *sock) { - struct privsep *ps = env->gotwebd_ps; - int id, s; - int fd = -1, n, m, j; - struct iovec iov[6]; - size_t c; - unsigned int what; + int i, fd; log_debug("%s: Allocating %d file descriptors", __func__, PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES); - for (j = 0; j < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; j++) { - for (id = 0; id < PROC_MAX; id++) { - what = ps->ps_what[id]; - - if ((what & CONFIG_SOCKS) == 0 || id == privsep_process) - continue; - - s = sock->conf.id; - c = 0; - iov[c].iov_base = &s; - iov[c++].iov_len = sizeof(s); - - if (id == PROC_SOCKS) { - /* - * XXX imsg code will close the fd - * after 1st call - */ - n = -1; - proc_range(ps, id, &n, &m); - for (n = 0; n < m; n++) { - fd = got_opentempfd(); - if (fd == -1) - return 1; - if (proc_composev_imsg(ps, id, n, - IMSG_CFG_FD, -1, fd, iov, c) != 0) { - log_warn("%s: failed to compose " - "IMSG_CFG_FD imsg", - __func__); - return 1; - } - if (proc_flush_imsg(ps, id, n) == -1) { - log_warn("%s: failed to flush " - "IMSG_CFG_FD imsg", - __func__); - return 1; - } - } - } - } - - /* Close fd early to prevent fd exhaustion in gotwebd. */ - if (fd != -1) - close(fd); + for (i = 0; i < PRIV_FDS__MAX + GOTWEB_PACK_NUM_TEMPFILES; i++) { + fd = got_opentempfd(); + if (fd == -1) + fatal("got_opentemp"); + if (main_compose_sockets(env, IMSG_CFG_FD, fd, + &sock->conf.id, sizeof(sock->conf.id)) == -1) + fatal("main_compose_sockets IMSG_CFG_FD"); } + return 0; } blob - b6905f7fda842f60988300371ff61ab63db68a4c file + gotwebd/fcgi.c --- gotwebd/fcgi.c +++ gotwebd/fcgi.c @@ -35,7 +35,6 @@ #include "got_error.h" #include "got_reference.h" -#include "proc.h" #include "gotwebd.h" #include "tmpl.h" blob - 6d9d5cf8b5507c4d545eca925df5fe128789c73a file + gotwebd/got_operations.c --- gotwebd/got_operations.c +++ gotwebd/got_operations.c @@ -39,7 +39,6 @@ #include "got_blame.h" #include "got_privsep.h" -#include "proc.h" #include "gotwebd.h" static const struct got_error *got_init_repo_commit(struct repo_commit **); blob - 5d1283460327c8a36e76c5f8ed29b5fd573a5ce8 file + gotwebd/gotweb.c --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -49,7 +49,6 @@ #include "got_blame.h" #include "got_privsep.h" -#include "proc.h" #include "gotwebd.h" #include "tmpl.h" blob - 9b7b6853658f6996141e0355f9a0a6f08fca0c7c file + gotwebd/gotwebd.c --- gotwebd/gotwebd.c +++ gotwebd/gotwebd.c @@ -42,7 +42,6 @@ #include "got_opentemp.h" #include "got_reference.h" -#include "proc.h" #include "gotwebd.h" __dead void usage(void); @@ -52,40 +51,138 @@ int gotwebd_configure(struct gotwebd *); void gotwebd_configure_done(struct gotwebd *); void gotwebd_sighdlr(int sig, short event, void *arg); void gotwebd_shutdown(void); -int gotwebd_dispatch_sockets(int, struct privsep_proc *, struct imsg *); +void gotwebd_dispatch_sockets(int, short, void *); struct gotwebd *gotwebd_env; -static struct privsep_proc procs[] = { - { "sockets", PROC_SOCKS, gotwebd_dispatch_sockets, sockets, - sockets_shutdown }, -}; +void +imsg_event_add(struct imsgev *iev) +{ + if (iev->handler == NULL) { + imsg_flush(&iev->ibuf); + return; + } + iev->events = EV_READ; + if (iev->ibuf.w.queued) + iev->events |= EV_WRITE; + + event_del(&iev->ev); + event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); + event_add(&iev->ev, NULL); +} + int -gotwebd_dispatch_sockets(int fd, struct privsep_proc *p, struct imsg *imsg) +imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, + pid_t pid, int fd, const void *data, uint16_t datalen) { - struct privsep *ps = p->p_ps; - struct gotwebd *env = ps->ps_env; + int ret; - switch (imsg->hdr.type) { - case IMSG_CFG_DONE: - gotwebd_configure_done(env); - break; - default: - return (-1); + ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen); + if (ret == -1) + return (ret); + imsg_event_add(iev); + return (ret); +} + +int +main_compose_sockets(struct gotwebd *env, uint32_t type, int fd, + const void *data, uint16_t len) +{ + size_t i; + int ret, d; + + for (i = 0; i < env->nserver; ++i) { + d = -1; + if (fd != -1 && (d = dup(fd)) == -1) + return (-1); + + ret = imsg_compose_event(&env->iev_server[i], type, 0, -1, + d, data, len); + if (ret == -1) + return (-1); + + /* prevent fd exhaustion */ + if (d != -1) { + do { + ret = imsg_flush(&env->iev_server[i].ibuf); + } while (ret == -1 && errno == EAGAIN); + if (ret == -1) + return (-1); + imsg_event_add(&env->iev_server[i]); + } } - return (0); + if (fd != -1) + close(fd); + + return 0; } +int +sockets_compose_main(struct gotwebd *env, uint32_t type, const void *d, + uint16_t len) +{ + return (imsg_compose_event(env->iev_parent, type, 0, -1, -1, d, len)); +} + void +gotwebd_dispatch_sockets(int fd, short event, void *arg) +{ + struct imsgev *iev = arg; + struct imsgbuf *ibuf; + struct imsg imsg; + struct gotwebd *env = gotwebd_env; + ssize_t n; + int shut = 0; + + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed */ + shut = 1; + } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed */ + shut = 1; + } + + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_CFG_DONE: + gotwebd_configure_done(env); + break; + default: + fatalx("%s: unknown imsg type %d", __func__, + imsg.hdr.type); + } + + imsg_free(&imsg); + } + + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler */ + event_del(&iev->ev); + event_loopexit(NULL); + } +} + +void gotwebd_sighdlr(int sig, short event, void *arg) { /* struct privsep *ps = arg; */ - if (privsep_process != PROC_GOTWEBD) - return; - switch (sig) { case SIGHUP: log_info("%s: ignoring SIGHUP", __func__); @@ -105,6 +202,52 @@ gotwebd_sighdlr(int sig, short event, void *arg) } } +static int +spawn_socket_process(struct gotwebd *env, const char *argv0, int n) +{ + const char *argv[5]; + int argc = 0; + int p[2]; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) == -1) + fatal("socketpair"); + + switch (pid = fork()) { + case -1: + fatal("fork"); + case 0: /* child */ + break; + default: /* parent */ + close(p[0]); + imsg_init(&env->iev_server[n].ibuf, p[1]); + env->iev_server[n].handler = gotwebd_dispatch_sockets; + env->iev_server[n].data = &env->iev_server[n]; + event_set(&env->iev_server[n].ev, p[1], EV_READ, + gotwebd_dispatch_sockets, &env->iev_server[n]); + event_add(&env->iev_server[n].ev, NULL); + return 0; + } + + close(p[1]); + + argv[argc++] = argv0; + argv[argc++] = "-S"; + if (env->gotwebd_verbose) + argv[argc++] = "-v"; + argv[argc] = NULL; + + if (p[0] != 3) { + if (dup2(p[0], 3) == -1) + fatal("dup2"); + } else if (fcntl(p[0], F_SETFD, 0) == -1) + fatal("fcntl"); + + /* obnoxious cast */ + execvp(argv0, (char * const *)argv); + fatal("execvp %s", argv0); +} + __dead void usage(void) { @@ -116,25 +259,27 @@ usage(void) int main(int argc, char **argv) { - struct gotwebd *env; - struct privsep *ps; - unsigned int proc; - int ch; - const char *conffile = GOTWEBD_CONF; - enum privsep_procid proc_id = PROC_GOTWEBD; - int proc_instance = 0; - const char *errp, *title = NULL; - int argc0 = argc; + struct event sigint, sigterm, sighup, sigpipe, sigusr1; + struct gotwebd *env; + struct passwd *pw; + int ch, i; + int no_action = 0; + int server_proc = 0; + const char *conffile = GOTWEBD_CONF; + const char *argv0; + if ((argv0 = argv[0]) == NULL) + argv0 = "gotwebd"; + env = calloc(1, sizeof(*env)); if (env == NULL) fatal("%s: calloc", __func__); + config_init(env); /* log to stderr until daemonized */ log_init(1, LOG_DAEMON); - /* XXX: add s and S for both sockets */ - while ((ch = getopt(argc, argv, "D:df:I:nP:v")) != -1) { + while ((ch = getopt(argc, argv, "D:df:nSv")) != -1) { switch (ch) { case 'D': if (cmdline_symset(optarg) < 0) @@ -142,26 +287,16 @@ main(int argc, char **argv) optarg); break; case 'd': - env->gotwebd_debug = 2; + env->gotwebd_debug = 1; break; case 'f': conffile = optarg; break; - case 'I': - proc_instance = strtonum(optarg, 0, - PROC_MAX_INSTANCES, &errp); - if (errp) - fatalx("invalid process instance"); - break; case 'n': - env->gotwebd_debug = 2; - env->gotwebd_noaction = 1; + no_action = 1; break; - case 'P': - title = optarg; - proc_id = proc_getid(procs, nitems(procs), title); - if (proc_id == PROC_MAX) - fatalx("invalid process name"); + case 'S': + server_proc = 1; break; case 'v': env->gotwebd_verbose++; @@ -175,72 +310,77 @@ main(int argc, char **argv) if (argc > 0) usage(); - ps = calloc(1, sizeof(*ps)); - if (ps == NULL) - fatal("%s: calloc:", __func__); - gotwebd_env = env; - env->gotwebd_ps = ps; - ps->ps_env = env; env->gotwebd_conffile = conffile; if (parse_config(env->gotwebd_conffile, env) == -1) exit(1); - if (env->gotwebd_noaction && !env->gotwebd_debug) - env->gotwebd_debug = 1; + if (no_action) { + fprintf(stderr, "configuration OK\n"); + exit(0); + } /* check for root privileges */ - if (env->gotwebd_noaction == 0) { - if (geteuid()) - fatalx("need root privileges"); - } + if (geteuid()) + fatalx("need root privileges"); - ps->ps_pw = getpwnam(GOTWEBD_USER); - if (ps->ps_pw == NULL) + pw = getpwnam(GOTWEBD_USER); + if (pw == NULL) fatalx("unknown user %s", GOTWEBD_USER); + env->pw = pw; + if (server_proc) { + setproctitle("sockets"); + log_procinit("sockets"); + + if (chroot(pw->pw_dir) == -1) + fatal("chroot %s", pw->pw_dir); + if (chdir("/") == -1) + fatal("chdir /"); + if (setgroups(1, &pw->pw_gid) == -1 || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) + fatal("failed to drop privileges"); + + sockets(env, 3); + return 1; + } + log_init(env->gotwebd_debug, LOG_DAEMON); log_setverbose(env->gotwebd_verbose); - if (env->gotwebd_noaction) - ps->ps_noaction = 1; + if (!env->gotwebd_debug && daemon(1, 0) == -1) + fatal("daemon"); - ps->ps_instances[PROC_SOCKS] = env->prefork_gotwebd; - ps->ps_instance = proc_instance; - if (title != NULL) - ps->ps_title[proc_id] = title; - - for (proc = 0; proc < nitems(procs); proc++) - procs[proc].p_chroot = env->httpd_chroot; - - /* only the gotwebd returns */ - proc_init(ps, procs, nitems(procs), argc0, argv, proc_id); - - log_procinit("gotwebd"); - if (!env->gotwebd_debug && daemon(0, 0) == -1) - fatal("can't daemonize"); - - if (ps->ps_noaction == 0) - log_info("%s startup", getprogname()); - event_init(); - signal_set(&ps->ps_evsigint, SIGINT, gotwebd_sighdlr, ps); - signal_set(&ps->ps_evsigterm, SIGTERM, gotwebd_sighdlr, ps); - signal_set(&ps->ps_evsighup, SIGHUP, gotwebd_sighdlr, ps); - signal_set(&ps->ps_evsigpipe, SIGPIPE, gotwebd_sighdlr, ps); - signal_set(&ps->ps_evsigusr1, SIGUSR1, gotwebd_sighdlr, ps); + env->nserver = env->prefork_gotwebd; + env->iev_server = calloc(env->nserver, sizeof(*env->iev_server)); + if (env->iev_server == NULL) + fatal("calloc"); - signal_add(&ps->ps_evsigint, NULL); - signal_add(&ps->ps_evsigterm, NULL); - signal_add(&ps->ps_evsighup, NULL); - signal_add(&ps->ps_evsigpipe, NULL); - signal_add(&ps->ps_evsigusr1, NULL); + for (i = 0; i < env->nserver; ++i) { + if (spawn_socket_process(env, argv0, i) == -1) + fatal("spawn_socket_process"); + } - if (!env->gotwebd_noaction) - proc_connect(ps); + log_procinit("gotwebd"); + log_info("%s startup", getprogname()); + + signal_set(&sigint, SIGINT, gotwebd_sighdlr, env); + signal_set(&sigterm, SIGTERM, gotwebd_sighdlr, env); + signal_set(&sighup, SIGHUP, gotwebd_sighdlr, env); + signal_set(&sigpipe, SIGPIPE, gotwebd_sighdlr, env); + signal_set(&sigusr1, SIGUSR1, gotwebd_sighdlr, env); + + signal_add(&sigint, NULL); + signal_add(&sigterm, NULL); + signal_add(&sighup, NULL); + signal_add(&sigpipe, NULL); + signal_add(&sigusr1, NULL); + if (gotwebd_configure(env) == -1) fatalx("configuration failed"); @@ -275,14 +415,7 @@ gotwebd_configure(struct gotwebd *env) { struct server *srv; struct socket *sock; - int id; - if (env->gotwebd_noaction) { - fprintf(stderr, "configuration OK\n"); - proc_kill(env->gotwebd_ps); - exit(0); - } - /* gotweb need to reload its config. */ env->gotwebd_reload = env->prefork_gotwebd; @@ -300,11 +433,8 @@ gotwebd_configure(struct gotwebd *env) fatalx("%s: send priv_fd error", __func__); } - for (id = 0; id < PROC_MAX; id++) { - if (id == privsep_process) - continue; - proc_compose(env->gotwebd_ps, id, IMSG_CFG_DONE, NULL, 0); - } + if (main_compose_sockets(env, IMSG_CFG_DONE, -1, NULL, 0) == -1) + fatal("main_compose_sockets IMSG_CFG_DONE"); return (0); } @@ -312,31 +442,44 @@ gotwebd_configure(struct gotwebd *env) void gotwebd_configure_done(struct gotwebd *env) { - int id; - if (env->gotwebd_reload == 0) { log_warnx("%s: configuration already finished", __func__); return; } env->gotwebd_reload--; - if (env->gotwebd_reload == 0) { - for (id = 0; id < PROC_MAX; id++) { - if (id == privsep_process) - continue; - proc_compose(env->gotwebd_ps, id, IMSG_CTL_START, - NULL, 0); - } - } + if (env->gotwebd_reload == 0 && + main_compose_sockets(env, IMSG_CTL_START, -1, NULL, 0) == -1) + fatal("main_compose_sockets IMSG_CTL_START"); } void gotwebd_shutdown(void) { - proc_kill(gotwebd_env->gotwebd_ps); + struct gotwebd *env = gotwebd_env; + pid_t pid; + int i, status; - /* unlink(gotwebd_env->gotweb->gotweb_conf.gotweb_unix_socket_name); */ - /* free(gotwebd_env->gotweb); */ + for (i = 0; i < env->nserver; ++i) { + event_del(&env->iev_server[i].ev); + imsg_clear(&env->iev_server[i].ibuf); + close(env->iev_server[i].ibuf.fd); + env->iev_server[i].ibuf.fd = -1; + } + + do { + pid = waitpid(WAIT_ANY, &status, 0); + if (pid <= 0) + continue; + + if (WIFSIGNALED(status)) + log_warnx("lost child: pid %u terminated; signal %d", + pid, WTERMSIG(status)); + else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) + log_warnx("lost child: pid %u exited abnormally", + pid); + } while (pid != -1 || (pid == -1 && errno == EINTR)); + free(gotwebd_env); log_warnx("gotwebd terminating"); blob - 44293b62e594c517072cd3268cb34949d7393bd0 file + gotwebd/gotwebd.h --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -49,6 +49,8 @@ #define GOTWEBD_NUMPROC 3 #define GOTWEBD_REPO_CACHESIZE 4 +#define PROC_MAX_INSTANCES 32 + /* GOTWEB DEFAULTS */ #define MAX_QUERYSTRING 2048 #define MAX_DOCUMENT_URI 255 @@ -120,13 +122,28 @@ struct got_tree_entry; struct got_reflist_head; enum imsg_type { - IMSG_CFG_SRV = IMSG_PROC_MAX, + IMSG_CFG_SRV, IMSG_CFG_SOCK, IMSG_CFG_FD, IMSG_CFG_DONE, IMSG_CTL_START, }; +struct imsgev { + struct imsgbuf ibuf; + void (*handler)(int, short, void *); + struct event ev; + void *data; + short events; +}; + +#define IMSG_SIZE_CHECK(imsg, p) do { \ + if (IMSG_DATA_SIZE(imsg) < sizeof(*p)) \ + fatalx("bad length imsg received (%s)", #p); \ +} while (0) + +#define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE) + struct env_val { SLIST_ENTRY(env_val) entry; char *val; @@ -345,17 +362,22 @@ struct socket { }; TAILQ_HEAD(socketlist, socket); +struct passwd; struct gotwebd { struct serverlist servers; struct socketlist sockets; - struct privsep *gotwebd_ps; const char *gotwebd_conffile; int gotwebd_debug; int gotwebd_verbose; - int gotwebd_noaction; + struct imsgev *iev_parent; + struct imsgev *iev_server; + size_t nserver; + + struct passwd *pw; + uint16_t prefork_gotwebd; int gotwebd_reload; @@ -442,9 +464,17 @@ extern struct gotwebd *gotwebd_env; typedef int (*got_render_blame_line_cb)(struct template *, const char *, struct blame_line *, int, int); +/* gotwebd.c */ +void imsg_event_add(struct imsgev *); +int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, + pid_t, int, const void *, uint16_t); +int main_compose_sockets(struct gotwebd *, uint32_t, int, + const void *, uint16_t); +int sockets_compose_main(struct gotwebd *, uint32_t, + const void *, uint16_t); + /* sockets.c */ -void sockets(struct privsep *, struct privsep_proc *); -void sockets_shutdown(void); +void sockets(struct gotwebd *, int); void sockets_parse_sockets(struct gotwebd *); void sockets_socket_accept(int, short, void *); int sockets_privinit(struct gotwebd *, struct socket *); @@ -519,3 +549,25 @@ int config_setfd(struct gotwebd *, struct socket *); int config_getfd(struct gotwebd *, struct imsg *); int config_getcfg(struct gotwebd *, struct imsg *); int config_init(struct gotwebd *); + +/* log.c */ +void log_init(int, int); +void log_procinit(const char *); +void log_setverbose(int); +int log_getverbose(void); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +__dead void fatal(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +__dead void fatalx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); blob - a51f74abb8dfc67479ed3558a8c7efd83400e068 file + gotwebd/pages.tmpl --- gotwebd/pages.tmpl +++ gotwebd/pages.tmpl @@ -34,8 +34,6 @@ #include "got_object.h" #include "got_reference.h" -#include "proc.h" - #include "gotwebd.h" #include "tmpl.h" blob - b02dbb86b14c946386f468402580e3119a1f1e61 file + gotwebd/parse.y --- gotwebd/parse.y +++ gotwebd/parse.y @@ -49,7 +49,6 @@ #include "got_reference.h" -#include "proc.h" #include "gotwebd.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); blob - 16a74076b94ffabf45821936ff713dacb0e1dff0 file + gotwebd/sockets.c --- gotwebd/sockets.c +++ gotwebd/sockets.c @@ -55,28 +55,25 @@ #include "got_repository.h" #include "got_privsep.h" -#include "proc.h" #include "gotwebd.h" #include "tmpl.h" #define SOCKS_BACKLOG 5 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) - volatile int client_cnt; static struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; static void sockets_sighdlr(int, short, void *); -static void sockets_run(struct privsep *, struct privsep_proc *, void *); +static void sockets_shutdown(void); static void sockets_launch(void); static void sockets_purge(struct gotwebd *); static void sockets_accept_paused(int, short, void *); static void sockets_rlimit(int); -static int sockets_dispatch_gotwebd(int, struct privsep_proc *, - struct imsg *); -static int sockets_unix_socket_listen(struct privsep *, struct socket *); +static void sockets_dispatch_main(int, short, void *); +static int sockets_unix_socket_listen(struct gotwebd *, struct socket *); static int sockets_create_socket(struct address *); static int sockets_accept_reserve(int, struct sockaddr *, socklen_t *, int, volatile int *); @@ -88,35 +85,44 @@ static struct socket *sockets_conf_new_socket_fcgi(str int cgi_inflight = 0; -static struct privsep_proc procs[] = { - { "gotwebd", PROC_GOTWEBD, sockets_dispatch_gotwebd }, -}; - void -sockets(struct privsep *ps, struct privsep_proc *p) +sockets(struct gotwebd *env, int fd) { - proc_run(ps, p, procs, nitems(procs), sockets_run, NULL); -} + struct event sighup, sigpipe, sigusr1, sigchld; -static void -sockets_run(struct privsep *ps, struct privsep_proc *p, void *arg) -{ - if (config_init(ps->ps_env) == -1) - fatal("failed to initialize configuration"); + event_init(); - p->p_shutdown = sockets_shutdown; - sockets_rlimit(-1); - signal_del(&ps->ps_evsigchld); - signal_set(&ps->ps_evsigchld, SIGCHLD, sockets_sighdlr, ps); - signal_add(&ps->ps_evsigchld, NULL); + if (config_init(env) == -1) + fatal("failed to initialize configuration"); + if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL) + fatal("malloc"); + imsg_init(&env->iev_parent->ibuf, fd); + env->iev_parent->handler = sockets_dispatch_main; + env->iev_parent->data = env->iev_parent; + event_set(&env->iev_parent->ev, fd, EV_READ, sockets_dispatch_main, + env->iev_parent); + event_add(&env->iev_parent->ev, NULL); + + signal_set(&sighup, SIGCHLD, sockets_sighdlr, env); + signal_add(&sighup, NULL); + signal_set(&sigpipe, SIGCHLD, sockets_sighdlr, env); + signal_add(&sigpipe, NULL); + signal_set(&sigusr1, SIGCHLD, sockets_sighdlr, env); + signal_add(&sigusr1, NULL); + signal_set(&sigchld, SIGCHLD, sockets_sighdlr, env); + signal_add(&sigchld, NULL); + #ifndef PROFILE if (pledge("stdio rpath inet recvfd proc exec sendfd unveil", NULL) == -1) fatal("pledge"); #endif + + event_dispatch(); + sockets_shutdown(); } void @@ -301,48 +307,68 @@ sockets_purge(struct gotwebd *env) } } -static int -sockets_dispatch_gotwebd(int fd, struct privsep_proc *p, struct imsg *imsg) +static void +sockets_dispatch_main(int fd, short event, void *arg) { - struct privsep *ps = p->p_ps; - int res = 0, cmd = 0, verbose; + struct imsgev *iev = arg; + struct imsgbuf *ibuf; + struct imsg imsg; + struct gotwebd *env = gotwebd_env; + ssize_t n; + int shut = 0; - switch (imsg->hdr.type) { - case IMSG_CFG_SRV: - config_getserver(gotwebd_env, imsg); - break; - case IMSG_CFG_SOCK: - config_getsock(gotwebd_env, imsg); - break; - case IMSG_CFG_FD: - config_getfd(gotwebd_env, imsg); - break; - case IMSG_CFG_DONE: - config_getcfg(gotwebd_env, imsg); - break; - case IMSG_CTL_START: - sockets_launch(); - break; - case IMSG_CTL_VERBOSE: - IMSG_SIZE_CHECK(imsg, &verbose); - memcpy(&verbose, imsg->data, sizeof(verbose)); - log_setverbose(verbose); - break; - default: - return -1; + ibuf = &iev->ibuf; + + if (event & EV_READ) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* Connection closed */ + shut = 1; } + if (event & EV_WRITE) { + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) /* Connection closed */ + shut = 1; + } - switch (cmd) { - case 0: - break; - default: - if (proc_compose_imsg(ps, PROC_GOTWEBD, -1, cmd, - imsg->hdr.peerid, -1, &res, sizeof(res)) == -1) - return -1; - break; + for (;;) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) /* No more messages. */ + break; + + switch (imsg.hdr.type) { + case IMSG_CFG_SRV: + config_getserver(env, &imsg); + break; + case IMSG_CFG_SOCK: + config_getsock(env, &imsg); + break; + case IMSG_CFG_FD: + config_getfd(env, &imsg); + break; + case IMSG_CFG_DONE: + config_getcfg(env, &imsg); + break; + case IMSG_CTL_START: + sockets_launch(); + break; + default: + fatalx("%s: unknown imsg type %d", __func__, + imsg.hdr.type); + } + + imsg_free(&imsg); } - return 0; + if (!shut) + imsg_event_add(iev); + else { + /* This pipe is dead. Remove its event handler */ + event_del(&iev->ev); + event_loopexit(NULL); + } } static void @@ -366,7 +392,7 @@ sockets_sighdlr(int sig, short event, void *arg) } } -void +static void sockets_shutdown(void) { struct server *srv, *tsrv; @@ -395,12 +421,10 @@ sockets_shutdown(void) int sockets_privinit(struct gotwebd *env, struct socket *sock) { - struct privsep *ps = env->gotwebd_ps; - if (sock->conf.af_type == AF_UNIX) { log_debug("%s: initializing unix socket %s", __func__, sock->conf.unix_socket_name); - sock->fd = sockets_unix_socket_listen(ps, sock); + sock->fd = sockets_unix_socket_listen(env, sock); if (sock->fd == -1) { log_warnx("%s: create unix socket failed", __func__); return -1; @@ -422,9 +446,8 @@ sockets_privinit(struct gotwebd *env, struct socket *s } static int -sockets_unix_socket_listen(struct privsep *ps, struct socket *sock) +sockets_unix_socket_listen(struct gotwebd *env, struct socket *sock) { - struct gotwebd *env = ps->ps_env; struct sockaddr_un sun; struct socket *tsock; int u_fd = -1; @@ -480,8 +503,8 @@ sockets_unix_socket_listen(struct privsep *ps, struct return -1; } - if (chown(sock->conf.unix_socket_name, ps->ps_pw->pw_uid, - ps->ps_pw->pw_gid) == -1) { + if (chown(sock->conf.unix_socket_name, env->pw->pw_uid, + env->pw->pw_gid) == -1) { log_warn("%s: chown", __func__); close(u_fd); (void)unlink(sock->conf.unix_socket_name);
gotwebd: get rid of proc.[ch]