commit - 7ee326cb704951ec81c37a236a98d8a62f755ad4
commit + f6020519d156c726a30a1be69ab736aa4bdf3d38
blob - b3a4fae0b273aa937461ce7fe139b1410c594ab5
blob + 532bc19306dddc32e7c2236a2b958a02e9c0bf8b
--- gotd/gotd.c
+++ gotd/gotd.c
}
static void
+gotd_dispatch_notifier(int fd, short event, void *arg)
+{
+ struct gotd_imsgev *iev = arg;
+ struct imsgbuf *ibuf = &iev->ibuf;
+ struct gotd_child_proc *proc = gotd.notify_proc;
+ ssize_t n;
+ int shut = 0;
+ struct imsg imsg;
+
+ if (proc->iev.ibuf.fd != fd)
+ fatalx("%s: unexpected fd %d", __func__, fd);
+
+ if (event & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+
+ if (event & EV_WRITE) {
+ n = msgbuf_write(&ibuf->w);
+ if (n == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("%s: imsg_get error", __func__);
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ default:
+ log_debug("unexpected imsg %d", imsg.hdr.type);
+ break;
+ }
+
+ imsg_free(&imsg);
+ }
+done:
+ if (!shut) {
+ gotd_imsg_event_add(iev);
+ } else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+
+ /*
+ * Do not exit all of gotd if the notification handler dies.
+ * We can continue operating without notifications until an
+ * operator intervenes.
+ */
+ log_warnx("notify child process (pid %d) closed its imsg pipe "
+ "unexpectedly", proc->pid);
+ gotd.notify_proc = NULL;
+ imsg_clear(&iev->ibuf);
+ free(proc);
+ }
+}
+
+static void
gotd_dispatch_auth_child(int fd, short event, void *arg)
{
const struct got_error *err = NULL;
}
}
+static const struct got_error *
+connect_notifier(struct gotd_client *client)
+{
+ const struct got_error *err = NULL;
+ int s;
+
+ if (gotd.notify_proc) {
+ s = dup(gotd.notify_proc->pipe[0]);
+ if (s == -1)
+ return got_error_from_errno("dup");
+ } else
+ s = -1;
+
+ if (gotd_imsg_compose_event(&client->session->iev,
+ GOTD_IMSG_CONNECT_NOTIFIER, PROC_GOTD, s, NULL, 0) == -1) {
+ err = got_error_from_errno("imsg compose CONNECT_NOTIFIER");
+ if (s != -1)
+ close(s);
+ return err;
+ }
+
+ return NULL;
+}
+
static void
gotd_dispatch_repo_child(int fd, short event, void *arg)
{
err = connect_session(client);
if (err)
break;
+ err = connect_notifier(client);
+ if (err)
+ break;
err = connect_repo_child(client, proc);
break;
default:
gotd.listen_proc = proc;
}
+static void
+start_notifier(char *argv0, const char *confpath, int daemonize, int verbosity)
+{
+ struct gotd_child_proc *proc;
+
+ proc = calloc(1, sizeof(*proc));
+ if (proc == NULL)
+ fatal("calloc");
+
+ TAILQ_INSERT_HEAD(&procs, proc, entry);
+
+ /* proc->tmo is initialized in main() after event_init() */
+
+ proc->type = PROC_NOTIFY;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK,
+ PF_UNSPEC, proc->pipe) == -1)
+ fatal("socketpair");
+
+ proc->pid = start_child(proc->type, NULL, argv0, confpath,
+ proc->pipe[1], daemonize, verbosity);
+ imsg_init(&proc->iev.ibuf, proc->pipe[0]);
+ proc->iev.handler = gotd_dispatch_notifier;
+ proc->iev.events = EV_READ;
+ proc->iev.handler_arg = NULL;
+
+ gotd.notify_proc = proc;
+}
+
static const struct got_error *
start_session_child(struct gotd_client *client, struct gotd_repo *repo,
char *argv0, const char *confpath, int daemonize, int verbosity)
fatal("daemon");
gotd.pid = getpid();
start_listener(argv0, confpath, daemonize, verbosity);
+ start_notifier(argv0, confpath, daemonize, verbosity);
} else if (proc_id == PROC_LISTEN) {
snprintf(title, sizeof(title), "%s", gotd_proc_names[proc_id]);
if (verbosity) {
evtimer_set(&gotd.listen_proc->tmo, kill_proc_timeout,
gotd.listen_proc);
+ evtimer_set(&gotd.notify_proc->tmo, kill_proc_timeout,
+ gotd.notify_proc);
apply_unveil_selfexec();
blob - e34d36cf3f78fa3e6dbc1962c74f9995d0a44e1a
blob + 536e8f08bcba8d30704aa3b6ee94d5a1bb340368
--- gotd/gotd.h
+++ gotd/gotd.h
struct gotd_repolist repos;
int nrepos;
struct gotd_child_proc *listen_proc;
+ struct gotd_child_proc *notify_proc;
+ int notifications_enabled;
struct timeval request_timeout;
struct timeval auth_timeout;
struct gotd_uid_connection_limit *connection_limits;
GOTD_IMSG_ACCESS_GRANTED,
/* Notify child process. */
- GOTD_IMSG_NOTIFY_READY,
+ GOTD_IMSG_CONNECT_NOTIFIER,
+ GOTD_IMSG_NOTIFY,
};
/* Structure for GOTD_IMSG_ERROR. */
blob - 929e63947c237f8baaeb6b5c9a27980e7054685c
blob + 78359bad4c5f1afe2fbc0dbf0c5a37663f8056b8
--- gotd/notify.c
+++ gotd/notify.c
gotd_notify.parent_iev.handler_arg = NULL;
event_set(&gotd_notify.parent_iev.ev, gotd_notify.parent_iev.ibuf.fd,
EV_READ, notify_dispatch, &gotd_notify.parent_iev);
- if (gotd_imsg_compose_event(&gotd_notify.parent_iev,
- GOTD_IMSG_NOTIFY_READY, PROC_NOTIFY, -1, NULL, 0) == -1) {
- err = got_error_from_errno("imsg compose NOTIFY_READY");
- goto done;
- }
event_dispatch();
-done:
+
if (err)
log_warnx("%s: %s", title, err->msg);
gotd_notify_shutdown();
blob - 402b1ccfef8728b954ba0339814fdc2e1b9c7ba4
blob + 1f2ffba1e002969197e6b483aaa711da48333150
--- gotd/session.c
+++ gotd/session.c
int *pack_fds;
int *temp_fds;
struct gotd_imsgev parent_iev;
+ struct gotd_imsgev notifier_iev;
struct timeval request_timeout;
enum gotd_procid proc_id;
} gotd_session;
return NULL;
}
+
+static void
+session_dispatch_notifier(int fd, short event, void *arg)
+{
+ struct gotd_imsgev *iev = arg;
+ struct imsgbuf *ibuf = &iev->ibuf;
+ ssize_t n;
+ int shut = 0;
+ struct imsg imsg;
+
+ if (event & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+
+ if (event & EV_WRITE) {
+ n = msgbuf_write(&ibuf->w);
+ if (n == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0) {
+ /* Connection closed. */
+ shut = 1;
+ goto done;
+ }
+ }
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("%s: imsg_get error", __func__);
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ default:
+ log_debug("unexpected imsg %d", imsg.hdr.type);
+ break;
+ }
+
+ imsg_free(&imsg);
+ }
+done:
+ if (!shut) {
+ gotd_imsg_event_add(iev);
+ } else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ imsg_clear(&iev->ibuf);
+ imsg_init(&iev->ibuf, -1);
+ }
+}
+
static const struct got_error *
+recv_notifier(struct imsg *imsg)
+{
+ struct gotd_imsgev *iev = &gotd_session.notifier_iev;
+ struct gotd_session_client *client = &gotd_session_client;
+ size_t datalen;
+
+ if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
+ return got_error(GOT_ERR_PRIVSEP_MSG);
+
+ /* We should already have received a pipe to the listener. */
+ if (client->fd == -1)
+ return got_error(GOT_ERR_PRIVSEP_MSG);
+
+ datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != 0)
+ return got_error(GOT_ERR_PRIVSEP_LEN);
+
+ if (imsg->fd == -1)
+ return NULL; /* notifications unused */
+
+ imsg_init(&iev->ibuf, imsg->fd);
+ iev->handler = session_dispatch_notifier;
+ iev->events = EV_READ;
+ iev->handler_arg = NULL;
+ event_set(&iev->ev, iev->ibuf.fd, EV_READ,
+ session_dispatch_notifier, iev);
+ gotd_imsg_event_add(iev);
+
+ return NULL;
+}
+
+static const struct got_error *
recv_repo_child(struct imsg *imsg)
{
struct gotd_imsg_connect_repo_child ichild;
case GOTD_IMSG_DISCONNECT:
do_disconnect = 1;
break;
+ case GOTD_IMSG_CONNECT_NOTIFIER:
+ err = recv_notifier(&imsg);
+ break;
case GOTD_IMSG_CONNECT_REPO_CHILD:
err = recv_repo_child(&imsg);
if (err)
sizeof(gotd_session.request_timeout));
gotd_session.proc_id = proc_id;
+ imsg_init(&gotd_session.notifier_iev.ibuf, -1);
+
err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds);
if (err)
goto done;