do not fail build if MAXSYMLINKS isn't defined
[oweals/busybox.git] / init / init.c
index f3a35d5328df0f1701c4326d9767392eef8d90b6..d29328c36f9a801af03a5ff403746fe9c41c74a0 100644 (file)
@@ -9,11 +9,6 @@
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
-//applet:IF_INIT(APPLET(init, BB_DIR_SBIN, BB_SUID_DROP))
-//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, BB_DIR_ROOT, BB_SUID_DROP, linuxrc))
-
-//kbuild:lib-$(CONFIG_INIT) += init.o
-
 //config:config INIT
 //config:      bool "init"
 //config:      default y
 //config:        Note that on Linux, init attempts to detect serial terminal and
 //config:        sets TERM to "vt102" if one is found.
 
+//applet:IF_INIT(APPLET(init, BB_DIR_SBIN, BB_SUID_DROP))
+//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, BB_DIR_ROOT, BB_SUID_DROP, linuxrc))
+
+//kbuild:lib-$(CONFIG_INIT) += init.o
+
 #define DEBUG_SEGV_HANDLER 0
 
 #include "libbb.h"
  * not fully functional init by switching it on! */
 #define DEBUG_INIT 0
 
-#define COMMAND_SIZE      256
 #define CONSOLE_NAME_SIZE 32
 
 /* Default sysinit script. */
@@ -195,7 +194,7 @@ struct init_action {
        pid_t pid;
        uint8_t action_type;
        char terminal[CONSOLE_NAME_SIZE];
-       char command[COMMAND_SIZE];
+       char command[1];
 };
 
 static struct init_action *init_action_list = NULL;
@@ -223,8 +222,8 @@ static void message(int where, const char *fmt, ...)
        msg[0] = '\r';
        va_start(arguments, fmt);
        l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
-       if (l > sizeof(msg) - 1)
-               l = sizeof(msg) - 1;
+       if (l > sizeof(msg) - 2)
+               l = sizeof(msg) - 2;
        va_end(arguments);
 
 #if ENABLE_FEATURE_INIT_SYSLOG
@@ -398,7 +397,7 @@ static void reset_sighandlers_and_unblock_sigs(void)
 }
 
 /* Wrapper around exec:
- * Takes string (max COMMAND_SIZE chars).
+ * Takes string.
  * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'.
  * Otherwise splits words on whitespace, deals with leading dash,
  * and uses plain exec().
@@ -406,10 +405,15 @@ static void reset_sighandlers_and_unblock_sigs(void)
  */
 static void init_exec(const char *command)
 {
-       char *cmd[COMMAND_SIZE / 2];
-       char buf[COMMAND_SIZE + 6];  /* COMMAND_SIZE+strlen("exec ")+1 */
-       int dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
-
+       /* +8 allows to write VLA sizes below more efficiently: */
+       unsigned command_size = strlen(command) + 8;
+       /* strlen(command) + strlen("exec ")+1: */
+       char buf[command_size];
+       /* strlen(command) / 2 + 4: */
+       char *cmd[command_size / 2];
+       int dash;
+
+       dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
        command += dash;
 
        /* See if any special /bin/sh requiring characters are present */
@@ -626,15 +630,15 @@ static void new_init_action(uint8_t action_type, const char *command, const char
                nextp = &a->next;
        }
 
-       a = xzalloc(sizeof(*a));
+       a = xzalloc(sizeof(*a) + strlen(command));
 
        /* Append to the end of the list */
  append:
        *nextp = a;
        a->action_type = action_type;
-       safe_strncpy(a->command, command, sizeof(a->command));
+       strcpy(a->command, command);
        safe_strncpy(a->terminal, cons, sizeof(a->terminal));
-       dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
+       dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%x tty='%s'\n",
                a->command, a->action_type, a->terminal);
 }
 
@@ -785,7 +789,7 @@ static void run_shutdown_and_kill_processes(void)
  * and only one will be remembered and acted upon.
  */
 
-/* The SIGUSR[12]/SIGTERM handler */
+/* The SIGPWR/SIGUSR[12]/SIGTERM handler */
 static void halt_reboot_pwoff(int sig) NORETURN;
 static void halt_reboot_pwoff(int sig)
 {
@@ -930,10 +934,17 @@ static void reload_inittab(void)
 
        /* Remove stale entries and SYSINIT entries.
         * We never rerun SYSINIT entries anyway,
-        * removing them too saves a few bytes */
+        * removing them too saves a few bytes
+        */
        nextp = &init_action_list;
        while ((a = *nextp) != NULL) {
-               if ((a->action_type & ~SYSINIT) == 0) {
+               /*
+                * Why pid == 0 check?
+                * Process can be removed from inittab and added *later*.
+                * If we delete its entry but process still runs,
+                * duplicate is spawned when the entry is re-added.
+                */
+               if ((a->action_type & ~SYSINIT) == 0 && a->pid == 0) {
                        *nextp = a->next;
                        free(a);
                } else {
@@ -1092,8 +1103,8 @@ int init_main(int argc UNUSED_PARAM, char **argv)
 
                /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
                 * then parse_inittab() simply adds in some default
-                * actions(i.e., INIT_SCRIPT and a pair
-                * of "askfirst" shells */
+                * actions (i.e., INIT_SCRIPT and a pair
+                * of "askfirst" shells) */
                parse_inittab();
        }
 
@@ -1117,13 +1128,14 @@ int init_main(int argc UNUSED_PARAM, char **argv)
        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));
+               nuke_str(*argv);
 
        /* Set up signal handlers */
        if (!DEBUG_INIT) {
                struct sigaction sa;
 
                bb_signals(0
+                       + (1 << SIGPWR)  /* halt */
                        + (1 << SIGUSR1) /* halt */
                        + (1 << SIGTERM) /* reboot */
                        + (1 << SIGUSR2) /* poweroff */
@@ -1219,7 +1231,14 @@ int init_main(int argc UNUSED_PARAM, char **argv)
 //usage:#define init_trivial_usage
 //usage:       ""
 //usage:#define init_full_usage "\n\n"
-//usage:       "Init is the parent of all processes"
+//usage:       "Init is the first process started during boot. It never exits."
+//usage:       IF_FEATURE_USE_INITTAB(
+//usage:   "\n""It (re)spawns children according to /etc/inittab."
+//usage:       )
+//usage:       IF_NOT_FEATURE_USE_INITTAB(
+//usage:   "\n""This version of init doesn't use /etc/inittab,"
+//usage:   "\n""has fixed set of processed to run."
+//usage:       )
 //usage:
 //usage:#define init_notes_usage
 //usage:       "This version of init is designed to be run only by the kernel.\n"