Download raw body.
gotwebd: get rid of proc.[ch]
On 2023/11/15 18:42:14 +0100, Omar Polo <op@omarpolo.com> wrote:
> 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.
Found it. The logging handling in the child was wrong, plus in
log_debug() we log only if verbose > 1. Now, we don't do anything
special for the case verbose == 1 so I just 'lowered' log_debug() to one
-v.
> 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.
updated diff, this includes the fix to the daemon() call too.
diff 5abbba2d467df0d641100b74fbe24428fbb1c2c6 c85d8cd6af267cd4529f13315a1e00a416621d5f
commit - 5abbba2d467df0d641100b74fbe24428fbb1c2c6
commit + c85d8cd6af267cd4529f13315a1e00a416621d5f
blob - 8a18107cdc7ef357964ae5a8c38a6e1205874e12
blob + 258caeda8f63d90382ebfba64f426fcbc541a389
--- 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
blob + 775d88bd837ed1c57363aea14c95b1793c999afa
--- 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
blob + 202f1af662fe84b6759cc1a1c53efca43470da98
--- 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
blob + 45a8a36ea39f6f705bfc81c145d550389dd82872
--- 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
blob + 228d0e727516198db3aa33c2653f669ee179b8d6
--- 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
blob + 4017a8fd50fbe849af03accbf3ef5e16ba4eb232
--- 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,54 @@ 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_debug)
+ argv[argc++] = "-d";
+ 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 +261,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 +289,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 +312,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;
log_init(env->gotwebd_debug, LOG_DAEMON);
log_setverbose(env->gotwebd_verbose);
- if (env->gotwebd_noaction)
- ps->ps_noaction = 1;
+ if (server_proc) {
+ setproctitle("sockets");
+ log_procinit("sockets");
- ps->ps_instances[PROC_SOCKS] = env->prefork_gotwebd;
- ps->ps_instance = proc_instance;
- if (title != NULL)
- ps->ps_title[proc_id] = title;
+ 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");
- for (proc = 0; proc < nitems(procs); proc++)
- procs[proc].p_chroot = env->httpd_chroot;
+ sockets(env, 3);
+ return 1;
+ }
- /* 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");
+ fatal("daemon");
- 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 +417,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 +435,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 +444,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
blob + fd1c0c99231219c08e4fc5bf185228b9925892c3
--- 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 - 79d3d334581eddd8ffcc0f02f067e5c64d0be72e
blob + 73cbf47a766ba764769018c3e5833cb0414ed1f8
--- gotwebd/log.c
+++ gotwebd/log.c
@@ -164,7 +164,7 @@ log_debug(const char *emsg, ...)
{
va_list ap;
- if (verbose > 1) {
+ if (verbose) {
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
blob - a51f74abb8dfc67479ed3558a8c7efd83400e068
blob + d04e49122cc951bb2815072249af493a694624f3
--- 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
blob + 207d9f20026688bdc8849f0125e73b94a285504e
--- 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
blob + dd100773cb3593bb4f04e31d024acf711bdc912e
--- 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]