#include <paths.h>
#include <sys/reboot.h>
#include <sys/resource.h>
+#include <linux/vt.h>
/* Was a CONFIG_xxx option. A lot of people were building
}
}
-/* From <linux/serial.h> */
-struct serial_struct {
- int type;
- int line;
- unsigned int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char io_type;
- char reserved_char[1];
- int hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- unsigned char *iomem_base;
- unsigned short iomem_reg_shift;
- unsigned int port_high;
- unsigned long iomap_base; /* cookie passed into ioremap */
- int reserved[1];
- /* Paranoia (imagine 64bit kernel overwriting 32bit userspace stack) */
- uint32_t bbox_reserved[16];
-};
static void console_init(void)
{
- struct serial_struct sr;
+ int vtno;
char *s;
s = getenv("CONSOLE");
}
s = getenv("TERM");
- if (ioctl(STDIN_FILENO, TIOCGSERIAL, &sr) == 0) {
- /* Force the TERM setting to vt102 for serial console
+ if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) {
+ /* Not a linux terminal, probably serial console.
+ * Force the TERM setting to vt102
* if TERM is set to linux (the default) */
if (!s || strcmp(s, "linux") == 0)
putenv((char*)"TERM=vt102");
{
pid_t pid;
+ /* Careful: don't be affected by a signal in vforked child */
+ sigprocmask_allsigs(SIG_BLOCK);
if (BB_MMU && (a->action_type & ASKFIRST))
pid = fork();
else
pid = vfork();
if (pid < 0)
message(L_LOG | L_CONSOLE, "can't fork");
- if (pid)
+ if (pid) {
+ sigprocmask_allsigs(SIG_UNBLOCK);
return pid; /* Parent or error */
+ }
/* Child */
/* Reset signal handlers that were set by the parent process */
-//TODO: block signals across fork(), prevent them to affect child before
-//signals are reset?
bb_signals(0
+ (1 << SIGUSR1)
+ (1 << SIGUSR2)
+ (1 << SIGHUP)
+ (1 << SIGTSTP)
, SIG_DFL);
+ sigprocmask_allsigs(SIG_UNBLOCK);
/* Create a new session and make ourself the process group leader */
setsid();
* it to happen even somewhere inside "sysinit" would be a bit awkward.
*
* There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide
- * and only one will be remebered and acted upon.
+ * and only one will be remembered and acted upon.
*/
static void halt_reboot_pwoff(int sig) NORETURN;
*/
parse_inittab();
- if (ENABLE_FEATURE_KILL_REMOVED) {
- /* Kill stale entries */
- /* Be nice and send SIGTERM first */
- for (a = init_action_list; a; a = a->next)
- if (a->action_type == ONCE && a->pid != 0)
- kill(a->pid, SIGTERM);
- if (CONFIG_FEATURE_KILL_DELAY) {
- /* NB: parent will wait in NOMMU case */
- if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
- sleep(CONFIG_FEATURE_KILL_DELAY);
- for (a = init_action_list; a; a = a->next)
- if (a->action_type == ONCE && a->pid != 0)
- kill(a->pid, SIGKILL);
- _exit(EXIT_SUCCESS);
- }
+#if ENABLE_FEATURE_KILL_REMOVED
+ /* Kill stale entries */
+ /* Be nice and send SIGTERM first */
+ for (a = init_action_list; a; a = a->next)
+ if (a->action_type == ONCE && a->pid != 0)
+ kill(a->pid, SIGTERM);
+ if (CONFIG_FEATURE_KILL_DELAY) {
+ /* NB: parent will wait in NOMMU case */
+ if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
+ sleep(CONFIG_FEATURE_KILL_DELAY);
+ for (a = init_action_list; a; a = a->next)
+ if (a->action_type == ONCE && a->pid != 0)
+ kill(a->pid, SIGKILL);
+ _exit(EXIT_SUCCESS);
}
}
+#endif
/* Remove stale (ONCE) and not useful (SYSINIT,WAIT) entries */
nextp = &init_action_list;
struct sysinfo info;
if (sysinfo(&info) == 0
- && (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024
+ && (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024
) {
message(L_CONSOLE, "Low memory, forcing swapon");
/* swapon -a requires /proc typically */
bb_signals_recursive_norestart((1 << SIGHUP), record_signo);
/* Now run the looping stuff for the rest of forever.
- * NB: if delayed signal happened, avoid blocking in wait().
*/
while (1) {
- pid_t wpid;
- int got_sigs;
+ int maybe_WNOHANG;
- got_sigs = check_delayed_sigs();
+ maybe_WNOHANG = check_delayed_sigs();
/* (Re)run the respawn/askfirst stuff */
run_actions(RESPAWN | ASKFIRST);
-
- got_sigs |= check_delayed_sigs();
+ maybe_WNOHANG |= check_delayed_sigs();
/* Don't consume all CPU time - sleep a bit */
sleep(1);
-
- got_sigs |= check_delayed_sigs();
-
- if (got_sigs)
- goto dont_block;
- /* Wait for any child process to exit.
- * NB: "delayed" signals will also interrupt this wait(),
- * bb_signals_recursive_norestart() set them up for that.
- * This guarantees we won't be stuck here
- * till next orphan dies.
+ maybe_WNOHANG |= check_delayed_sigs();
+
+ /* Wait for any child process(es) to exit.
+ *
+ * If check_delayed_sigs above reported that a signal
+ * was caught, wait will be nonblocking. This ensures
+ * that if SIGHUP has reloaded inittab, respawn and askfirst
+ * actions will not be delayed until next child death.
*/
- wpid = wait(NULL);
- while (wpid > 0) {
- struct init_action *a = mark_terminated(wpid);
+ if (maybe_WNOHANG)
+ maybe_WNOHANG = WNOHANG;
+ while (1) {
+ pid_t wpid;
+ struct init_action *a;
+
+ /* If signals happen _in_ the wait, they interrupt it,
+ * bb_signals_recursive_norestart set them up that way
+ */
+ wpid = waitpid(-1, NULL, maybe_WNOHANG);
+ if (wpid <= 0)
+ break;
+
+ a = mark_terminated(wpid);
if (a) {
message(L_LOG, "process '%s' (pid %d) exited. "
"Scheduling for restart.",
a->command, wpid);
}
/* See if anyone else is waiting to be reaped */
- dont_block:
- wpid = wait_any_nohang(NULL);
+ maybe_WNOHANG = WNOHANG;
}
} /* while (1) */
}