Commit Diff


commit - b38e9a2a1732c7dd3d16d76facf977f5a4c4a454
commit + f85c939fb7758c7cad91e0705b4d932d52597867
blob - 1941a98fb622f228478b023b38875d38fd7d1561
blob + 12a2092721ec726e20708168ee48877070cfdb78
--- gotwebd/config.c
+++ gotwebd/config.c
@@ -37,33 +37,18 @@
 #include "got_opentemp.h"
 #include "got_reference.h"
 
-#include "got_compat.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 +56,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 +76,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 +102,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 +163,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 - 3b66f82ce8ca320dfbef2bfe19db158e464eeb8c
blob + 1c77a0a03233522ae1e8b7a23dcb1a64ded98fae
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
@@ -37,7 +37,6 @@
 #include "got_error.h"
 #include "got_reference.h"
 
-#include "proc.h"
 #include "gotwebd.h"
 #include "tmpl.h"
 
blob - 39e6d570aff5f809ccc1326d4431dca03779b3bd
blob + 493b0eb04d060577b13e460e71c376ff81efcaf0
--- 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 - 57847f9088185127ba71f00e741f8b5daae32cad
blob + 7a9a9f0e03cad61e54c7ec8338638d8012926bd2
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
@@ -48,7 +48,6 @@
 #include "got_blame.h"
 #include "got_privsep.h"
 
-#include "proc.h"
 #include "gotwebd.h"
 #include "tmpl.h"
 
blob - c0282b4c4ed5c26df5081eae8ff8cd917d250ed5
blob + b498aeb95d0c3982fd3b2dca375879bbfff492d4
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
@@ -41,7 +41,6 @@
 #include "got_opentemp.h"
 #include "got_reference.h"
 
-#include "proc.h"
 #include "gotwebd.h"
 
 __dead void usage(void);
@@ -51,40 +50,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__);
@@ -104,6 +201,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)
 {
@@ -115,25 +260,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)
@@ -141,26 +288,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++;
@@ -174,72 +311,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");
 
@@ -274,14 +416,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;
 
@@ -299,11 +434,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);
 }
@@ -311,31 +443,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 - 8f6bd6f3682bf436854e307fec5f3f9ed867d144
blob + fd2973c33fb3621793863c961b07ab4fa811ba36
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -51,6 +51,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
@@ -122,13 +124,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;
@@ -347,17 +364,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;
 
@@ -441,10 +463,18 @@ 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 - 8ce3646dd57116eca048f4b956d3b256e3d67e15
blob + c807c4f7cbdcaa9a1474c2292bc855024fe49bae
--- gotwebd/log.c
+++ gotwebd/log.c
@@ -166,7 +166,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 - 6d8b3f89b8e9dced575cd6ef3e3d7ab58f60502d
blob + 5f47afc1244ea03fcd8d649bf7f9ea71e13cea9c
--- gotwebd/pages.tmpl
+++ gotwebd/pages.tmpl
@@ -33,8 +33,6 @@
 #include "got_error.h"
 #include "got_object.h"
 #include "got_reference.h"
-
-#include "proc.h"
 
 #include "gotwebd.h"
 #include "tmpl.h"
blob - f6d1bd31dc57cb3054504d3c510b96d61473e5a3
blob + 76826bfca0a204a99c8679cd0b3a965cf08b6f41
--- gotwebd/parse.y
+++ gotwebd/parse.y
@@ -50,7 +50,6 @@
 
 #include "got_reference.h"
 
-#include "proc.h"
 #include "gotwebd.h"
 
 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
blob - b1c287f143899db622e0faf4777c1a4baaadd4da (mode 644)
blob + /dev/null
--- gotwebd/proc.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
- *
- * 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 "got_compat.h"
-
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <pwd.h>
-#include <event.h>
-
-#include "proc.h"
-
-void	 proc_exec(struct privsep *, struct privsep_proc *, unsigned int,
-	    int, char **);
-void	 proc_setup(struct privsep *, struct privsep_proc *, unsigned int);
-void	 proc_open(struct privsep *, int, int);
-void	 proc_accept(struct privsep *, int, enum privsep_procid,
-	    unsigned int);
-void	 proc_close(struct privsep *);
-void	 proc_shutdown(struct privsep_proc *);
-void	 proc_sig_handler(int, short, void *);
-int	 proc_dispatch_null(int, struct privsep_proc *, struct imsg *);
-
-enum privsep_procid privsep_process;
-
-enum privsep_procid
-proc_getid(struct privsep_proc *procs, unsigned int nproc,
-    const char *proc_name)
-{
-	struct privsep_proc *p;
-	unsigned int proc;
-
-	for (proc = 0; proc < nproc; proc++) {
-		p = &procs[proc];
-		if (strcmp(p->p_title, proc_name))
-			continue;
-
-		return (p->p_id);
-	}
-
-	return (PROC_MAX);
-}
-
-void
-proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
-    int argc, char **argv)
-{
-	unsigned int proc, nargc, i, proc_i;
-	char **nargv;
-	struct privsep_proc *p;
-	char num[32];
-	int fd;
-
-	/* Prepare the new process argv. */
-	nargv = calloc(argc + 5, sizeof(char *));
-	if (nargv == NULL)
-		fatal("%s: calloc", __func__);
-
-	/* Copy call argument first. */
-	nargc = 0;
-	nargv[nargc++] = argv[0];
-
-	/* Set process name argument and save the position. */
-	nargv[nargc] = strdup("-P");
-	if (nargv[nargc] == NULL)
-		fatal("%s: strdup", __func__);
-	nargc++;
-	proc_i = nargc;
-	nargc++;
-
-	/* Point process instance arg to stack and copy the original args. */
-	nargv[nargc] = strdup("-I");
-	if (nargv[nargc] == NULL)
-		fatal("%s: strdup", __func__);
-	nargc++;
-	nargv[nargc++] = num;
-	for (i = 1; i < (unsigned int) argc; i++)
-		nargv[nargc++] = argv[i];
-
-	nargv[nargc] = NULL;
-
-	for (proc = 0; proc < nproc; proc++) {
-		p = &procs[proc];
-
-		/* Update args with process title. */
-		nargv[proc_i] = (char *)(uintptr_t)p->p_title;
-
-		/* Fire children processes. */
-		for (i = 0; i < ps->ps_instances[p->p_id]; i++) {
-			/* Update the process instance number. */
-			snprintf(num, sizeof(num), "%u", i);
-
-			fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_GOTWEBD][0];
-			ps->ps_pipes[p->p_id][i].pp_pipes[PROC_GOTWEBD][0] = -1;
-
-			switch (fork()) {
-			case -1:
-				fatal("%s: fork", __func__);
-				break;
-			case 0:
-				/* First create a new session */
-				if (setsid() == -1)
-					fatal("setsid");
-
-				/* Prepare parent socket. */
-				if (fd != PROC_GOTWEBD_SOCK_FILENO) {
-					if (dup2(fd, PROC_GOTWEBD_SOCK_FILENO)
-					    == -1)
-						fatal("dup2");
-				} else if (fcntl(fd, F_SETFD, 0) == -1)
-					fatal("fcntl");
-
-				execvp(argv[0], nargv);
-				fatal("%s: execvp", __func__);
-				break;
-			default:
-				/* Close child end. */
-				close(fd);
-				break;
-			}
-		}
-	}
-
-	free(nargv);
-}
-
-void
-proc_connect(struct privsep *ps)
-{
-	struct imsgev *iev;
-	unsigned int src, dst, inst;
-
-	/* Don't distribute any sockets if we are not really going to run. */
-	if (ps->ps_noaction)
-		return;
-
-	for (dst = 0; dst < PROC_MAX; dst++) {
-		/* We don't communicate with ourselves. */
-		if (dst == PROC_GOTWEBD)
-			continue;
-
-		for (inst = 0; inst < ps->ps_instances[dst]; inst++) {
-			iev = &ps->ps_ievs[dst][inst];
-			imsg_init(&iev->ibuf, ps->ps_pp->pp_pipes[dst][inst]);
-			event_set(&iev->ev, iev->ibuf.fd, iev->events,
-			    iev->handler, iev->data);
-			event_add(&iev->ev, NULL);
-		}
-	}
-
-	/* Distribute the socketpair()s for everyone. */
-	for (src = 0; src < PROC_MAX; src++)
-		for (dst = src; dst < PROC_MAX; dst++) {
-			/* Parent already distributed its fds. */
-			if (src == PROC_GOTWEBD || dst == PROC_GOTWEBD)
-				continue;
-
-			proc_open(ps, src, dst);
-		}
-}
-
-void
-proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
-    int argc, char **argv, enum privsep_procid proc_id)
-{
-	struct privsep_proc *p = NULL;
-	struct privsep_pipes *pa, *pb;
-	unsigned int proc;
-	unsigned int dst;
-	int fds[2];
-
-	/* Don't initiate anything if we are not really going to run. */
-	if (ps->ps_noaction)
-		return;
-
-	if (proc_id == PROC_GOTWEBD) {
-		privsep_process = PROC_GOTWEBD;
-		proc_setup(ps, procs, nproc);
-
-		/*
-		 * Create the children sockets so we can use them
-		 * to distribute the rest of the socketpair()s using
-		 * proc_connect() later.
-		 */
-		for (dst = 0; dst < PROC_MAX; dst++) {
-			/* Don't create socket for ourselves. */
-			if (dst == PROC_GOTWEBD)
-				continue;
-
-			for (proc = 0; proc < ps->ps_instances[dst]; proc++) {
-				pa = &ps->ps_pipes[PROC_GOTWEBD][0];
-				pb = &ps->ps_pipes[dst][proc];
-				int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
-#ifdef SOCK_CLOEXEC
-				sock_flags |= SOCK_CLOEXEC;
-#endif
-				if (socketpair(AF_UNIX, sock_flags,
-				    PF_UNSPEC, fds) == -1)
-					fatal("%s: socketpair", __func__);
-
-				pa->pp_pipes[dst][proc] = fds[0];
-				pb->pp_pipes[PROC_GOTWEBD][0] = fds[1];
-			}
-		}
-
-		/* Engage! */
-		proc_exec(ps, procs, nproc, argc, argv);
-		return;
-	}
-
-	/* Initialize a child */
-	for (proc = 0; proc < nproc; proc++) {
-		if (procs[proc].p_id != proc_id)
-			continue;
-		p = &procs[proc];
-		break;
-	}
-	if (p == NULL || p->p_init == NULL)
-		fatalx("%s: process %d missing process initialization",
-		    __func__, proc_id);
-
-	p->p_init(ps, p);
-
-	fatalx("failed to initiate child process");
-}
-
-void
-proc_accept(struct privsep *ps, int fd, enum privsep_procid dst,
-    unsigned int n)
-{
-	struct privsep_pipes *pp = ps->ps_pp;
-	struct imsgev *iev;
-
-	if (ps->ps_ievs[dst] == NULL) {
-#if DEBUG > 1
-		log_debug("%s: %s src %d %d to dst %d %d not connected",
-		    __func__, ps->ps_title[privsep_process],
-		    privsep_process, ps->ps_instance + 1,
-		    dst, n + 1);
-#endif
-		close(fd);
-		return;
-	}
-
-	if (pp->pp_pipes[dst][n] != -1) {
-		log_warnx("%s: duplicated descriptor", __func__);
-		close(fd);
-		return;
-	} else
-		pp->pp_pipes[dst][n] = fd;
-
-	iev = &ps->ps_ievs[dst][n];
-	imsg_init(&iev->ibuf, fd);
-	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
-	event_add(&iev->ev, NULL);
-}
-
-void
-proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc)
-{
-	unsigned int i, j, src, dst, id;
-	struct privsep_pipes *pp;
-
-	/* Initialize parent title, ps_instances and procs. */
-	ps->ps_title[PROC_GOTWEBD] = "parent";
-
-	for (src = 0; src < PROC_MAX; src++)
-		/* Default to 1 process instance */
-		if (ps->ps_instances[src] < 1)
-			ps->ps_instances[src] = 1;
-
-	for (src = 0; src < nproc; src++) {
-		procs[src].p_ps = ps;
-		if (procs[src].p_cb == NULL)
-			procs[src].p_cb = proc_dispatch_null;
-
-		id = procs[src].p_id;
-		ps->ps_title[id] = procs[src].p_title;
-		ps->ps_ievs[id] = calloc(ps->ps_instances[id],
-		    sizeof(struct imsgev));
-		if (ps->ps_ievs[id] == NULL)
-			fatal("%s: calloc", __func__);
-
-		/* With this set up, we are ready to call imsg_init(). */
-		for (i = 0; i < ps->ps_instances[id]; i++) {
-			ps->ps_ievs[id][i].handler = proc_dispatch;
-			ps->ps_ievs[id][i].events = EV_READ;
-			ps->ps_ievs[id][i].proc = &procs[src];
-			ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i];
-		}
-	}
-
-	/*
-	 * Allocate pipes for all process instances (incl. parent)
-	 *
-	 * - ps->ps_pipes: N:M mapping
-	 * N source processes connected to M destination processes:
-	 * [src][instances][dst][instances], for example
-	 * [PROC_RELAY][3][PROC_CA][3]
-	 *
-	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
-	 * Each process instance has a destination array of socketpair fds:
-	 * [dst][instances], for example
-	 * [PROC_GOTWEBD][0]
-	 */
-	for (src = 0; src < PROC_MAX; src++) {
-		/* Allocate destination array for each process */
-		ps->ps_pipes[src] = calloc(ps->ps_instances[src],
-		    sizeof(struct privsep_pipes));
-		if (ps->ps_pipes[src] == NULL)
-			fatal("%s: calloc", __func__);
-
-		for (i = 0; i < ps->ps_instances[src]; i++) {
-			pp = &ps->ps_pipes[src][i];
-
-			for (dst = 0; dst < PROC_MAX; dst++) {
-				/* Allocate maximum fd integers */
-				pp->pp_pipes[dst] =
-				    calloc(ps->ps_instances[dst],
-				    sizeof(int));
-				if (pp->pp_pipes[dst] == NULL)
-					fatal("%s: calloc", __func__);
-
-				/* Mark fd as unused */
-				for (j = 0; j < ps->ps_instances[dst]; j++)
-					pp->pp_pipes[dst][j] = -1;
-			}
-		}
-	}
-
-	ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance];
-}
-
-void
-proc_kill(struct privsep *ps)
-{
-	char *cause;
-	pid_t pid;
-	int len, status;
-
-	if (privsep_process != PROC_GOTWEBD)
-		return;
-
-	proc_close(ps);
-
-	do {
-		pid = waitpid(WAIT_ANY, &status, 0);
-		if (pid <= 0)
-			continue;
-
-		if (WIFSIGNALED(status)) {
-			len = asprintf(&cause, "terminated; signal %d",
-			    WTERMSIG(status));
-		} else if (WIFEXITED(status)) {
-			if (WEXITSTATUS(status) != 0)
-				len = asprintf(&cause, "exited abnormally");
-			else
-				len = 0;
-		} else
-			len = -1;
-
-		if (len == 0) {
-			/* child exited OK, don't print a warning message */
-		} else if (len != -1) {
-			log_warnx("lost child: pid %u %s", pid, cause);
-			free(cause);
-		} else
-			log_warnx("lost child: pid %u", pid);
-	} while (pid != -1 || (pid == -1 && errno == EINTR));
-}
-
-void
-proc_open(struct privsep *ps, int src, int dst)
-{
-	struct privsep_pipes *pa, *pb;
-	struct privsep_fd pf;
-	int fds[2];
-	unsigned int i, j;
-
-	/* Exchange pipes between process. */
-	for (i = 0; i < ps->ps_instances[src]; i++) {
-		for (j = 0; j < ps->ps_instances[dst]; j++) {
-			/* Don't create sockets for ourself. */
-			if (src == dst && i == j)
-				continue;
-
-			pa = &ps->ps_pipes[src][i];
-			pb = &ps->ps_pipes[dst][j];
-			int sock_flags = SOCK_STREAM | SOCK_NONBLOCK;
-#ifdef SOCK_CLOEXEC
-			sock_flags |= SOCK_CLOEXEC;
-#endif
-			if (socketpair(AF_UNIX, sock_flags,
-			    PF_UNSPEC, fds) == -1)
-				fatal("%s: socketpair", __func__);
-
-			pa->pp_pipes[dst][j] = fds[0];
-			pb->pp_pipes[src][i] = fds[1];
-
-			pf.pf_procid = src;
-			pf.pf_instance = i;
-			if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD,
-			    -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1)
-				fatal("%s: proc_compose_imsg", __func__);
-
-			pf.pf_procid = dst;
-			pf.pf_instance = j;
-			if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD,
-			    -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1)
-				fatal("%s: proc_compose_imsg", __func__);
-
-			/*
-			 * We have to flush to send the descriptors and close
-			 * them to avoid the fd ramp on startup.
-			 */
-			if (proc_flush_imsg(ps, src, i) == -1 ||
-			    proc_flush_imsg(ps, dst, j) == -1)
-				fatal("%s: imsg_flush", __func__);
-		}
-	}
-}
-
-void
-proc_close(struct privsep *ps)
-{
-	unsigned int dst, n;
-	struct privsep_pipes *pp;
-
-	if (ps == NULL)
-		return;
-
-	pp = ps->ps_pp;
-
-	for (dst = 0; dst < PROC_MAX; dst++) {
-		if (ps->ps_ievs[dst] == NULL)
-			continue;
-
-		for (n = 0; n < ps->ps_instances[dst]; n++) {
-			if (pp->pp_pipes[dst][n] == -1)
-				continue;
-
-			/* Cancel the fd, close and invalidate the fd */
-			event_del(&(ps->ps_ievs[dst][n].ev));
-			imsg_clear(&(ps->ps_ievs[dst][n].ibuf));
-			close(pp->pp_pipes[dst][n]);
-			pp->pp_pipes[dst][n] = -1;
-		}
-		free(ps->ps_ievs[dst]);
-	}
-}
-
-void
-proc_shutdown(struct privsep_proc *p)
-{
-	struct privsep *ps = p->p_ps;
-
-	if (p->p_shutdown != NULL)
-		(*p->p_shutdown)();
-
-	proc_close(ps);
-
-	log_info("%s, %s exiting, pid %d", getprogname(), p->p_title, getpid());
-
-	exit(0);
-}
-
-void
-proc_sig_handler(int sig, short event, void *arg)
-{
-	struct privsep_proc *p = arg;
-
-	switch (sig) {
-	case SIGINT:
-	case SIGTERM:
-		proc_shutdown(p);
-		break;
-	case SIGCHLD:
-	case SIGHUP:
-	case SIGPIPE:
-	case SIGUSR1:
-		/* ignore */
-		break;
-	default:
-		fatalx("proc_sig_handler: unexpected signal");
-		/* NOTREACHED */
-	}
-}
-
-void
-proc_run(struct privsep *ps, struct privsep_proc *p,
-    struct privsep_proc *procs, unsigned int nproc,
-    void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
-{
-	struct passwd *pw;
-	const char *root;
-
-	log_procinit(p->p_title);
-
-	/* Set the process group of the current process */
-	setpgid(0, 0);
-
-	/* Use non-standard user */
-	if (p->p_pw != NULL)
-		pw = p->p_pw;
-	else
-		pw = ps->ps_pw;
-
-	/* Change root directory */
-	if (p->p_chroot != NULL)
-		root = p->p_chroot;
-	else
-		root = pw->pw_dir;
-
-	if (chroot(root) == -1)
-		fatal("proc_run: chroot");
-	if (chdir("/") == -1)
-		fatal("proc_run: chdir(\"/\")");
-
-	privsep_process = p->p_id;
-
-	setproctitle("%s", p->p_title);
-
-	if (setgroups(1, &pw->pw_gid) ||
-	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
-	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
-		fatal("proc_run: cannot drop privileges");
-
-	event_init();
-
-	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
-	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
-	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
-	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
-	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
-	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
-
-	signal_add(&ps->ps_evsigint, NULL);
-	signal_add(&ps->ps_evsigterm, NULL);
-	signal_add(&ps->ps_evsigchld, NULL);
-	signal_add(&ps->ps_evsighup, NULL);
-	signal_add(&ps->ps_evsigpipe, NULL);
-	signal_add(&ps->ps_evsigusr1, NULL);
-
-	proc_setup(ps, procs, nproc);
-	proc_accept(ps, PROC_GOTWEBD_SOCK_FILENO, PROC_GOTWEBD, 0);
-
-	DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title,
-	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
-
-	if (run != NULL)
-		run(ps, p, arg);
-
-	event_dispatch();
-
-	proc_shutdown(p);
-}
-
-void
-proc_dispatch(int fd, short event, void *arg)
-{
-	struct imsgev *iev = arg;
-	struct privsep_proc *p = iev->proc;
-	struct privsep *ps = p->p_ps;
-	struct imsgbuf *ibuf;
-	struct imsg imsg;
-	ssize_t n;
-	int verbose;
-	const char *title;
-	struct privsep_fd pf;
-
-	title = ps->ps_title[privsep_process];
-	ibuf = &iev->ibuf;
-
-	if (event & EV_READ) {
-		n = imsg_read(ibuf);
-		if (n == -1 && errno != EAGAIN)
-			fatal("%s: imsg_read", __func__);
-		if (n == 0) {
-			/* this pipe is dead, so remove the event handler */
-			event_del(&iev->ev);
-			event_loopexit(NULL);
-			return;
-		}
-	}
-
-	if (event & EV_WRITE) {
-		n = msgbuf_write(&ibuf->w);
-		if (n == -1 && errno != EAGAIN)
-			fatal("%s: msgbuf_write", __func__);
-		if (n == 0) {
-			/* this pipe is dead, so remove the event handler */
-			event_del(&iev->ev);
-			event_loopexit(NULL);
-			return;
-		}
-	}
-
-	for (;;) {
-		n = imsg_get(ibuf, &imsg);
-		if (n == -1)
-			fatal("%s: imsg_get", __func__);
-		if (n == 0)
-			break;
-
-#if DEBUG > 1
-		log_debug("%s: %s %d got imsg %d peerid %d from %s %d",
-		    __func__, title, ps->ps_instance + 1,
-		    imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid);
-#endif
-
-		/*
-		 * Check the message with the program callback
-		 */
-		if ((p->p_cb)(fd, p, &imsg) == 0) {
-			/* Message was handled by the callback, continue */
-			imsg_free(&imsg);
-			continue;
-		}
-
-		/*
-		 * Generic message handling
-		 */
-		switch (imsg.hdr.type) {
-		case IMSG_CTL_VERBOSE:
-			log_info("%s", __func__);
-			IMSG_SIZE_CHECK(&imsg, &verbose);
-			memcpy(&verbose, imsg.data, sizeof(verbose));
-			log_setverbose(verbose);
-			break;
-		case IMSG_CTL_PROCFD:
-			IMSG_SIZE_CHECK(&imsg, &pf);
-			memcpy(&pf, imsg.data, sizeof(pf));
-			proc_accept(ps, imsg.fd, pf.pf_procid,
-			    pf.pf_instance);
-			break;
-		default:
-			log_warnx("%s: %s %d got invalid imsg %d peerid %d "
-			    "from %s %d",
-			    __func__, title, ps->ps_instance + 1,
-			    imsg.hdr.type, imsg.hdr.peerid,
-			    p->p_title, imsg.hdr.pid);
-		}
-		imsg_free(&imsg);
-	}
-	imsg_event_add(iev);
-}
-
-int
-proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg)
-{
-	return (-1);
-}
-
-/*
- * imsg helper functions
- */
-
-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
-imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
-    pid_t pid, int fd, void *data, uint16_t datalen)
-{
-	int ret;
-
-	ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen);
-	if (ret == -1)
-		return (ret);
-	imsg_event_add(iev);
-	return (ret);
-}
-
-int
-imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
-    pid_t pid, int fd, const struct iovec *iov, int iovcnt)
-{
-	int ret;
-
-	ret = imsg_composev(&iev->ibuf, type, peerid, pid, fd, iov, iovcnt);
-	if (ret == -1)
-		return (ret);
-	imsg_event_add(iev);
-	return (ret);
-}
-
-void
-proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
-{
-	if (*n == -1) {
-		/* Use a range of all target instances */
-		*n = 0;
-		*m = ps->ps_instances[id];
-	} else {
-		/* Use only a single slot of the specified peer process */
-		*m = *n + 1;
-	}
-}
-
-int
-proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
-    uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen)
-{
-	int m;
-
-	proc_range(ps, id, &n, &m);
-	for (; n < m; n++) {
-		if (imsg_compose_event(&ps->ps_ievs[id][n],
-		    type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1)
-			return (-1);
-	}
-
-	return (0);
-}
-
-int
-proc_compose(struct privsep *ps, enum privsep_procid id,
-    uint16_t type, void *data, uint16_t datalen)
-{
-	return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen));
-}
-
-int
-proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
-    uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt)
-{
-	int m;
-
-	proc_range(ps, id, &n, &m);
-	for (; n < m; n++)
-		if (imsg_composev_event(&ps->ps_ievs[id][n],
-		    type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1)
-			return (-1);
-
-	return (0);
-}
-
-int
-proc_composev(struct privsep *ps, enum privsep_procid id,
-    uint16_t type, const struct iovec *iov, int iovcnt)
-{
-	return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt));
-}
-
-int
-proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
-    enum privsep_procid id, int n)
-{
-	return (proc_compose_imsg(ps, id, n, imsg->hdr.type,
-	    imsg->hdr.peerid, imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg)));
-}
-
-struct imsgbuf *
-proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
-{
-	int m;
-
-	proc_range(ps, id, &n, &m);
-	return (&ps->ps_ievs[id][n].ibuf);
-}
-
-struct imsgev *
-proc_iev(struct privsep *ps, enum privsep_procid id, int n)
-{
-	int m;
-
-	proc_range(ps, id, &n, &m);
-	return (&ps->ps_ievs[id][n]);
-}
-
-/* This function should only be called with care as it breaks async I/O */
-int
-proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n)
-{
-	struct imsgbuf *ibuf;
-	int m, ret = 0;
-
-	proc_range(ps, id, &n, &m);
-	for (; n < m; n++) {
-		ibuf = proc_ibuf(ps, id, n);
-		if (ibuf == NULL)
-			return (-1);
-		do {
-			ret = imsg_flush(ibuf);
-		} while (ret == -1 && errno == EAGAIN);
-		if (ret == -1)
-			break;
-		imsg_event_add(&ps->ps_ievs[id][n]);
-	}
-
-	return (ret);
-}
blob - 217c9e4be9fba252cfbaf0026bb6f2c271888bfc (mode 644)
blob + /dev/null
--- gotwebd/proc.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
- *
- * 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 "got_compat.h"
-
-enum {
-	IMSG_NONE,
-	IMSG_CTL_OK,
-	IMSG_CTL_FAIL,
-	IMSG_CTL_VERBOSE,
-	IMSG_CTL_NOTIFY,
-	IMSG_CTL_RESET,
-	IMSG_CTL_PROCFD,
-	IMSG_PROC_MAX
-};
-
-/* imsg */
-struct imsgev {
-	struct imsgbuf		 ibuf;
-	void			(*handler)(int, short, void *);
-	struct event		 ev;
-	struct privsep_proc	*proc;
-	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 ctl_conn {
-	TAILQ_ENTRY(ctl_conn)	 entry;
-	uint8_t			 flags;
-	unsigned int		 waiting;
-#define CTL_CONN_NOTIFY		 0x01
-	struct imsgev		 iev;
-	uid_t			 uid;
-};
-TAILQ_HEAD(ctl_connlist, ctl_conn);
-extern  struct ctl_connlist ctl_conns;
-
-/* privsep */
-enum privsep_procid {
-	PROC_GOTWEBD	= 0,
-	PROC_SOCKS,
-	PROC_MAX,
-};
-extern enum privsep_procid privsep_process;
-
-#define CONFIG_RELOAD		0x00
-#define CONFIG_SOCKS		0x01
-#define CONFIG_ALL		0xff
-
-struct privsep_pipes {
-	int				*pp_pipes[PROC_MAX];
-};
-
-struct privsep {
-	struct privsep_pipes		*ps_pipes[PROC_MAX];
-	struct privsep_pipes		*ps_pp;
-
-	struct imsgev			*ps_ievs[PROC_MAX];
-	const char			*ps_title[PROC_MAX];
-	uint8_t				 ps_what[PROC_MAX];
-
-	struct passwd			*ps_pw;
-	int				 ps_noaction;
-
-	unsigned int			 ps_instances[PROC_MAX];
-	unsigned int			 ps_instance;
-
-	/* Event and signal handlers */
-	struct event			 ps_evsigint;
-	struct event			 ps_evsigterm;
-	struct event			 ps_evsigchld;
-	struct event			 ps_evsighup;
-	struct event			 ps_evsigpipe;
-	struct event			 ps_evsigusr1;
-
-	void				*ps_env;
-};
-
-struct privsep_proc {
-	const char		*p_title;
-	enum privsep_procid	 p_id;
-	int			(*p_cb)(int, struct privsep_proc *,
-				    struct imsg *);
-	void			(*p_init)(struct privsep *,
-				    struct privsep_proc *);
-	void			(*p_shutdown)(void);
-	const char		*p_chroot;
-	struct passwd		*p_pw;
-	struct privsep		*p_ps;
-};
-
-struct privsep_fd {
-	enum privsep_procid		 pf_procid;
-	unsigned int			 pf_instance;
-};
-
-#if DEBUG
-#define DPRINTF		log_debug
-#else
-#define DPRINTF(x...)	do {} while(0)
-#endif
-
-#define PROC_GOTWEBD_SOCK_FILENO 3
-#define PROC_MAX_INSTANCES      32
-
-/* proc.c */
-void	 proc_init(struct privsep *, struct privsep_proc *, unsigned int,
-	    int, char **, enum privsep_procid);
-void	 proc_kill(struct privsep *);
-void	 proc_connect(struct privsep *ps);
-void	 proc_dispatch(int, short event, void *);
-void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
-void	 proc_run(struct privsep *, struct privsep_proc *,
-	    struct privsep_proc *, unsigned int,
-	    void (*)(struct privsep *, struct privsep_proc *, void *), void *);
-void	 imsg_event_add(struct imsgev *);
-int	 imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
-	    pid_t, int, void *, uint16_t);
-int	 imsg_composev_event(struct imsgev *, uint16_t, uint32_t,
-	    pid_t, int, const struct iovec *, int);
-int	 proc_compose_imsg(struct privsep *, enum privsep_procid, int,
-	    uint16_t, uint32_t, int, void *, uint16_t);
-int	 proc_compose(struct privsep *, enum privsep_procid,
-	    uint16_t, void *data, uint16_t);
-int	 proc_composev_imsg(struct privsep *, enum privsep_procid, int,
-	    uint16_t, uint32_t, int, const struct iovec *, int);
-int	 proc_composev(struct privsep *, enum privsep_procid,
-	    uint16_t, const struct iovec *, int);
-int	 proc_forward_imsg(struct privsep *, struct imsg *,
-	    enum privsep_procid, int);
-struct imsgbuf *
-	 proc_ibuf(struct privsep *, enum privsep_procid, int);
-struct imsgev *
-	 proc_iev(struct privsep *, enum privsep_procid, int);
-enum privsep_procid
-	 proc_getid(struct privsep_proc *, unsigned int, const char *);
-int	 proc_flush_imsg(struct privsep *, enum privsep_procid, int);
-
-/* 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 - 2cb58d31e23df12526770e9fbb9d4c031ce446e9
blob + 8a3acf39855f8b061b54268d68d4bd0978010edb
--- 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;
@@ -485,8 +508,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);