[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [PATCH 7/8] mdev: add SIGHUP handler to reload configuration
From:       Jan Klötzke <jan () kloetzke ! net>
Date:       2019-12-16 21:56:55
Message-ID: 20191216215656.6438-8-jan () kloetzke ! net
[Download RAW message or body]

Like a well behaved daemon the reception of SIGHUP triggers a reload of
/etc/mdev.conf. The file is parsed immediately to catch any errors early
and to cache the current version.

Signed-off-by: Jan Klötzke <jan@kloetzke.net>
---
 util-linux/mdev.c | 106 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 86 insertions(+), 20 deletions(-)

diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 671221af5..81c4336af 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -314,6 +314,10 @@ struct globals {
 #endif
 	struct rule cur_rule;
 	char timestr[sizeof("HH:MM:SS.123456")];
+#if ENABLE_FEATURE_MDEV_DAEMON
+	int netlink_fd;
+	struct fd_pair signal_pipe;
+#endif
 } FIX_ALIASING;
 #define G (*(struct globals*)bb_common_bufsiz1)
 #define INIT_G() do { \
@@ -1160,6 +1164,15 @@ static void initial_scan(char *temp)
 
 #if ENABLE_FEATURE_MDEV_DAEMON
 
+static void daemon_sighandler(int sig)
+{
+	int olderrno = errno;
+	unsigned char ch = sig; /* use char, avoid dealing with partial writes */
+	if (write(G.signal_pipe.wr, &ch, 1) != 1)
+		bb_simple_perror_msg("can't send signal");
+	errno = olderrno;
+}
+
 /*
  * The kernel (as of v5.4) will pass up to 32 environment variables with a
  * total of 2kiB on each event. On top of that the action string and device
@@ -1177,10 +1190,8 @@ static void initial_scan(char *temp)
 # define RCVBUF (128 * 1024 * 1024)
 # define MAX_ENV 32
 
-static int daemon_init(char *temp)
+static void daemon_init(char *temp)
 {
-	int fd;
-
 	/* Subscribe for UEVENT kernel messages */
 	/* Without a sufficiently big RCVBUF, a ton of simultaneous events
 	 * can trigger ENOBUFS on read, which is unrecoverable.
@@ -1188,7 +1199,9 @@ static int daemon_init(char *temp)
 	 *	mdev -d
 	 *	find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
 	 */
-	fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, 1 << 0, RCVBUF);
+	G.netlink_fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT,
+			1 << 0, RCVBUF);
+	ndelay_on(G.netlink_fd);
 
 	/*
 	 * Make inital scan after the uevent socket is alive and
@@ -1196,29 +1209,53 @@ static int daemon_init(char *temp)
 	 * in daemon mode.
 	 */
 	initial_scan(temp);
+}
+
+static void daemon_handle_sighup(void)
+{
+	unsigned char sig;
+
+	while (safe_read(G.signal_pipe.rd, &sig, 1) == 1);
+
+#if ENABLE_FEATURE_MDEV_CONF
+	// reset parser state
+	G.filename = "/etc/mdev.conf";
+	if (G.parser) {
+		config_close(G.parser);
+		G.parser = NULL;
+	}
+	G.rule_idx = 0;
 
-	return fd;
+	// parse whole file to flag errors immediately
+	dbg1("SIGHUP: reload '%s'", G.filename);
+	do {
+		next_rule();
+	} while (G.parser);
+#endif
 }
 
-static void daemon_loop(char *temp, int fd)
+static void daemon_handle_events(char *temp)
 {
-	for (;;) {
-		char netbuf[BUFFER_SIZE];
-		char *env[MAX_ENV];
-		char *s, *end;
-		ssize_t len;
-		int idx;
+	char netbuf[BUFFER_SIZE];
+	char *env[MAX_ENV];
+	char *s, *end;
+	ssize_t len;
+	int idx;
 
-		len = safe_read(fd, netbuf, sizeof(netbuf) - 1);
+	for (;;) {
+		len = safe_read(G.netlink_fd, netbuf, sizeof(netbuf) - 1);
 		if (len < 0) {
-			if (errno == ENOBUFS) {
+			if (errno == EAGAIN || errno == EWOULDBLOCK) {
+				// done reading events
+				break;
+			} else if (errno == ENOBUFS) {
 				/*
 				 * We ran out of socket receive buffer space.
 				 * Start from scratch.
 				 */
 				dbg1s("uevent overrun! Rescanning...");
-				close(fd);
-				fd = daemon_init(temp);
+				close(G.netlink_fd);
+				daemon_init(temp);
 				continue;
 			}
 			bb_simple_perror_msg_and_die("read");
@@ -1242,6 +1279,37 @@ static void daemon_loop(char *temp, int fd)
 			bb_unsetenv(env[--idx]);
 	}
 }
+
+static void daemon_loop(char *temp)
+{
+	xpiped_pair(G.signal_pipe);
+	close_on_exec_on(G.signal_pipe.rd);
+	close_on_exec_on(G.signal_pipe.wr);
+	ndelay_on(G.signal_pipe.rd);
+	ndelay_on(G.signal_pipe.wr);
+	bb_signals((1 << SIGHUP), daemon_sighandler);
+
+	for (;;) {
+		struct pollfd pfds[2];
+		int ret;
+
+		pfds[0].fd = G.netlink_fd;
+		pfds[0].events = POLLIN;
+		pfds[1].fd = G.signal_pipe.rd;
+		pfds[1].events = POLLIN;
+		ret = poll(pfds, 2, -1);
+		if (ret <= 0) {
+			if (ret < 0 && errno != EINTR)
+				bb_simple_perror_msg_and_die("poll");
+			continue;
+		}
+
+		if (pfds[0].revents)
+			daemon_handle_events(temp);
+		if (pfds[1].revents)
+			daemon_handle_sighup();
+	}
+}
 #endif
 
 int mdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -1297,12 +1365,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
 		 * after initial scan so that caller can be sure everything
 		 * is up-to-date when mdev process returns.
 		 */
-		int fd = daemon_init(temp);
-
+		daemon_init(temp);
 		if (!(opt & MDEV_OPT_FOREGROUND))
 			bb_daemonize_or_rexec(0, argv);
-
-		daemon_loop(temp, fd);
+		daemon_loop(temp);
 	}
 #endif
 	if (opt & MDEV_OPT_SCAN) {
-- 
2.20.1

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic