*
* Version: @(#)init.c 2.86 30-Jul-2004 miquels@cistron.nl
*/
-#define VERSION "2.88"
-#define DATE "31-Jul-2004"
+#define VERSION "2.89"
+#define DATE "26-Mar-2010"
/*
* This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg.
#include <utmp.h>
#include <ctype.h>
#include <stdarg.h>
+#include <sys/ttydefaults.h>
#include <sys/syslog.h>
#include <sys/time.h>
#ifdef WITH_SELINUX
-#include <selinux/selinux.h>
+# include <selinux/selinux.h>
#endif
-
#ifdef __i386__
-# if (__GLIBC__ >= 2)
+# ifdef __GLIBC__
/* GNU libc 2.x */
# define STACK_DEBUG 1
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
/* Only glibc 2.0 needs this */
# include <sigcontext.h>
+# elif ( __GLIBC__ > 2) && ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
+# include <bits/sigcontext.h>
# endif
# endif
#endif
/* Set a signal handler. */
#define SETSIG(sa, sig, fun, flags) \
do { \
+ memset(&sa, 0, sizeof(sa)); \
sa.sa_handler = fun; \
sa.sa_flags = flags; \
sigemptyset(&sa.sa_mask); \
int emerg_shell = 0; /* Start emergency shell? */
int wrote_wtmp_reboot = 1; /* Set when we wrote the reboot record */
int wrote_utmp_reboot = 1; /* Set when we wrote the reboot record */
+int wrote_wtmp_rlevel = 1; /* Set when we wrote the runlevel record */
+int wrote_utmp_rlevel = 1; /* Set when we wrote the runlevel record */
int sltime = 5; /* Sleep time between TERM and KILL */
char *argv0; /* First arguments; show up in ps listing */
int maxproclen; /* Maximal length of argv[0] with \0 */
{ "-WU", D_WROTE_UTMP_REBOOT},
{ "-ST", D_SLTIME },
{ "-DB", D_DIDBOOT },
+ { "-LW", D_WROTE_WTMP_RLEVEL},
+ { "-LU", D_WROTE_UTMP_RLEVEL},
{ "", 0 }
};
struct {
* This only works correctly because the linux select updates
* the elapsed time in the struct timeval passed to select!
*/
+static
void do_sleep(int sec)
{
struct timeval tv;
/*
* Non-failing allocation routines (init cannot fail).
*/
+static
void *imalloc(size_t size)
{
void *m;
return m;
}
-
-char *istrdup(char *s)
+static
+char *istrdup(const char *s)
{
char *m;
int l;
* Send the state info of the previous running init to
* the new one, in a version-independant way.
*/
+static
void send_state(int fd)
{
FILE *fp;
case D_DIDBOOT:
fscanf(f, "%d\n", &did_boot);
break;
+ case D_WROTE_WTMP_RLEVEL:
+ fscanf(f, "%d\n", &wrote_wtmp_rlevel);
+ break;
+ case D_WROTE_UTMP_RLEVEL:
+ fscanf(f, "%d\n", &wrote_utmp_rlevel);
+ break;
default:
if (cmd > 0 || cmd == C_EOF) {
oops_error = -1;
* Read the complete state info from the state pipe.
* Returns 0 on success
*/
+static
int receive_state(int fd)
{
FILE *f;
f = fdopen(fd, "r");
- if (get_cmd(f) != C_VER)
+ if (get_cmd(f) != C_VER) {
+ fclose(f);
return -1;
+ }
get_string(old_version, sizeof(old_version), f);
oops_error = 0;
for (pp = &family; (*pp = get_record(f)) != NULL; pp = &((*pp)->next))
/*
* Set console_dev to a working console.
*/
+static
void console_init(void)
{
int fd;
/*
* Open the console with retries.
*/
+static
int console_open(int mode)
{
int f, fd = -1;
*/
for(f = 0; f < 5; f++) {
if ((fd = open(console_dev, m)) >= 0) break;
- usleep(100);
+ usleep(10000);
}
if (fd < 0) return fd;
/*
* We got a signal (HUP PWR WINCH ALRM INT)
*/
+static
void signal_handler(int sig)
{
ADDSET(got_signals, sig);
/*
* SIGCHLD: one of our children has died.
*/
-void chld_handler()
+static
+# ifdef __GNUC__
+void chld_handler(int sig __attribute__((unused)))
+# else
+void chld_handler(int sig)
+# endif
{
CHILD *ch;
int pid, st;
*
* The SIGCONT handler
*/
-void cont_handler()
+static
+# ifdef __GNUC__
+void cont_handler(int sig __attribute__((unused)))
+# else
+void cont_handler(int sig)
+# endif
{
got_cont = 1;
}
/*
* Fork and dump core in /.
*/
+static
void coredump(void)
{
static int dumped = 0;
* If we have the info, print where it occured.
* Then sleep 30 seconds and try to continue.
*/
+static
#if defined(STACK_DEBUG) && defined(__linux__)
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)), struct sigcontext ctx)
+# else
void segv_handler(int sig, struct sigcontext ctx)
+# endif
{
char *p = "";
int saved_errno = errno;
errno = saved_errno;
}
#else
-void segv_handler()
+# ifdef __GNUC__
+void segv_handler(int sig __attribute__((unused)))
+# else
+void segv_handler(int sig)
+# endif
{
int saved_errno = errno;
/*
* The SIGSTOP & SIGTSTP handler
*/
-void stop_handler()
+static
+# ifdef __GNUC__
+void stop_handler(int sig __attribute__((unused)))
+# else
+void stop_handler(int sig)
+# endif
{
int saved_errno = errno;
/*
* Set terminal settings to reasonable defaults
*/
+static
void console_stty(void)
{
struct termios tty;
return;
}
+#ifdef __FreeBSD_kernel__
+ /*
+ * The kernel of FreeBSD expects userland to set TERM. Usually, we want
+ * "cons25". Later, gettys might disagree on this (i.e. we're not using
+ * syscons) but some boot scripts, like /etc/init.d/xserver-xorg, still
+ * need a non-dumb terminal.
+ */
+ putenv ("TERM=cons25");
+#endif
+
(void) tcgetattr(fd, &tty);
tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
tty.c_cflag |= HUPCL|CLOCAL|CREAD;
- tty.c_cc[VINTR] = 3; /* ctrl('c') */
- tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
- tty.c_cc[VERASE] = 127;
- tty.c_cc[VKILL] = 24; /* ctrl('x') */
- tty.c_cc[VEOF] = 4; /* ctrl('d') */
- tty.c_cc[VTIME] = 0;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VSTART] = 17; /* ctrl('q') */
- tty.c_cc[VSTOP] = 19; /* ctrl('s') */
- tty.c_cc[VSUSP] = 26; /* ctrl('z') */
+ tty.c_cc[VINTR] = CINTR;
+ tty.c_cc[VQUIT] = CQUIT;
+ tty.c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */
+ tty.c_cc[VKILL] = CKILL;
+ tty.c_cc[VEOF] = CEOF;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+#ifdef VSWTC /* not defined on FreeBSD */
+ tty.c_cc[VSWTC] = _POSIX_VDISABLE;
+#endif /* VSWTC */
+ tty.c_cc[VSTART] = CSTART;
+ tty.c_cc[VSTOP] = CSTOP;
+ tty.c_cc[VSUSP] = CSUSP;
+ tty.c_cc[VEOL] = _POSIX_VDISABLE;
+ tty.c_cc[VREPRINT] = CREPRINT;
+ tty.c_cc[VDISCARD] = CDISCARD;
+ tty.c_cc[VWERASE] = CWERASE;
+ tty.c_cc[VLNEXT] = CLNEXT;
+ tty.c_cc[VEOL2] = _POSIX_VDISABLE;
/*
* Set pre and post processing
*/
- tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
+ tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY
+#ifdef IUTF8 /* Not defined on FreeBSD */
+ | (tty.c_iflag & IUTF8)
+#endif /* IUTF8 */
+ ;
tty.c_oflag = OPOST|ONLCR;
tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
+#if defined(SANE_TIO) && (SANE_TIO == 1)
+ /*
+ * Disable flow control (-ixon), ignore break (ignbrk),
+ * and make nl/cr more usable (sane).
+ */
+ tty.c_iflag |= IGNBRK;
+ tty.c_iflag &= ~(BRKINT|INLCR|IGNCR|IXON);
+ tty.c_oflag &= ~(OCRNL|ONLRET);
+#endif
/*
* Now set the terminal line.
* We don't care about non-transmitted output data
(void) close(fd);
}
+static ssize_t
+safe_write(int fd, const char *buffer, size_t count)
+{
+ ssize_t offset = 0;
+
+ while (count > 0) {
+ ssize_t block = write(fd, &buffer[offset], count);
+
+ if (block < 0 && errno == EINTR)
+ continue;
+ if (block <= 0)
+ return offset ? offset : block;
+ offset += block;
+ count -= block;
+ }
+ return offset;
+}
+
/*
* Print to the system console
*/
int fd;
if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
- write(fd, s, strlen(s));
+ safe_write(fd, s, strlen(s));
close(fd);
}
}
}
}
+/*
+ * Add or replace specific environment value
+ */
+int addnewenv(const char *new, char **curr, int n)
+{
+ size_t nlen = strcspn(new, "=");
+ int i;
+ for (i = 0; i < n; i++) {
+ if (nlen != strcspn(curr[i], "="))
+ continue;
+ if (strncmp (new, curr[i], nlen) == 0)
+ break;
+ }
+ if (i >= n)
+ curr[n++] = istrdup(new);
+ else {
+ free(curr[i]);
+ curr[i] = istrdup(new);
+ }
+ return n;
+}
/*
* Build a new environment for execve().
{
char i_lvl[] = "RUNLEVEL=x";
char i_prev[] = "PREVLEVEL=x";
- char i_cons[32];
+ char i_cons[128];
+ char i_shell[] = "SHELL=" SHELL;
char **e;
int n, i;
for (n = 0; environ[n]; n++)
;
- n += NR_EXTRA_ENV + 8;
- e = calloc(n, sizeof(char *));
+ n += NR_EXTRA_ENV + 1; /* Also room for last NULL */
+ if (child)
+ n += 8;
+
+ while ((e = (char**)calloc(n, sizeof(char *))) == NULL) {
+ initlog(L_VB, "out of memory");
+ do_sleep(5);
+ }
for (n = 0; environ[n]; n++)
e[n] = istrdup(environ[n]);
- for (i = 0; i < NR_EXTRA_ENV; i++)
- if (extra_env[i])
- e[n++] = istrdup(extra_env[i]);
+ for (i = 0; i < NR_EXTRA_ENV; i++) {
+ if (extra_env[i] == NULL || *extra_env[i] == '\0')
+ continue;
+ n = addnewenv(extra_env[i], e, n);
+ }
if (child) {
snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
i_lvl[9] = thislevel;
i_prev[10] = prevlevel;
- e[n++] = istrdup(i_lvl);
- e[n++] = istrdup(i_prev);
- e[n++] = istrdup(i_cons);
- e[n++] = istrdup(E_VERSION);
+ n = addnewenv(i_shell, e, n);
+ n = addnewenv(i_lvl, e, n);
+ n = addnewenv(i_prev, e, n);
+ n = addnewenv(i_cons, e, n);
+ n = addnewenv(E_VERSION, e, n);
}
e[n++] = NULL;
* This function is too long and indents too deep.
*
*/
-int spawn(CHILD *ch, int *res)
+static
+pid_t spawn(CHILD *ch, int *res)
{
char *args[16]; /* Argv array */
char buf[136]; /* Line buffer */
- int f, st, rc; /* Scratch variables */
+ int f, st; /* Scratch variables */
char *ptr; /* Ditto */
time_t t; /* System time */
int oldAlarm; /* Previous alarm value */
dup(f);
dup(f);
}
+
+ /*
+ * 4 Sep 2001, Andrea Arcangeli:
+ * Fix a race in spawn() that is used to deadlock init in a
+ * waitpid() loop: must set the childhandler as default before forking
+ * off the child or the chld_handler could run before the waitpid loop
+ * has a chance to find its zombie-child.
+ */
SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
if ((pid = fork()) < 0) {
initlog(L_VB, "cannot fork: %s",
exit(1);
}
if (pid > 0) {
+ pid_t rc;
/*
* Ignore keyboard signals etc.
* Then wait for child to exit.
dup(f);
}
+ /*
+ * Update utmp/wtmp file prior to starting
+ * any child. This MUST be done right here in
+ * the child process in order to prevent a race
+ * condition that occurs when the child
+ * process' time slice executes before the
+ * parent (can and does happen in a uniprocessor
+ * environment). If the child is a getty and
+ * the race condition happens, then init's utmp
+ * update will happen AFTER the getty runs
+ * and expects utmp to be updated already!
+ *
+ * Do NOT log if process field starts with '+'
+ * FIXME: that's for compatibility with *very*
+ * old getties - probably it can be taken out.
+ */
+ if (ch->process[0] != '+')
+ write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
+
/* Reset all the signals, set up environment */
for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
environ = init_buildenv(1);
execvp(args[1], args + 1);
}
initlog(L_VB, "cannot execute \"%s\"", args[1]);
+
+ if (ch->process[0] != '+')
+ write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
exit(1);
}
*res = pid;
/*
* Start a child running!
*/
+static
void startup(CHILD *ch)
{
/*
case POWEROKWAIT:
case CTRLALTDEL:
if (!(ch->flags & XECUTED)) ch->flags |= WAITING;
+ /* Fall through */
case KBREQUEST:
case BOOT:
case POWERFAIL:
case ONDEMAND:
case RESPAWN:
ch->flags |= RUNNING;
- if (spawn(ch, &(ch->pid)) < 0) break;
- /*
- * Do NOT log if process field starts with '+'
- * FIXME: that's for compatibility with *very*
- * old getties - probably it can be taken out.
- */
- if (ch->process[0] != '+')
- write_utmp_wtmp("", ch->id, ch->pid,
- INIT_PROCESS, "");
+ (void)spawn(ch, &(ch->pid));
break;
}
}
/*
* Read the inittab file.
*/
+static
void read_inittab(void)
{
FILE *fp; /* The INITTAB file */
#endif
/*
- * Open INITTAB and real line by line.
+ * Open INITTAB and read line by line.
*/
if ((fp = fopen(INITTAB, "r")) == NULL)
initlog(L_VB, "No inittab file found");
strncpy(ch->id, id, sizeof(utproto.ut_id) + 1); /* Hack for different libs. */
strncpy(ch->process, process, sizeof(ch->process) - 1);
if (rlevel[0]) {
- for(f = 0; f < sizeof(rlevel) - 1 && rlevel[f]; f++) {
+ for(f = 0; f < (int)sizeof(rlevel) - 1 && rlevel[f]; f++) {
ch->rlevel[f] = rlevel[f];
if (ch->rlevel[f] == 's') ch->rlevel[f] = 'S';
}
case 0: /* Send TERM signal */
if (talk)
initlog(L_CO,
- "Sending processes the TERM signal");
+ "Sending processes configured via /etc/inittab the TERM signal");
kill(-(ch->pid), SIGTERM);
foundOne = 1;
break;
case 1: /* Send KILL signal and collect status */
if (talk)
initlog(L_CO,
- "Sending processes the KILL signal");
+ "Sending processes configured via /etc/inittab the KILL signal");
kill(-(ch->pid), SIGKILL);
break;
}
* The entries that do not belong here at all are removed
* from the list.
*/
+static
void start_if_needed(void)
{
CHILD *ch; /* Pointer to child */
/*
* Ask the user on the console for a runlevel
*/
+static
int ask_runlevel(void)
{
const char prompt[] = "\nEnter runlevel: ";
if (fd < 0) return('S');
while(!strchr("0123456789S", lvl)) {
- write(fd, prompt, sizeof(prompt) - 1);
- buf[0] = 0;
- read(fd, buf, sizeof(buf));
+ safe_write(fd, prompt, sizeof(prompt) - 1);
+ if (read(fd, buf, sizeof(buf)) <= 0)
+ buf[0] = 0;
if (buf[0] != 0 && (buf[1] == '\r' || buf[1] == '\n'))
lvl = buf[0];
if (islower(lvl)) lvl = toupper(lvl);
* Search the INITTAB file for the 'initdefault' field, with the default
* runlevel. If this fails, ask the user to supply a runlevel.
*/
+static
int get_init_default(void)
{
CHILD *ch;
* the "old" INITLVL and arg == 0, try to read the new
* runlevel from that file first.
*/
+static
int read_level(int arg)
{
CHILD *ch; /* Walk through list */
initlog(L_VB, "Switching to runlevel: %c", foo);
}
- if (foo == 'Q') return runlevel;
+ if (foo == 'Q') {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+ /* Re-enable signal from keyboard */
+ struct sigaction sa;
+ SETSIG(sa, SIGINT, signal_handler, 0);
+#endif
+ return runlevel;
+ }
/* Check if this is a runlevel a, b or c */
if (strchr("ABC", foo)) {
}
/* Store both the old and the new runlevel. */
+ wrote_utmp_rlevel = 0;
+ wrote_wtmp_rlevel = 0;
write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
thislevel = foo;
prevlevel = runlevel;
* longer than 5 minutes, or inittab was read again due
* to user interaction.
*/
+static
void fail_check(void)
{
CHILD *ch; /* Pointer to child structure */
}
/* Set all 'Fail' timers to 0 */
+static
void fail_cancel(void)
{
CHILD *ch;
/*
* Start up powerfail entries.
*/
+static
void do_power_fail(int pwrstat)
{
CHILD *ch;
/*
* Check for state-pipe presence
*/
+static
int check_pipe(int fd)
{
struct timeval t;
/*
* Make a state-pipe.
*/
+static
int make_pipe(int fd)
{
int fds[2];
- pipe(fds);
+ if (pipe(fds)) {
+ initlog(L_VB, "pipe: %m");
+ return -1;
+ }
dup2(fds[0], fd);
close(fds[0]);
fcntl(fds[1], F_SETFD, 1);
fcntl(fd, F_SETFD, 0);
- write(fds[1], Signature, 8);
+ safe_write(fds[1], Signature, 8);
return fds[1];
}
/*
* Attempt to re-exec.
*/
+static
void re_exec(void)
{
CHILD *ch;
/*
* construct a pipe fd --> STATE_PIPE and write a signature
*/
- fd = make_pipe(STATE_PIPE);
+ if ((fd = make_pipe(STATE_PIPE)) < 0) {
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ initlog(L_CO, "Attempt to re-exec failed");
+ }
/*
* It's a backup day today, so I'm pissed off. Being a BOFH, however,
* We shouldn't be here, something failed.
* Bitch, close the state pipe, unblock signals and return.
*/
+ init_freeenv(env);
close(fd);
close(STATE_PIPE);
sigprocmask(SIG_SETMASK, &oldset, NULL);
- init_freeenv(env);
initlog(L_CO, "Attempt to re-exec failed");
}
+/*
+ * Redo utmp/wtmp entries if required or requested
+ * Check for written records and size of utmp
+ */
+static
+void redo_utmp_wtmp(void)
+{
+ struct stat ustat;
+ const int ret = stat(UTMP_FILE, &ustat);
+
+ if ((ret < 0) || (ustat.st_size == 0))
+ wrote_utmp_rlevel = wrote_utmp_reboot = 0;
+
+ if ((wrote_wtmp_reboot == 0) || (wrote_utmp_reboot == 0))
+ write_utmp_wtmp("reboot", "~~", 0, BOOT_TIME, "~");
+
+ if ((wrote_wtmp_rlevel == 0) || (wrote_wtmp_rlevel == 0))
+ write_utmp_wtmp("runlevel", "~~", thislevel + 256 * prevlevel, RUN_LVL, "~");
+}
/*
* We got a change runlevel request through the
* init.fifo. Process it.
*/
+static
void fifo_new_level(int level)
{
#if CHANGE_WAIT
if (oldlevel != 'S' && runlevel == 'S') console_stty();
if (runlevel == '6' || runlevel == '0' ||
runlevel == '1') console_stty();
+ if (runlevel > '1' && runlevel < '6') redo_utmp_wtmp();
read_inittab();
fail_cancel();
- setproctitle("init [%c]", runlevel);
+ setproctitle("init [%c]", (int)runlevel);
}
}
}
* encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means
* setenv, without it means unsetenv.
*/
+static
void initcmd_setenv(char *data, int size)
{
- char *env, *p, *e, *eq;
- int i, sz;
+ char *env, *p, *e;
+ size_t sz;
+ int i, eq;
e = data + size;
while (*data && data < e) {
- eq = NULL;
for (p = data; *p && p < e; p++)
- if (*p == '=') eq = p;
+ ;
if (*p) break;
env = data;
data = ++p;
- sz = eq ? (eq - env) : (p - env);
-
- /*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
-
/*
* We only allow INIT_* to be set.
*/
if (strncmp(env, "INIT_", 5) != 0)
continue;
+ sz = strcspn(env, "=");
+ eq = (env[sz] == '=');
+
+ /*initlog(L_SY, "init_setenv: %s, %d, %d", env, eq, sz);*/
+
/* Free existing vars. */
for (i = 0; i < NR_EXTRA_ENV; i++) {
- if (extra_env[i] == NULL) continue;
- if (!strncmp(extra_env[i], env, sz) &&
- extra_env[i][sz] == '=') {
+ if (extra_env[i] == NULL)
+ continue;
+ if (sz != strcspn(extra_env[i], "="))
+ continue;
+ if (strncmp(extra_env[i], env, sz) == 0) {
free(extra_env[i]);
extra_env[i] = NULL;
}
}
+ if (eq == 0)
+ continue;
+
/* Set new vars if needed. */
- if (eq == NULL) continue;
for (i = 0; i < NR_EXTRA_ENV; i++) {
if (extra_env[i] == NULL) {
extra_env[i] = istrdup(env);
* the 2.2 kernel credential stuff to see who we're talking to.
*
*/
+static
void check_init_fifo(void)
{
struct init_request request;
* This function is used in the transition
* sysinit (-> single user) boot -> multi-user.
*/
+static
void boot_transitions()
{
CHILD *ch;
}
if (loglevel > 0) {
initlog(L_VB, "Entering runlevel: %c", runlevel);
+ wrote_utmp_rlevel = 0;
+ wrote_wtmp_rlevel = 0;
write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
thislevel = runlevel;
prevlevel = oldlevel;
- setproctitle("init [%c]", runlevel);
+ setproctitle("init [%c]", (int)runlevel);
}
}
}
* Init got hit by a signal. See which signal it is,
* and act accordingly.
*/
+static
void process_signals()
{
CHILD *ch;
/* See _what_ kind of SIGPWR this is. */
pwrstat = 0;
if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
- c = 0;
- read(fd, &c, 1);
+ if (read(fd, &c, 1) != 1)
+ c = 0;
pwrstat = c;
close(fd);
unlink(PWRSTAT);
- }
+ } else if ((fd = open(PWRSTAT_OLD, O_RDONLY)) >= 0) {
+ /* Path changed 2010-03-20. Look for the old path for a while. */
+ initlog(L_VB, "warning: found obsolete path %s, use %s instead",
+ PWRSTAT_OLD, PWRSTAT);
+ if (read(fd, &c, 1) != 1)
+ c = 0;
+ pwrstat = c;
+ close(fd);
+ unlink(PWRSTAT_OLD);
+ }
do_power_fail(pwrstat);
DELSET(got_signals, SIGPWR);
}
if (ISMEMBER(got_signals, SIGINT)) {
+#if defined(SIGINT_ONLYONCE) && (SIGINT_ONLYONCE == 1)
+ /* Ignore any further signal from keyboard */
+ struct sigaction sa;
+ SETSIG(sa, SIGINT, SIG_IGN, SA_RESTART);
+#endif
INITDBG(L_VB, "got SIGINT");
/* Tell ctrlaltdel entry to start up */
for(ch = family; ch; ch = ch->next)
runlevel == '1') console_stty();
read_inittab();
fail_cancel();
- setproctitle("init [%c]", runlevel);
+ setproctitle("init [%c]", (int)runlevel);
DELSET(got_signals, SIGHUP);
}
}
/*
* The main loop
*/
-int init_main()
+static
+void init_main(void)
{
CHILD *ch;
struct sigaction sa;
sigset_t sgt;
- pid_t rc;
int f, st;
if (!reload) {
while((rc = wait(&st)) != f)
if (rc < 0 && errno == ECHILD)
break;
- write(1, killmsg, sizeof(killmsg) - 1);
+ safe_write(1, killmsg, sizeof(killmsg) - 1);
while(1) pause();
}
#endif
console_init();
if (!reload) {
+ int fd;
/* Close whatever files are open, and reset the console. */
close(0);
* Initialize /var/run/utmp (only works if /var is on
* root and mounted rw)
*/
- (void) close(open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644));
+ if ((fd = open(UTMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0644)) >= 0)
+ close(fd);
/*
* Say hello to the world
* See if we have to start an emergency shell.
*/
if (emerg_shell) {
+ pid_t rc;
SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
if (spawn(&ch_emerg, &f) > 0) {
while((rc = wait(&st)) != f)
/*
* Tell the user about the syntax we expect.
*/
+static
void usage(char *s)
{
fprintf(stderr, "Usage: %s {-e VAR[=VAL] | [-t SECONDS] {0|1|2|3|4|5|6|S|s|Q|q|A|a|B|b|C|c|U|u}}\n", s);
exit(1);
}
+static
int telinit(char *progname, int argc, char **argv)
{
#ifdef TELINIT_USES_INITLVL
if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))
usage(progname);
request.cmd = INIT_CMD_RUNLVL;
- request.runlevel = env ? 0 : argv[optind][0];
+ request.runlevel = argv[optind][0];
request.sleeptime = sltime;
}
+ /* Change to the root directory. */
+ chdir("/");
+
/* Open the fifo and write a command. */
/* Make sure we don't hang on opening /dev/initctl */
SETSIG(sa, SIGALRM, signal_handler, 0);
alarm(3);
- if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 &&
- write(fd, &request, sizeof(request)) == sizeof(request)) {
+ if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0) {
+ ssize_t p = 0;
+ size_t s = sizeof(request);
+ void *ptr = &request;
+
+ while (s > 0) {
+ p = write(fd, ptr, s);
+ if (p < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ break;
+ }
+ ptr += p;
+ s -= p;
+ }
close(fd);
alarm(0);
return 0;
char *p;
int f;
int isinit;
+#ifdef WITH_SELINUX
int enforce = 0;
+#endif
/* Get my own name */
if ((p = strrchr(argv[0], '/')) != NULL)
p++;
else
p = argv[0];
- umask(022);
+
+ /* Common umask */
+ umask(umask(077) | 022);
/* Quick check */
if (geteuid() != 0) {
for (f = 0; f < argc; f++)
maxproclen += strlen(argv[f]) + 1;
reload = 1;
- setproctitle("init [%c]",runlevel);
+ setproctitle("init [%c]", (int)runlevel);
init_main();
}
}
#ifdef WITH_SELINUX
- if (getenv("SELINUX_INIT") == NULL && !is_selinux_enabled()) {
- putenv("SELINUX_INIT=YES");
- if (selinux_init_load_policy(&enforce) == 0 ) {
- execv(myname, argv);
- } else {
- if (enforce > 0) {
- /* SELinux in enforcing mode but load_policy failed */
- /* At this point, we probably can't open /dev/console, so log() won't work */
- fprintf(stderr,"Unable to load SELinux Policy. Machine is in enforcing mode. Halting now.\n");
- exit(1);
+ if (getenv("SELINUX_INIT") == NULL) {
+ if (is_selinux_enabled() != 1) {
+ if (selinux_init_load_policy(&enforce) == 0) {
+ putenv("SELINUX_INIT=YES");
+ execv(myname, argv);
+ } else {
+ if (enforce > 0) {
+ /* SELinux in enforcing mode but load_policy failed */
+ /* At this point, we probably can't open /dev/console, so log() won't work */
+ fprintf(stderr,"Unable to load SELinux Policy. Machine is in enforcing mode. Halting now.\n");
+ exit(1);
+ }
}
}
}
argv0 = argv[0];
argv[1] = NULL;
setproctitle("init boot");
- init_main(dfl_level);
+ init_main();
/*NOTREACHED*/
return 0;