init: remove superfluous forks and messing up with argv[0]
cttyhack: add stealing of ctty

diff --git a/init/init.c b/init/init.c
index fe0ec03..c0c8b17 100644
--- a/init/init.c
+++ b/init/init.c
@@ -47,31 +47,22 @@
 #define SHUTDOWN    0x040
 #define RESTART     0x080
 
-/* A mapping between "inittab" action name strings and action type codes. */
-struct init_action_type {
-	const char *name;
-	int action;
-};
-
-static const struct init_action_type actions[] = {
-	{"sysinit", SYSINIT},
-	{"respawn", RESPAWN},
-	{"askfirst", ASKFIRST},
-	{"wait", WAIT},
-	{"once", ONCE},
-	{"ctrlaltdel", CTRLALTDEL},
-	{"shutdown", SHUTDOWN},
-	{"restart", RESTART},
-	{0, 0}
-};
+#define STR_SYSINIT     "\x01"
+#define STR_RESPAWN     "\x02"
+#define STR_ASKFIRST    "\x04"
+#define STR_WAIT        "\x08"
+#define STR_ONCE        "\x10"
+#define STR_CTRLALTDEL  "\x20"
+#define STR_SHUTDOWN    "\x40"
+#define STR_RESTART     "\x80"
 
 /* Set up a linked list of init_actions, to be read from inittab */
 struct init_action {
 	struct init_action *next;
-	int action;
 	pid_t pid;
-	char command[INIT_BUFFS_SIZE];
+	uint8_t action;
 	char terminal[CONSOLE_NAME_SIZE];
+	char command[INIT_BUFFS_SIZE];
 };
 
 /* Static variables */
@@ -113,7 +104,7 @@
 
 /* Function prototypes */
 static void delete_init_action(struct init_action *a);
-static int waitfor(const struct init_action *a, pid_t pid);
+static int waitfor(pid_t pid);
 #if !ENABLE_DEBUG_INIT
 static void shutdown_signal(int sig);
 #endif
@@ -193,43 +184,6 @@
 	}
 }
 
-/* Set terminal settings to reasonable defaults */
-static void set_sane_term(void)
-{
-	struct termios tty;
-
-	tcgetattr(STDIN_FILENO, &tty);
-
-	/* set control chars */
-	tty.c_cc[VINTR] = 3;	/* C-c */
-	tty.c_cc[VQUIT] = 28;	/* C-\ */
-	tty.c_cc[VERASE] = 127;	/* C-? */
-	tty.c_cc[VKILL] = 21;	/* C-u */
-	tty.c_cc[VEOF] = 4;	/* C-d */
-	tty.c_cc[VSTART] = 17;	/* C-q */
-	tty.c_cc[VSTOP] = 19;	/* C-s */
-	tty.c_cc[VSUSP] = 26;	/* C-z */
-
-	/* use line dicipline 0 */
-	tty.c_line = 0;
-
-	/* Make it be sane */
-	tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
-	tty.c_cflag |= CREAD | HUPCL | CLOCAL;
-
-	/* input modes */
-	tty.c_iflag = ICRNL | IXON | IXOFF;
-
-	/* output modes */
-	tty.c_oflag = OPOST | ONLCR;
-
-	/* local modes */
-	tty.c_lflag =
-		ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
-
-	tcsetattr(STDIN_FILENO, TCSANOW, &tty);
-}
-
 /* From <linux/serial.h> */
 struct serial_struct {
 	int	type;
@@ -277,7 +231,7 @@
 
 	s = getenv("TERM");
 	if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
-		/* Force the TERM setting to vt102 for serial console --
+		/* Force the TERM setting to vt102 for serial console
 		 * if TERM is set to linux (the default) */
 		if (!s || strcmp(s, "linux") == 0)
 			putenv((char*)"TERM=vt102");
@@ -288,14 +242,41 @@
 		putenv((char*)"TERM=linux");
 }
 
-static void fixup_argv(char **argv)
+/* Set terminal settings to reasonable defaults */
+static void set_sane_term(void)
 {
-	/* Fix up argv[0] to be certain we claim to be init */
-	strncpy(argv[0], "init", strlen(argv[0]));
+	struct termios tty;
 
-	/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
-	while (*++argv)
-		memset(*argv, 0, strlen(*argv));
+	tcgetattr(STDIN_FILENO, &tty);
+
+	/* set control chars */
+	tty.c_cc[VINTR] = 3;	/* C-c */
+	tty.c_cc[VQUIT] = 28;	/* C-\ */
+	tty.c_cc[VERASE] = 127;	/* C-? */
+	tty.c_cc[VKILL] = 21;	/* C-u */
+	tty.c_cc[VEOF] = 4;	/* C-d */
+	tty.c_cc[VSTART] = 17;	/* C-q */
+	tty.c_cc[VSTOP] = 19;	/* C-s */
+	tty.c_cc[VSUSP] = 26;	/* C-z */
+
+	/* use line dicipline 0 */
+	tty.c_line = 0;
+
+	/* Make it be sane */
+	tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
+	tty.c_cflag |= CREAD | HUPCL | CLOCAL;
+
+	/* input modes */
+	tty.c_iflag = ICRNL | IXON | IXOFF;
+
+	/* output modes */
+	tty.c_oflag = OPOST | ONLCR;
+
+	/* local modes */
+	tty.c_lflag =
+		ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+
+	tcsetattr(STDIN_FILENO, TCSANOW, &tty);
 }
 
 /* Open the new terminal device */
@@ -324,6 +305,7 @@
 	set_sane_term();
 }
 
+/* Used only by run_actions */
 static pid_t run(const struct init_action *a)
 {
 	int i;
@@ -333,16 +315,20 @@
 	char buf[INIT_BUFFS_SIZE + 6];	/* INIT_BUFFS_SIZE+strlen("exec ")+1 */
 	sigset_t nmask, omask;
 
-	/* Block sigchild while forking.  */
+	/* Block sigchild while forking (why?) */
 	sigemptyset(&nmask);
 	sigaddset(&nmask, SIGCHLD);
 	sigprocmask(SIG_BLOCK, &nmask, &omask);
 	pid = fork();
 	sigprocmask(SIG_SETMASK, &omask, NULL);
 
+	if (pid < 0)
+		message(L_LOG | L_CONSOLE, "Can't fork");
 	if (pid)
 		return pid;
 
+	/* Child */
+
 	/* Reset signal handlers that were set by the parent process */
 	signal(SIGUSR1, SIG_DFL);
 	signal(SIGUSR2, SIG_DFL);
@@ -359,8 +345,9 @@
 	setsid();
 
 	/* Open the new terminal device */
-	open_stdio_to_tty(a->terminal, 1);
+	open_stdio_to_tty(a->terminal, 1 /* - exit if open fails*/);
 
+#ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING
 	/* If the init Action requires us to wait, then force the
 	 * supplied terminal to be the controlling tty. */
 	if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
@@ -373,13 +360,13 @@
 		}
 
 		if (pid > 0) {
-			/* We are the parent -- wait till the child is done */
+			/* Parent - wait till the child is done */
 			signal(SIGINT, SIG_IGN);
 			signal(SIGTSTP, SIG_IGN);
 			signal(SIGQUIT, SIG_IGN);
 			signal(SIGCHLD, SIG_DFL);
 
-			waitfor(NULL, pid);
+			waitfor(pid);
 			/* See if stealing the controlling tty back is necessary */
 			if (tcgetpgrp(0) != getpid())
 				_exit(0);
@@ -395,12 +382,13 @@
 				ioctl(0, TIOCSCTTY, 1);
 				_exit(0);
 			}
-			waitfor(NULL, pid);
+			waitfor(pid);
 			_exit(0);
 		}
 
-		/* Now fall though to actually execute things */
+		/* Child - fall though to actually execute things */
 	}
+#endif
 
 	/* See if any special /bin/sh requiring characters are present */
 	if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
@@ -433,9 +421,9 @@
 		/* skip over the dash */
 		++cmdpath;
 
+#ifdef WHY_WE_DO_THIS_SHELL_MUST_HANDLE_THIS_ITSELF
 		/* find the last component in the command pathname */
 		s = bb_get_last_path_component_nostrip(cmdpath);
-
 		/* make a new argv[0] */
 		cmd[0] = malloc(strlen(s) + 2);
 		if (cmd[0] == NULL) {
@@ -445,16 +433,16 @@
 			cmd[0][0] = '-';
 			strcpy(cmd[0] + 1, s);
 		}
+#endif
+
 #if ENABLE_FEATURE_INIT_SCTTY
 		/* Establish this process as session leader and
-		 * (attempt) to make the tty (if any) a controlling tty.
+		 * _attempt_ to make stdin a controlling tty.
 		 */
-		setsid();
-		ioctl(0, TIOCSCTTY, 0 /*don't steal it*/);
+		ioctl(0, TIOCSCTTY, 0 /*only try, don't steal*/);
 #endif
 	}
 
-#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
 	if (a->action & ASKFIRST) {
 		static const char press_enter[] ALIGN1 =
 #ifdef CUSTOMIZED_BANNER
@@ -474,10 +462,10 @@
 					"(pid %d, tty '%s')\n",
 				  cmdpath, getpid(), a->terminal);
 		full_write(1, press_enter, sizeof(press_enter) - 1);
-		while (read(0, &c, 1) == 1 && c != '\n')
-			;
+		while (safe_read(0, &c, 1) == 1 && c != '\n')
+			continue;
 	}
-#endif
+
 	/* Log the process name and args */
 	message(L_LOG, "starting pid %d, tty '%s': '%s'",
 			  getpid(), a->terminal, cmdpath);
@@ -504,22 +492,15 @@
 	_exit(-1);
 }
 
-static int waitfor(const struct init_action *a, pid_t pid)
+static int waitfor(pid_t runpid)
 {
-	int runpid;
 	int status, wpid;
 
-	runpid = (NULL == a)? pid : run(a);
 	while (1) {
 		wpid = waitpid(runpid, &status, 0);
-		if (wpid == runpid)
-			break;
-		if (wpid == -1 && errno == ECHILD) {
-			/* we missed its termination */
-			break;
-		}
-		/* FIXME other errors should maybe trigger an error, but allow
-		 * the program to continue */
+		if (wpid == -1 && errno == EINTR)
+			continue;
+		break;
 	}
 	return wpid;
 }
@@ -534,9 +515,10 @@
 		if (a->action == action) {
 			/* a->terminal of "" means "init's console" */
 			if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
+				//message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);
 				delete_init_action(a);
 			} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
-				waitfor(a, 0);
+				waitfor(run(a));
 				delete_init_action(a);
 			} else if (a->action & ONCE) {
 				run(a);
@@ -607,6 +589,29 @@
 	sleep(1);
 }
 
+static void shutdown_signal(int sig)
+{
+	const char *m;
+	int rb;
+
+	shutdown_system();
+
+	m = "halt";
+	rb = RB_HALT_SYSTEM;
+	if (sig == SIGTERM) {
+		m = "reboot";
+		rb = RB_AUTOBOOT;
+	} else if (sig == SIGUSR2) {
+		m = "poweroff";
+		rb = RB_POWER_OFF;
+	}
+	message(L_CONSOLE | L_LOG, "Requesting system %s", m);
+	/* allow time for last message to reach serial console */
+	sleep(2);
+	init_reboot(rb);
+	loop_forever();
+}
+
 static void exec_signal(int sig ATTRIBUTE_UNUSED)
 {
 	struct init_action *a, *tmp;
@@ -632,7 +637,7 @@
 			sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL);
 
 			/* Open the new terminal device */
-			open_stdio_to_tty(a->terminal, 0);
+			open_stdio_to_tty(a->terminal, 0 /* - shutdown_signal(SIGUSR1) [halt] if open fails */);
 
 			messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command);
 			BB_EXECLP(a->command, a->command, NULL);
@@ -646,29 +651,6 @@
 	}
 }
 
-static void shutdown_signal(int sig)
-{
-	const char *m;
-	int rb;
-
-	shutdown_system();
-
-	m = "halt";
-	rb = RB_HALT_SYSTEM;
-	if (sig == SIGTERM) {
-		m = "reboot";
-		rb = RB_AUTOBOOT;
-	} else if (sig == SIGUSR2) {
-		m = "poweroff";
-		rb = RB_POWER_OFF;
-	}
-	message(L_CONSOLE | L_LOG, "Requesting system %s", m);
-	/* allow time for last message to reach serial console */
-	sleep(2);
-	init_reboot(rb);
-	loop_forever();
-}
-
 static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)
 {
 	run_actions(CTRLALTDEL);
@@ -682,7 +664,7 @@
 	got_cont = 0;
 	while (!got_cont)
 		pause();
-	got_cont = 0;
+
 	errno = saved_errno;
 }
 
@@ -694,7 +676,7 @@
 
 #endif	/* !ENABLE_DEBUG_INIT */
 
-static void new_init_action(int action, const char *command, const char *cons)
+static void new_init_action(uint8_t action, const char *command, const char *cons)
 {
 	struct init_action *new_action, *a, *last;
 
@@ -754,11 +736,21 @@
 static void parse_inittab(void)
 {
 #if ENABLE_FEATURE_USE_INITTAB
+	static const char actions[] =
+		STR_SYSINIT    "sysinit\0"
+		STR_RESPAWN    "respawn\0"
+		STR_ASKFIRST   "askfirst\0"
+		STR_WAIT       "wait\0"
+		STR_ONCE       "once\0"
+		STR_CTRLALTDEL "ctrlaltdel\0"
+		STR_SHUTDOWN   "shutdown\0"
+		STR_RESTART    "restart\0"
+	;
+
 	FILE *file;
 	char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE];
 	char tmpConsole[CONSOLE_NAME_SIZE];
 	char *id, *runlev, *action, *command, *eol;
-	const struct init_action_type *a = actions;
 
 	file = fopen(INITTAB, "r");
 	if (file == NULL) {
@@ -769,7 +761,8 @@
 		/* Umount all filesystems on halt/reboot */
 		new_init_action(SHUTDOWN, "umount -a -r", "");
 		/* Swapoff on halt/reboot */
-		if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");
+		if (ENABLE_SWAPONOFF)
+			new_init_action(SHUTDOWN, "swapoff -a", "");
 		/* Prepare to restart init when a HUP is received */
 		new_init_action(RESTART, "init", "");
 		/* Askfirst shell on tty1-4 */
@@ -785,6 +778,8 @@
 	}
 
 	while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
+		const char *a;
+
 		/* Skip leading spaces */
 		for (id = buf; *id == ' ' || *id == '\t'; id++);
 
@@ -832,8 +827,8 @@
 		}
 
 		/* Ok, now process it */
-		for (a = actions; a->name != 0; a++) {
-			if (strcmp(a->name, action) == 0) {
+		for (a = actions; a[0]; a += strlen(a) + 1) {
+			if (strcmp(a + 1, action) == 0) {
 				if (*id != '\0') {
 					if (strncmp(id, "/dev/", 5) == 0)
 						id += 5;
@@ -842,11 +837,11 @@
 						sizeof(tmpConsole) - 5);
 					id = tmpConsole;
 				}
-				new_init_action(a->action, command, id);
+				new_init_action((uint8_t)a[0], command, id);
 				break;
 			}
 		}
-		if (a->name == 0) {
+		if (!a[0]) {
 			/* Choke on an unknown action */
 			message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
 		}
@@ -981,8 +976,11 @@
 	}
 #endif /* CONFIG_SELINUX */
 
-	/* Make the command line just say "init"  -- thats all, nothing else */
-	fixup_argv(argv);
+	/* Make the command line just say "init"  - thats all, nothing else */
+	strncpy(argv[0], "init", strlen(argv[0]));
+	/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
+	while (*++argv)
+		memset(*argv, 0, strlen(*argv));
 
 	/* Now run everything that needs to be run */