svn commit: trunk/busybox/init

vda at busybox.net vda at busybox.net
Sat Jan 31 18:55:55 UTC 2009


Author: vda
Date: 2009-01-31 18:55:54 +0000 (Sat, 31 Jan 2009)
New Revision: 25182

Log:
init: fix a bug where on reload order of entries might be wrong

function                                             old     new   delta
run_shutdown_and_kill_processes                        -      97     +97
pause_and_low_level_reboot                             -      48     +48
run_actions                                           81     107     +26
restart_handler                                       56      81     +25
new_init_action                                      137     150     +13
run                                                  576     579      +3
open_stdio_to_tty                                    110      98     -12
check_delayed_sigs                                   195     170     -25
waitfor                                              354     318     -36
low_level_reboot                                      53       -     -53
kill_all_processes                                   115       -    -115
------------------------------------------------------------------------------
(add/remove: 2/2 grow/shrink: 4/3 up/down: 212/-241)          Total: -29 bytes



Modified:
   trunk/busybox/init/init.c


Changeset:
Modified: trunk/busybox/init/init.c
===================================================================
--- trunk/busybox/init/init.c	2009-01-31 18:39:55 UTC (rev 25181)
+++ trunk/busybox/init/init.c	2009-01-31 18:55:54 UTC (rev 25182)
@@ -95,18 +95,15 @@
 #endif
 };
 
-static void halt_reboot_pwoff(int sig) NORETURN;
-
 /* Print a message to the specified device.
  * "where" may be bitwise-or'd from L_LOG | L_CONSOLE
  * NB: careful, we can be called after vfork!
  */
-#define messageD(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0)
+#define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0)
 static void message(int where, const char *fmt, ...)
 	__attribute__ ((format(printf, 2, 3)));
 static void message(int where, const char *fmt, ...)
 {
-	static int log_fd = -1;
 	va_list arguments;
 	unsigned l;
 	char msg[128];
@@ -116,22 +113,25 @@
 	l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
 	if (l > sizeof(msg) - 1)
 		l = sizeof(msg) - 1;
-	msg[l] = '\0';
 	va_end(arguments);
 
-	if (ENABLE_FEATURE_INIT_SYSLOG) {
-		if (where & L_LOG) {
-			/* Log the message to syslogd */
-			openlog("init", 0, LOG_DAEMON);
-			/* don't print "\r" */
-			syslog(LOG_INFO, "%s", msg + 1);
-			closelog();
-		}
+#if ENABLE_FEATURE_INIT_SYSLOG
+	msg[l] = '\0';
+	if (where & L_LOG) {
+		/* Log the message to syslogd */
+		openlog("init", 0, LOG_DAEMON);
+		/* don't print "\r" */
+		syslog(LOG_INFO, "%s", msg + 1);
+		closelog();
+	}
+	msg[l++] = '\n';
+	msg[l] = '\0';
+#else
+	{
+		static int log_fd = -1;
+
 		msg[l++] = '\n';
 		msg[l] = '\0';
-	} else {
-		msg[l++] = '\n';
-		msg[l] = '\0';
 		/* Take full control of the log tty, and never close it.
 		 * It's mine, all mine!  Muhahahaha! */
 		if (log_fd < 0) {
@@ -153,6 +153,7 @@
 				return; /* don't print dup messages */
 		}
 	}
+#endif
 
 	if (where & L_CONSOLE) {
 		/* Send console messages to console so people will see them. */
@@ -199,7 +200,7 @@
 			dup2(fd, STDOUT_FILENO);
 			xmove_fd(fd, STDERR_FILENO);
 		}
-		messageD(L_LOG, "console='%s'", s);
+		dbg_message(L_LOG, "console='%s'", s);
 	} else {
 		/* Make sure fd 0,1,2 are not closed
 		 * (so that they won't be used by future opens) */
@@ -261,7 +262,7 @@
 
 /* Open the new terminal device.
  * NB: careful, we can be called after vfork! */
-static void open_stdio_to_tty(const char* tty_name, int exit_on_failure)
+static int open_stdio_to_tty(const char* tty_name)
 {
 	/* empty tty_name means "use init's tty", else... */
 	if (tty_name[0]) {
@@ -273,19 +274,13 @@
 		if (fd) {
 			message(L_LOG | L_CONSOLE, "can't open %s: %s",
 				tty_name, strerror(errno));
-			if (exit_on_failure)
-				_exit(EXIT_FAILURE);
-			if (DEBUG_INIT)
-				_exit(2);
-			/* NB: we don't reach this if we were called after vfork.
-			 * Thus halt_reboot_pwoff() itself needs not be vfork-safe.
-			 */
-			halt_reboot_pwoff(SIGUSR1); /* halt the system */
+			return 0; /* failure */
 		}
 		dup2(STDIN_FILENO, STDOUT_FILENO);
 		dup2(STDIN_FILENO, STDERR_FILENO);
 	}
 	set_sane_term();
+	return 1; /* success */
 }
 
 /* Wrapper around exec:
@@ -369,7 +364,8 @@
 	setsid();
 
 	/* Open the new terminal device */
-	open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */);
+	if (!open_stdio_to_tty(a->terminal))
+		_exit(EXIT_FAILURE);
 
 	/* NB: on NOMMU we can't wait for input in child, so
 	 * "askfirst" will work the same as "respawn". */
@@ -388,7 +384,7 @@
 		 * be allowed to start a shell or whatever an init script
 		 * specifies.
 		 */
-		messageD(L_LOG, "waiting for enter to start '%s'"
+		dbg_message(L_LOG, "waiting for enter to start '%s'"
 					"(pid %d, tty '%s')\n",
 				a->command, getpid(), a->terminal);
 		full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
@@ -422,21 +418,6 @@
 	_exit(-1);
 }
 
-static void delete_init_action(struct init_action *action)
-{
-	struct init_action *a, **nextp;
-
-	nextp = &init_action_list;
-	while ((a = *nextp) != NULL) {
-		if (a == action) {
-			*nextp = a->next;
-			free(a);
-			break;
-		}
-		nextp = &a->next;
-	}
-}
-
 static struct init_action *mark_terminated(int pid)
 {
 	struct init_action *a;
@@ -497,36 +478,44 @@
 {
 	struct init_action *a, **nextp;
 
-//BUG
-//old:
-//::shutdown:umount -a -r
-//::shutdown:swapoff -a
-//new: swapped:
-//::shutdown:swapoff -a
-//::shutdown:umount -a -r
-//on SIGHUP, new one will be loaded, but order will be wrong.
+	/* Scenario:
+	 * old inittab:
+	 * ::shutdown:umount -a -r
+	 * ::shutdown:swapoff -a
+	 * new inittab:
+	 * ::shutdown:swapoff -a
+	 * ::shutdown:umount -a -r
+	 * On reload, we must ensure entries end up in correct order.
+	 * To achieve that, if we find a matching entry, we move it
+	 * to the end.
+	 */
 	nextp = &init_action_list;
 	while ((a = *nextp) != NULL) {
 		/* Don't enter action if it's already in the list,
-		 * just overwrite existing one's type.
 		 * This prevents losing running RESPAWNs.
 		 */
 		if ((strcmp(a->command, command) == 0)
 		 && (strcmp(a->terminal, cons) == 0)
 		) {
-			a->action_type = action_type;
-			return;
+			/* Remove from list */
+			*nextp = a->next;
+			/* Find the end of the list */
+			while (*nextp != NULL)
+				nextp = &(*nextp)->next;
+			a->next = NULL;
+			break;
 		}
 		nextp = &a->next;
 	}
 
+	if (!a)
+		a = xzalloc(sizeof(*a));
 	/* Append to the end of the list */
-	a = xzalloc(sizeof(*a));
 	*nextp = a;
 	a->action_type = action_type;
 	safe_strncpy(a->command, command, sizeof(a->command));
 	safe_strncpy(a->terminal, cons, sizeof(a->terminal));
-	messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
+	dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
 		a->command, a->action_type, a->terminal);
 }
 
@@ -603,8 +592,8 @@
 #endif
 }
 
-static void low_level_reboot(unsigned magic) NORETURN;
-static void low_level_reboot(unsigned magic)
+static void pause_and_low_level_reboot(unsigned magic) NORETURN;
+static void pause_and_low_level_reboot(unsigned magic)
 {
 	pid_t pid;
 
@@ -619,12 +608,11 @@
 		reboot(magic);
 		_exit(EXIT_SUCCESS);
 	}
-	waitfor(pid);
 	while (1)
 		sleep(1);
 }
 
-static void kill_all_processes(void)
+static void run_shutdown_and_kill_processes(void)
 {
 	/* Run everything to be run at "shutdown".  This is done _prior_
 	 * to killing everything, in case people wish to use scripts to
@@ -633,19 +621,16 @@
 
 	message(L_CONSOLE | L_LOG, "The system is going down NOW!");
 
-	/* Allow Ctrl-Alt-Del to reboot system. */
-	reboot(RB_ENABLE_CAD); /* misnomer */
-
 	/* Send signals to every process _except_ pid 1 */
-	message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");
 	kill(-1, SIGTERM);
+	message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
 	sync();
 	sleep(1);
 
-	message(L_CONSOLE, "Sending SIG%s to all processes", "KILL");
 	kill(-1, SIGKILL);
+	message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
 	sync();
-	sleep(1);
+	/*sleep(1); - callers take care about making a pause */
 }
 
 /* Signal handling by init:
@@ -684,12 +669,13 @@
  * and only one will be remebered and acted upon.
  */
 
+static void halt_reboot_pwoff(int sig) NORETURN;
 static void halt_reboot_pwoff(int sig)
 {
 	const char *m;
 	unsigned rb;
 
-	kill_all_processes();
+	run_shutdown_and_kill_processes();
 
 	m = "halt";
 	rb = RB_HALT_SYSTEM;
@@ -701,7 +687,7 @@
 		rb = RB_POWER_OFF;
 	}
 	message(L_CONSOLE, "Requesting system %s", m);
-	low_level_reboot(rb);
+	pause_and_low_level_reboot(rb);
 	/* not reached */
 }
 
@@ -752,11 +738,21 @@
 		 * Thus don't need to worry about preserving errno
 		 * and such.
 		 */
-		kill_all_processes();
-		open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */);
-		messageD(L_CONSOLE, "Trying to re-exec %s", a->command);
-		init_exec(a->command);
-		low_level_reboot(RB_HALT_SYSTEM);
+		run_shutdown_and_kill_processes();
+
+		/* Allow Ctrl-Alt-Del to reboot the system.
+		 * This is how kernel sets it up for init, we follow suit.
+		 */
+		reboot(RB_ENABLE_CAD); /* misnomer */
+
+		if (open_stdio_to_tty(a->terminal)) {
+			dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
+			while (wait(NULL) > 0)
+				continue;
+			init_exec(a->command);
+		}
+		/* Open or exec failed */
+		pause_and_low_level_reboot(RB_HALT_SYSTEM);
 		/* not reached */
 	}
 }
@@ -764,40 +760,50 @@
 #if ENABLE_FEATURE_USE_INITTAB
 static void reload_inittab(void)
 {
-	struct init_action *a, *tmp;
+	struct init_action *a, **nextp;
 
 	message(L_LOG, "reloading /etc/inittab");
 
 	/* Disable old entries */
-	for (a = init_action_list; a; a = a->next) {
+	for (a = init_action_list; a; a = a->next)
 		a->action_type = ONCE;
-	}
 
+	/* Append new entries, or modify existing entries
+	 * (set a->action_type) if cmd and device name
+	 * match new ones. End result: only entries with
+	 * a->action_type == ONCE are stale.
+	 */
 	parse_inittab();
 
 	if (ENABLE_FEATURE_KILL_REMOVED) {
+		/* Kill stale entries */
 		/* Be nice and send SIGTERM first */
 		for (a = init_action_list; a; a = a->next)
-			if (a->pid != 0)
+			if (a->action_type == ONCE && a->pid != 0)
 				kill(a->pid, SIGTERM);
 		if (CONFIG_FEATURE_KILL_DELAY) {
 			/* NB: parent will wait in NOMMU case */
 			if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
 				sleep(CONFIG_FEATURE_KILL_DELAY);
 				for (a = init_action_list; a; a = a->next)
-					if (a->pid != 0)
+					if (a->action_type == ONCE && a->pid != 0)
 						kill(a->pid, SIGKILL);
 				_exit(EXIT_SUCCESS);
 			}
 		}
 	}
 
-	/* Remove old and unused entries */
-	for (a = init_action_list; a; a = tmp) {
-		tmp = a->next;
-		if (a->action_type & (ONCE | SYSINIT | WAIT))
-			delete_init_action(a);
+	/* Remove stale (ONCE) and not useful (SYSINIT,WAIT) entries */
+	nextp = &init_action_list;
+	while ((a = *nextp) != NULL) {
+		if (a->action_type & (ONCE | SYSINIT | WAIT)) {
+			*nextp = a->next;
+			free(a);
+		} else {
+			nextp = &a->next;
+		}
 	}
+
 	/* Not needed: */
 	/* run_actions(RESPAWN | ASKFIRST); */
 	/* - we return to main loop, which does this automagically */



More information about the busybox-cvs mailing list