From: Vincent Bernat Date: Wed, 18 Mar 2015 13:20:26 +0000 (+0100) Subject: priv: monitor the monitor process X-Git-Tag: 0.7.14~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=327b1d625c2df0a8d078356f16c2c3f0aa06d485;p=thirdparty%2Flldpd.git priv: monitor the monitor process By monitoring the socket connection with the monitor process, we ensure that we kill ourselves if the monitor disappears and fails to notice us. This doesn't work yet because there is no "end of file" event for a SOCK_DGRAM. See the next commit. --- diff --git a/src/daemon/event.c b/src/daemon/event.c index 314d71b9..d575b991 100644 --- a/src/daemon/event.c +++ b/src/daemon/event.c @@ -382,6 +382,42 @@ accept_failed: levent_ctl_free_client(client); } +static void +levent_priv(evutil_socket_t fd, short what, void *arg) +{ + struct event_base *base = arg; + ssize_t n; + int err; + char one; + (void)what; + /* Check if we have some data available. We need to pass the socket in + * non-blocking mode to be able to run the check without disruption. */ + levent_make_socket_nonblocking(fd); + n = read(fd, &one, 0); err = errno; + levent_make_socket_blocking(fd); + + switch (n) { + case -1: + if (err == EAGAIN || err == EWOULDBLOCK) + /* No data, all good */ + return; + log_warnx("event", "unable to poll monitor process, exit"); + break; + case 0: + log_warnx("event", "monitor process has terminated, exit"); + break; + default: + /* Unfortunately, dead code, if we have data, we have requested + * 0 byte, so we will fall in the previous case. It seems safer + * to ask for 0 byte than asking for 1 byte. In the later case, + * if we have to speak with the monitor again before exiting, we + * would be out of sync. */ + log_warnx("event", "received unexpected data from monitor process, exit"); + break; + } + event_base_loopbreak(base); +} + static void levent_dump(evutil_socket_t fd, short what, void *arg) { @@ -471,6 +507,14 @@ levent_init(struct lldpd *cfg) fatalx("event", "unable to setup control socket event"); event_add(ctl_event, NULL); + /* Somehow monitor the monitor process */ + struct event *monitor_event; + log_debug("event", "monitor the monitor process"); + if ((monitor_event = event_new(cfg->g_base, priv_fd(PRIV_UNPRIVILEGED), + EV_READ|EV_PERSIST, levent_priv, cfg->g_base)) == NULL) + fatalx("event", "unable to monitor monitor process"); + event_add(monitor_event, NULL); + /* Signals */ log_debug("event", "register signals"); evsignal_add(evsignal_new(cfg->g_base, SIGUSR1, @@ -788,3 +832,19 @@ levent_make_socket_nonblocking(int fd) } return 0; } + +int +levent_make_socket_blocking(int fd) +{ + int flags; + if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) { + log_warn("event", "fcntl(%d, F_GETFL)", fd); + return -1; + } + if (!(flags & O_NONBLOCK)) return 0; + if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) { + log_warn("event", "fcntl(%d, F_SETFL)", fd); + return -1; + } + return 0; +} diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index aea2b716..c93128ad 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -157,6 +157,7 @@ int levent_iface_subscribe(struct lldpd *, int); void levent_schedule_pdu(struct lldpd_hardware *); void levent_schedule_cleanup(struct lldpd *); int levent_make_socket_nonblocking(int); +int levent_make_socket_blocking(int); /* lldp.c */ int lldp_send_shutdown(PROTO_SEND_SIG); @@ -268,6 +269,7 @@ void must_read(enum priv_context, void *, size_t); void must_write(enum priv_context, const void *, size_t); void priv_privileged_fd(int); void priv_unprivileged_fd(int); +int priv_fd(enum priv_context); int receive_fd(enum priv_context); void send_fd(enum priv_context, int); diff --git a/src/daemon/privsep_io.c b/src/daemon/privsep_io.c index 39a66be8..59187919 100644 --- a/src/daemon/privsep_io.c +++ b/src/daemon/privsep_io.c @@ -26,7 +26,7 @@ priv_unprivileged_fd(int fd) { unprivileged = fd; } -static int +int priv_fd(enum priv_context ctx) { switch (ctx) {