diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-31 18:55:54 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-31 18:55:54 +0000 |
commit | 4ae8a05b131836184eb32c440a6bf814ff81b069 (patch) | |
tree | f64538f2ec02df64b8cf37016df31113684858bb /init/init.c | |
parent | e35af567900ec2a7abb17e09cc5b5641f7faafe7 (diff) | |
download | busybox-w32-4ae8a05b131836184eb32c440a6bf814ff81b069.tar.gz busybox-w32-4ae8a05b131836184eb32c440a6bf814ff81b069.tar.bz2 busybox-w32-4ae8a05b131836184eb32c440a6bf814ff81b069.zip |
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
Diffstat (limited to 'init/init.c')
-rw-r--r-- | init/init.c | 172 |
1 files changed, 89 insertions, 83 deletions
diff --git a/init/init.c b/init/init.c index ed01e71c0..7ba8b67ec 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -95,18 +95,15 @@ enum { | |||
95 | #endif | 95 | #endif |
96 | }; | 96 | }; |
97 | 97 | ||
98 | static void halt_reboot_pwoff(int sig) NORETURN; | ||
99 | |||
100 | /* Print a message to the specified device. | 98 | /* Print a message to the specified device. |
101 | * "where" may be bitwise-or'd from L_LOG | L_CONSOLE | 99 | * "where" may be bitwise-or'd from L_LOG | L_CONSOLE |
102 | * NB: careful, we can be called after vfork! | 100 | * NB: careful, we can be called after vfork! |
103 | */ | 101 | */ |
104 | #define messageD(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0) | 102 | #define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0) |
105 | static void message(int where, const char *fmt, ...) | 103 | static void message(int where, const char *fmt, ...) |
106 | __attribute__ ((format(printf, 2, 3))); | 104 | __attribute__ ((format(printf, 2, 3))); |
107 | static void message(int where, const char *fmt, ...) | 105 | static void message(int where, const char *fmt, ...) |
108 | { | 106 | { |
109 | static int log_fd = -1; | ||
110 | va_list arguments; | 107 | va_list arguments; |
111 | unsigned l; | 108 | unsigned l; |
112 | char msg[128]; | 109 | char msg[128]; |
@@ -116,20 +113,23 @@ static void message(int where, const char *fmt, ...) | |||
116 | l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); | 113 | l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); |
117 | if (l > sizeof(msg) - 1) | 114 | if (l > sizeof(msg) - 1) |
118 | l = sizeof(msg) - 1; | 115 | l = sizeof(msg) - 1; |
119 | msg[l] = '\0'; | ||
120 | va_end(arguments); | 116 | va_end(arguments); |
121 | 117 | ||
122 | if (ENABLE_FEATURE_INIT_SYSLOG) { | 118 | #if ENABLE_FEATURE_INIT_SYSLOG |
123 | if (where & L_LOG) { | 119 | msg[l] = '\0'; |
124 | /* Log the message to syslogd */ | 120 | if (where & L_LOG) { |
125 | openlog("init", 0, LOG_DAEMON); | 121 | /* Log the message to syslogd */ |
126 | /* don't print "\r" */ | 122 | openlog("init", 0, LOG_DAEMON); |
127 | syslog(LOG_INFO, "%s", msg + 1); | 123 | /* don't print "\r" */ |
128 | closelog(); | 124 | syslog(LOG_INFO, "%s", msg + 1); |
129 | } | 125 | closelog(); |
130 | msg[l++] = '\n'; | 126 | } |
131 | msg[l] = '\0'; | 127 | msg[l++] = '\n'; |
132 | } else { | 128 | msg[l] = '\0'; |
129 | #else | ||
130 | { | ||
131 | static int log_fd = -1; | ||
132 | |||
133 | msg[l++] = '\n'; | 133 | msg[l++] = '\n'; |
134 | msg[l] = '\0'; | 134 | msg[l] = '\0'; |
135 | /* Take full control of the log tty, and never close it. | 135 | /* Take full control of the log tty, and never close it. |
@@ -153,6 +153,7 @@ static void message(int where, const char *fmt, ...) | |||
153 | return; /* don't print dup messages */ | 153 | return; /* don't print dup messages */ |
154 | } | 154 | } |
155 | } | 155 | } |
156 | #endif | ||
156 | 157 | ||
157 | if (where & L_CONSOLE) { | 158 | if (where & L_CONSOLE) { |
158 | /* Send console messages to console so people will see them. */ | 159 | /* Send console messages to console so people will see them. */ |
@@ -199,7 +200,7 @@ static void console_init(void) | |||
199 | dup2(fd, STDOUT_FILENO); | 200 | dup2(fd, STDOUT_FILENO); |
200 | xmove_fd(fd, STDERR_FILENO); | 201 | xmove_fd(fd, STDERR_FILENO); |
201 | } | 202 | } |
202 | messageD(L_LOG, "console='%s'", s); | 203 | dbg_message(L_LOG, "console='%s'", s); |
203 | } else { | 204 | } else { |
204 | /* Make sure fd 0,1,2 are not closed | 205 | /* Make sure fd 0,1,2 are not closed |
205 | * (so that they won't be used by future opens) */ | 206 | * (so that they won't be used by future opens) */ |
@@ -261,7 +262,7 @@ static void set_sane_term(void) | |||
261 | 262 | ||
262 | /* Open the new terminal device. | 263 | /* Open the new terminal device. |
263 | * NB: careful, we can be called after vfork! */ | 264 | * NB: careful, we can be called after vfork! */ |
264 | static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | 265 | static int open_stdio_to_tty(const char* tty_name) |
265 | { | 266 | { |
266 | /* empty tty_name means "use init's tty", else... */ | 267 | /* empty tty_name means "use init's tty", else... */ |
267 | if (tty_name[0]) { | 268 | if (tty_name[0]) { |
@@ -273,19 +274,13 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | |||
273 | if (fd) { | 274 | if (fd) { |
274 | message(L_LOG | L_CONSOLE, "can't open %s: %s", | 275 | message(L_LOG | L_CONSOLE, "can't open %s: %s", |
275 | tty_name, strerror(errno)); | 276 | tty_name, strerror(errno)); |
276 | if (exit_on_failure) | 277 | return 0; /* failure */ |
277 | _exit(EXIT_FAILURE); | ||
278 | if (DEBUG_INIT) | ||
279 | _exit(2); | ||
280 | /* NB: we don't reach this if we were called after vfork. | ||
281 | * Thus halt_reboot_pwoff() itself needs not be vfork-safe. | ||
282 | */ | ||
283 | halt_reboot_pwoff(SIGUSR1); /* halt the system */ | ||
284 | } | 278 | } |
285 | dup2(STDIN_FILENO, STDOUT_FILENO); | 279 | dup2(STDIN_FILENO, STDOUT_FILENO); |
286 | dup2(STDIN_FILENO, STDERR_FILENO); | 280 | dup2(STDIN_FILENO, STDERR_FILENO); |
287 | } | 281 | } |
288 | set_sane_term(); | 282 | set_sane_term(); |
283 | return 1; /* success */ | ||
289 | } | 284 | } |
290 | 285 | ||
291 | /* Wrapper around exec: | 286 | /* Wrapper around exec: |
@@ -369,7 +364,8 @@ static pid_t run(const struct init_action *a) | |||
369 | setsid(); | 364 | setsid(); |
370 | 365 | ||
371 | /* Open the new terminal device */ | 366 | /* Open the new terminal device */ |
372 | open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */); | 367 | if (!open_stdio_to_tty(a->terminal)) |
368 | _exit(EXIT_FAILURE); | ||
373 | 369 | ||
374 | /* NB: on NOMMU we can't wait for input in child, so | 370 | /* NB: on NOMMU we can't wait for input in child, so |
375 | * "askfirst" will work the same as "respawn". */ | 371 | * "askfirst" will work the same as "respawn". */ |
@@ -388,7 +384,7 @@ static pid_t run(const struct init_action *a) | |||
388 | * be allowed to start a shell or whatever an init script | 384 | * be allowed to start a shell or whatever an init script |
389 | * specifies. | 385 | * specifies. |
390 | */ | 386 | */ |
391 | messageD(L_LOG, "waiting for enter to start '%s'" | 387 | dbg_message(L_LOG, "waiting for enter to start '%s'" |
392 | "(pid %d, tty '%s')\n", | 388 | "(pid %d, tty '%s')\n", |
393 | a->command, getpid(), a->terminal); | 389 | a->command, getpid(), a->terminal); |
394 | full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1); | 390 | full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1); |
@@ -422,21 +418,6 @@ static pid_t run(const struct init_action *a) | |||
422 | _exit(-1); | 418 | _exit(-1); |
423 | } | 419 | } |
424 | 420 | ||
425 | static void delete_init_action(struct init_action *action) | ||
426 | { | ||
427 | struct init_action *a, **nextp; | ||
428 | |||
429 | nextp = &init_action_list; | ||
430 | while ((a = *nextp) != NULL) { | ||
431 | if (a == action) { | ||
432 | *nextp = a->next; | ||
433 | free(a); | ||
434 | break; | ||
435 | } | ||
436 | nextp = &a->next; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | static struct init_action *mark_terminated(int pid) | 421 | static struct init_action *mark_terminated(int pid) |
441 | { | 422 | { |
442 | struct init_action *a; | 423 | struct init_action *a; |
@@ -497,36 +478,44 @@ static void new_init_action(uint8_t action_type, const char *command, const char | |||
497 | { | 478 | { |
498 | struct init_action *a, **nextp; | 479 | struct init_action *a, **nextp; |
499 | 480 | ||
500 | //BUG | 481 | /* Scenario: |
501 | //old: | 482 | * old inittab: |
502 | //::shutdown:umount -a -r | 483 | * ::shutdown:umount -a -r |
503 | //::shutdown:swapoff -a | 484 | * ::shutdown:swapoff -a |
504 | //new: swapped: | 485 | * new inittab: |
505 | //::shutdown:swapoff -a | 486 | * ::shutdown:swapoff -a |
506 | //::shutdown:umount -a -r | 487 | * ::shutdown:umount -a -r |
507 | //on SIGHUP, new one will be loaded, but order will be wrong. | 488 | * On reload, we must ensure entries end up in correct order. |
489 | * To achieve that, if we find a matching entry, we move it | ||
490 | * to the end. | ||
491 | */ | ||
508 | nextp = &init_action_list; | 492 | nextp = &init_action_list; |
509 | while ((a = *nextp) != NULL) { | 493 | while ((a = *nextp) != NULL) { |
510 | /* Don't enter action if it's already in the list, | 494 | /* Don't enter action if it's already in the list, |
511 | * just overwrite existing one's type. | ||
512 | * This prevents losing running RESPAWNs. | 495 | * This prevents losing running RESPAWNs. |
513 | */ | 496 | */ |
514 | if ((strcmp(a->command, command) == 0) | 497 | if ((strcmp(a->command, command) == 0) |
515 | && (strcmp(a->terminal, cons) == 0) | 498 | && (strcmp(a->terminal, cons) == 0) |
516 | ) { | 499 | ) { |
517 | a->action_type = action_type; | 500 | /* Remove from list */ |
518 | return; | 501 | *nextp = a->next; |
502 | /* Find the end of the list */ | ||
503 | while (*nextp != NULL) | ||
504 | nextp = &(*nextp)->next; | ||
505 | a->next = NULL; | ||
506 | break; | ||
519 | } | 507 | } |
520 | nextp = &a->next; | 508 | nextp = &a->next; |
521 | } | 509 | } |
522 | 510 | ||
511 | if (!a) | ||
512 | a = xzalloc(sizeof(*a)); | ||
523 | /* Append to the end of the list */ | 513 | /* Append to the end of the list */ |
524 | a = xzalloc(sizeof(*a)); | ||
525 | *nextp = a; | 514 | *nextp = a; |
526 | a->action_type = action_type; | 515 | a->action_type = action_type; |
527 | safe_strncpy(a->command, command, sizeof(a->command)); | 516 | safe_strncpy(a->command, command, sizeof(a->command)); |
528 | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); | 517 | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); |
529 | messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", | 518 | dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", |
530 | a->command, a->action_type, a->terminal); | 519 | a->command, a->action_type, a->terminal); |
531 | } | 520 | } |
532 | 521 | ||
@@ -603,8 +592,8 @@ static void parse_inittab(void) | |||
603 | #endif | 592 | #endif |
604 | } | 593 | } |
605 | 594 | ||
606 | static void low_level_reboot(unsigned magic) NORETURN; | 595 | static void pause_and_low_level_reboot(unsigned magic) NORETURN; |
607 | static void low_level_reboot(unsigned magic) | 596 | static void pause_and_low_level_reboot(unsigned magic) |
608 | { | 597 | { |
609 | pid_t pid; | 598 | pid_t pid; |
610 | 599 | ||
@@ -619,12 +608,11 @@ static void low_level_reboot(unsigned magic) | |||
619 | reboot(magic); | 608 | reboot(magic); |
620 | _exit(EXIT_SUCCESS); | 609 | _exit(EXIT_SUCCESS); |
621 | } | 610 | } |
622 | waitfor(pid); | ||
623 | while (1) | 611 | while (1) |
624 | sleep(1); | 612 | sleep(1); |
625 | } | 613 | } |
626 | 614 | ||
627 | static void kill_all_processes(void) | 615 | static void run_shutdown_and_kill_processes(void) |
628 | { | 616 | { |
629 | /* Run everything to be run at "shutdown". This is done _prior_ | 617 | /* Run everything to be run at "shutdown". This is done _prior_ |
630 | * to killing everything, in case people wish to use scripts to | 618 | * to killing everything, in case people wish to use scripts to |
@@ -633,19 +621,16 @@ static void kill_all_processes(void) | |||
633 | 621 | ||
634 | message(L_CONSOLE | L_LOG, "The system is going down NOW!"); | 622 | message(L_CONSOLE | L_LOG, "The system is going down NOW!"); |
635 | 623 | ||
636 | /* Allow Ctrl-Alt-Del to reboot system. */ | ||
637 | reboot(RB_ENABLE_CAD); /* misnomer */ | ||
638 | |||
639 | /* Send signals to every process _except_ pid 1 */ | 624 | /* Send signals to every process _except_ pid 1 */ |
640 | message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM"); | ||
641 | kill(-1, SIGTERM); | 625 | kill(-1, SIGTERM); |
626 | message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM"); | ||
642 | sync(); | 627 | sync(); |
643 | sleep(1); | 628 | sleep(1); |
644 | 629 | ||
645 | message(L_CONSOLE, "Sending SIG%s to all processes", "KILL"); | ||
646 | kill(-1, SIGKILL); | 630 | kill(-1, SIGKILL); |
631 | message(L_CONSOLE, "Sent SIG%s to all processes", "KILL"); | ||
647 | sync(); | 632 | sync(); |
648 | sleep(1); | 633 | /*sleep(1); - callers take care about making a pause */ |
649 | } | 634 | } |
650 | 635 | ||
651 | /* Signal handling by init: | 636 | /* Signal handling by init: |
@@ -684,12 +669,13 @@ static void kill_all_processes(void) | |||
684 | * and only one will be remebered and acted upon. | 669 | * and only one will be remebered and acted upon. |
685 | */ | 670 | */ |
686 | 671 | ||
672 | static void halt_reboot_pwoff(int sig) NORETURN; | ||
687 | static void halt_reboot_pwoff(int sig) | 673 | static void halt_reboot_pwoff(int sig) |
688 | { | 674 | { |
689 | const char *m; | 675 | const char *m; |
690 | unsigned rb; | 676 | unsigned rb; |
691 | 677 | ||
692 | kill_all_processes(); | 678 | run_shutdown_and_kill_processes(); |
693 | 679 | ||
694 | m = "halt"; | 680 | m = "halt"; |
695 | rb = RB_HALT_SYSTEM; | 681 | rb = RB_HALT_SYSTEM; |
@@ -701,7 +687,7 @@ static void halt_reboot_pwoff(int sig) | |||
701 | rb = RB_POWER_OFF; | 687 | rb = RB_POWER_OFF; |
702 | } | 688 | } |
703 | message(L_CONSOLE, "Requesting system %s", m); | 689 | message(L_CONSOLE, "Requesting system %s", m); |
704 | low_level_reboot(rb); | 690 | pause_and_low_level_reboot(rb); |
705 | /* not reached */ | 691 | /* not reached */ |
706 | } | 692 | } |
707 | 693 | ||
@@ -752,11 +738,21 @@ static void restart_handler(int sig UNUSED_PARAM) | |||
752 | * Thus don't need to worry about preserving errno | 738 | * Thus don't need to worry about preserving errno |
753 | * and such. | 739 | * and such. |
754 | */ | 740 | */ |
755 | kill_all_processes(); | 741 | run_shutdown_and_kill_processes(); |
756 | open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); | 742 | |
757 | messageD(L_CONSOLE, "Trying to re-exec %s", a->command); | 743 | /* Allow Ctrl-Alt-Del to reboot the system. |
758 | init_exec(a->command); | 744 | * This is how kernel sets it up for init, we follow suit. |
759 | low_level_reboot(RB_HALT_SYSTEM); | 745 | */ |
746 | reboot(RB_ENABLE_CAD); /* misnomer */ | ||
747 | |||
748 | if (open_stdio_to_tty(a->terminal)) { | ||
749 | dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); | ||
750 | while (wait(NULL) > 0) | ||
751 | continue; | ||
752 | init_exec(a->command); | ||
753 | } | ||
754 | /* Open or exec failed */ | ||
755 | pause_and_low_level_reboot(RB_HALT_SYSTEM); | ||
760 | /* not reached */ | 756 | /* not reached */ |
761 | } | 757 | } |
762 | } | 758 | } |
@@ -764,40 +760,50 @@ static void restart_handler(int sig UNUSED_PARAM) | |||
764 | #if ENABLE_FEATURE_USE_INITTAB | 760 | #if ENABLE_FEATURE_USE_INITTAB |
765 | static void reload_inittab(void) | 761 | static void reload_inittab(void) |
766 | { | 762 | { |
767 | struct init_action *a, *tmp; | 763 | struct init_action *a, **nextp; |
768 | 764 | ||
769 | message(L_LOG, "reloading /etc/inittab"); | 765 | message(L_LOG, "reloading /etc/inittab"); |
770 | 766 | ||
771 | /* Disable old entries */ | 767 | /* Disable old entries */ |
772 | for (a = init_action_list; a; a = a->next) { | 768 | for (a = init_action_list; a; a = a->next) |
773 | a->action_type = ONCE; | 769 | a->action_type = ONCE; |
774 | } | ||
775 | 770 | ||
771 | /* Append new entries, or modify existing entries | ||
772 | * (set a->action_type) if cmd and device name | ||
773 | * match new ones. End result: only entries with | ||
774 | * a->action_type == ONCE are stale. | ||
775 | */ | ||
776 | parse_inittab(); | 776 | parse_inittab(); |
777 | 777 | ||
778 | if (ENABLE_FEATURE_KILL_REMOVED) { | 778 | if (ENABLE_FEATURE_KILL_REMOVED) { |
779 | /* Kill stale entries */ | ||
779 | /* Be nice and send SIGTERM first */ | 780 | /* Be nice and send SIGTERM first */ |
780 | for (a = init_action_list; a; a = a->next) | 781 | for (a = init_action_list; a; a = a->next) |
781 | if (a->pid != 0) | 782 | if (a->action_type == ONCE && a->pid != 0) |
782 | kill(a->pid, SIGTERM); | 783 | kill(a->pid, SIGTERM); |
783 | if (CONFIG_FEATURE_KILL_DELAY) { | 784 | if (CONFIG_FEATURE_KILL_DELAY) { |
784 | /* NB: parent will wait in NOMMU case */ | 785 | /* NB: parent will wait in NOMMU case */ |
785 | if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ | 786 | if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ |
786 | sleep(CONFIG_FEATURE_KILL_DELAY); | 787 | sleep(CONFIG_FEATURE_KILL_DELAY); |
787 | for (a = init_action_list; a; a = a->next) | 788 | for (a = init_action_list; a; a = a->next) |
788 | if (a->pid != 0) | 789 | if (a->action_type == ONCE && a->pid != 0) |
789 | kill(a->pid, SIGKILL); | 790 | kill(a->pid, SIGKILL); |
790 | _exit(EXIT_SUCCESS); | 791 | _exit(EXIT_SUCCESS); |
791 | } | 792 | } |
792 | } | 793 | } |
793 | } | 794 | } |
794 | 795 | ||
795 | /* Remove old and unused entries */ | 796 | /* Remove stale (ONCE) and not useful (SYSINIT,WAIT) entries */ |
796 | for (a = init_action_list; a; a = tmp) { | 797 | nextp = &init_action_list; |
797 | tmp = a->next; | 798 | while ((a = *nextp) != NULL) { |
798 | if (a->action_type & (ONCE | SYSINIT | WAIT)) | 799 | if (a->action_type & (ONCE | SYSINIT | WAIT)) { |
799 | delete_init_action(a); | 800 | *nextp = a->next; |
801 | free(a); | ||
802 | } else { | ||
803 | nextp = &a->next; | ||
804 | } | ||
800 | } | 805 | } |
806 | |||
801 | /* Not needed: */ | 807 | /* Not needed: */ |
802 | /* run_actions(RESPAWN | ASKFIRST); */ | 808 | /* run_actions(RESPAWN | ASKFIRST); */ |
803 | /* - we return to main loop, which does this automagically */ | 809 | /* - we return to main loop, which does this automagically */ |