aboutsummaryrefslogtreecommitdiff
path: root/init/init.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-01-31 18:55:54 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-01-31 18:55:54 +0000
commit4ae8a05b131836184eb32c440a6bf814ff81b069 (patch)
treef64538f2ec02df64b8cf37016df31113684858bb /init/init.c
parente35af567900ec2a7abb17e09cc5b5641f7faafe7 (diff)
downloadbusybox-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.c172
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
98static 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)
105static void message(int where, const char *fmt, ...) 103static void message(int where, const char *fmt, ...)
106 __attribute__ ((format(printf, 2, 3))); 104 __attribute__ ((format(printf, 2, 3)));
107static void message(int where, const char *fmt, ...) 105static 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! */
264static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) 265static 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
425static 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
440static struct init_action *mark_terminated(int pid) 421static 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
606static void low_level_reboot(unsigned magic) NORETURN; 595static void pause_and_low_level_reboot(unsigned magic) NORETURN;
607static void low_level_reboot(unsigned magic) 596static 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
627static void kill_all_processes(void) 615static 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
672static void halt_reboot_pwoff(int sig) NORETURN;
687static void halt_reboot_pwoff(int sig) 673static 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
765static void reload_inittab(void) 761static 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 */