mirror of
https://github.com/sheumann/hush.git
synced 2024-12-21 23:29:34 +00:00
init: fix a bug where on reload order of entries might be wrong
function old new delta run_shutdown_and_kill_processes - 97 +97 pause_and_low_level_reboot - 48 +48 run_actions 81 107 +26 restart_handler 56 81 +25 new_init_action 137 150 +13 run 576 579 +3 open_stdio_to_tty 110 98 -12 check_delayed_sigs 195 170 -25 waitfor 354 318 -36 low_level_reboot 53 - -53 kill_all_processes 115 - -115 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 4/3 up/down: 212/-241) Total: -29 bytes
This commit is contained in:
parent
e35af56790
commit
4ae8a05b13
172
init/init.c
172
init/init.c
@ -95,18 +95,15 @@ enum {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void halt_reboot_pwoff(int sig) NORETURN;
|
|
||||||
|
|
||||||
/* Print a message to the specified device.
|
/* Print a message to the specified device.
|
||||||
* "where" may be bitwise-or'd from L_LOG | L_CONSOLE
|
* "where" may be bitwise-or'd from L_LOG | L_CONSOLE
|
||||||
* NB: careful, we can be called after vfork!
|
* NB: careful, we can be called after vfork!
|
||||||
*/
|
*/
|
||||||
#define messageD(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0)
|
#define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0)
|
||||||
static void message(int where, const char *fmt, ...)
|
static void message(int where, const char *fmt, ...)
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
static void message(int where, const char *fmt, ...)
|
static void message(int where, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
static int log_fd = -1;
|
|
||||||
va_list arguments;
|
va_list arguments;
|
||||||
unsigned l;
|
unsigned l;
|
||||||
char msg[128];
|
char msg[128];
|
||||||
@ -116,20 +113,23 @@ static void message(int where, const char *fmt, ...)
|
|||||||
l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
|
l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
|
||||||
if (l > sizeof(msg) - 1)
|
if (l > sizeof(msg) - 1)
|
||||||
l = sizeof(msg) - 1;
|
l = sizeof(msg) - 1;
|
||||||
msg[l] = '\0';
|
|
||||||
va_end(arguments);
|
va_end(arguments);
|
||||||
|
|
||||||
if (ENABLE_FEATURE_INIT_SYSLOG) {
|
#if ENABLE_FEATURE_INIT_SYSLOG
|
||||||
if (where & L_LOG) {
|
msg[l] = '\0';
|
||||||
/* Log the message to syslogd */
|
if (where & L_LOG) {
|
||||||
openlog("init", 0, LOG_DAEMON);
|
/* Log the message to syslogd */
|
||||||
/* don't print "\r" */
|
openlog("init", 0, LOG_DAEMON);
|
||||||
syslog(LOG_INFO, "%s", msg + 1);
|
/* don't print "\r" */
|
||||||
closelog();
|
syslog(LOG_INFO, "%s", msg + 1);
|
||||||
}
|
closelog();
|
||||||
msg[l++] = '\n';
|
}
|
||||||
msg[l] = '\0';
|
msg[l++] = '\n';
|
||||||
} else {
|
msg[l] = '\0';
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
static int log_fd = -1;
|
||||||
|
|
||||||
msg[l++] = '\n';
|
msg[l++] = '\n';
|
||||||
msg[l] = '\0';
|
msg[l] = '\0';
|
||||||
/* Take full control of the log tty, and never close it.
|
/* Take full control of the log tty, and never close it.
|
||||||
@ -153,6 +153,7 @@ static void message(int where, const char *fmt, ...)
|
|||||||
return; /* don't print dup messages */
|
return; /* don't print dup messages */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (where & L_CONSOLE) {
|
if (where & L_CONSOLE) {
|
||||||
/* Send console messages to console so people will see them. */
|
/* Send console messages to console so people will see them. */
|
||||||
@ -199,7 +200,7 @@ static void console_init(void)
|
|||||||
dup2(fd, STDOUT_FILENO);
|
dup2(fd, STDOUT_FILENO);
|
||||||
xmove_fd(fd, STDERR_FILENO);
|
xmove_fd(fd, STDERR_FILENO);
|
||||||
}
|
}
|
||||||
messageD(L_LOG, "console='%s'", s);
|
dbg_message(L_LOG, "console='%s'", s);
|
||||||
} else {
|
} else {
|
||||||
/* Make sure fd 0,1,2 are not closed
|
/* Make sure fd 0,1,2 are not closed
|
||||||
* (so that they won't be used by future opens) */
|
* (so that they won't be used by future opens) */
|
||||||
@ -261,7 +262,7 @@ static void set_sane_term(void)
|
|||||||
|
|
||||||
/* Open the new terminal device.
|
/* Open the new terminal device.
|
||||||
* NB: careful, we can be called after vfork! */
|
* NB: careful, we can be called after vfork! */
|
||||||
static void open_stdio_to_tty(const char* tty_name, int exit_on_failure)
|
static int open_stdio_to_tty(const char* tty_name)
|
||||||
{
|
{
|
||||||
/* empty tty_name means "use init's tty", else... */
|
/* empty tty_name means "use init's tty", else... */
|
||||||
if (tty_name[0]) {
|
if (tty_name[0]) {
|
||||||
@ -273,19 +274,13 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure)
|
|||||||
if (fd) {
|
if (fd) {
|
||||||
message(L_LOG | L_CONSOLE, "can't open %s: %s",
|
message(L_LOG | L_CONSOLE, "can't open %s: %s",
|
||||||
tty_name, strerror(errno));
|
tty_name, strerror(errno));
|
||||||
if (exit_on_failure)
|
return 0; /* failure */
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
if (DEBUG_INIT)
|
|
||||||
_exit(2);
|
|
||||||
/* NB: we don't reach this if we were called after vfork.
|
|
||||||
* Thus halt_reboot_pwoff() itself needs not be vfork-safe.
|
|
||||||
*/
|
|
||||||
halt_reboot_pwoff(SIGUSR1); /* halt the system */
|
|
||||||
}
|
}
|
||||||
dup2(STDIN_FILENO, STDOUT_FILENO);
|
dup2(STDIN_FILENO, STDOUT_FILENO);
|
||||||
dup2(STDIN_FILENO, STDERR_FILENO);
|
dup2(STDIN_FILENO, STDERR_FILENO);
|
||||||
}
|
}
|
||||||
set_sane_term();
|
set_sane_term();
|
||||||
|
return 1; /* success */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wrapper around exec:
|
/* Wrapper around exec:
|
||||||
@ -369,7 +364,8 @@ static pid_t run(const struct init_action *a)
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
/* Open the new terminal device */
|
/* Open the new terminal device */
|
||||||
open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */);
|
if (!open_stdio_to_tty(a->terminal))
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
|
||||||
/* NB: on NOMMU we can't wait for input in child, so
|
/* NB: on NOMMU we can't wait for input in child, so
|
||||||
* "askfirst" will work the same as "respawn". */
|
* "askfirst" will work the same as "respawn". */
|
||||||
@ -388,7 +384,7 @@ static pid_t run(const struct init_action *a)
|
|||||||
* be allowed to start a shell or whatever an init script
|
* be allowed to start a shell or whatever an init script
|
||||||
* specifies.
|
* specifies.
|
||||||
*/
|
*/
|
||||||
messageD(L_LOG, "waiting for enter to start '%s'"
|
dbg_message(L_LOG, "waiting for enter to start '%s'"
|
||||||
"(pid %d, tty '%s')\n",
|
"(pid %d, tty '%s')\n",
|
||||||
a->command, getpid(), a->terminal);
|
a->command, getpid(), a->terminal);
|
||||||
full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
|
full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
|
||||||
@ -422,21 +418,6 @@ static pid_t run(const struct init_action *a)
|
|||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_init_action(struct init_action *action)
|
|
||||||
{
|
|
||||||
struct init_action *a, **nextp;
|
|
||||||
|
|
||||||
nextp = &init_action_list;
|
|
||||||
while ((a = *nextp) != NULL) {
|
|
||||||
if (a == action) {
|
|
||||||
*nextp = a->next;
|
|
||||||
free(a);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nextp = &a->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct init_action *mark_terminated(int pid)
|
static struct init_action *mark_terminated(int pid)
|
||||||
{
|
{
|
||||||
struct init_action *a;
|
struct init_action *a;
|
||||||
@ -497,36 +478,44 @@ static void new_init_action(uint8_t action_type, const char *command, const char
|
|||||||
{
|
{
|
||||||
struct init_action *a, **nextp;
|
struct init_action *a, **nextp;
|
||||||
|
|
||||||
//BUG
|
/* Scenario:
|
||||||
//old:
|
* old inittab:
|
||||||
//::shutdown:umount -a -r
|
* ::shutdown:umount -a -r
|
||||||
//::shutdown:swapoff -a
|
* ::shutdown:swapoff -a
|
||||||
//new: swapped:
|
* new inittab:
|
||||||
//::shutdown:swapoff -a
|
* ::shutdown:swapoff -a
|
||||||
//::shutdown:umount -a -r
|
* ::shutdown:umount -a -r
|
||||||
//on SIGHUP, new one will be loaded, but order will be wrong.
|
* On reload, we must ensure entries end up in correct order.
|
||||||
|
* To achieve that, if we find a matching entry, we move it
|
||||||
|
* to the end.
|
||||||
|
*/
|
||||||
nextp = &init_action_list;
|
nextp = &init_action_list;
|
||||||
while ((a = *nextp) != NULL) {
|
while ((a = *nextp) != NULL) {
|
||||||
/* Don't enter action if it's already in the list,
|
/* Don't enter action if it's already in the list,
|
||||||
* just overwrite existing one's type.
|
|
||||||
* This prevents losing running RESPAWNs.
|
* This prevents losing running RESPAWNs.
|
||||||
*/
|
*/
|
||||||
if ((strcmp(a->command, command) == 0)
|
if ((strcmp(a->command, command) == 0)
|
||||||
&& (strcmp(a->terminal, cons) == 0)
|
&& (strcmp(a->terminal, cons) == 0)
|
||||||
) {
|
) {
|
||||||
a->action_type = action_type;
|
/* Remove from list */
|
||||||
return;
|
*nextp = a->next;
|
||||||
|
/* Find the end of the list */
|
||||||
|
while (*nextp != NULL)
|
||||||
|
nextp = &(*nextp)->next;
|
||||||
|
a->next = NULL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
nextp = &a->next;
|
nextp = &a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!a)
|
||||||
|
a = xzalloc(sizeof(*a));
|
||||||
/* Append to the end of the list */
|
/* Append to the end of the list */
|
||||||
a = xzalloc(sizeof(*a));
|
|
||||||
*nextp = a;
|
*nextp = a;
|
||||||
a->action_type = action_type;
|
a->action_type = action_type;
|
||||||
safe_strncpy(a->command, command, sizeof(a->command));
|
safe_strncpy(a->command, command, sizeof(a->command));
|
||||||
safe_strncpy(a->terminal, cons, sizeof(a->terminal));
|
safe_strncpy(a->terminal, cons, sizeof(a->terminal));
|
||||||
messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
|
dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
|
||||||
a->command, a->action_type, a->terminal);
|
a->command, a->action_type, a->terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,8 +592,8 @@ static void parse_inittab(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void low_level_reboot(unsigned magic) NORETURN;
|
static void pause_and_low_level_reboot(unsigned magic) NORETURN;
|
||||||
static void low_level_reboot(unsigned magic)
|
static void pause_and_low_level_reboot(unsigned magic)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
@ -619,12 +608,11 @@ static void low_level_reboot(unsigned magic)
|
|||||||
reboot(magic);
|
reboot(magic);
|
||||||
_exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
waitfor(pid);
|
|
||||||
while (1)
|
while (1)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_all_processes(void)
|
static void run_shutdown_and_kill_processes(void)
|
||||||
{
|
{
|
||||||
/* Run everything to be run at "shutdown". This is done _prior_
|
/* Run everything to be run at "shutdown". This is done _prior_
|
||||||
* to killing everything, in case people wish to use scripts to
|
* to killing everything, in case people wish to use scripts to
|
||||||
@ -633,19 +621,16 @@ static void kill_all_processes(void)
|
|||||||
|
|
||||||
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
|
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
|
||||||
|
|
||||||
/* Allow Ctrl-Alt-Del to reboot system. */
|
|
||||||
reboot(RB_ENABLE_CAD); /* misnomer */
|
|
||||||
|
|
||||||
/* Send signals to every process _except_ pid 1 */
|
/* Send signals to every process _except_ pid 1 */
|
||||||
message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");
|
|
||||||
kill(-1, SIGTERM);
|
kill(-1, SIGTERM);
|
||||||
|
message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
|
||||||
sync();
|
sync();
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
||||||
message(L_CONSOLE, "Sending SIG%s to all processes", "KILL");
|
|
||||||
kill(-1, SIGKILL);
|
kill(-1, SIGKILL);
|
||||||
|
message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
|
||||||
sync();
|
sync();
|
||||||
sleep(1);
|
/*sleep(1); - callers take care about making a pause */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signal handling by init:
|
/* Signal handling by init:
|
||||||
@ -684,12 +669,13 @@ static void kill_all_processes(void)
|
|||||||
* and only one will be remebered and acted upon.
|
* and only one will be remebered and acted upon.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void halt_reboot_pwoff(int sig) NORETURN;
|
||||||
static void halt_reboot_pwoff(int sig)
|
static void halt_reboot_pwoff(int sig)
|
||||||
{
|
{
|
||||||
const char *m;
|
const char *m;
|
||||||
unsigned rb;
|
unsigned rb;
|
||||||
|
|
||||||
kill_all_processes();
|
run_shutdown_and_kill_processes();
|
||||||
|
|
||||||
m = "halt";
|
m = "halt";
|
||||||
rb = RB_HALT_SYSTEM;
|
rb = RB_HALT_SYSTEM;
|
||||||
@ -701,7 +687,7 @@ static void halt_reboot_pwoff(int sig)
|
|||||||
rb = RB_POWER_OFF;
|
rb = RB_POWER_OFF;
|
||||||
}
|
}
|
||||||
message(L_CONSOLE, "Requesting system %s", m);
|
message(L_CONSOLE, "Requesting system %s", m);
|
||||||
low_level_reboot(rb);
|
pause_and_low_level_reboot(rb);
|
||||||
/* not reached */
|
/* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,11 +738,21 @@ static void restart_handler(int sig UNUSED_PARAM)
|
|||||||
* Thus don't need to worry about preserving errno
|
* Thus don't need to worry about preserving errno
|
||||||
* and such.
|
* and such.
|
||||||
*/
|
*/
|
||||||
kill_all_processes();
|
run_shutdown_and_kill_processes();
|
||||||
open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */);
|
|
||||||
messageD(L_CONSOLE, "Trying to re-exec %s", a->command);
|
/* Allow Ctrl-Alt-Del to reboot the system.
|
||||||
init_exec(a->command);
|
* This is how kernel sets it up for init, we follow suit.
|
||||||
low_level_reboot(RB_HALT_SYSTEM);
|
*/
|
||||||
|
reboot(RB_ENABLE_CAD); /* misnomer */
|
||||||
|
|
||||||
|
if (open_stdio_to_tty(a->terminal)) {
|
||||||
|
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
|
||||||
|
while (wait(NULL) > 0)
|
||||||
|
continue;
|
||||||
|
init_exec(a->command);
|
||||||
|
}
|
||||||
|
/* Open or exec failed */
|
||||||
|
pause_and_low_level_reboot(RB_HALT_SYSTEM);
|
||||||
/* not reached */
|
/* not reached */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -764,40 +760,50 @@ static void restart_handler(int sig UNUSED_PARAM)
|
|||||||
#if ENABLE_FEATURE_USE_INITTAB
|
#if ENABLE_FEATURE_USE_INITTAB
|
||||||
static void reload_inittab(void)
|
static void reload_inittab(void)
|
||||||
{
|
{
|
||||||
struct init_action *a, *tmp;
|
struct init_action *a, **nextp;
|
||||||
|
|
||||||
message(L_LOG, "reloading /etc/inittab");
|
message(L_LOG, "reloading /etc/inittab");
|
||||||
|
|
||||||
/* Disable old entries */
|
/* Disable old entries */
|
||||||
for (a = init_action_list; a; a = a->next) {
|
for (a = init_action_list; a; a = a->next)
|
||||||
a->action_type = ONCE;
|
a->action_type = ONCE;
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Append new entries, or modify existing entries
|
||||||
|
* (set a->action_type) if cmd and device name
|
||||||
|
* match new ones. End result: only entries with
|
||||||
|
* a->action_type == ONCE are stale.
|
||||||
|
*/
|
||||||
parse_inittab();
|
parse_inittab();
|
||||||
|
|
||||||
if (ENABLE_FEATURE_KILL_REMOVED) {
|
if (ENABLE_FEATURE_KILL_REMOVED) {
|
||||||
|
/* Kill stale entries */
|
||||||
/* Be nice and send SIGTERM first */
|
/* Be nice and send SIGTERM first */
|
||||||
for (a = init_action_list; a; a = a->next)
|
for (a = init_action_list; a; a = a->next)
|
||||||
if (a->pid != 0)
|
if (a->action_type == ONCE && a->pid != 0)
|
||||||
kill(a->pid, SIGTERM);
|
kill(a->pid, SIGTERM);
|
||||||
if (CONFIG_FEATURE_KILL_DELAY) {
|
if (CONFIG_FEATURE_KILL_DELAY) {
|
||||||
/* NB: parent will wait in NOMMU case */
|
/* NB: parent will wait in NOMMU case */
|
||||||
if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
|
if ((BB_MMU ? fork() : vfork()) == 0) { /* child */
|
||||||
sleep(CONFIG_FEATURE_KILL_DELAY);
|
sleep(CONFIG_FEATURE_KILL_DELAY);
|
||||||
for (a = init_action_list; a; a = a->next)
|
for (a = init_action_list; a; a = a->next)
|
||||||
if (a->pid != 0)
|
if (a->action_type == ONCE && a->pid != 0)
|
||||||
kill(a->pid, SIGKILL);
|
kill(a->pid, SIGKILL);
|
||||||
_exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove old and unused entries */
|
/* Remove stale (ONCE) and not useful (SYSINIT,WAIT) entries */
|
||||||
for (a = init_action_list; a; a = tmp) {
|
nextp = &init_action_list;
|
||||||
tmp = a->next;
|
while ((a = *nextp) != NULL) {
|
||||||
if (a->action_type & (ONCE | SYSINIT | WAIT))
|
if (a->action_type & (ONCE | SYSINIT | WAIT)) {
|
||||||
delete_init_action(a);
|
*nextp = a->next;
|
||||||
|
free(a);
|
||||||
|
} else {
|
||||||
|
nextp = &a->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not needed: */
|
/* Not needed: */
|
||||||
/* run_actions(RESPAWN | ASKFIRST); */
|
/* run_actions(RESPAWN | ASKFIRST); */
|
||||||
/* - we return to main loop, which does this automagically */
|
/* - we return to main loop, which does this automagically */
|
||||||
|
Loading…
Reference in New Issue
Block a user