* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* Turn this on to disable all the dangerous
- rebooting stuff when debugging.
-#define DEBUG_INIT
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
+#include "busybox.h"
#include <errno.h>
#include <paths.h>
#include <signal.h>
-#include <stdarg.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
#include <sys/wait.h>
#include <sys/reboot.h>
-#include "busybox.h"
#include "init_shared.h"
-
#ifdef CONFIG_SYSLOGD
# include <sys/syslog.h>
#endif
-
-#ifdef CONFIG_SELINUX
-# include <selinux/selinux.h>
-#endif /* CONFIG_SELINUX */
-
-
#define INIT_BUFFS_SIZE 256
/* From <linux/vt.h> */
int reserved[1];
};
-
#ifndef _PATH_STDPATH
#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
#endif
#include <sys/resource.h>
#endif
-#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
#define INITTAB "/etc/inittab" /* inittab file location */
#ifndef INIT_SCRIPT
#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */
/* Static variables */
static struct init_action *init_action_list = NULL;
-static char console[CONSOLE_BUFF_SIZE] = _PATH_CONSOLE;
+static char console[CONSOLE_BUFF_SIZE] = CONSOLE_DEV;
#ifndef CONFIG_SYSLOGD
static char *log_console = VC_5;
#endif
+#if !ENABLE_DEBUG_INIT
static sig_atomic_t got_cont = 0;
+#endif
enum {
LOG = 0x1,
#endif
#ifndef RB_HALT_SYSTEM
- RB_HALT_SYSTEM = 0xcdef0123,
+ RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */
RB_ENABLE_CAD = 0x89abcdef,
RB_DISABLE_CAD = 0,
RB_POWER_OFF = 0x4321fedc,
/* Function prototypes */
static void delete_init_action(struct init_action *a);
-static int waitfor(const struct init_action *a);
-static void halt_signal(int sig);
-
+static int waitfor(const struct init_action *a, pid_t pid);
+#if !ENABLE_DEBUG_INIT
+static void shutdown_signal(int sig);
+#endif
static void loop_forever(void)
{
/* Print a message to the specified device.
* Device may be bitwise-or'd from LOG | CONSOLE */
-#ifndef DEBUG_INIT
-static inline void messageD(int ATTRIBUTE_UNUSED device,
- const char ATTRIBUTE_UNUSED *fmt, ...)
-{
-}
-#else
+#if ENABLE_DEBUG_INIT
#define messageD message
+#else
+#define messageD(...) do {} while (0)
#endif
static void message(int device, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
{
va_list arguments;
int l;
- char msg[1024];
+ RESERVE_CONFIG_BUFFER(msg, 1024);
#ifndef CONFIG_SYSLOGD
static int log_fd = -1;
#endif
msg[0] = '\r';
va_start(arguments, fmt);
- l = vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments) + 1;
+ l = vsnprintf(msg + 1, 1024 - 2, fmt, arguments) + 1;
va_end(arguments);
#ifdef CONFIG_SYSLOGD
/* Log the message to syslogd */
if (device & LOG) {
/* don`t out "\r\n" */
- openlog(bb_applet_name, 0, LOG_DAEMON);
+ openlog(applet_name, 0, LOG_DAEMON);
syslog(LOG_INFO, "%s", msg + 1);
closelog();
}
if (log_fd < 0) {
if ((log_fd = device_open(log_console, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
log_fd = -2;
- bb_error_msg("Bummer, can't write to log on %s!", log_console);
+ bb_error_msg("bummer, can't write to log on %s!", log_console);
device = CONSOLE;
} else {
fcntl(log_fd, F_SETFD, FD_CLOEXEC);
}
}
if ((device & LOG) && (log_fd >= 0)) {
- bb_full_write(log_fd, msg, l);
+ full_write(log_fd, msg, l);
}
#endif
if (device & CONSOLE) {
- int fd = device_open(_PATH_CONSOLE,
+ int fd = device_open(CONSOLE_DEV,
O_WRONLY | O_NOCTTY | O_NONBLOCK);
/* Always send console messages to /dev/console so people will see them. */
if (fd >= 0) {
- bb_full_write(fd, msg, l);
+ full_write(fd, msg, l);
close(fd);
-#ifdef DEBUG_INIT
+#if ENABLE_DEBUG_INIT
/* all descriptors may be closed */
} else {
- bb_error_msg("Bummer, can't print: ");
+ bb_error_msg("bummer, can't print: ");
va_start(arguments, fmt);
vfprintf(stderr, fmt, arguments);
va_end(arguments);
#endif
}
}
+ RELEASE_CONFIG_BUFFER(msg);
}
/* Set terminal settings to reasonable defaults */
if ((s = getenv("CONSOLE")) != NULL || (s = getenv("console")) != NULL) {
safe_strncpy(console, s, sizeof(console));
-#if 0 /* #cpu(sparc) */
- /* sparc kernel supports console=tty[ab] parameter which is also
- * passed to init, so catch it here */
- /* remap tty[ab] to /dev/ttyS[01] */
- if (strcmp(s, "ttya") == 0)
- safe_strncpy(console, SC_0, sizeof(console));
- else if (strcmp(s, "ttyb") == 0)
- safe_strncpy(console, SC_1, sizeof(console));
-#endif
} else {
/* 2.2 kernels: identify the real console backend and try to use it */
if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
/* this is linux virtual tty */
snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active);
} else {
- safe_strncpy(console, _PATH_CONSOLE, sizeof(console));
+ safe_strncpy(console, CONSOLE_DEV, sizeof(console));
tried++;
}
}
while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0 && tried < 2) {
/* Can't open selected console -- try
logical system console and VT_MASTER */
- safe_strncpy(console, (tried == 0 ? _PATH_CONSOLE : CURRENT_VC),
+ safe_strncpy(console, (tried == 0 ? CONSOLE_DEV : CURRENT_VC),
sizeof(console));
tried++;
}
}
/* Open the new terminal device */
-static void open_new_terminal(const char *device, char fail) {
+static void open_new_terminal(const char * const device, const int fail) {
struct stat sb;
if ((device_open(device, O_RDWR)) < 0) {
if (fail)
_exit(1);
/* else */
- halt_signal(SIGUSR1);
+#if !ENABLE_DEBUG_INIT
+ shutdown_signal(SIGUSR1);
+#else
+ _exit(2);
+#endif
}
}
static pid_t run(const struct init_action *a)
{
- int i, junk;
+ int i;
pid_t pid;
char *s, *tmpCmd, *cmd[INIT_BUFFS_SIZE], *cmdpath;
char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */
/* If the init Action requires us to wait, then force the
* supplied terminal to be the controlling tty. */
if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
- pid_t pgrp, tmp_pid;
/* Now fork off another process to just hang around */
if ((pid = fork()) < 0) {
signal(SIGQUIT, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
- /* Wait for child to exit */
- while ((tmp_pid = waitpid(pid, &junk, 0)) != pid) {
- if (tmp_pid == -1 && errno == ECHILD) {
- break;
- }
- /* FIXME handle other errors */
- }
-
+ waitfor(NULL, pid);
/* See if stealing the controlling tty back is necessary */
- pgrp = tcgetpgrp(0);
- if (pgrp != getpid())
+ if (tcgetpgrp(0) != getpid())
_exit(0);
/* Use a temporary process to steal the controlling tty. */
ioctl(0, TIOCSCTTY, 1);
_exit(0);
}
- while ((tmp_pid = waitpid(pid, &junk, 0)) != pid) {
- if (tmp_pid < 0 && errno == ECHILD)
- break;
- }
+ waitfor(NULL, pid);
_exit(0);
}
messageD(LOG, "Waiting for enter to start '%s'"
"(pid %d, terminal %s)\n",
cmdpath, getpid(), a->terminal);
- bb_full_write(1, press_enter, sizeof(press_enter) - 1);
- while(read(0, &c, 1) == 1 && c != '\n')
+ full_write(1, press_enter, sizeof(press_enter) - 1);
+ while (read(0, &c, 1) == 1 && c != '\n')
;
}
#endif
execv(cmdpath, cmd);
/* We're still here? Some error happened. */
- message(LOG | CONSOLE, "Bummer, could not run '%s': %m", cmdpath);
+ message(LOG | CONSOLE, "Bummer, cannot run '%s': %m", cmdpath);
_exit(-1);
}
sigprocmask(SIG_SETMASK, &omask, NULL);
return pid;
}
-static int waitfor(const struct init_action *a)
+static int waitfor(const struct init_action *a, pid_t pid)
{
- int pid;
+ int runpid;
int status, wpid;
- pid = run(a);
+ runpid = (NULL == a)? pid : run(a);
while (1) {
- wpid = waitpid(pid,&status,0);
- if (wpid == pid)
+ wpid = waitpid(runpid,&status,0);
+ if (wpid == runpid)
break;
if (wpid == -1 && errno == ECHILD) {
/* we missed its termination */
if (access(a->terminal, R_OK | W_OK)) {
delete_init_action(a);
} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
- waitfor(a);
+ waitfor(a, 0);
delete_init_action(a);
} else if (a->action & ONCE) {
run(a);
}
}
-#ifndef DEBUG_INIT
+#if !ENABLE_DEBUG_INIT
static void init_reboot(unsigned long magic)
{
pid_t pid;
sync();
/* Send signals to every process _except_ pid 1 */
- message(CONSOLE | LOG, "Sending SIGTERM to all processes.");
+ message(CONSOLE | LOG, init_sending_format, "TERM");
kill(-1, SIGTERM);
sleep(1);
sync();
- message(CONSOLE | LOG, "Sending SIGKILL to all processes.");
+ message(CONSOLE | LOG, init_sending_format, "KILL");
kill(-1, SIGKILL);
sleep(1);
}
}
-static void halt_signal(int sig ATTRIBUTE_UNUSED)
+static void shutdown_signal(int sig)
{
- shutdown_system();
- message(CONSOLE | LOG, "The system is halted.");
- sync();
-
- /* allow time for last message to reach serial console */
- sleep(2);
-
- if (sig == SIGUSR2)
- init_reboot(RB_POWER_OFF);
- else
- init_reboot(RB_HALT_SYSTEM);
+ char *m;
+ int rb;
- loop_forever();
-}
-
-static void reboot_signal(int sig ATTRIBUTE_UNUSED)
-{
shutdown_system();
- message(CONSOLE | LOG, "Please stand by while rebooting the system.");
+
+ if (sig == SIGTERM) {
+ m = "reboot";
+ rb = RB_AUTOBOOT;
+ } else if (sig == SIGUSR2) {
+ m = "poweroff";
+ rb = RB_POWER_OFF;
+ } else {
+ m = "halt";
+ rb = RB_HALT_SYSTEM;
+ }
+ message(CONSOLE | LOG, "Requesting system %s.", m);
sync();
/* allow time for last message to reach serial console */
sleep(2);
- init_reboot(RB_AUTOBOOT);
+ init_reboot(rb);
loop_forever();
}
got_cont = 1;
}
-#endif /* ! DEBUG_INIT */
+#endif /* ! ENABLE_DEBUG_INIT */
static void new_init_action(int action, const char *command, const char *cons)
{
strcpy(new_action->command, command);
new_action->action = action;
strcpy(new_action->terminal, cons);
-#if 0 /* calloc zeroed always */
- new_action->pid = 0;
-#endif
messageD(LOG|CONSOLE, "command='%s' action='%d' terminal='%s'\n",
new_action->command, new_action->action, new_action->terminal);
}
{
struct init_action *a;
pid_t wpid;
- int status;
if (argc > 1 && !strcmp(argv[1], "-q")) {
return kill(1,SIGHUP);
}
-#ifndef DEBUG_INIT
+#if !ENABLE_DEBUG_INIT
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
if (getpid() != 1 &&
- (!ENABLE_FEATURE_INITRD || !strstr(bb_applet_name, "linuxrc")))
+ (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")))
{
bb_show_usage();
}
* clear all of these in run() */
signal(SIGHUP, exec_signal);
signal(SIGQUIT, exec_signal);
- signal(SIGUSR1, halt_signal);
- signal(SIGUSR2, halt_signal);
+ signal(SIGUSR1, shutdown_signal);
+ signal(SIGUSR2, shutdown_signal);
signal(SIGINT, ctrlaltdel_signal);
- signal(SIGTERM, reboot_signal);
+ signal(SIGTERM, shutdown_signal);
signal(SIGCONT, cont_handler);
signal(SIGSTOP, stop_handler);
signal(SIGTSTP, stop_handler);
{
const char * const *e;
/* Make sure environs is set to something sane */
- for(e = environment; *e; e++)
+ for (e = environment; *e; e++)
putenv((char *) *e);
}
+
+ if (argc > 1) setenv("RUNLEVEL", argv[1], 1);
+
/* Hello world */
message(MAYBE_CONSOLE | LOG, "init started: %s", bb_msg_full_version);
struct sysinfo info;
if (!sysinfo(&info) &&
- (info.mem_unit ? : 1) * (long long)info.totalram < MEGABYTE)
+ (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)
{
message(CONSOLE,"Low memory: forcing swapon.");
/* swapon -a requires /proc typically */
}
/* Check if we are supposed to be in single user mode */
- if (argc > 1 && (!strcmp(argv[1], "single") ||
- !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
+ if (argc > 1
+ && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
+ ) {
/* Start a shell on console */
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
sleep(1);
/* Wait for a child process to exit */
- wpid = wait(&status);
+ wpid = wait(NULL);
while (wpid > 0) {
/* Find out who died and clean up their corpse */
for (a = init_action_list; a; a = a->next) {
}
}
/* see if anyone else is waiting to be reaped */
- wpid = waitpid (-1, &status, WNOHANG);
+ wpid = waitpid(-1, NULL, WNOHANG);
}
}
}