Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/init


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
Location:
branches/2.2.9/mindi-busybox/init
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/init/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    67menu "Init Utilities"
    78
     9config BOOTCHARTD
     10    bool "bootchartd"
     11    default y
     12    help
     13      bootchartd is commonly used to profile the boot process
     14      for the purpose of speeding it up. In this case, it is started
     15      by the kernel as the init process. This is configured by adding
     16      the init=/sbin/bootchartd option to the kernel command line.
     17
     18      It can also be used to monitor the resource usage of a specific
     19      application or the running system in general. In this case,
     20      bootchartd is started interactively by running bootchartd start
     21      and stopped using bootchartd stop.
     22
     23config FEATURE_BOOTCHARTD_BLOATED_HEADER
     24    bool "Compatible, bloated header"
     25    default y
     26    depends on BOOTCHARTD
     27    help
     28      Create extended header file compatible with "big" bootchartd.
     29      "Big" bootchartd is a shell script and it dumps some
     30      "convenient" info int the header, such as:
     31        title = Boot chart for `hostname` (`date`)
     32        system.uname = `uname -srvm`
     33        system.release = `cat /etc/DISTRO-release`
     34        system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount)
     35        system.kernel.options = `cat /proc/cmdline`
     36      This data is not mandatory for bootchart graph generation,
     37      and is considered bloat. Nevertheless, this option
     38      makes bootchartd applet to dump a subset of it.
     39
     40config FEATURE_BOOTCHARTD_CONFIG_FILE
     41    bool "Support bootchartd.conf"
     42    default y
     43    depends on BOOTCHARTD
     44    help
     45      Enable reading and parsing of $PWD/bootchartd.conf
     46      and /etc/bootchartd.conf files.
     47config HALT
     48    bool "poweroff, halt, and reboot"
     49    default y
     50    help
     51      Stop all processes and either halt, reboot, or power off the system.
     52
     53config FEATURE_CALL_TELINIT
     54    bool "Call telinit on shutdown and reboot"
     55    default y
     56    depends on HALT && !INIT
     57    help
     58      Call an external program (normally telinit) to facilitate
     59      a switch to a proper runlevel.
     60
     61      This option is only available if you selected halt and friends,
     62      but did not select init.
     63
     64config TELINIT_PATH
     65    string "Path to telinit executable"
     66    default "/sbin/telinit"
     67    depends on FEATURE_CALL_TELINIT
     68    help
     69      When busybox halt and friends have to call external telinit
     70      to facilitate proper shutdown, this path is to be used when
     71      locating telinit executable.
    872config INIT
    973    bool "init"
    10     default n
     74    default y
    1175    select FEATURE_SYSLOG
    1276    help
    1377      init is the first program run when the system boots.
    14 
    15 config DEBUG_INIT
    16     bool "debugging aid"
    17     default n
    18     depends on INIT
    19     help
    20       Turn this on to disable all the dangerous
    21       rebooting stuff when debugging.
    2278
    2379config FEATURE_USE_INITTAB
     
    2884      Allow init to read an inittab file when the system boot.
    2985
     86config FEATURE_KILL_REMOVED
     87    bool "Support killing processes that have been removed from inittab"
     88    default n
     89    depends on FEATURE_USE_INITTAB
     90    help
     91      When respawn entries are removed from inittab and a SIGHUP is
     92      sent to init, this option will make init kill the processes
     93      that have been removed.
     94
     95config FEATURE_KILL_DELAY
     96    int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
     97    range 0 1024
     98    default 0
     99    depends on FEATURE_KILL_REMOVED
     100    help
     101      With nonzero setting, init sends TERM, forks, child waits N
     102      seconds, sends KILL and exits. Setting it too high is unwise
     103      (child will hang around for too long and could actually kill
     104      the wrong process!)
     105
    30106config FEATURE_INIT_SCTTY
    31     bool "Support running commands with a controlling-tty"
    32     default n
     107    bool "Run commands with leading dash with controlling tty"
     108    default y
    33109    depends on INIT
    34110    help
    35       If this option is enabled a command starting with hyphen (-)
    36       is run in its own session (setsid(2)) and possibly with a
    37       controlling tty (TIOCSCTTY).  This is not the traditional init
    38       behavour, but is often what you want in an embedded system where
    39       the console is only accessed during development or for maintenance.
     111      If this option is enabled, init will try to give a controlling
     112      tty to any command which has leading hyphen (often it's "-/bin/sh").
     113      More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
     114      If device attached to STDIN_FILENO can be a ctty but is not yet
     115      a ctty for other session, it will become this process' ctty.
     116      This is not the traditional init behavour, but is often what you want
     117      in an embedded system where the console is only accessed during
     118      development or for maintenance.
     119      NB: using cttyhack applet may work better.
    40120
    41121config FEATURE_INIT_SYSLOG
    42122    bool "Enable init to write to syslog"
    43     default n
     123    default y
    44124    depends on INIT
    45125
     
    53133config FEATURE_INIT_COREDUMPS
    54134    bool "Support dumping core for child processes (debugging only)"
    55     default n
     135    default y
    56136    depends on INIT
    57137    help
    58138      If this option is enabled and the file /.init_enable_core
    59139      exists, then init will call setrlimit() to allow unlimited
    60       core file sizes.  If this option is disabled, processes
     140      core file sizes. If this option is disabled, processes
    61141      will not generate any core files.
    62 
    63 
    64142
    65143config FEATURE_INITRD
     
    68146    depends on INIT
    69147    help
    70       Legacy support for running init under the old-style initrd.  Allows
     148      Legacy support for running init under the old-style initrd. Allows
    71149      the name linuxrc to act as init, and it doesn't assume init is PID 1.
    72150
     
    74152      requires no special support.
    75153
    76 config HALT
    77     bool "poweroff, halt, and reboot"
    78     default y
     154config INIT_TERMINAL_TYPE
     155    string "Initial terminal type"
     156    default "linux"
     157    depends on INIT
    79158    help
    80       Stop all processes and either halt, reboot, or power off the system.
     159      This is the initial value set by init for the TERM environment
     160      variable. This variable is used by programs which make use of
     161      extended terminal capabilities.
    81162
     163      Note that on Linux, init attempts to detect serial terminal and
     164      sets TERM to "vt102" if one is found.
    82165config MESG
    83166    bool "mesg"
    84167    default y
    85168    help
    86       Mesg controls access to your terminal by others.  It is typically
     169      Mesg controls access to your terminal by others. It is typically
    87170      used to allow or disallow other users to write to your terminal
    88171
  • branches/2.2.9/mindi-busybox/init/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2, see the file LICENSE in this tarball.
     6# Licensed under GPLv2, see file LICENSE in this source tree.
    67
    78lib-y:=
    8 lib-$(CONFIG_HALT)  += halt.o
    9 lib-$(CONFIG_INIT)  += init.o
    10 lib-$(CONFIG_MESG)  += mesg.o
     9
     10lib-$(CONFIG_BOOTCHARTD) += bootchartd.o
     11lib-$(CONFIG_HALT) += halt.o
     12lib-$(CONFIG_INIT) += init.o
     13lib-$(CONFIG_MESG) += mesg.o
  • branches/2.2.9/mindi-busybox/init/halt.c

    r1765 r2725  
    55 * Copyright 2006 by Rob Landley <rob@landley.net>
    66 *
    7  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    99
     10//applet:IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP))
     11//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff))
     12//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot))
     13
     14//kbuild:lib-$(CONFIG_HALT) += halt.o
     15
     16//config:config HALT
     17//config:   bool "poweroff, halt, and reboot"
     18//config:   default y
     19//config:   help
     20//config:     Stop all processes and either halt, reboot, or power off the system.
     21//config:
     22//config:config FEATURE_CALL_TELINIT
     23//config:   bool "Call telinit on shutdown and reboot"
     24//config:   default y
     25//config:   depends on HALT && !INIT
     26//config:   help
     27//config:     Call an external program (normally telinit) to facilitate
     28//config:     a switch to a proper runlevel.
     29//config:
     30//config:     This option is only available if you selected halt and friends,
     31//config:     but did not select init.
     32//config:
     33//config:config TELINIT_PATH
     34//config:   string "Path to telinit executable"
     35//config:   default "/sbin/telinit"
     36//config:   depends on FEATURE_CALL_TELINIT
     37//config:   help
     38//config:     When busybox halt and friends have to call external telinit
     39//config:     to facilitate proper shutdown, this path is to be used when
     40//config:     locating telinit executable.
     41
     42//usage:#define halt_trivial_usage
     43//usage:       "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
     44//usage:#define halt_full_usage "\n\n"
     45//usage:       "Halt the system\n"
     46//usage:     "\nOptions:"
     47//usage:     "\n    -d SEC  Delay interval"
     48//usage:     "\n    -n  Do not sync"
     49//usage:     "\n    -f  Force (don't go through init)"
     50//usage:    IF_FEATURE_WTMP(
     51//usage:     "\n    -w  Only write a wtmp record"
     52//usage:    )
     53//usage:
     54//usage:#define poweroff_trivial_usage
     55//usage:       "[-d DELAY] [-n] [-f]"
     56//usage:#define poweroff_full_usage "\n\n"
     57//usage:       "Halt and shut off power\n"
     58//usage:     "\nOptions:"
     59//usage:     "\n    -d SEC  Delay interval"
     60//usage:     "\n    -n  Do not sync"
     61//usage:     "\n    -f  Force (don't go through init)"
     62//usage:
     63//usage:#define reboot_trivial_usage
     64//usage:       "[-d DELAY] [-n] [-f]"
     65//usage:#define reboot_full_usage "\n\n"
     66//usage:       "Reboot the system\n"
     67//usage:     "\nOptions:"
     68//usage:     "\n    -d SEC  Delay interval"
     69//usage:     "\n    -n  Do not sync"
     70//usage:     "\n    -f  Force (don't go through init)"
     71
    1072#include "libbb.h"
    11 #include <sys/reboot.h>
     73#include "reboot.h"
    1274
    13 int halt_main(int argc, char **argv);
    14 int halt_main(int argc, char **argv)
     75#if ENABLE_FEATURE_WTMP
     76#include <sys/utsname.h>
     77#include <utmp.h>
     78
     79static void write_wtmp(void)
     80{
     81    struct utmp utmp;
     82    struct utsname uts;
     83    /* "man utmp" says wtmp file should *not* be created automagically */
     84    /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) {
     85        close(creat(bb_path_wtmp_file, 0664));
     86    }*/
     87    memset(&utmp, 0, sizeof(utmp));
     88    utmp.ut_tv.tv_sec = time(NULL);
     89    strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */
     90    utmp.ut_type = RUN_LVL;
     91    utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */
     92    utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */
     93    uname(&uts);
     94    safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host));
     95    updwtmp(bb_path_wtmp_file, &utmp);
     96}
     97#else
     98#define write_wtmp() ((void)0)
     99#endif
     100
     101
     102int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     103int halt_main(int argc UNUSED_PARAM, char **argv)
    15104{
    16105    static const int magic[] = {
    17 #ifdef RB_HALT_SYSTEM
    18 RB_HALT_SYSTEM,
    19 #elif defined RB_HALT
    20 RB_HALT,
    21 #endif
    22 #ifdef RB_POWER_OFF
    23 RB_POWER_OFF,
    24 #elif defined RB_POWERDOWN
    25 RB_POWERDOWN,
    26 #endif
    27 RB_AUTOBOOT
     106        RB_HALT_SYSTEM,
     107        RB_POWER_OFF,
     108        RB_AUTOBOOT
    28109    };
    29     static const int signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
     110    static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
    30111
    31     char *delay;
    32     int which, flags, rc = 1;
     112    int delay = 0;
     113    int which, flags, rc;
    33114
    34115    /* Figure out which applet we're running */
    35     for (which = 0; "hpr"[which] != *applet_name; which++);
     116    for (which = 0; "hpr"[which] != applet_name[0]; which++)
     117        continue;
    36118
    37119    /* Parse and handle arguments */
    38     flags = getopt32(argv, "d:nf", &delay);
    39     if (flags & 1) sleep(xatou(delay));
    40     if (!(flags & 2)) sync();
     120    opt_complementary = "d+"; /* -d N */
     121    /* We support -w even if !ENABLE_FEATURE_WTMP,
     122     * in order to not break scripts.
     123     * -i (shut down network interfaces) is ignored.
     124     */
     125    flags = getopt32(argv, "d:nfwi", &delay);
     126
     127    sleep(delay);
     128
     129    write_wtmp();
     130
     131    if (flags & 8) /* -w */
     132        return EXIT_SUCCESS;
     133
     134    if (!(flags & 2)) /* no -n */
     135        sync();
    41136
    42137    /* Perform action. */
    43     if (ENABLE_INIT && !(flags & 4)) {
     138    rc = 1;
     139    if (!(flags & 4)) { /* no -f */
     140//TODO: I tend to think that signalling linuxrc is wrong
     141// pity original author didn't comment on it...
    44142        if (ENABLE_FEATURE_INITRD) {
     143            /* talk to linuxrc */
     144            /* bbox init/linuxrc assumed */
    45145            pid_t *pidlist = find_pid_by_name("linuxrc");
    46146            if (pidlist[0] > 0)
     
    49149                free(pidlist);
    50150        }
    51         if (rc)
    52             rc = kill(1, signals[which]);
    53     } else
     151        if (rc) {
     152            /* talk to init */
     153            if (!ENABLE_FEATURE_CALL_TELINIT) {
     154                /* bbox init assumed */
     155                rc = kill(1, signals[which]);
     156            } else {
     157                /* SysV style init assumed */
     158                /* runlevels:
     159                 * 0 == shutdown
     160                 * 6 == reboot */
     161                rc = execlp(CONFIG_TELINIT_PATH,
     162                        CONFIG_TELINIT_PATH,
     163                        which == 2 ? "6" : "0",
     164                        (char *)NULL
     165                );
     166            }
     167        }
     168    } else {
    54169        rc = reboot(magic[which]);
     170    }
    55171
    56172    if (rc)
    57         bb_error_msg("no");
     173        bb_perror_nomsg_and_die();
    58174    return rc;
    59175}
  • branches/2.2.9/mindi-busybox/init/init.c

    r1765 r2725  
    77 * Adjusted by so many folks, it's impossible to keep track.
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    1111
     12//applet:IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP))
     13//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc))
     14
     15//kbuild:lib-$(CONFIG_INIT) += init.o
     16
     17//config:config INIT
     18//config:   bool "init"
     19//config:   default y
     20//config:   select FEATURE_SYSLOG
     21//config:   help
     22//config:     init is the first program run when the system boots.
     23//config:
     24//config:config FEATURE_USE_INITTAB
     25//config:   bool "Support reading an inittab file"
     26//config:   default y
     27//config:   depends on INIT
     28//config:   help
     29//config:     Allow init to read an inittab file when the system boot.
     30//config:
     31//config:config FEATURE_KILL_REMOVED
     32//config:   bool "Support killing processes that have been removed from inittab"
     33//config:   default n
     34//config:   depends on FEATURE_USE_INITTAB
     35//config:   help
     36//config:     When respawn entries are removed from inittab and a SIGHUP is
     37//config:     sent to init, this option will make init kill the processes
     38//config:     that have been removed.
     39//config:
     40//config:config FEATURE_KILL_DELAY
     41//config:   int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
     42//config:   range 0 1024
     43//config:   default 0
     44//config:   depends on FEATURE_KILL_REMOVED
     45//config:   help
     46//config:     With nonzero setting, init sends TERM, forks, child waits N
     47//config:     seconds, sends KILL and exits. Setting it too high is unwise
     48//config:     (child will hang around for too long and could actually kill
     49//config:     the wrong process!)
     50//config:
     51//config:config FEATURE_INIT_SCTTY
     52//config:   bool "Run commands with leading dash with controlling tty"
     53//config:   default y
     54//config:   depends on INIT
     55//config:   help
     56//config:     If this option is enabled, init will try to give a controlling
     57//config:     tty to any command which has leading hyphen (often it's "-/bin/sh").
     58//config:     More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
     59//config:     If device attached to STDIN_FILENO can be a ctty but is not yet
     60//config:     a ctty for other session, it will become this process' ctty.
     61//config:     This is not the traditional init behavour, but is often what you want
     62//config:     in an embedded system where the console is only accessed during
     63//config:     development or for maintenance.
     64//config:     NB: using cttyhack applet may work better.
     65//config:
     66//config:config FEATURE_INIT_SYSLOG
     67//config:   bool "Enable init to write to syslog"
     68//config:   default y
     69//config:   depends on INIT
     70//config:
     71//config:config FEATURE_EXTRA_QUIET
     72//config:   bool "Be _extra_ quiet on boot"
     73//config:   default y
     74//config:   depends on INIT
     75//config:   help
     76//config:     Prevent init from logging some messages to the console during boot.
     77//config:
     78//config:config FEATURE_INIT_COREDUMPS
     79//config:   bool "Support dumping core for child processes (debugging only)"
     80//config:   default y
     81//config:   depends on INIT
     82//config:   help
     83//config:     If this option is enabled and the file /.init_enable_core
     84//config:     exists, then init will call setrlimit() to allow unlimited
     85//config:     core file sizes. If this option is disabled, processes
     86//config:     will not generate any core files.
     87//config:
     88//config:config FEATURE_INITRD
     89//config:   bool "Support running init from within an initrd (not initramfs)"
     90//config:   default y
     91//config:   depends on INIT
     92//config:   help
     93//config:     Legacy support for running init under the old-style initrd. Allows
     94//config:     the name linuxrc to act as init, and it doesn't assume init is PID 1.
     95//config:
     96//config:     This does not apply to initramfs, which runs /init as PID 1 and
     97//config:     requires no special support.
     98//config:
     99//config:config INIT_TERMINAL_TYPE
     100//config:   string "Initial terminal type"
     101//config:   default "linux"
     102//config:   depends on INIT
     103//config:   help
     104//config:     This is the initial value set by init for the TERM environment
     105//config:     variable. This variable is used by programs which make use of
     106//config:     extended terminal capabilities.
     107//config:
     108//config:     Note that on Linux, init attempts to detect serial terminal and
     109//config:     sets TERM to "vt102" if one is found.
     110
    12111#include "libbb.h"
     112#include <syslog.h>
    13113#include <paths.h>
    14 //#include <signal.h>
    15 //#include <sys/ioctl.h>
    16 //#include <sys/wait.h>
    17 #include <sys/reboot.h>
    18 
    19 #if ENABLE_FEATURE_INIT_SYSLOG
    20 # include <sys/syslog.h>
    21 #endif
    22 
    23 #define INIT_BUFFS_SIZE 256
     114#include <sys/resource.h>
     115#ifdef __linux__
     116#include <linux/vt.h>
     117#endif
     118#if ENABLE_FEATURE_UTMP
     119# include <utmp.h> /* DEAD_PROCESS */
     120#endif
     121#include "reboot.h" /* reboot() constants */
     122
     123/* Used only for sanitizing purposes in set_sane_term() below. On systems where
     124 * the baud rate is stored in a separate field, we can safely disable them. */
     125#ifndef CBAUD
     126# define CBAUD 0
     127# define CBAUDEX 0
     128#endif
     129
     130/* Was a CONFIG_xxx option. A lot of people were building
     131 * not fully functional init by switching it on! */
     132#define DEBUG_INIT 0
     133
     134#define COMMAND_SIZE      256
    24135#define CONSOLE_NAME_SIZE 32
    25 #define MAXENV  16      /* Number of env. vars */
    26 
    27 #if ENABLE_FEATURE_INIT_COREDUMPS
     136
     137/* Default sysinit script. */
     138#ifndef INIT_SCRIPT
     139#define INIT_SCRIPT  "/etc/init.d/rcS"
     140#endif
     141
     142/* Each type of actions can appear many times. They will be
     143 * handled in order. RESTART is an exception, only 1st is used.
     144 */
     145/* Start these actions first and wait for completion */
     146#define SYSINIT     0x01
     147/* Start these after SYSINIT and wait for completion */
     148#define WAIT        0x02
     149/* Start these after WAIT and *dont* wait for completion */
     150#define ONCE        0x04
    28151/*
    29  * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called
    30  * before processes are spawned to set core file size as unlimited.
    31  * This is for debugging only.  Don't use this is production, unless
    32  * you want core dumps lying about....
     152 * NB: while SYSINIT/WAIT/ONCE are being processed,
     153 * SIGHUP ("reread /etc/inittab") will be processed only after
     154 * each group of actions. If new inittab adds, say, a SYSINIT action,
     155 * it will not be run, since init is already "past SYSINIT stage".
    33156 */
    34 #define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
    35 #include <sys/resource.h>
    36 #endif
    37 
    38 #define INITTAB      "/etc/inittab" /* inittab file location */
    39 #ifndef INIT_SCRIPT
    40 #define INIT_SCRIPT  "/etc/init.d/rcS"  /* Default sysinit script. */
    41 #endif
    42 
    43 /* Allowed init action types */
    44 #define SYSINIT     0x001
    45 #define RESPAWN     0x002
    46 #define ASKFIRST    0x004
    47 #define WAIT        0x008
    48 #define ONCE        0x010
    49 #define CTRLALTDEL  0x020
    50 #define SHUTDOWN    0x040
    51 #define RESTART     0x080
    52 
    53 /* A mapping between "inittab" action name strings and action type codes. */
    54 struct init_action_type {
    55     const char *name;
    56     int action;
    57 };
    58 
    59 static const struct init_action_type actions[] = {
    60     {"sysinit", SYSINIT},
    61     {"respawn", RESPAWN},
    62     {"askfirst", ASKFIRST},
    63     {"wait", WAIT},
    64     {"once", ONCE},
    65     {"ctrlaltdel", CTRLALTDEL},
    66     {"shutdown", SHUTDOWN},
    67     {"restart", RESTART},
    68     {0, 0}
    69 };
    70 
    71 /* Set up a linked list of init_actions, to be read from inittab */
     157/* Start these after ONCE are started, restart on exit */
     158#define RESPAWN     0x08
     159/* Like RESPAWN, but wait for <Enter> to be pressed on tty */
     160#define ASKFIRST    0x10
     161/*
     162 * Start these on SIGINT, and wait for completion.
     163 * Then go back to respawning RESPAWN and ASKFIRST actions.
     164 * NB: kernel sends SIGINT to us if Ctrl-Alt-Del was pressed.
     165 */
     166#define CTRLALTDEL  0x20
     167/*
     168 * Start these before killing all processes in preparation for
     169 * running RESTART actions or doing low-level halt/reboot/poweroff
     170 * (initiated by SIGUSR1/SIGTERM/SIGUSR2).
     171 * Wait for completion before proceeding.
     172 */
     173#define SHUTDOWN    0x40
     174/*
     175 * exec() on SIGQUIT. SHUTDOWN actions are started and waited for,
     176 * then all processes are killed, then init exec's 1st RESTART action,
     177 * replacing itself by it. If no RESTART action specified,
     178 * SIGQUIT has no effect.
     179 */
     180#define RESTART     0x80
     181
     182
     183/* A linked list of init_actions, to be read from inittab */
    72184struct init_action {
    73185    struct init_action *next;
    74     int action;
    75186    pid_t pid;
    76     char command[INIT_BUFFS_SIZE];
     187    uint8_t action_type;
    77188    char terminal[CONSOLE_NAME_SIZE];
     189    char command[COMMAND_SIZE];
    78190};
    79191
    80 /* Static variables */
    81192static struct init_action *init_action_list = NULL;
    82193
    83 #if !ENABLE_FEATURE_INIT_SYSLOG
    84194static const char *log_console = VC_5;
    85 #endif
    86 #if !ENABLE_DEBUG_INIT
    87 static sig_atomic_t got_cont = 0;
    88 #endif
    89195
    90196enum {
    91197    L_LOG = 0x1,
    92198    L_CONSOLE = 0x2,
    93 
    94 #if ENABLE_FEATURE_EXTRA_QUIET
    95     MAYBE_CONSOLE = 0x0,
    96 #else
    97     MAYBE_CONSOLE = L_CONSOLE,
    98 #endif
    99 
    100 #ifndef RB_HALT_SYSTEM
    101     RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */
    102     RB_ENABLE_CAD = 0x89abcdef,
    103     RB_DISABLE_CAD = 0,
    104     RB_POWER_OFF = 0x4321fedc,
    105     RB_AUTOBOOT = 0x01234567,
    106 #endif
    107199};
    108200
    109 static const char *const environment[] = {
    110     "HOME=/",
    111     bb_PATH_root_path,
    112     "SHELL=/bin/sh",
    113     "USER=root",
    114     NULL
    115 };
    116 
    117 /* Function prototypes */
    118 static void delete_init_action(struct init_action *a);
    119 static int waitfor(const struct init_action *a, pid_t pid);
    120 #if !ENABLE_DEBUG_INIT
    121 static void shutdown_signal(int sig);
    122 #endif
    123 
    124 #if !ENABLE_DEBUG_INIT
    125 static void loop_forever(void)
    126 {
    127     while (1)
    128         sleep(1);
    129 }
    130 #endif
    131 
    132201/* Print a message to the specified device.
    133  * Device may be bitwise-or'd from L_LOG | L_CONSOLE */
    134 #if ENABLE_DEBUG_INIT
    135 #define messageD message
    136 #else
    137 #define messageD(...)  do {} while (0)
    138 #endif
    139 static void message(int device, const char *fmt, ...)
     202 * "where" may be bitwise-or'd from L_LOG | L_CONSOLE
     203 * NB: careful, we can be called after vfork!
     204 */
     205#define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0)
     206static void message(int where, const char *fmt, ...)
    140207    __attribute__ ((format(printf, 2, 3)));
    141 static void message(int device, const char *fmt, ...)
    142 {
    143 #if !ENABLE_FEATURE_INIT_SYSLOG
    144     static int log_fd = -1;
    145 #endif
    146 
     208static void message(int where, const char *fmt, ...)
     209{
    147210    va_list arguments;
    148     int l;
     211    unsigned l;
    149212    char msg[128];
    150213
    151214    msg[0] = '\r';
    152215    va_start(arguments, fmt);
    153     vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
     216    l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
     217    if (l > sizeof(msg) - 1)
     218        l = sizeof(msg) - 1;
    154219    va_end(arguments);
    155     msg[sizeof(msg) - 2] = '\0';
    156     l = strlen(msg);
    157220
    158221#if ENABLE_FEATURE_INIT_SYSLOG
    159     /* Log the message to syslogd */
    160     if (device & L_LOG) {
    161         /* don't out "\r" */
     222    msg[l] = '\0';
     223    if (where & L_LOG) {
     224        /* Log the message to syslogd */
    162225        openlog(applet_name, 0, LOG_DAEMON);
    163         syslog(LOG_INFO, "init: %s", msg + 1);
     226        /* don't print "\r" */
     227        syslog(LOG_INFO, "%s", msg + 1);
    164228        closelog();
    165229    }
     
    167231    msg[l] = '\0';
    168232#else
    169     msg[l++] = '\n';
    170     msg[l] = '\0';
    171     /* Take full control of the log tty, and never close it.
    172      * It's mine, all mine!  Muhahahaha! */
    173     if (log_fd < 0) {
    174         if (!log_console) {
    175             log_fd = 2;
    176         } else {
    177             log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY);
    178             if (log_fd < 0) {
    179                 bb_error_msg("can't log to %s", log_console);
    180                 device = L_CONSOLE;
     233    {
     234        static int log_fd = -1;
     235
     236        msg[l++] = '\n';
     237        msg[l] = '\0';
     238        /* Take full control of the log tty, and never close it.
     239         * It's mine, all mine!  Muhahahaha! */
     240        if (log_fd < 0) {
     241            if (!log_console) {
     242                log_fd = STDERR_FILENO;
    181243            } else {
    182                 fcntl(log_fd, F_SETFD, FD_CLOEXEC);
     244                log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY);
     245                if (log_fd < 0) {
     246                    bb_error_msg("can't log to %s", log_console);
     247                    where = L_CONSOLE;
     248                } else {
     249                    close_on_exec_on(log_fd);
     250                }
    183251            }
    184252        }
    185     }
    186     if (device & L_LOG) {
    187         full_write(log_fd, msg, l);
    188         if (log_fd == 2)
    189             return; /* don't print dup messages */
    190     }
    191 #endif
    192 
    193     if (device & L_CONSOLE) {
     253        if (where & L_LOG) {
     254            full_write(log_fd, msg, l);
     255            if (log_fd == STDERR_FILENO)
     256                return; /* don't print dup messages */
     257        }
     258    }
     259#endif
     260
     261    if (where & L_CONSOLE) {
    194262        /* Send console messages to console so people will see them. */
    195         full_write(2, msg, l);
    196     }
    197 }
    198 
    199 /* Set terminal settings to reasonable defaults */
     263        full_write(STDERR_FILENO, msg, l);
     264    }
     265}
     266
     267static void console_init(void)
     268{
     269#ifdef VT_OPENQRY
     270    int vtno;
     271#endif
     272    char *s;
     273
     274    s = getenv("CONSOLE");
     275    if (!s)
     276        s = getenv("console");
     277    if (s) {
     278        int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY);
     279        if (fd >= 0) {
     280            dup2(fd, STDIN_FILENO);
     281            dup2(fd, STDOUT_FILENO);
     282            xmove_fd(fd, STDERR_FILENO);
     283        }
     284        dbg_message(L_LOG, "console='%s'", s);
     285    } else {
     286        /* Make sure fd 0,1,2 are not closed
     287         * (so that they won't be used by future opens) */
     288        bb_sanitize_stdio();
     289// Users report problems
     290//      /* Make sure init can't be blocked by writing to stderr */
     291//      fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK);
     292    }
     293
     294    s = getenv("TERM");
     295#ifdef VT_OPENQRY
     296    if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) {
     297        /* Not a linux terminal, probably serial console.
     298         * Force the TERM setting to vt102
     299         * if TERM is set to linux (the default) */
     300        if (!s || strcmp(s, "linux") == 0)
     301            putenv((char*)"TERM=vt102");
     302        if (!ENABLE_FEATURE_INIT_SYSLOG)
     303            log_console = NULL;
     304    } else
     305#endif
     306    if (!s)
     307        putenv((char*)"TERM=" CONFIG_INIT_TERMINAL_TYPE);
     308}
     309
     310/* Set terminal settings to reasonable defaults.
     311 * NB: careful, we can be called after vfork! */
    200312static void set_sane_term(void)
    201313{
     
    214326    tty.c_cc[VSUSP] = 26;   /* C-z */
    215327
    216     /* use line dicipline 0 */
     328#ifdef __linux__
     329    /* use line discipline 0 */
    217330    tty.c_line = 0;
     331#endif
    218332
    219333    /* Make it be sane */
    220     tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
     334#ifndef CRTSCTS
     335# define CRTSCTS 0
     336#endif
     337    /* added CRTSCTS to fix Debian bug 528560 */
     338    tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS;
    221339    tty.c_cflag |= CREAD | HUPCL | CLOCAL;
    222340
     
    228346
    229347    /* local modes */
    230     tty.c_lflag =
    231         ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
    232 
    233     tcsetattr(STDIN_FILENO, TCSANOW, &tty);
    234 }
    235 
    236 /* From <linux/serial.h> */
    237 struct serial_struct {
    238     int type;
    239     int line;
    240     unsigned int    port;
    241     int irq;
    242     int flags;
    243     int xmit_fifo_size;
    244     int custom_divisor;
    245     int baud_base;
    246     unsigned short  close_delay;
    247     char    io_type;
    248     char    reserved_char[1];
    249     int hub6;
    250     unsigned short  closing_wait; /* time to wait before closing */
    251     unsigned short  closing_wait2; /* no longer used... */
    252     unsigned char   *iomem_base;
    253     unsigned short  iomem_reg_shift;
    254     unsigned int    port_high;
    255     unsigned long   iomap_base; /* cookie passed into ioremap */
    256     int reserved[1];
    257     /* Paranoia (imagine 64bit kernel overwriting 32bit userspace stack) */
    258     uint32_t bbox_reserved[16];
    259 };
    260 static void console_init(void)
    261 {
    262     struct serial_struct sr;
    263     char *s;
    264 
    265     s = getenv("CONSOLE");
    266     if (!s) s = getenv("console");
    267     if (s) {
    268         int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY);
    269         if (fd >= 0) {
    270             dup2(fd, 0);
    271             dup2(fd, 1);
    272             dup2(fd, 2);
    273             while (fd > 2) close(fd--);
    274         }
    275         messageD(L_LOG, "console='%s'", s);
    276     } else {
    277         /* Make sure fd 0,1,2 are not closed */
    278         bb_sanitize_stdio();
    279     }
    280 
    281     s = getenv("TERM");
    282     if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
    283         /* Force the TERM setting to vt102 for serial console --
    284          * if TERM is set to linux (the default) */
    285         if (!s || strcmp(s, "linux") == 0)
    286             putenv((char*)"TERM=vt102");
    287 #if !ENABLE_FEATURE_INIT_SYSLOG
    288         log_console = NULL;
    289 #endif
    290     } else if (!s)
    291         putenv((char*)"TERM=linux");
    292 }
    293 
    294 static void fixup_argv(char **argv)
    295 {
    296     /* Fix up argv[0] to be certain we claim to be init */
    297     strncpy(argv[0], "init", strlen(argv[0]));
    298 
    299     /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
    300     while (*++argv)
    301         memset(*argv, 0, strlen(*argv));
    302 }
    303 
    304 /* Open the new terminal device */
    305 static void open_stdio_to_tty(const char* tty_name, int fail)
     348    tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
     349
     350    tcsetattr_stdin_TCSANOW(&tty);
     351}
     352
     353/* Open the new terminal device.
     354 * NB: careful, we can be called after vfork! */
     355static int open_stdio_to_tty(const char* tty_name)
    306356{
    307357    /* empty tty_name means "use init's tty", else... */
    308358    if (tty_name[0]) {
    309         int fd = device_open(tty_name, O_RDWR);
    310         if (fd < 0) {
    311             message(L_LOG | L_CONSOLE, "Can't open %s: %s",
     359        int fd;
     360
     361        close(STDIN_FILENO);
     362        /* fd can be only < 0 or 0: */
     363        fd = device_open(tty_name, O_RDWR);
     364        if (fd) {
     365            message(L_LOG | L_CONSOLE, "can't open %s: %s",
    312366                tty_name, strerror(errno));
    313             if (fail)
    314                 _exit(1);
    315 #if !ENABLE_DEBUG_INIT
    316             shutdown_signal(SIGUSR1);
    317 #else
    318             _exit(2);
    319 #endif
    320         } else {
    321             dup2(fd, 0);
    322             dup2(fd, 1);
    323             dup2(fd, 2);
    324             if (fd > 2) close(fd);
    325         }
     367            return 0; /* failure */
     368        }
     369        dup2(STDIN_FILENO, STDOUT_FILENO);
     370        dup2(STDIN_FILENO, STDERR_FILENO);
    326371    }
    327372    set_sane_term();
    328 }
    329 
    330 static pid_t run(const struct init_action *a)
    331 {
    332     int i;
    333     pid_t pid;
    334     char *s, *tmpCmd, *cmdpath;
    335     char *cmd[INIT_BUFFS_SIZE];
    336     char buf[INIT_BUFFS_SIZE + 6];  /* INIT_BUFFS_SIZE+strlen("exec ")+1 */
    337     sigset_t nmask, omask;
    338 
    339     /* Block sigchild while forking.  */
    340     sigemptyset(&nmask);
    341     sigaddset(&nmask, SIGCHLD);
    342     sigprocmask(SIG_BLOCK, &nmask, &omask);
    343     pid = fork();
    344     sigprocmask(SIG_SETMASK, &omask, NULL);
    345 
    346     if (pid)
    347         return pid;
    348 
    349     /* Reset signal handlers that were set by the parent process */
    350     signal(SIGUSR1, SIG_DFL);
    351     signal(SIGUSR2, SIG_DFL);
    352     signal(SIGINT, SIG_DFL);
    353     signal(SIGTERM, SIG_DFL);
    354     signal(SIGHUP, SIG_DFL);
    355     signal(SIGQUIT, SIG_DFL);
    356     signal(SIGCONT, SIG_DFL);
    357     signal(SIGSTOP, SIG_DFL);
    358     signal(SIGTSTP, SIG_DFL);
    359 
    360     /* Create a new session and make ourself the process
    361      * group leader */
    362     setsid();
    363 
    364     /* Open the new terminal device */
    365     open_stdio_to_tty(a->terminal, 1);
    366 
    367     /* If the init Action requires us to wait, then force the
    368      * supplied terminal to be the controlling tty. */
    369     if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
    370 
    371         /* Now fork off another process to just hang around */
    372         if ((pid = fork()) < 0) {
    373             message(L_LOG | L_CONSOLE, "Can't fork");
    374             _exit(1);
    375         }
    376 
    377         if (pid > 0) {
    378 
    379             /* We are the parent -- wait till the child is done */
    380             signal(SIGINT, SIG_IGN);
    381             signal(SIGTSTP, SIG_IGN);
    382             signal(SIGQUIT, SIG_IGN);
    383             signal(SIGCHLD, SIG_DFL);
    384 
    385             waitfor(NULL, pid);
    386             /* See if stealing the controlling tty back is necessary */
    387             if (tcgetpgrp(0) != getpid())
    388                 _exit(0);
    389 
    390             /* Use a temporary process to steal the controlling tty. */
    391             if ((pid = fork()) < 0) {
    392                 message(L_LOG | L_CONSOLE, "Can't fork");
    393                 _exit(1);
    394             }
    395             if (pid == 0) {
    396                 setsid();
    397                 ioctl(0, TIOCSCTTY, 1);
    398                 _exit(0);
    399             }
    400             waitfor(NULL, pid);
    401             _exit(0);
    402         }
    403 
    404         /* Now fall though to actually execute things */
    405     }
     373    return 1; /* success */
     374}
     375
     376static void reset_sighandlers_and_unblock_sigs(void)
     377{
     378    bb_signals(0
     379        + (1 << SIGUSR1)
     380        + (1 << SIGUSR2)
     381        + (1 << SIGTERM)
     382        + (1 << SIGQUIT)
     383        + (1 << SIGINT)
     384        + (1 << SIGHUP)
     385        + (1 << SIGTSTP)
     386        + (1 << SIGSTOP)
     387        , SIG_DFL);
     388    sigprocmask_allsigs(SIG_UNBLOCK);
     389}
     390
     391/* Wrapper around exec:
     392 * Takes string (max COMMAND_SIZE chars).
     393 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'.
     394 * Otherwise splits words on whitespace, deals with leading dash,
     395 * and uses plain exec().
     396 * NB: careful, we can be called after vfork!
     397 */
     398static void init_exec(const char *command)
     399{
     400    char *cmd[COMMAND_SIZE / 2];
     401    char buf[COMMAND_SIZE + 6];  /* COMMAND_SIZE+strlen("exec ")+1 */
     402    int dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
    406403
    407404    /* See if any special /bin/sh requiring characters are present */
    408     if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
    409         cmd[0] = (char*)DEFAULT_SHELL;
     405    if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
     406        strcpy(buf, "exec ");
     407        strcpy(buf + 5, command + dash); /* excluding "-" */
     408        /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */
     409        cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash);
    410410        cmd[1] = (char*)"-c";
    411         cmd[2] = strcat(strcpy(buf, "exec "), a->command);
     411        cmd[2] = buf;
    412412        cmd[3] = NULL;
    413413    } else {
    414414        /* Convert command (char*) into cmd (char**, one word per string) */
    415         strcpy(buf, a->command);
    416         s = buf;
    417         for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) {
    418             if (*tmpCmd != '\0') {
    419                 cmd[i] = tmpCmd;
     415        char *word, *next;
     416        int i = 0;
     417        next = strcpy(buf, command); /* including "-" */
     418        while ((word = strsep(&next, " \t")) != NULL) {
     419            if (*word != '\0') { /* not two spaces/tabs together? */
     420                cmd[i] = word;
    420421                i++;
    421422            }
     
    423424        cmd[i] = NULL;
    424425    }
    425 
    426     cmdpath = cmd[0];
    427 
    428     /*
    429      * Interactive shells want to see a dash in argv[0].  This
    430      * typically is handled by login, argv will be setup this
    431      * way if a dash appears at the front of the command path
    432      * (like "-/bin/sh").
    433      */
    434     if (*cmdpath == '-') {
    435         /* skip over the dash */
    436         ++cmdpath;
    437 
    438         /* find the last component in the command pathname */
    439         s = bb_get_last_path_component(cmdpath);
    440 
    441         /* make a new argv[0] */
    442         if ((cmd[0] = malloc(strlen(s) + 2)) == NULL) {
    443             message(L_LOG | L_CONSOLE, bb_msg_memory_exhausted);
    444             cmd[0] = cmdpath;
    445         } else {
    446             cmd[0][0] = '-';
    447             strcpy(cmd[0] + 1, s);
    448         }
    449 #if ENABLE_FEATURE_INIT_SCTTY
    450         /* Establish this process as session leader and
    451          * (attempt) to make the tty (if any) a controlling tty.
    452          */
    453         setsid();
    454         ioctl(0, TIOCSCTTY, 0 /*don't steal it*/);
    455 #endif
    456     }
    457 
    458 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
    459     if (a->action & ASKFIRST) {
     426    /* If we saw leading "-", it is interactive shell.
     427     * Try harder to give it a controlling tty.
     428     * And skip "-" in actual exec call. */
     429    if (dash) {
     430        /* _Attempt_ to make stdin a controlling tty. */
     431        if (ENABLE_FEATURE_INIT_SCTTY)
     432            ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/);
     433    }
     434    BB_EXECVP(cmd[0] + dash, cmd);
     435    message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno));
     436    /* returns if execvp fails */
     437}
     438
     439/* Used only by run_actions */
     440static pid_t run(const struct init_action *a)
     441{
     442    pid_t pid;
     443
     444    /* Careful: don't be affected by a signal in vforked child */
     445    sigprocmask_allsigs(SIG_BLOCK);
     446    if (BB_MMU && (a->action_type & ASKFIRST))
     447        pid = fork();
     448    else
     449        pid = vfork();
     450    if (pid < 0)
     451        message(L_LOG | L_CONSOLE, "can't fork");
     452    if (pid) {
     453        sigprocmask_allsigs(SIG_UNBLOCK);
     454        return pid; /* Parent or error */
     455    }
     456
     457    /* Child */
     458
     459    /* Reset signal handlers that were set by the parent process */
     460    reset_sighandlers_and_unblock_sigs();
     461
     462    /* Create a new session and make ourself the process group leader */
     463    setsid();
     464
     465    /* Open the new terminal device */
     466    if (!open_stdio_to_tty(a->terminal))
     467        _exit(EXIT_FAILURE);
     468
     469    /* NB: on NOMMU we can't wait for input in child, so
     470     * "askfirst" will work the same as "respawn". */
     471    if (BB_MMU && (a->action_type & ASKFIRST)) {
    460472        static const char press_enter[] ALIGN1 =
    461473#ifdef CUSTOMIZED_BANNER
     
    472484         * specifies.
    473485         */
    474         messageD(L_LOG, "waiting for enter to start '%s'"
     486        dbg_message(L_LOG, "waiting for enter to start '%s'"
    475487                    "(pid %d, tty '%s')\n",
    476                   cmdpath, getpid(), a->terminal);
    477         full_write(1, press_enter, sizeof(press_enter) - 1);
    478         while (read(0, &c, 1) == 1 && c != '\n')
    479             ;
    480     }
    481 #endif
    482     /* Log the process name and args */
    483     message(L_LOG, "starting pid %d, tty '%s': '%s'",
    484               getpid(), a->terminal, cmdpath);
    485 
    486 #if ENABLE_FEATURE_INIT_COREDUMPS
    487     {
    488         struct stat sb;
    489         if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) {
     488                a->command, getpid(), a->terminal);
     489        full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
     490        while (safe_read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
     491            continue;
     492    }
     493
     494    /*
     495     * When a file named /.init_enable_core exists, setrlimit is called
     496     * before processes are spawned to set core file size as unlimited.
     497     * This is for debugging only.  Don't use this is production, unless
     498     * you want core dumps lying about....
     499     */
     500    if (ENABLE_FEATURE_INIT_COREDUMPS) {
     501        if (access("/.init_enable_core", F_OK) == 0) {
    490502            struct rlimit limit;
    491 
    492503            limit.rlim_cur = RLIM_INFINITY;
    493504            limit.rlim_max = RLIM_INFINITY;
     
    495506        }
    496507    }
    497 #endif
     508
     509    /* Log the process name and args */
     510    message(L_LOG, "starting pid %d, tty '%s': '%s'",
     511              getpid(), a->terminal, a->command);
     512
    498513    /* Now run it.  The new program will take over this PID,
    499514     * so nothing further in init.c should be run. */
    500     BB_EXECVP(cmdpath, cmd);
    501 
     515    init_exec(a->command);
    502516    /* We're still here?  Some error happened. */
    503     message(L_LOG | L_CONSOLE, "Cannot run '%s': %s",
    504             cmdpath, strerror(errno));
    505517    _exit(-1);
    506518}
    507519
    508 static int waitfor(const struct init_action *a, pid_t pid)
    509 {
    510     int runpid;
    511     int status, wpid;
    512 
    513     runpid = (NULL == a)? pid : run(a);
     520static struct init_action *mark_terminated(pid_t pid)
     521{
     522    struct init_action *a;
     523
     524    if (pid > 0) {
     525        for (a = init_action_list; a; a = a->next) {
     526            if (a->pid == pid) {
     527                a->pid = 0;
     528                return a;
     529            }
     530        }
     531        update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL,
     532                /*username:*/ NULL,
     533                /*hostname:*/ NULL);
     534    }
     535    return NULL;
     536}
     537
     538static void waitfor(pid_t pid)
     539{
     540    /* waitfor(run(x)): protect against failed fork inside run() */
     541    if (pid <= 0)
     542        return;
     543
     544    /* Wait for any child (prevent zombies from exiting orphaned processes)
     545     * but exit the loop only when specified one has exited. */
    514546    while (1) {
    515         wpid = waitpid(runpid, &status, 0);
    516         if (wpid == runpid)
     547        pid_t wpid = wait(NULL);
     548        mark_terminated(wpid);
     549        /* Unsafe. SIGTSTP handler might have wait'ed it already */
     550        /*if (wpid == pid) break;*/
     551        /* More reliable: */
     552        if (kill(pid, 0))
    517553            break;
    518         if (wpid == -1 && errno == ECHILD) {
    519             /* we missed its termination */
     554    }
     555}
     556
     557/* Run all commands of a particular type */
     558static void run_actions(int action_type)
     559{
     560    struct init_action *a;
     561
     562    for (a = init_action_list; a; a = a->next) {
     563        if (!(a->action_type & action_type))
     564            continue;
     565
     566        if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) {
     567            pid_t pid = run(a);
     568            if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN))
     569                waitfor(pid);
     570        }
     571        if (a->action_type & (RESPAWN | ASKFIRST)) {
     572            /* Only run stuff with pid == 0. If pid != 0,
     573             * it is already running
     574             */
     575            if (a->pid == 0)
     576                a->pid = run(a);
     577        }
     578    }
     579}
     580
     581static void new_init_action(uint8_t action_type, const char *command, const char *cons)
     582{
     583    struct init_action *a, **nextp;
     584
     585    /* Scenario:
     586     * old inittab:
     587     * ::shutdown:umount -a -r
     588     * ::shutdown:swapoff -a
     589     * new inittab:
     590     * ::shutdown:swapoff -a
     591     * ::shutdown:umount -a -r
     592     * On reload, we must ensure entries end up in correct order.
     593     * To achieve that, if we find a matching entry, we move it
     594     * to the end.
     595     */
     596    nextp = &init_action_list;
     597    while ((a = *nextp) != NULL) {
     598        /* Don't enter action if it's already in the list,
     599         * This prevents losing running RESPAWNs.
     600         */
     601        if (strcmp(a->command, command) == 0
     602         && strcmp(a->terminal, cons) == 0
     603        ) {
     604            /* Remove from list */
     605            *nextp = a->next;
     606            /* Find the end of the list */
     607            while (*nextp != NULL)
     608                nextp = &(*nextp)->next;
     609            a->next = NULL;
    520610            break;
    521611        }
    522         /* FIXME other errors should maybe trigger an error, but allow
    523          * the program to continue */
    524     }
    525     return wpid;
    526 }
    527 
    528 /* Run all commands of a particular type */
    529 static void run_actions(int action)
    530 {
    531     struct init_action *a, *tmp;
    532 
    533     for (a = init_action_list; a; a = tmp) {
    534         tmp = a->next;
    535         if (a->action == action) {
    536             /* a->terminal of "" means "init's console" */
    537             if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
    538                 delete_init_action(a);
    539             } else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
    540                 waitfor(a, 0);
    541                 delete_init_action(a);
    542             } else if (a->action & ONCE) {
    543                 run(a);
    544                 delete_init_action(a);
    545             } else if (a->action & (RESPAWN | ASKFIRST)) {
    546                 /* Only run stuff with pid==0.  If they have
    547                  * a pid, that means it is still running */
    548                 if (a->pid == 0) {
    549                     a->pid = run(a);
    550                 }
    551             }
    552         }
    553     }
    554 }
    555 
    556 #if !ENABLE_DEBUG_INIT
    557 static void init_reboot(unsigned long magic)
     612        nextp = &a->next;
     613    }
     614
     615    if (!a)
     616        a = xzalloc(sizeof(*a));
     617    /* Append to the end of the list */
     618    *nextp = a;
     619    a->action_type = action_type;
     620    safe_strncpy(a->command, command, sizeof(a->command));
     621    safe_strncpy(a->terminal, cons, sizeof(a->terminal));
     622    dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
     623        a->command, a->action_type, a->terminal);
     624}
     625
     626/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
     627 * then parse_inittab() simply adds in some default
     628 * actions(i.e., runs INIT_SCRIPT and then starts a pair
     629 * of "askfirst" shells).  If CONFIG_FEATURE_USE_INITTAB
     630 * _is_ defined, but /etc/inittab is missing, this
     631 * results in the same set of default behaviors.
     632 */
     633static void parse_inittab(void)
     634{
     635#if ENABLE_FEATURE_USE_INITTAB
     636    char *token[4];
     637    parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
     638
     639    if (parser == NULL)
     640#endif
     641    {
     642        /* No inittab file - set up some default behavior */
     643        /* Reboot on Ctrl-Alt-Del */
     644        new_init_action(CTRLALTDEL, "reboot", "");
     645        /* Umount all filesystems on halt/reboot */
     646        new_init_action(SHUTDOWN, "umount -a -r", "");
     647        /* Swapoff on halt/reboot */
     648        if (ENABLE_SWAPONOFF)
     649            new_init_action(SHUTDOWN, "swapoff -a", "");
     650        /* Prepare to restart init when a QUIT is received */
     651        new_init_action(RESTART, "init", "");
     652        /* Askfirst shell on tty1-4 */
     653        new_init_action(ASKFIRST, bb_default_login_shell, "");
     654//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
     655        new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
     656        new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
     657        new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
     658        /* sysinit */
     659        new_init_action(SYSINIT, INIT_SCRIPT, "");
     660        return;
     661    }
     662
     663#if ENABLE_FEATURE_USE_INITTAB
     664    /* optional_tty:ignored_runlevel:action:command
     665     * Delims are not to be collapsed and need exactly 4 tokens
     666     */
     667    while (config_read(parser, token, 4, 0, "#:",
     668                PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
     669        /* order must correspond to SYSINIT..RESTART constants */
     670        static const char actions[] ALIGN1 =
     671            "sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
     672            "ctrlaltdel\0""shutdown\0""restart\0";
     673        int action;
     674        char *tty = token[0];
     675
     676        if (!token[3]) /* less than 4 tokens */
     677            goto bad_entry;
     678        action = index_in_strings(actions, token[2]);
     679        if (action < 0 || !token[3][0]) /* token[3]: command */
     680            goto bad_entry;
     681        /* turn .*TTY -> /dev/TTY */
     682        if (tty[0]) {
     683            tty = concat_path_file("/dev/", skip_dev_pfx(tty));
     684        }
     685        new_init_action(1 << action, token[3], tty);
     686        if (tty[0])
     687            free(tty);
     688        continue;
     689 bad_entry:
     690        message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
     691                parser->lineno);
     692    }
     693    config_close(parser);
     694#endif
     695}
     696
     697static void pause_and_low_level_reboot(unsigned magic) NORETURN;
     698static void pause_and_low_level_reboot(unsigned magic)
    558699{
    559700    pid_t pid;
    560     /* We have to fork here, since the kernel calls do_exit(0) in
    561      * linux/kernel/sys.c, which can cause the machine to panic when
    562      * the init process is killed.... */
     701
     702    /* Allow time for last message to reach serial console, etc */
     703    sleep(1);
     704
     705    /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
     706     * in linux/kernel/sys.c, which can cause the machine to panic when
     707     * the init process exits... */
    563708    pid = vfork();
    564709    if (pid == 0) { /* child */
    565710        reboot(magic);
    566         _exit(0);
    567     }
    568     waitpid(pid, NULL, 0);
    569 }
    570 
    571 static void shutdown_system(void)
    572 {
    573     sigset_t block_signals;
    574 
    575     /* run everything to be run at "shutdown".  This is done _prior_
     711        _exit(EXIT_SUCCESS);
     712    }
     713    while (1)
     714        sleep(1);
     715}
     716
     717static void run_shutdown_and_kill_processes(void)
     718{
     719    /* Run everything to be run at "shutdown".  This is done _prior_
    576720     * to killing everything, in case people wish to use scripts to
    577721     * shut things down gracefully... */
    578722    run_actions(SHUTDOWN);
    579723
    580     /* first disable all our signals */
    581     sigemptyset(&block_signals);
    582     sigaddset(&block_signals, SIGHUP);
    583     sigaddset(&block_signals, SIGQUIT);
    584     sigaddset(&block_signals, SIGCHLD);
    585     sigaddset(&block_signals, SIGUSR1);
    586     sigaddset(&block_signals, SIGUSR2);
    587     sigaddset(&block_signals, SIGINT);
    588     sigaddset(&block_signals, SIGTERM);
    589     sigaddset(&block_signals, SIGCONT);
    590     sigaddset(&block_signals, SIGSTOP);
    591     sigaddset(&block_signals, SIGTSTP);
    592     sigprocmask(SIG_BLOCK, &block_signals, NULL);
    593 
    594724    message(L_CONSOLE | L_LOG, "The system is going down NOW!");
    595725
    596     /* Allow Ctrl-Alt-Del to reboot system. */
    597     init_reboot(RB_ENABLE_CAD);
    598 
    599726    /* Send signals to every process _except_ pid 1 */
    600     message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");
    601727    kill(-1, SIGTERM);
     728    message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
    602729    sync();
    603730    sleep(1);
    604731
    605     message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL");
    606732    kill(-1, SIGKILL);
     733    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    607734    sync();
    608     sleep(1);
    609 }
    610 
    611 static void exec_signal(int sig ATTRIBUTE_UNUSED)
    612 {
    613     struct init_action *a, *tmp;
    614     sigset_t unblock_signals;
    615 
    616     for (a = init_action_list; a; a = tmp) {
    617         tmp = a->next;
    618         if (a->action & RESTART) {
    619             shutdown_system();
    620 
    621             /* unblock all signals, blocked in shutdown_system() */
    622             sigemptyset(&unblock_signals);
    623             sigaddset(&unblock_signals, SIGHUP);
    624             sigaddset(&unblock_signals, SIGQUIT);
    625             sigaddset(&unblock_signals, SIGCHLD);
    626             sigaddset(&unblock_signals, SIGUSR1);
    627             sigaddset(&unblock_signals, SIGUSR2);
    628             sigaddset(&unblock_signals, SIGINT);
    629             sigaddset(&unblock_signals, SIGTERM);
    630             sigaddset(&unblock_signals, SIGCONT);
    631             sigaddset(&unblock_signals, SIGSTOP);
    632             sigaddset(&unblock_signals, SIGTSTP);
    633             sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL);
    634 
    635             /* Open the new terminal device */
    636             open_stdio_to_tty(a->terminal, 0);
    637 
    638             messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command);
    639             BB_EXECLP(a->command, a->command, NULL);
    640 
    641             message(L_CONSOLE | L_LOG, "Cannot run '%s': %s",
    642                     a->command, strerror(errno));
    643             sleep(2);
    644             init_reboot(RB_HALT_SYSTEM);
    645             loop_forever();
    646         }
    647     }
    648 }
    649 
    650 static void shutdown_signal(int sig)
     735    /*sleep(1); - callers take care about making a pause */
     736}
     737
     738/* Signal handling by init:
     739 *
     740 * For process with PID==1, on entry kernel sets all signals to SIG_DFL
     741 * and unmasks all signals. However, for process with PID==1,
     742 * default action (SIG_DFL) on any signal is to ignore it,
     743 * even for special signals SIGKILL and SIGCONT.
     744 * Also, any signal can be caught or blocked.
     745 * (but SIGSTOP is still handled specially, at least in 2.6.20)
     746 *
     747 * We install two kinds of handlers, "immediate" and "delayed".
     748 *
     749 * Immediate handlers execute at any time, even while, say, sysinit
     750 * is running.
     751 *
     752 * Delayed handlers just set a flag variable. The variable is checked
     753 * in the main loop and acted upon.
     754 *
     755 * halt/poweroff/reboot and restart have immediate handlers.
     756 * They only traverse linked list of struct action's, never modify it,
     757 * this should be safe to do even in signal handler. Also they
     758 * never return.
     759 *
     760 * SIGSTOP and SIGTSTP have immediate handlers. They just wait
     761 * for SIGCONT to happen.
     762 *
     763 * SIGHUP has a delayed handler, because modifying linked list
     764 * of struct action's from a signal handler while it is manipulated
     765 * by the program may be disastrous.
     766 *
     767 * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing
     768 * it to happen even somewhere inside "sysinit" would be a bit awkward.
     769 *
     770 * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide
     771 * and only one will be remembered and acted upon.
     772 */
     773
     774/* The SIGUSR[12]/SIGTERM handler */
     775static void halt_reboot_pwoff(int sig) NORETURN;
     776static void halt_reboot_pwoff(int sig)
    651777{
    652778    const char *m;
    653     int rb;
    654 
    655     shutdown_system();
     779    unsigned rb;
     780
     781    /* We may call run() and it unmasks signals,
     782     * including the one masked inside this signal handler.
     783     * Testcase which would start multiple reboot scripts:
     784     *  while true; do reboot; done
     785     * Preventing it:
     786     */
     787    reset_sighandlers_and_unblock_sigs();
     788
     789    run_shutdown_and_kill_processes();
    656790
    657791    m = "halt";
     
    664798        rb = RB_POWER_OFF;
    665799    }
    666     message(L_CONSOLE | L_LOG, "Requesting system %s", m);
    667     /* allow time for last message to reach serial console */
    668     sleep(2);
    669     init_reboot(rb);
    670     loop_forever();
    671 }
    672 
    673 static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)
    674 {
    675     run_actions(CTRLALTDEL);
    676 }
    677 
    678 /* The SIGSTOP & SIGTSTP handler */
    679 static void stop_handler(int sig ATTRIBUTE_UNUSED)
    680 {
    681     int saved_errno = errno;
    682 
    683     got_cont = 0;
    684     while (!got_cont)
    685         pause();
    686     got_cont = 0;
     800    message(L_CONSOLE, "Requesting system %s", m);
     801    pause_and_low_level_reboot(rb);
     802    /* not reached */
     803}
     804
     805/* Handler for QUIT - exec "restart" action,
     806 * else (no such action defined) do nothing */
     807static void restart_handler(int sig UNUSED_PARAM)
     808{
     809    struct init_action *a;
     810
     811    for (a = init_action_list; a; a = a->next) {
     812        if (!(a->action_type & RESTART))
     813            continue;
     814
     815        /* Starting from here, we won't return.
     816         * Thus don't need to worry about preserving errno
     817         * and such.
     818         */
     819
     820        reset_sighandlers_and_unblock_sigs();
     821
     822        run_shutdown_and_kill_processes();
     823
     824#ifdef RB_ENABLE_CAD
     825        /* Allow Ctrl-Alt-Del to reboot the system.
     826         * This is how kernel sets it up for init, we follow suit.
     827         */
     828        reboot(RB_ENABLE_CAD); /* misnomer */
     829#endif
     830
     831        if (open_stdio_to_tty(a->terminal)) {
     832            dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
     833            /* Theoretically should be safe.
     834             * But in practice, kernel bugs may leave
     835             * unkillable processes, and wait() may block forever.
     836             * Oh well. Hoping "new" init won't be too surprised
     837             * by having children it didn't create.
     838             */
     839            //while (wait(NULL) > 0)
     840            //  continue;
     841            init_exec(a->command);
     842        }
     843        /* Open or exec failed */
     844        pause_and_low_level_reboot(RB_HALT_SYSTEM);
     845        /* not reached */
     846    }
     847}
     848
     849/* The SIGSTOP/SIGTSTP handler
     850 * NB: inside it, all signals except SIGCONT are masked
     851 * via appropriate setup in sigaction().
     852 */
     853static void stop_handler(int sig UNUSED_PARAM)
     854{
     855    smallint saved_bb_got_signal;
     856    int saved_errno;
     857
     858    saved_bb_got_signal = bb_got_signal;
     859    saved_errno = errno;
     860    signal(SIGCONT, record_signo);
     861
     862    while (1) {
     863        pid_t wpid;
     864
     865        if (bb_got_signal == SIGCONT)
     866            break;
     867        /* NB: this can accidentally wait() for a process
     868         * which we waitfor() elsewhere! waitfor() must have
     869         * code which is resilient against this.
     870         */
     871        wpid = wait_any_nohang(NULL);
     872        mark_terminated(wpid);
     873        sleep(1);
     874    }
     875
     876    signal(SIGCONT, SIG_DFL);
    687877    errno = saved_errno;
    688 }
    689 
    690 /* The SIGCONT handler */
    691 static void cont_handler(int sig ATTRIBUTE_UNUSED)
    692 {
    693     got_cont = 1;
    694 }
    695 
    696 #endif  /* !ENABLE_DEBUG_INIT */
    697 
    698 static void new_init_action(int action, const char *command, const char *cons)
    699 {
    700     struct init_action *new_action, *a, *last;
    701 
    702     if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
    703         return;
    704 
    705     /* Append to the end of the list */
    706     for (a = last = init_action_list; a; a = a->next) {
    707         /* don't enter action if it's already in the list,
    708          * but do overwrite existing actions */
    709         if ((strcmp(a->command, command) == 0)
    710          && (strcmp(a->terminal, cons) == 0)
     878    bb_got_signal = saved_bb_got_signal;
     879}
     880
     881#if ENABLE_FEATURE_USE_INITTAB
     882static void reload_inittab(void)
     883{
     884    struct init_action *a, **nextp;
     885
     886    message(L_LOG, "reloading /etc/inittab");
     887
     888    /* Disable old entries */
     889    for (a = init_action_list; a; a = a->next)
     890        a->action_type = 0;
     891
     892    /* Append new entries, or modify existing entries
     893     * (incl. setting a->action_type) if cmd and device name
     894     * match new ones. End result: only entries with
     895     * a->action_type == 0 are stale.
     896     */
     897    parse_inittab();
     898
     899#if ENABLE_FEATURE_KILL_REMOVED
     900    /* Kill stale entries */
     901    /* Be nice and send SIGTERM first */
     902    for (a = init_action_list; a; a = a->next)
     903        if (a->action_type == 0 && a->pid != 0)
     904            kill(a->pid, SIGTERM);
     905    if (CONFIG_FEATURE_KILL_DELAY) {
     906        /* NB: parent will wait in NOMMU case */
     907        if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
     908            sleep(CONFIG_FEATURE_KILL_DELAY);
     909            for (a = init_action_list; a; a = a->next)
     910                if (a->action_type == 0 && a->pid != 0)
     911                    kill(a->pid, SIGKILL);
     912            _exit(EXIT_SUCCESS);
     913        }
     914    }
     915#endif
     916
     917    /* Remove stale entries and SYSINIT entries.
     918     * We never rerun SYSINIT entries anyway,
     919     * removing them too saves a few bytes */
     920    nextp = &init_action_list;
     921    while ((a = *nextp) != NULL) {
     922        if ((a->action_type & ~SYSINIT) == 0) {
     923            *nextp = a->next;
     924            free(a);
     925        } else {
     926            nextp = &a->next;
     927        }
     928    }
     929
     930    /* Not needed: */
     931    /* run_actions(RESPAWN | ASKFIRST); */
     932    /* - we return to main loop, which does this automagically */
     933}
     934#endif
     935
     936static int check_delayed_sigs(void)
     937{
     938    int sigs_seen = 0;
     939
     940    while (1) {
     941        smallint sig = bb_got_signal;
     942
     943        if (!sig)
     944            return sigs_seen;
     945        bb_got_signal = 0;
     946        sigs_seen = 1;
     947#if ENABLE_FEATURE_USE_INITTAB
     948        if (sig == SIGHUP)
     949            reload_inittab();
     950#endif
     951        if (sig == SIGINT)
     952            run_actions(CTRLALTDEL);
     953    }
     954}
     955
     956int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     957int init_main(int argc UNUSED_PARAM, char **argv)
     958{
     959    if (argv[1] && strcmp(argv[1], "-q") == 0) {
     960        return kill(1, SIGHUP);
     961    }
     962
     963    if (!DEBUG_INIT) {
     964        /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
     965        if (getpid() != 1
     966         && (!ENABLE_FEATURE_INITRD || applet_name[0] != 'l') /* not linuxrc? */
    711967        ) {
    712             a->action = action;
    713             return;
    714         }
    715         last = a;
    716     }
    717 
    718     new_action = xzalloc(sizeof(struct init_action));
    719     if (last) {
    720         last->next = new_action;
    721     } else {
    722         init_action_list = new_action;
    723     }
    724     strcpy(new_action->command, command);
    725     new_action->action = action;
    726     strcpy(new_action->terminal, cons);
    727     messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
    728         new_action->command, new_action->action, new_action->terminal);
    729 }
    730 
    731 static void delete_init_action(struct init_action *action)
    732 {
    733     struct init_action *a, *b = NULL;
    734 
    735     for (a = init_action_list; a; b = a, a = a->next) {
    736         if (a == action) {
    737             if (b == NULL) {
    738                 init_action_list = a->next;
    739             } else {
    740                 b->next = a->next;
    741             }
    742             free(a);
    743             break;
    744         }
    745     }
    746 }
    747 
    748 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
    749  * then parse_inittab() simply adds in some default
    750  * actions(i.e., runs INIT_SCRIPT and then starts a pair
    751  * of "askfirst" shells).  If CONFIG_FEATURE_USE_INITTAB
    752  * _is_ defined, but /etc/inittab is missing, this
    753  * results in the same set of default behaviors.
    754  */
    755 static void parse_inittab(void)
    756 {
    757 #if ENABLE_FEATURE_USE_INITTAB
    758     FILE *file;
    759     char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE];
    760     char tmpConsole[CONSOLE_NAME_SIZE];
    761     char *id, *runlev, *action, *command, *eol;
    762     const struct init_action_type *a = actions;
    763 
    764     file = fopen(INITTAB, "r");
    765     if (file == NULL) {
    766         /* No inittab file -- set up some default behavior */
    767 #endif
    768         /* Reboot on Ctrl-Alt-Del */
    769         new_init_action(CTRLALTDEL, "reboot", "");
    770         /* Umount all filesystems on halt/reboot */
    771         new_init_action(SHUTDOWN, "umount -a -r", "");
    772         /* Swapoff on halt/reboot */
    773         if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");
    774         /* Prepare to restart init when a HUP is received */
    775         new_init_action(RESTART, "init", "");
    776         /* Askfirst shell on tty1-4 */
    777         new_init_action(ASKFIRST, bb_default_login_shell, "");
    778         new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
    779         new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
    780         new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
    781         /* sysinit */
    782         new_init_action(SYSINIT, INIT_SCRIPT, "");
    783 
    784         return;
    785 #if ENABLE_FEATURE_USE_INITTAB
    786     }
    787 
    788     while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
    789         /* Skip leading spaces */
    790         for (id = buf; *id == ' ' || *id == '\t'; id++);
    791 
    792         /* Skip the line if it's a comment */
    793         if (*id == '#' || *id == '\n')
    794             continue;
    795 
    796         /* Trim the trailing \n */
    797         //XXX: chomp() ?
    798         eol = strrchr(id, '\n');
    799         if (eol != NULL)
    800             *eol = '\0';
    801 
    802         /* Keep a copy around for posterity's sake (and error msgs) */
    803         strcpy(lineAsRead, buf);
    804 
    805         /* Separate the ID field from the runlevels */
    806         runlev = strchr(id, ':');
    807         if (runlev == NULL || *(runlev + 1) == '\0') {
    808             message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
    809             continue;
    810         } else {
    811             *runlev = '\0';
    812             ++runlev;
    813         }
    814 
    815         /* Separate the runlevels from the action */
    816         action = strchr(runlev, ':');
    817         if (action == NULL || *(action + 1) == '\0') {
    818             message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
    819             continue;
    820         } else {
    821             *action = '\0';
    822             ++action;
    823         }
    824 
    825         /* Separate the action from the command */
    826         command = strchr(action, ':');
    827         if (command == NULL || *(command + 1) == '\0') {
    828             message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
    829             continue;
    830         } else {
    831             *command = '\0';
    832             ++command;
    833         }
    834 
    835         /* Ok, now process it */
    836         for (a = actions; a->name != 0; a++) {
    837             if (strcmp(a->name, action) == 0) {
    838                 if (*id != '\0') {
    839                     if (strncmp(id, "/dev/", 5) == 0)
    840                         id += 5;
    841                     strcpy(tmpConsole, "/dev/");
    842                     safe_strncpy(tmpConsole + 5, id,
    843                         sizeof(tmpConsole) - 5);
    844                     id = tmpConsole;
    845                 }
    846                 new_init_action(a->action, command, id);
    847                 break;
    848             }
    849         }
    850         if (a->name == 0) {
    851             /* Choke on an unknown action */
    852             message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
    853         }
    854     }
    855     fclose(file);
    856 #endif /* FEATURE_USE_INITTAB */
    857 }
    858 
    859 #if ENABLE_FEATURE_USE_INITTAB
    860 static void reload_signal(int sig ATTRIBUTE_UNUSED)
    861 {
    862     struct init_action *a, *tmp;
    863 
    864     message(L_LOG, "reloading /etc/inittab");
    865 
    866     /* disable old entrys */
    867     for (a = init_action_list; a; a = a->next ) {
    868         a->action = ONCE;
    869     }
    870 
    871     parse_inittab();
    872 
    873     /* remove unused entrys */
    874     for (a = init_action_list; a; a = tmp) {
    875         tmp = a->next;
    876         if ((a->action & (ONCE | SYSINIT | WAIT)) && a->pid == 0) {
    877             delete_init_action(a);
    878         }
    879     }
    880     run_actions(RESPAWN);
    881 }
    882 #endif  /* FEATURE_USE_INITTAB */
    883 
    884 int init_main(int argc, char **argv);
    885 int init_main(int argc, char **argv)
    886 {
    887     struct init_action *a;
    888     pid_t wpid;
    889 
    890     die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */
    891 
    892     if (argc > 1 && !strcmp(argv[1], "-q")) {
    893         return kill(1, SIGHUP);
    894     }
    895 #if !ENABLE_DEBUG_INIT
    896     /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
    897     if (getpid() != 1
    898      && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
    899     ) {
    900         bb_show_usage();
    901     }
    902     /* Set up sig handlers  -- be sure to
    903      * clear all of these in run() */
    904     signal(SIGHUP, exec_signal);
    905     signal(SIGQUIT, exec_signal);
    906     signal(SIGUSR1, shutdown_signal);
    907     signal(SIGUSR2, shutdown_signal);
    908     signal(SIGINT, ctrlaltdel_signal);
    909     signal(SIGTERM, shutdown_signal);
    910     signal(SIGCONT, cont_handler);
    911     signal(SIGSTOP, stop_handler);
    912     signal(SIGTSTP, stop_handler);
    913 
    914     /* Turn off rebooting via CTL-ALT-DEL -- we get a
    915      * SIGINT on CAD so we can shut things down gracefully... */
    916     init_reboot(RB_DISABLE_CAD);
    917 #endif
    918 
     968            bb_error_msg_and_die("must be run as PID 1");
     969        }
     970#ifdef RB_DISABLE_CAD
     971        /* Turn off rebooting via CTL-ALT-DEL - we get a
     972         * SIGINT on CAD so we can shut things down gracefully... */
     973        reboot(RB_DISABLE_CAD); /* misnomer */
     974#endif
     975    }
     976
     977    /* If, say, xmalloc would ever die, we don't want to oops kernel
     978     * by exiting.
     979     * NB: we set die_sleep *after* PID 1 check and bb_show_usage.
     980     * Otherwise, for example, "init u" ("please rexec yourself"
     981     * command for sysvinit) will show help text (which isn't too bad),
     982     * *and sleep forever* (which is bad!)
     983     */
     984    die_sleep = 30 * 24*60*60;
    919985
    920986    /* Figure out where the default console should be */
    921987    console_init();
    922988    set_sane_term();
    923     chdir("/");
     989    xchdir("/");
    924990    setsid();
    925     {
    926         const char *const *e;
    927         /* Make sure environs is set to something sane */
    928         for (e = environment; *e; e++)
    929             putenv((char *) *e);
    930     }
    931 
    932     if (argc > 1) setenv("RUNLEVEL", argv[1], 1);
    933 
     991
     992    /* Make sure environs is set to something sane */
     993    putenv((char *) "HOME=/");
     994    putenv((char *) bb_PATH_root_path);
     995    putenv((char *) "SHELL=/bin/sh");
     996    putenv((char *) "USER=root"); /* needed? why? */
     997
     998    if (argv[1])
     999        xsetenv("RUNLEVEL", argv[1]);
     1000
     1001#if !ENABLE_FEATURE_EXTRA_QUIET
    9341002    /* Hello world */
    935     message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner);
    936 
     1003    message(L_CONSOLE | L_LOG, "init started: %s", bb_banner);
     1004#endif
     1005
     1006/* struct sysinfo is linux-specific */
     1007#ifdef __linux__
    9371008    /* Make sure there is enough memory to do something useful. */
    9381009    if (ENABLE_SWAPONOFF) {
    9391010        struct sysinfo info;
    9401011
    941         if (!sysinfo(&info) &&
    942             (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)
    943         {
     1012        if (sysinfo(&info) == 0
     1013         && (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024
     1014        ) {
    9441015            message(L_CONSOLE, "Low memory, forcing swapon");
    9451016            /* swapon -a requires /proc typically */
     
    9501021        }
    9511022    }
     1023#endif
    9521024
    9531025    /* Check if we are supposed to be in single user mode */
    954     if (argc > 1
    955      && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
     1026    if (argv[1]
     1027     && (strcmp(argv[1], "single") == 0 || strcmp(argv[1], "-s") == 0 || LONE_CHAR(argv[1], '1'))
    9561028    ) {
     1029        /* ??? shouldn't we set RUNLEVEL="b" here? */
    9571030        /* Start a shell on console */
    9581031        new_init_action(RESPAWN, bb_default_login_shell, "");
    9591032    } else {
    960         /* Not in single user mode -- see what inittab says */
     1033        /* Not in single user mode - see what inittab says */
    9611034
    9621035        /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
    9631036         * then parse_inittab() simply adds in some default
    964          * actions(i.e., runs INIT_SCRIPT and then starts a pair
     1037         * actions(i.e., INIT_SCRIPT and a pair
    9651038         * of "askfirst" shells */
    9661039        parse_inittab();
     
    9761049        } else if (enforce > 0) {
    9771050            /* SELinux in enforcing mode but load_policy failed */
    978             /* At this point, we probably can't open /dev/console, so log() won't work */
    979             message(L_CONSOLE, "Cannot load SELinux Policy. "
     1051            message(L_CONSOLE, "can't load SELinux Policy. "
    9801052                "Machine is in enforcing mode. Halting now.");
    981             exit(1);
    982         }
    983     }
    984 #endif /* CONFIG_SELINUX */
    985 
    986     /* Make the command line just say "init"  -- thats all, nothing else */
    987     fixup_argv(argv);
     1053            return EXIT_FAILURE;
     1054        }
     1055    }
     1056#endif
     1057
     1058    /* Make the command line just say "init"  - thats all, nothing else */
     1059    strncpy(argv[0], "init", strlen(argv[0]));
     1060    /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
     1061    while (*++argv)
     1062        memset(*argv, 0, strlen(*argv));
     1063
     1064    /* Set up signal handlers */
     1065    if (!DEBUG_INIT) {
     1066        struct sigaction sa;
     1067
     1068        bb_signals(0
     1069            + (1 << SIGUSR1) /* halt */
     1070            + (1 << SIGTERM) /* reboot */
     1071            + (1 << SIGUSR2) /* poweroff */
     1072            , halt_reboot_pwoff);
     1073        signal(SIGQUIT, restart_handler); /* re-exec another init */
     1074
     1075        /* Stop handler must allow only SIGCONT inside itself */
     1076        memset(&sa, 0, sizeof(sa));
     1077        sigfillset(&sa.sa_mask);
     1078        sigdelset(&sa.sa_mask, SIGCONT);
     1079        sa.sa_handler = stop_handler;
     1080        /* NB: sa_flags doesn't have SA_RESTART.
     1081         * It must be able to interrupt wait().
     1082         */
     1083        sigaction_set(SIGTSTP, &sa); /* pause */
     1084        /* Does not work as intended, at least in 2.6.20.
     1085         * SIGSTOP is simply ignored by init:
     1086         */
     1087        sigaction_set(SIGSTOP, &sa); /* pause */
     1088
     1089        /* SIGINT (Ctrl-Alt-Del) must interrupt wait(),
     1090         * setting handler without SA_RESTART flag.
     1091         */
     1092        bb_signals_recursive_norestart((1 << SIGINT), record_signo);
     1093    }
     1094
     1095    /* Set up "reread /etc/inittab" handler.
     1096     * Handler is set up without SA_RESTART, it will interrupt syscalls.
     1097     */
     1098    if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB)
     1099        bb_signals_recursive_norestart((1 << SIGHUP), record_signo);
    9881100
    9891101    /* Now run everything that needs to be run */
    990 
    9911102    /* First run the sysinit command */
    9921103    run_actions(SYSINIT);
    993 
     1104    check_delayed_sigs();
    9941105    /* Next run anything that wants to block */
    9951106    run_actions(WAIT);
    996 
     1107    check_delayed_sigs();
    9971108    /* Next run anything to be run only once */
    9981109    run_actions(ONCE);
    9991110
    1000 #if ENABLE_FEATURE_USE_INITTAB
    1001     /* Redefine SIGHUP to reread /etc/inittab */
    1002     signal(SIGHUP, reload_signal);
    1003 #else
    1004     signal(SIGHUP, SIG_IGN);
    1005 #endif /* FEATURE_USE_INITTAB */
    1006 
    1007     /* Now run the looping stuff for the rest of forever */
     1111    /* Now run the looping stuff for the rest of forever.
     1112     */
    10081113    while (1) {
    1009         /* run the respawn stuff */
    1010         run_actions(RESPAWN);
    1011 
    1012         /* run the askfirst stuff */
    1013         run_actions(ASKFIRST);
    1014 
    1015         /* Don't consume all CPU time -- sleep a bit */
     1114        int maybe_WNOHANG;
     1115
     1116        maybe_WNOHANG = check_delayed_sigs();
     1117
     1118        /* (Re)run the respawn/askfirst stuff */
     1119        run_actions(RESPAWN | ASKFIRST);
     1120        maybe_WNOHANG |= check_delayed_sigs();
     1121
     1122        /* Don't consume all CPU time - sleep a bit */
    10161123        sleep(1);
    1017 
    1018         /* Wait for a child process to exit */
    1019         wpid = wait(NULL);
    1020         while (wpid > 0) {
    1021             /* Find out who died and clean up their corpse */
    1022             for (a = init_action_list; a; a = a->next) {
    1023                 if (a->pid == wpid) {
    1024                     /* Set the pid to 0 so that the process gets
    1025                      * restarted by run_actions() */
    1026                     a->pid = 0;
    1027                     message(L_LOG, "process '%s' (pid %d) exited. "
    1028                             "Scheduling it for restart.",
    1029                             a->command, wpid);
    1030                 }
     1124        maybe_WNOHANG |= check_delayed_sigs();
     1125
     1126        /* Wait for any child process(es) to exit.
     1127         *
     1128         * If check_delayed_sigs above reported that a signal
     1129         * was caught, wait will be nonblocking. This ensures
     1130         * that if SIGHUP has reloaded inittab, respawn and askfirst
     1131         * actions will not be delayed until next child death.
     1132         */
     1133        if (maybe_WNOHANG)
     1134            maybe_WNOHANG = WNOHANG;
     1135        while (1) {
     1136            pid_t wpid;
     1137            struct init_action *a;
     1138
     1139            /* If signals happen _in_ the wait, they interrupt it,
     1140             * bb_signals_recursive_norestart set them up that way
     1141             */
     1142            wpid = waitpid(-1, NULL, maybe_WNOHANG);
     1143            if (wpid <= 0)
     1144                break;
     1145
     1146            a = mark_terminated(wpid);
     1147            if (a) {
     1148                message(L_LOG, "process '%s' (pid %d) exited. "
     1149                        "Scheduling for restart.",
     1150                        a->command, wpid);
    10311151            }
    1032             /* see if anyone else is waiting to be reaped */
    1033             wpid = waitpid(-1, NULL, WNOHANG);
    1034         }
    1035     }
    1036 }
     1152            /* See if anyone else is waiting to be reaped */
     1153            maybe_WNOHANG = WNOHANG;
     1154        }
     1155    } /* while (1) */
     1156}
     1157
     1158//usage:#define linuxrc_trivial_usage NOUSAGE_STR
     1159//usage:#define linuxrc_full_usage ""
     1160
     1161//usage:#define init_trivial_usage
     1162//usage:       ""
     1163//usage:#define init_full_usage "\n\n"
     1164//usage:       "Init is the parent of all processes"
     1165//usage:
     1166//usage:#define init_notes_usage
     1167//usage:    "This version of init is designed to be run only by the kernel.\n"
     1168//usage:    "\n"
     1169//usage:    "BusyBox init doesn't support multiple runlevels. The runlevels field of\n"
     1170//usage:    "the /etc/inittab file is completely ignored by BusyBox init. If you want\n"
     1171//usage:    "runlevels, use sysvinit.\n"
     1172//usage:    "\n"
     1173//usage:    "BusyBox init works just fine without an inittab. If no inittab is found,\n"
     1174//usage:    "it has the following default behavior:\n"
     1175//usage:    "\n"
     1176//usage:    "   ::sysinit:/etc/init.d/rcS\n"
     1177//usage:    "   ::askfirst:/bin/sh\n"
     1178//usage:    "   ::ctrlaltdel:/sbin/reboot\n"
     1179//usage:    "   ::shutdown:/sbin/swapoff -a\n"
     1180//usage:    "   ::shutdown:/bin/umount -a -r\n"
     1181//usage:    "   ::restart:/sbin/init\n"
     1182//usage:    "\n"
     1183//usage:    "if it detects that /dev/console is _not_ a serial console, it will also run:\n"
     1184//usage:    "\n"
     1185//usage:    "   tty2::askfirst:/bin/sh\n"
     1186//usage:    "   tty3::askfirst:/bin/sh\n"
     1187//usage:    "   tty4::askfirst:/bin/sh\n"
     1188//usage:    "\n"
     1189//usage:    "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n"
     1190//usage:    "\n"
     1191//usage:    "   <id>:<runlevels>:<action>:<process>\n"
     1192//usage:    "\n"
     1193//usage:    "   <id>:\n"
     1194//usage:    "\n"
     1195//usage:    "       WARNING: This field has a non-traditional meaning for BusyBox init!\n"
     1196//usage:    "       The id field is used by BusyBox init to specify the controlling tty for\n"
     1197//usage:    "       the specified process to run on. The contents of this field are\n"
     1198//usage:    "       appended to \"/dev/\" and used as-is. There is no need for this field to\n"
     1199//usage:    "       be unique, although if it isn't you may have strange results. If this\n"
     1200//usage:    "       field is left blank, the controlling tty is set to the console. Also\n"
     1201//usage:    "       note that if BusyBox detects that a serial console is in use, then only\n"
     1202//usage:    "       entries whose controlling tty is either the serial console or /dev/null\n"
     1203//usage:    "       will be run. BusyBox init does nothing with utmp. We don't need no\n"
     1204//usage:    "       stinkin' utmp.\n"
     1205//usage:    "\n"
     1206//usage:    "   <runlevels>:\n"
     1207//usage:    "\n"
     1208//usage:    "       The runlevels field is completely ignored.\n"
     1209//usage:    "\n"
     1210//usage:    "   <action>:\n"
     1211//usage:    "\n"
     1212//usage:    "       Valid actions include: sysinit, respawn, askfirst, wait,\n"
     1213//usage:    "       once, restart, ctrlaltdel, and shutdown.\n"
     1214//usage:    "\n"
     1215//usage:    "       The available actions can be classified into two groups: actions\n"
     1216//usage:    "       that are run only once, and actions that are re-run when the specified\n"
     1217//usage:    "       process exits.\n"
     1218//usage:    "\n"
     1219//usage:    "       Run only-once actions:\n"
     1220//usage:    "\n"
     1221//usage:    "           'sysinit' is the first item run on boot. init waits until all\n"
     1222//usage:    "           sysinit actions are completed before continuing. Following the\n"
     1223//usage:    "           completion of all sysinit actions, all 'wait' actions are run.\n"
     1224//usage:    "           'wait' actions, like 'sysinit' actions, cause init to wait until\n"
     1225//usage:    "           the specified task completes. 'once' actions are asynchronous,\n"
     1226//usage:    "           therefore, init does not wait for them to complete. 'restart' is\n"
     1227//usage:    "           the action taken to restart the init process. By default this should\n"
     1228//usage:    "           simply run /sbin/init, but can be a script which runs pivot_root or it\n"
     1229//usage:    "           can do all sorts of other interesting things. The 'ctrlaltdel' init\n"
     1230//usage:    "           actions are run when the system detects that someone on the system\n"
     1231//usage:    "           console has pressed the CTRL-ALT-DEL key combination. Typically one\n"
     1232//usage:    "           wants to run 'reboot' at this point to cause the system to reboot.\n"
     1233//usage:    "           Finally the 'shutdown' action specifies the actions to taken when\n"
     1234//usage:    "           init is told to reboot. Unmounting filesystems and disabling swap\n"
     1235//usage:    "           is a very good here.\n"
     1236//usage:    "\n"
     1237//usage:    "       Run repeatedly actions:\n"
     1238//usage:    "\n"
     1239//usage:    "           'respawn' actions are run after the 'once' actions. When a process\n"
     1240//usage:    "           started with a 'respawn' action exits, init automatically restarts\n"
     1241//usage:    "           it. Unlike sysvinit, BusyBox init does not stop processes from\n"
     1242//usage:    "           respawning out of control. The 'askfirst' actions acts just like\n"
     1243//usage:    "           respawn, except that before running the specified process it\n"
     1244//usage:    "           displays the line \"Please press Enter to activate this console.\"\n"
     1245//usage:    "           and then waits for the user to press enter before starting the\n"
     1246//usage:    "           specified process.\n"
     1247//usage:    "\n"
     1248//usage:    "       Unrecognized actions (like initdefault) will cause init to emit an\n"
     1249//usage:    "       error message, and then go along with its business. All actions are\n"
     1250//usage:    "       run in the order they appear in /etc/inittab.\n"
     1251//usage:    "\n"
     1252//usage:    "   <process>:\n"
     1253//usage:    "\n"
     1254//usage:    "       Specifies the process to be executed and its command line.\n"
     1255//usage:    "\n"
     1256//usage:    "Example /etc/inittab file:\n"
     1257//usage:    "\n"
     1258//usage:    "   # This is run first except when booting in single-user mode\n"
     1259//usage:    "   #\n"
     1260//usage:    "   ::sysinit:/etc/init.d/rcS\n"
     1261//usage:    "   \n"
     1262//usage:    "   # /bin/sh invocations on selected ttys\n"
     1263//usage:    "   #\n"
     1264//usage:    "   # Start an \"askfirst\" shell on the console (whatever that may be)\n"
     1265//usage:    "   ::askfirst:-/bin/sh\n"
     1266//usage:    "   # Start an \"askfirst\" shell on /dev/tty2-4\n"
     1267//usage:    "   tty2::askfirst:-/bin/sh\n"
     1268//usage:    "   tty3::askfirst:-/bin/sh\n"
     1269//usage:    "   tty4::askfirst:-/bin/sh\n"
     1270//usage:    "   \n"
     1271//usage:    "   # /sbin/getty invocations for selected ttys\n"
     1272//usage:    "   #\n"
     1273//usage:    "   tty4::respawn:/sbin/getty 38400 tty4\n"
     1274//usage:    "   tty5::respawn:/sbin/getty 38400 tty5\n"
     1275//usage:    "   \n"
     1276//usage:    "   \n"
     1277//usage:    "   # Example of how to put a getty on a serial line (for a terminal)\n"
     1278//usage:    "   #\n"
     1279//usage:    "   #::respawn:/sbin/getty -L ttyS0 9600 vt100\n"
     1280//usage:    "   #::respawn:/sbin/getty -L ttyS1 9600 vt100\n"
     1281//usage:    "   #\n"
     1282//usage:    "   # Example how to put a getty on a modem line\n"
     1283//usage:    "   #::respawn:/sbin/getty 57600 ttyS2\n"
     1284//usage:    "   \n"
     1285//usage:    "   # Stuff to do when restarting the init process\n"
     1286//usage:    "   ::restart:/sbin/init\n"
     1287//usage:    "   \n"
     1288//usage:    "   # Stuff to do before rebooting\n"
     1289//usage:    "   ::ctrlaltdel:/sbin/reboot\n"
     1290//usage:    "   ::shutdown:/bin/umount -a -r\n"
     1291//usage:    "   ::shutdown:/sbin/swapoff -a\n"
  • branches/2.2.9/mindi-busybox/init/mesg.c

    r1765 r2725  
    55 * Copyright (c) 2002 Manuel Novoa III  <mjn3@codepoet.org>
    66 *
    7  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    88 */
     9
     10//applet:IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP))
     11
     12//kbuild:lib-$(CONFIG_MESG) += mesg.o
     13
     14//config:config MESG
     15//config:   bool "mesg"
     16//config:   default y
     17//config:   help
     18//config:     Mesg controls access to your terminal by others. It is typically
     19//config:     used to allow or disallow other users to write to your terminal
     20
     21//usage:#define mesg_trivial_usage
     22//usage:       "[y|n]"
     23//usage:#define mesg_full_usage "\n\n"
     24//usage:       "Control write access to your terminal\n"
     25//usage:       "    y   Allow write access to your terminal\n"
     26//usage:       "    n   Disallow write access to your terminal"
    927
    1028#include "libbb.h"
    1129
    1230#ifdef USE_TTY_GROUP
    13 #define S_IWGRP_OR_S_IWOTH  S_IWGRP
     31#define S_IWGRP_OR_S_IWOTH  S_IWGRP
    1432#else
    15 #define S_IWGRP_OR_S_IWOTH  (S_IWGRP | S_IWOTH)
     33#define S_IWGRP_OR_S_IWOTH  (S_IWGRP | S_IWOTH)
    1634#endif
    1735
    18 int mesg_main(int argc, char **argv);
    19 int mesg_main(int argc, char **argv)
     36int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     37int mesg_main(int argc UNUSED_PARAM, char **argv)
    2038{
    2139    struct stat sb;
     
    2341    char c = 0;
    2442
    25     if (--argc == 0
    26      || (argc == 1 && ((c = **++argv) == 'y' || c == 'n'))
     43    argv++;
     44
     45    if (!argv[0]
     46     || (!argv[1] && ((c = argv[0][0]) == 'y' || c == 'n'))
    2747    ) {
    28         tty = ttyname(STDERR_FILENO);
     48        tty = xmalloc_ttyname(STDERR_FILENO);
    2949        if (tty == NULL) {
    3050            tty = "ttyname";
    3151        } else if (stat(tty, &sb) == 0) {
    3252            mode_t m;
    33             if (argc == 0) {
     53            if (c == 0) {
    3454                puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n");
    3555                return EXIT_SUCCESS;
     
    4161            }
    4262        }
    43         bb_perror_msg_and_die("%s", tty);
     63        bb_simple_perror_msg_and_die(tty);
    4464    }
    4565    bb_show_usage();
Note: See TracChangeset for help on using the changeset viewer.