commit - 03e70dd4d41906645718ee5b780d7e948404f292
commit + 26678adde25a1fb7fa3e4b78c82a888cc3b767e4
blob - 8a18107cdc7ef357964ae5a8c38a6e1205874e12
blob + 258caeda8f63d90382ebfba64f426fcbc541a389
--- gotwebd/Makefile
+++ gotwebd/Makefile
.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
#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;
}
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;
}
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,
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;
}
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
#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
#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 - 072c326702282d6c37c250bb57b593f5ce07776f
blob + 807b59726fb1bd60b655c7536a08f348058f1da3
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
#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
#include "got_opentemp.h"
#include "got_reference.h"
-#include "proc.h"
#include "gotwebd.h"
__dead void usage(void);
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__);
}
}
+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)
{
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)
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++;
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");
{
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;
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);
}
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 - f2e1d1c756973046a69181f403f1187c8b7432cc
blob + d47297375a5f9fe3888d5e964455fbc3a3d9416a
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
#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
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;
};
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;
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 *);
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
{
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
#include "got_error.h"
#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
#include "got_reference.h"
-#include "proc.h"
#include "gotwebd.h"
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
blob - af1919d98925cc1f5ca97aed9a73ce4eb60bad00 (mode 644)
blob + /dev/null
--- gotwebd/proc.c
+++ /dev/null
-/*
- * 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 <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 <imsg.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];
- if (socketpair(AF_UNIX,
- SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
- 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];
- if (socketpair(AF_UNIX,
- SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
- 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 - 524112fcf4b0c72a25c6f5a4cb85c16bd33ef3a9 (mode 644)
blob + /dev/null
--- gotwebd/proc.h
+++ /dev/null
-/*
- * 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.
- */
-
-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 - 16a74076b94ffabf45821936ff713dacb0e1dff0
blob + dd100773cb3593bb4f04e31d024acf711bdc912e
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
#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 *);
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
}
}
-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
}
}
-void
+static void
sockets_shutdown(void)
{
struct server *srv, *tsrv;
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;
}
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;
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);