diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-31 01:03:45 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-31 01:03:45 +0000 |
commit | 72c99af0b44e150a712891f6a3ea7d41827cfffe (patch) | |
tree | efd1f29d140f906deca0e8816e6b50ff2e87a77f /init/init.c | |
parent | cab28aa7de336b0a39ef43ce0eb035a2cab30d4d (diff) | |
download | busybox-w32-72c99af0b44e150a712891f6a3ea7d41827cfffe.tar.gz busybox-w32-72c99af0b44e150a712891f6a3ea7d41827cfffe.tar.bz2 busybox-w32-72c99af0b44e150a712891f6a3ea7d41827cfffe.zip |
init: major improvement in documentation and signal handling.
Lots of nasty, but hard to trip, races are fixed.
text data bss dec hex filename
1038828 924 10932 1050684 10083c busybox_old
1038787 924 10932 1050643 100813 busybox_unstripped
Diffstat (limited to 'init/init.c')
-rw-r--r-- | init/init.c | 671 |
1 files changed, 374 insertions, 297 deletions
diff --git a/init/init.c b/init/init.c index 6af6830e4..3a02ece4b 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <sys/reboot.h> | 15 | #include <sys/reboot.h> |
16 | #include <sys/resource.h> | 16 | #include <sys/resource.h> |
17 | 17 | ||
18 | |||
18 | /* Was a CONFIG_xxx option. A lot of people were building | 19 | /* Was a CONFIG_xxx option. A lot of people were building |
19 | * not fully functional init by switching it on! */ | 20 | * not fully functional init by switching it on! */ |
20 | #define DEBUG_INIT 0 | 21 | #define DEBUG_INIT 0 |
@@ -22,22 +23,53 @@ | |||
22 | #define COMMAND_SIZE 256 | 23 | #define COMMAND_SIZE 256 |
23 | #define CONSOLE_NAME_SIZE 32 | 24 | #define CONSOLE_NAME_SIZE 32 |
24 | 25 | ||
26 | /* Default sysinit script. */ | ||
25 | #ifndef INIT_SCRIPT | 27 | #ifndef INIT_SCRIPT |
26 | #define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ | 28 | #define INIT_SCRIPT "/etc/init.d/rcS" |
27 | #endif | 29 | #endif |
28 | 30 | ||
29 | /* Allowed init action types */ | 31 | /* Each type of actions can appear many times. They will be |
32 | * handled in order. RESTART is an exception, only 1st is used. | ||
33 | */ | ||
34 | /* Start these actions first and wait for completion */ | ||
30 | #define SYSINIT 0x01 | 35 | #define SYSINIT 0x01 |
31 | #define RESPAWN 0x02 | 36 | /* Start these after SYSINIT and wait for completion */ |
32 | /* like respawn, but wait for <Enter> to be pressed on tty: */ | 37 | #define WAIT 0x02 |
33 | #define ASKFIRST 0x04 | 38 | /* Start these after WAIT and *dont* wait for completion */ |
34 | #define WAIT 0x08 | 39 | #define ONCE 0x04 |
35 | #define ONCE 0x10 | 40 | /* |
41 | * NB: while SYSINIT/WAIT/ONCE are being processed, | ||
42 | * SIGHUP ("reread /etc/inittab") will be ignored. | ||
43 | * Rationale: it would be ambiguous whether SYSINIT/WAIT/ONCE | ||
44 | * need to be rerun or not. | ||
45 | */ | ||
46 | /* Start these after ONCE are started, restart on exit */ | ||
47 | #define RESPAWN 0x08 | ||
48 | /* Like RESPAWN, but wait for <Enter> to be pressed on tty */ | ||
49 | #define ASKFIRST 0x10 | ||
50 | /* | ||
51 | * Start these on SIGINT, and wait for completion. | ||
52 | * Then go back to respawning RESPAWN and ASKFIRST actions. | ||
53 | * NB: kernel sends SIGINT to us if Ctrl-Alt-Del was pressed. | ||
54 | */ | ||
36 | #define CTRLALTDEL 0x20 | 55 | #define CTRLALTDEL 0x20 |
56 | /* | ||
57 | * Start these before killing all processes in preparation for | ||
58 | * running RESTART actions or doing low-level halt/reboot/poweroff | ||
59 | * (initiated by SIGUSR1/SIGTERM/SIGUSR2). | ||
60 | * Wait for completion before proceeding. | ||
61 | */ | ||
37 | #define SHUTDOWN 0x40 | 62 | #define SHUTDOWN 0x40 |
63 | /* | ||
64 | * exec() on SIGQUIT. SHUTDOWN actions are started and waited for, | ||
65 | * then all processes are killed, then init exec's 1st RESTART action, | ||
66 | * replacing itself by it. If no RESTART action specified, | ||
67 | * SIGQUIT has no effect. | ||
68 | */ | ||
38 | #define RESTART 0x80 | 69 | #define RESTART 0x80 |
39 | 70 | ||
40 | /* Set up a linked list of init_actions, to be read from inittab */ | 71 | |
72 | /* A linked list of init_actions, to be read from inittab */ | ||
41 | struct init_action { | 73 | struct init_action { |
42 | struct init_action *next; | 74 | struct init_action *next; |
43 | pid_t pid; | 75 | pid_t pid; |
@@ -65,13 +97,6 @@ enum { | |||
65 | 97 | ||
66 | static void halt_reboot_pwoff(int sig) NORETURN; | 98 | static void halt_reboot_pwoff(int sig) NORETURN; |
67 | 99 | ||
68 | static void loop_forever(void) NORETURN; | ||
69 | static void loop_forever(void) | ||
70 | { | ||
71 | while (1) | ||
72 | sleep(1); | ||
73 | } | ||
74 | |||
75 | /* Print a message to the specified device. | 100 | /* Print a message to the specified device. |
76 | * "where" may be bitwise-or'd from L_LOG | L_CONSOLE | 101 | * "where" may be bitwise-or'd from L_LOG | L_CONSOLE |
77 | * NB: careful, we can be called after vfork! | 102 | * NB: careful, we can be called after vfork! |
@@ -241,6 +266,7 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | |||
241 | /* empty tty_name means "use init's tty", else... */ | 266 | /* empty tty_name means "use init's tty", else... */ |
242 | if (tty_name[0]) { | 267 | if (tty_name[0]) { |
243 | int fd; | 268 | int fd; |
269 | |||
244 | close(STDIN_FILENO); | 270 | close(STDIN_FILENO); |
245 | /* fd can be only < 0 or 0: */ | 271 | /* fd can be only < 0 or 0: */ |
246 | fd = device_open(tty_name, O_RDWR); | 272 | fd = device_open(tty_name, O_RDWR); |
@@ -252,7 +278,8 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | |||
252 | if (DEBUG_INIT) | 278 | if (DEBUG_INIT) |
253 | _exit(2); | 279 | _exit(2); |
254 | /* NB: we don't reach this if we were called after vfork. | 280 | /* NB: we don't reach this if we were called after vfork. |
255 | * Thus halt_reboot_pwoff() itself need not be vfork-safe. */ | 281 | * Thus halt_reboot_pwoff() itself needs not be vfork-safe. |
282 | */ | ||
256 | halt_reboot_pwoff(SIGUSR1); /* halt the system */ | 283 | halt_reboot_pwoff(SIGUSR1); /* halt the system */ |
257 | } | 284 | } |
258 | dup2(STDIN_FILENO, STDOUT_FILENO); | 285 | dup2(STDIN_FILENO, STDOUT_FILENO); |
@@ -313,89 +340,37 @@ static void init_exec(const char *command) | |||
313 | static pid_t run(const struct init_action *a) | 340 | static pid_t run(const struct init_action *a) |
314 | { | 341 | { |
315 | pid_t pid; | 342 | pid_t pid; |
316 | sigset_t nmask, omask; | ||
317 | 343 | ||
318 | /* Block sigchild while forking (why?) */ | ||
319 | sigemptyset(&nmask); | ||
320 | sigaddset(&nmask, SIGCHLD); | ||
321 | sigprocmask(SIG_BLOCK, &nmask, &omask); | ||
322 | if (BB_MMU && (a->action_type & ASKFIRST)) | 344 | if (BB_MMU && (a->action_type & ASKFIRST)) |
323 | pid = fork(); | 345 | pid = fork(); |
324 | else | 346 | else |
325 | pid = vfork(); | 347 | pid = vfork(); |
326 | sigprocmask(SIG_SETMASK, &omask, NULL); | ||
327 | |||
328 | if (pid < 0) | 348 | if (pid < 0) |
329 | message(L_LOG | L_CONSOLE, "can't fork"); | 349 | message(L_LOG | L_CONSOLE, "can't fork"); |
330 | if (pid) | 350 | if (pid) |
331 | return pid; | 351 | return pid; /* Parent or error */ |
332 | 352 | ||
333 | /* Child */ | 353 | /* Child */ |
334 | 354 | ||
335 | /* Reset signal handlers that were set by the parent process */ | 355 | /* Reset signal handlers that were set by the parent process */ |
356 | //TODO: block signals across fork(), prevent them to affect child before | ||
357 | //signals are reset? | ||
336 | bb_signals(0 | 358 | bb_signals(0 |
337 | + (1 << SIGUSR1) | 359 | + (1 << SIGUSR1) |
338 | + (1 << SIGUSR2) | 360 | + (1 << SIGUSR2) |
339 | + (1 << SIGINT) | ||
340 | + (1 << SIGTERM) | 361 | + (1 << SIGTERM) |
341 | + (1 << SIGHUP) | ||
342 | + (1 << SIGQUIT) | 362 | + (1 << SIGQUIT) |
343 | + (1 << SIGCONT) | 363 | + (1 << SIGINT) |
344 | + (1 << SIGSTOP) | 364 | + (1 << SIGHUP) |
345 | + (1 << SIGTSTP) | 365 | + (1 << SIGTSTP) |
346 | , SIG_DFL); | 366 | , SIG_DFL); |
347 | 367 | ||
348 | /* Create a new session and make ourself the process | 368 | /* Create a new session and make ourself the process group leader */ |
349 | * group leader */ | ||
350 | setsid(); | 369 | setsid(); |
351 | 370 | ||
352 | /* Open the new terminal device */ | 371 | /* Open the new terminal device */ |
353 | open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */); | 372 | open_stdio_to_tty(a->terminal, 1 /* - exit if open fails */); |
354 | 373 | ||
355 | // NB: do not enable unless you change vfork to fork above | ||
356 | #ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING | ||
357 | /* If the init Action requires us to wait, then force the | ||
358 | * supplied terminal to be the controlling tty. */ | ||
359 | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { | ||
360 | /* Now fork off another process to just hang around */ | ||
361 | pid = fork(); | ||
362 | if (pid < 0) { | ||
363 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
364 | _exit(EXIT_FAILURE); | ||
365 | } | ||
366 | |||
367 | if (pid > 0) { | ||
368 | /* Parent - wait till the child is done */ | ||
369 | bb_signals(0 | ||
370 | + (1 << SIGINT) | ||
371 | + (1 << SIGTSTP) | ||
372 | + (1 << SIGQUIT) | ||
373 | , SIG_IGN); | ||
374 | signal(SIGCHLD, SIG_DFL); | ||
375 | |||
376 | waitfor(pid); | ||
377 | /* See if stealing the controlling tty back is necessary */ | ||
378 | if (tcgetpgrp(0) != getpid()) | ||
379 | _exit(EXIT_SUCCESS); | ||
380 | |||
381 | /* Use a temporary process to steal the controlling tty. */ | ||
382 | pid = fork(); | ||
383 | if (pid < 0) { | ||
384 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
385 | _exit(EXIT_FAILURE); | ||
386 | } | ||
387 | if (pid == 0) { | ||
388 | setsid(); | ||
389 | ioctl(0, TIOCSCTTY, 1); | ||
390 | _exit(EXIT_SUCCESS); | ||
391 | } | ||
392 | waitfor(pid); | ||
393 | _exit(EXIT_SUCCESS); | ||
394 | } | ||
395 | /* Child - fall though to actually execute things */ | ||
396 | } | ||
397 | #endif | ||
398 | |||
399 | /* NB: on NOMMU we can't wait for input in child, so | 374 | /* NB: on NOMMU we can't wait for input in child, so |
400 | * "askfirst" will work the same as "respawn". */ | 375 | * "askfirst" will work the same as "respawn". */ |
401 | if (BB_MMU && (a->action_type & ASKFIRST)) { | 376 | if (BB_MMU && (a->action_type & ASKFIRST)) { |
@@ -449,21 +424,32 @@ static pid_t run(const struct init_action *a) | |||
449 | 424 | ||
450 | static void delete_init_action(struct init_action *action) | 425 | static void delete_init_action(struct init_action *action) |
451 | { | 426 | { |
452 | struct init_action *a, *b = NULL; | 427 | struct init_action *a, **nextp; |
453 | 428 | ||
454 | for (a = init_action_list; a; b = a, a = a->next) { | 429 | nextp = &init_action_list; |
430 | while ((a = *nextp) != NULL) { | ||
455 | if (a == action) { | 431 | if (a == action) { |
456 | if (b == NULL) { | 432 | *nextp = a->next; |
457 | init_action_list = a->next; | ||
458 | } else { | ||
459 | b->next = a->next; | ||
460 | } | ||
461 | free(a); | 433 | free(a); |
462 | break; | 434 | break; |
463 | } | 435 | } |
436 | nextp = &a->next; | ||
464 | } | 437 | } |
465 | } | 438 | } |
466 | 439 | ||
440 | static struct init_action *mark_terminated(int pid) | ||
441 | { | ||
442 | struct init_action *a; | ||
443 | |||
444 | for (a = init_action_list; a; a = a->next) { | ||
445 | if (a->pid == pid) { | ||
446 | a->pid = 0; | ||
447 | return a; | ||
448 | } | ||
449 | } | ||
450 | return NULL; | ||
451 | } | ||
452 | |||
467 | static void waitfor(pid_t pid) | 453 | static void waitfor(pid_t pid) |
468 | { | 454 | { |
469 | /* waitfor(run(x)): protect against failed fork inside run() */ | 455 | /* waitfor(run(x)): protect against failed fork inside run() */ |
@@ -472,176 +458,71 @@ static void waitfor(pid_t pid) | |||
472 | 458 | ||
473 | /* Wait for any child (prevent zombies from exiting orphaned processes) | 459 | /* Wait for any child (prevent zombies from exiting orphaned processes) |
474 | * but exit the loop only when specified one has exited. */ | 460 | * but exit the loop only when specified one has exited. */ |
475 | while (wait(NULL) != pid) | 461 | while (1) { |
476 | continue; | 462 | pid_t wpid = wait(NULL); |
463 | mark_terminated(wpid); | ||
464 | /* Unsafe. SIGTSTP handler might have wait'ed it already */ | ||
465 | /*if (wpid == pid) break;*/ | ||
466 | /* More reliable */ | ||
467 | if (kill(pid, 0)) | ||
468 | break; | ||
469 | } | ||
477 | } | 470 | } |
478 | 471 | ||
479 | /* Run all commands of a particular type */ | 472 | /* Run all commands of a particular type */ |
480 | static void run_actions(int action_type) | 473 | static void run_actions(int action_type) |
481 | { | 474 | { |
482 | struct init_action *a, *tmp; | ||
483 | |||
484 | for (a = init_action_list; a; a = tmp) { | ||
485 | tmp = a->next; | ||
486 | if (a->action_type & action_type) { | ||
487 | // Pointless: run() will error out if open of device fails. | ||
488 | ///* a->terminal of "" means "init's console" */ | ||
489 | //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) { | ||
490 | // //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/); | ||
491 | // delete_init_action(a); | ||
492 | //} else | ||
493 | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { | ||
494 | waitfor(run(a)); | ||
495 | delete_init_action(a); | ||
496 | } else if (a->action_type & ONCE) { | ||
497 | run(a); | ||
498 | delete_init_action(a); | ||
499 | } else if (a->action_type & (RESPAWN | ASKFIRST)) { | ||
500 | /* Only run stuff with pid==0. If they have | ||
501 | * a pid, that means it is still running */ | ||
502 | if (a->pid == 0) { | ||
503 | a->pid = run(a); | ||
504 | } | ||
505 | } | ||
506 | } | ||
507 | } | ||
508 | } | ||
509 | |||
510 | static void low_level_reboot(unsigned long magic) | ||
511 | { | ||
512 | pid_t pid; | ||
513 | /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) in | ||
514 | * linux/kernel/sys.c, which can cause the machine to panic when | ||
515 | * the init process is killed.... */ | ||
516 | pid = vfork(); | ||
517 | if (pid == 0) { /* child */ | ||
518 | reboot(magic); | ||
519 | _exit(EXIT_SUCCESS); | ||
520 | } | ||
521 | waitfor(pid); | ||
522 | } | ||
523 | |||
524 | static void kill_all_processes(void) | ||
525 | { | ||
526 | /* run everything to be run at "shutdown". This is done _prior_ | ||
527 | * to killing everything, in case people wish to use scripts to | ||
528 | * shut things down gracefully... */ | ||
529 | run_actions(SHUTDOWN); | ||
530 | |||
531 | /* first disable all our signals */ | ||
532 | sigprocmask_allsigs(SIG_BLOCK); | ||
533 | |||
534 | message(L_CONSOLE | L_LOG, "The system is going down NOW!"); | ||
535 | |||
536 | /* Allow Ctrl-Alt-Del to reboot system. */ | ||
537 | low_level_reboot(RB_ENABLE_CAD); | ||
538 | |||
539 | /* Send signals to every process _except_ pid 1 */ | ||
540 | message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM"); | ||
541 | kill(-1, SIGTERM); | ||
542 | sync(); | ||
543 | sleep(1); | ||
544 | |||
545 | message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL"); | ||
546 | kill(-1, SIGKILL); | ||
547 | sync(); | ||
548 | sleep(1); | ||
549 | } | ||
550 | |||
551 | static void halt_reboot_pwoff(int sig) | ||
552 | { | ||
553 | const char *m = "halt"; | ||
554 | int rb; | ||
555 | |||
556 | kill_all_processes(); | ||
557 | |||
558 | rb = RB_HALT_SYSTEM; | ||
559 | if (sig == SIGTERM) { | ||
560 | m = "reboot"; | ||
561 | rb = RB_AUTOBOOT; | ||
562 | } else if (sig == SIGUSR2) { | ||
563 | m = "poweroff"; | ||
564 | rb = RB_POWER_OFF; | ||
565 | } | ||
566 | message(L_CONSOLE | L_LOG, "Requesting system %s", m); | ||
567 | /* allow time for last message to reach serial console */ | ||
568 | sleep(2); | ||
569 | low_level_reboot(rb); | ||
570 | loop_forever(); | ||
571 | } | ||
572 | |||
573 | /* Handler for QUIT - exec "restart" action, | ||
574 | * else (no such action defined) do nothing */ | ||
575 | static void restart_handler(int sig UNUSED_PARAM) | ||
576 | { | ||
577 | struct init_action *a; | 475 | struct init_action *a; |
578 | 476 | ||
579 | for (a = init_action_list; a; a = a->next) { | 477 | for (a = init_action_list; a; a = a->next) { |
580 | if (a->action_type & RESTART) { | 478 | if (!(a->action_type & action_type)) |
581 | kill_all_processes(); | 479 | continue; |
582 | |||
583 | /* unblock all signals (blocked in kill_all_processes()) */ | ||
584 | sigprocmask_allsigs(SIG_UNBLOCK); | ||
585 | |||
586 | /* Open the new terminal device */ | ||
587 | open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); | ||
588 | 480 | ||
589 | messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); | 481 | if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) { |
590 | init_exec(a->command); | 482 | pid_t pid = run(a); |
591 | sleep(2); | 483 | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN)) |
592 | low_level_reboot(RB_HALT_SYSTEM); | 484 | waitfor(pid); |
593 | loop_forever(); | 485 | } |
486 | if (a->action_type & (RESPAWN | ASKFIRST)) { | ||
487 | /* Only run stuff with pid == 0. If pid != 0, | ||
488 | * it is already running | ||
489 | */ | ||
490 | if (a->pid == 0) | ||
491 | a->pid = run(a); | ||
594 | } | 492 | } |
595 | } | 493 | } |
596 | } | 494 | } |
597 | 495 | ||
598 | static void ctrlaltdel_signal(int sig UNUSED_PARAM) | ||
599 | { | ||
600 | run_actions(CTRLALTDEL); | ||
601 | } | ||
602 | |||
603 | /* The SIGCONT handler is set to record_signo(). | ||
604 | * It just sets bb_got_signal = SIGCONT. */ | ||
605 | |||
606 | /* The SIGSTOP & SIGTSTP handler */ | ||
607 | static void stop_handler(int sig UNUSED_PARAM) | ||
608 | { | ||
609 | int saved_errno = errno; | ||
610 | |||
611 | bb_got_signal = 0; | ||
612 | while (bb_got_signal == 0) | ||
613 | pause(); | ||
614 | |||
615 | errno = saved_errno; | ||
616 | } | ||
617 | |||
618 | static void new_init_action(uint8_t action_type, const char *command, const char *cons) | 496 | static void new_init_action(uint8_t action_type, const char *command, const char *cons) |
619 | { | 497 | { |
620 | struct init_action *a, *last; | 498 | struct init_action *a, **nextp; |
621 | 499 | ||
622 | // Why? | 500 | //BUG |
623 | // if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) | 501 | //old: |
624 | // return; | 502 | //::shutdown:umount -a -r |
625 | 503 | //::shutdown:swapoff -a | |
626 | /* Append to the end of the list */ | 504 | //new: swapped: |
627 | for (a = last = init_action_list; a; a = a->next) { | 505 | //::shutdown:swapoff -a |
628 | /* don't enter action if it's already in the list, | 506 | //::shutdown:umount -a -r |
629 | * but do overwrite existing actions */ | 507 | //on SIGHUP, new one will be loaded, but order will be wrong. |
508 | nextp = &init_action_list; | ||
509 | while ((a = *nextp) != NULL) { | ||
510 | /* Don't enter action if it's already in the list, | ||
511 | * just overwrite existing one's type. | ||
512 | * This prevents losing running RESPAWNs. | ||
513 | */ | ||
630 | if ((strcmp(a->command, command) == 0) | 514 | if ((strcmp(a->command, command) == 0) |
631 | && (strcmp(a->terminal, cons) == 0) | 515 | && (strcmp(a->terminal, cons) == 0) |
632 | ) { | 516 | ) { |
633 | a->action_type = action_type; | 517 | a->action_type = action_type; |
634 | return; | 518 | return; |
635 | } | 519 | } |
636 | last = a; | 520 | nextp = &a->next; |
637 | } | 521 | } |
638 | 522 | ||
523 | /* Append to the end of the list */ | ||
639 | a = xzalloc(sizeof(*a)); | 524 | a = xzalloc(sizeof(*a)); |
640 | if (last) { | 525 | *nextp = a; |
641 | last->next = a; | ||
642 | } else { | ||
643 | init_action_list = a; | ||
644 | } | ||
645 | a->action_type = action_type; | 526 | a->action_type = action_type; |
646 | safe_strncpy(a->command, command, sizeof(a->command)); | 527 | safe_strncpy(a->command, command, sizeof(a->command)); |
647 | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); | 528 | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); |
@@ -665,7 +546,7 @@ static void parse_inittab(void) | |||
665 | if (parser == NULL) | 546 | if (parser == NULL) |
666 | #endif | 547 | #endif |
667 | { | 548 | { |
668 | /* No inittab file -- set up some default behavior */ | 549 | /* No inittab file - set up some default behavior */ |
669 | /* Reboot on Ctrl-Alt-Del */ | 550 | /* Reboot on Ctrl-Alt-Del */ |
670 | new_init_action(CTRLALTDEL, "reboot", ""); | 551 | new_init_action(CTRLALTDEL, "reboot", ""); |
671 | /* Umount all filesystems on halt/reboot */ | 552 | /* Umount all filesystems on halt/reboot */ |
@@ -694,7 +575,7 @@ static void parse_inittab(void) | |||
694 | PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) { | 575 | PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) { |
695 | /* order must correspond to SYSINIT..RESTART constants */ | 576 | /* order must correspond to SYSINIT..RESTART constants */ |
696 | static const char actions[] ALIGN1 = | 577 | static const char actions[] ALIGN1 = |
697 | "sysinit\0""respawn\0""askfirst\0""wait\0""once\0" | 578 | "sysinit\0""wait\0""once\0""respawn\0""askfirst\0" |
698 | "ctrlaltdel\0""shutdown\0""restart\0"; | 579 | "ctrlaltdel\0""shutdown\0""restart\0"; |
699 | int action; | 580 | int action; |
700 | char *tty = token[0]; | 581 | char *tty = token[0]; |
@@ -722,14 +603,172 @@ static void parse_inittab(void) | |||
722 | #endif | 603 | #endif |
723 | } | 604 | } |
724 | 605 | ||
606 | static void low_level_reboot(unsigned magic) NORETURN; | ||
607 | static void low_level_reboot(unsigned magic) | ||
608 | { | ||
609 | pid_t pid; | ||
610 | |||
611 | /* Allow time for last message to reach serial console, etc */ | ||
612 | sleep(1); | ||
613 | |||
614 | /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) | ||
615 | * in linux/kernel/sys.c, which can cause the machine to panic when | ||
616 | * the init process exits... */ | ||
617 | pid = vfork(); | ||
618 | if (pid == 0) { /* child */ | ||
619 | reboot(magic); | ||
620 | _exit(EXIT_SUCCESS); | ||
621 | } | ||
622 | waitfor(pid); | ||
623 | while (1) | ||
624 | sleep(1); | ||
625 | } | ||
626 | |||
627 | static void kill_all_processes(void) | ||
628 | { | ||
629 | /* Run everything to be run at "shutdown". This is done _prior_ | ||
630 | * to killing everything, in case people wish to use scripts to | ||
631 | * shut things down gracefully... */ | ||
632 | run_actions(SHUTDOWN); | ||
633 | |||
634 | message(L_CONSOLE | L_LOG, "The system is going down NOW!"); | ||
635 | |||
636 | /* Allow Ctrl-Alt-Del to reboot system. */ | ||
637 | reboot(RB_ENABLE_CAD); /* misnomer */ | ||
638 | |||
639 | /* 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); | ||
642 | sync(); | ||
643 | sleep(1); | ||
644 | |||
645 | message(L_CONSOLE, "Sending SIG%s to all processes", "KILL"); | ||
646 | kill(-1, SIGKILL); | ||
647 | sync(); | ||
648 | sleep(1); | ||
649 | } | ||
650 | |||
651 | /* Signal handling by init: | ||
652 | * | ||
653 | * For process with PID==1, on entry kernel sets all signals to SIG_DFL | ||
654 | * and unmasks all signals. However, for process with PID==1, | ||
655 | * default action (SIG_DFL) on any signal is to ignore it, | ||
656 | * even for special signals SIGKILL and SIGCONT. | ||
657 | * (SIGSTOP is still handled specially, at least in 2.6.20) | ||
658 | * Also, any signal can be caught or blocked. | ||
659 | * | ||
660 | * We install two kinds of handlers, "immediate" and "delayed". | ||
661 | * | ||
662 | * Immediate handlers execute at any time, even while, say, sysinit | ||
663 | * is running. | ||
664 | * | ||
665 | * Delayed handlers just set a flag variable. The variable is checked | ||
666 | * in the main loop and acted upon. | ||
667 | * | ||
668 | * halt/poweroff/reboot and restart have immediate handlers. | ||
669 | * They only traverse linked list of struct action's, never modify it, | ||
670 | * this should be safe to do even in signal handler. Also they | ||
671 | * never return. | ||
672 | * | ||
673 | * SIGSTOP and SIGTSTP have immediate handlers. They just wait | ||
674 | * for SIGCONT to happen. | ||
675 | * | ||
676 | * SIGHUP has a delayed handler, because modifying linked list | ||
677 | * of struct action's from a signal handler while it is manipulated | ||
678 | * by the program may be disastrous. | ||
679 | * | ||
680 | * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing | ||
681 | * it to happen even somewhere inside "sysinit" would be a bit awkward. | ||
682 | * | ||
683 | * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide | ||
684 | * and only one will be remebered and acted upon. | ||
685 | */ | ||
686 | |||
687 | static void halt_reboot_pwoff(int sig) | ||
688 | { | ||
689 | const char *m; | ||
690 | unsigned rb; | ||
691 | |||
692 | kill_all_processes(); | ||
693 | |||
694 | m = "halt"; | ||
695 | rb = RB_HALT_SYSTEM; | ||
696 | if (sig == SIGTERM) { | ||
697 | m = "reboot"; | ||
698 | rb = RB_AUTOBOOT; | ||
699 | } else if (sig == SIGUSR2) { | ||
700 | m = "poweroff"; | ||
701 | rb = RB_POWER_OFF; | ||
702 | } | ||
703 | message(L_CONSOLE, "Requesting system %s", m); | ||
704 | low_level_reboot(rb); | ||
705 | /* not reached */ | ||
706 | } | ||
707 | |||
708 | /* The SIGSTOP/SIGTSTP handler | ||
709 | * NB: inside it, all signals except SIGCONT are masked | ||
710 | * via appropriate setup in sigaction(). | ||
711 | */ | ||
712 | static void stop_handler(int sig UNUSED_PARAM) | ||
713 | { | ||
714 | int saved_errno; | ||
715 | smallint saved_bb_got_signal; | ||
716 | |||
717 | saved_errno = errno; | ||
718 | saved_bb_got_signal = bb_got_signal; | ||
719 | signal(SIGCONT, record_signo); | ||
720 | |||
721 | while (1) { | ||
722 | pid_t wpid; | ||
723 | |||
724 | if (bb_got_signal == SIGCONT) | ||
725 | break; | ||
726 | /* NB: this can accidentally wait() for a process | ||
727 | * which we waitfor() elsewhere! waitfor() must have | ||
728 | * code which is resilient against this. | ||
729 | */ | ||
730 | wpid = wait_any_nohang(NULL); | ||
731 | if (wpid > 0) | ||
732 | mark_terminated(wpid); | ||
733 | sleep(1); | ||
734 | } | ||
735 | |||
736 | signal(SIGCONT, SIG_DFL); | ||
737 | bb_got_signal = saved_bb_got_signal; | ||
738 | errno = saved_errno; | ||
739 | } | ||
740 | |||
741 | /* Handler for QUIT - exec "restart" action, | ||
742 | * else (no such action defined) do nothing */ | ||
743 | static void restart_handler(int sig UNUSED_PARAM) | ||
744 | { | ||
745 | struct init_action *a; | ||
746 | |||
747 | for (a = init_action_list; a; a = a->next) { | ||
748 | if (!(a->action_type & RESTART)) | ||
749 | continue; | ||
750 | |||
751 | /* Starting from here, we won't return. | ||
752 | * Thus don't need to worry about preserving errno | ||
753 | * and such. | ||
754 | */ | ||
755 | kill_all_processes(); | ||
756 | open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); | ||
757 | messageD(L_CONSOLE, "Trying to re-exec %s", a->command); | ||
758 | init_exec(a->command); | ||
759 | low_level_reboot(RB_HALT_SYSTEM); | ||
760 | /* not reached */ | ||
761 | } | ||
762 | } | ||
763 | |||
725 | #if ENABLE_FEATURE_USE_INITTAB | 764 | #if ENABLE_FEATURE_USE_INITTAB |
726 | static void reload_inittab(int sig UNUSED_PARAM) | 765 | static void reload_inittab(void) |
727 | { | 766 | { |
728 | struct init_action *a, *tmp; | 767 | struct init_action *a, *tmp; |
729 | 768 | ||
730 | message(L_LOG, "reloading /etc/inittab"); | 769 | message(L_LOG, "reloading /etc/inittab"); |
731 | 770 | ||
732 | /* disable old entrys */ | 771 | /* Disable old entries */ |
733 | for (a = init_action_list; a; a = a->next) { | 772 | for (a = init_action_list; a; a = a->next) { |
734 | a->action_type = ONCE; | 773 | a->action_type = ONCE; |
735 | } | 774 | } |
@@ -738,47 +777,57 @@ static void reload_inittab(int sig UNUSED_PARAM) | |||
738 | 777 | ||
739 | if (ENABLE_FEATURE_KILL_REMOVED) { | 778 | if (ENABLE_FEATURE_KILL_REMOVED) { |
740 | /* Be nice and send SIGTERM first */ | 779 | /* Be nice and send SIGTERM first */ |
741 | for (a = init_action_list; a; a = a->next) { | 780 | for (a = init_action_list; a; a = a->next) |
742 | pid_t pid = a->pid; | 781 | if (a->pid != 0) |
743 | if ((a->action_type & ONCE) && pid != 0) { | 782 | kill(a->pid, SIGTERM); |
744 | kill(pid, SIGTERM); | ||
745 | } | ||
746 | } | ||
747 | #if CONFIG_FEATURE_KILL_DELAY | 783 | #if CONFIG_FEATURE_KILL_DELAY |
748 | /* NB: parent will wait in NOMMU case */ | 784 | /* NB: parent will wait in NOMMU case */ |
749 | if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ | 785 | if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ |
750 | sleep(CONFIG_FEATURE_KILL_DELAY); | 786 | sleep(CONFIG_FEATURE_KILL_DELAY); |
751 | for (a = init_action_list; a; a = a->next) { | 787 | for (a = init_action_list; a; a = a->next) |
752 | pid_t pid = a->pid; | 788 | if (a->pid != 0) |
753 | if ((a->action_type & ONCE) && pid != 0) { | 789 | kill(a->pid, SIGKILL); |
754 | kill(pid, SIGKILL); | ||
755 | } | ||
756 | } | ||
757 | _exit(EXIT_SUCCESS); | 790 | _exit(EXIT_SUCCESS); |
758 | } | 791 | } |
759 | #endif | 792 | #endif |
760 | } | 793 | } |
761 | 794 | ||
762 | /* remove unused entrys */ | 795 | /* Remove old and unused entries */ |
763 | for (a = init_action_list; a; a = tmp) { | 796 | for (a = init_action_list; a; a = tmp) { |
764 | tmp = a->next; | 797 | tmp = a->next; |
765 | if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { | 798 | if (a->action_type & (ONCE | SYSINIT | WAIT)) |
766 | delete_init_action(a); | 799 | delete_init_action(a); |
767 | } | ||
768 | } | 800 | } |
769 | run_actions(RESPAWN | ASKFIRST); | 801 | /* Not needed: */ |
802 | /* run_actions(RESPAWN | ASKFIRST); */ | ||
803 | /* - we return to main loop, which does this automagically */ | ||
770 | } | 804 | } |
771 | #else | ||
772 | void reload_inittab(int sig); | ||
773 | #endif | 805 | #endif |
774 | 806 | ||
807 | static int check_delayed_sigs(void) | ||
808 | { | ||
809 | int sigs_seen = 0; | ||
810 | |||
811 | while (1) { | ||
812 | smallint sig = bb_got_signal; | ||
813 | |||
814 | if (!sig) | ||
815 | return sigs_seen; | ||
816 | bb_got_signal = 0; | ||
817 | sigs_seen = 1; | ||
818 | #if ENABLE_FEATURE_USE_INITTAB | ||
819 | if (sig == SIGHUP) | ||
820 | reload_inittab(); | ||
821 | #endif | ||
822 | if (sig == SIGINT) | ||
823 | run_actions(CTRLALTDEL); | ||
824 | } | ||
825 | } | ||
826 | |||
775 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 827 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
776 | int init_main(int argc UNUSED_PARAM, char **argv) | 828 | int init_main(int argc UNUSED_PARAM, char **argv) |
777 | { | 829 | { |
778 | struct init_action *a; | 830 | die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */ |
779 | pid_t wpid; | ||
780 | |||
781 | die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */ | ||
782 | 831 | ||
783 | if (argv[1] && !strcmp(argv[1], "-q")) { | 832 | if (argv[1] && !strcmp(argv[1], "-q")) { |
784 | return kill(1, SIGHUP); | 833 | return kill(1, SIGHUP); |
@@ -791,28 +840,9 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
791 | ) { | 840 | ) { |
792 | bb_show_usage(); | 841 | bb_show_usage(); |
793 | } | 842 | } |
794 | /* Set up sig handlers -- be sure to | 843 | /* Turn off rebooting via CTL-ALT-DEL - we get a |
795 | * clear all of these in run() */ | ||
796 | // TODO: handlers should just set a flag variable. | ||
797 | // Move signal handling from handlers to main loop - | ||
798 | // we have bad races otherwise. | ||
799 | // E.g. parse_inittab() vs. delete_init_action()... | ||
800 | signal(SIGQUIT, restart_handler); | ||
801 | bb_signals(0 | ||
802 | + (1 << SIGUSR1) /* halt */ | ||
803 | + (1 << SIGUSR2) /* poweroff */ | ||
804 | + (1 << SIGTERM) /* reboot */ | ||
805 | , halt_reboot_pwoff); | ||
806 | signal(SIGINT, ctrlaltdel_signal); | ||
807 | signal(SIGCONT, record_signo); | ||
808 | bb_signals(0 | ||
809 | + (1 << SIGSTOP) | ||
810 | + (1 << SIGTSTP) | ||
811 | , stop_handler); | ||
812 | |||
813 | /* Turn off rebooting via CTL-ALT-DEL -- we get a | ||
814 | * SIGINT on CAD so we can shut things down gracefully... */ | 844 | * SIGINT on CAD so we can shut things down gracefully... */ |
815 | low_level_reboot(RB_DISABLE_CAD); | 845 | reboot(RB_DISABLE_CAD); /* misnomer */ |
816 | } | 846 | } |
817 | 847 | ||
818 | /* Figure out where the default console should be */ | 848 | /* Figure out where the default console should be */ |
@@ -857,11 +887,11 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
857 | /* Start a shell on console */ | 887 | /* Start a shell on console */ |
858 | new_init_action(RESPAWN, bb_default_login_shell, ""); | 888 | new_init_action(RESPAWN, bb_default_login_shell, ""); |
859 | } else { | 889 | } else { |
860 | /* Not in single user mode -- see what inittab says */ | 890 | /* Not in single user mode - see what inittab says */ |
861 | 891 | ||
862 | /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, | 892 | /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, |
863 | * then parse_inittab() simply adds in some default | 893 | * then parse_inittab() simply adds in some default |
864 | * actions(i.e., runs INIT_SCRIPT and then starts a pair | 894 | * actions(i.e., INIT_SCRIPT and a pair |
865 | * of "askfirst" shells */ | 895 | * of "askfirst" shells */ |
866 | parse_inittab(); | 896 | parse_inittab(); |
867 | } | 897 | } |
@@ -888,44 +918,91 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
888 | while (*++argv) | 918 | while (*++argv) |
889 | memset(*argv, 0, strlen(*argv)); | 919 | memset(*argv, 0, strlen(*argv)); |
890 | 920 | ||
891 | /* Now run everything that needs to be run */ | 921 | /* Set up signal handlers */ |
922 | if (!DEBUG_INIT) { | ||
923 | struct sigaction sa; | ||
892 | 924 | ||
925 | bb_signals(0 | ||
926 | + (1 << SIGUSR1) /* halt */ | ||
927 | + (1 << SIGTERM) /* reboot */ | ||
928 | + (1 << SIGUSR2) /* poweroff */ | ||
929 | , halt_reboot_pwoff); | ||
930 | signal(SIGQUIT, restart_handler); /* re-exec another init */ | ||
931 | |||
932 | /* Stop handler must allow only SIGCONT inside itself */ | ||
933 | memset(&sa, 0, sizeof(sa)); | ||
934 | sigfillset(&sa.sa_mask); | ||
935 | sigdelset(&sa.sa_mask, SIGCONT); | ||
936 | sa.sa_handler = stop_handler; | ||
937 | /* NB: sa_flags doesn't have SA_RESTART. | ||
938 | * It must be able to interrupt wait(). | ||
939 | */ | ||
940 | sigaction_set(SIGTSTP, &sa); /* pause */ | ||
941 | /* Does not work as intended, at least in 2.6.20. | ||
942 | * SIGSTOP is simply ignored by init: | ||
943 | */ | ||
944 | sigaction_set(SIGSTOP, &sa); /* pause */ | ||
945 | |||
946 | /* SIGINT (Ctrl-Alt-Del) must interrupt wait(), | ||
947 | * setting handler without SA_RESTART flag. | ||
948 | */ | ||
949 | bb_signals_recursive_norestart((1 << SIGINT), record_signo); | ||
950 | } | ||
951 | |||
952 | /* Now run everything that needs to be run */ | ||
893 | /* First run the sysinit command */ | 953 | /* First run the sysinit command */ |
894 | run_actions(SYSINIT); | 954 | run_actions(SYSINIT); |
895 | 955 | check_delayed_sigs(); | |
896 | /* Next run anything that wants to block */ | 956 | /* Next run anything that wants to block */ |
897 | run_actions(WAIT); | 957 | run_actions(WAIT); |
898 | 958 | check_delayed_sigs(); | |
899 | /* Next run anything to be run only once */ | 959 | /* Next run anything to be run only once */ |
900 | run_actions(ONCE); | 960 | run_actions(ONCE); |
901 | 961 | ||
902 | /* Redefine SIGHUP to reread /etc/inittab */ | 962 | /* Set up "reread /etc/inittab" handler. |
903 | signal(SIGHUP, ENABLE_FEATURE_USE_INITTAB ? reload_inittab : SIG_IGN); | 963 | * Handler is set up without SA_RESTART, it will interrupt syscalls. |
964 | */ | ||
965 | if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB) | ||
966 | bb_signals_recursive_norestart((1 << SIGHUP), record_signo); | ||
904 | 967 | ||
905 | /* Now run the looping stuff for the rest of forever */ | 968 | /* Now run the looping stuff for the rest of forever. |
969 | * NB: if delayed signal happened, avoid blocking in wait(). | ||
970 | */ | ||
906 | while (1) { | 971 | while (1) { |
907 | /* run the respawn/askfirst stuff */ | 972 | pid_t wpid; |
973 | int got_sigs; | ||
974 | |||
975 | got_sigs = check_delayed_sigs(); | ||
976 | |||
977 | /* (Re)run the respawn/askfirst stuff */ | ||
908 | run_actions(RESPAWN | ASKFIRST); | 978 | run_actions(RESPAWN | ASKFIRST); |
909 | 979 | ||
910 | /* Don't consume all CPU time -- sleep a bit */ | 980 | got_sigs |= check_delayed_sigs(); |
981 | |||
982 | /* Don't consume all CPU time - sleep a bit */ | ||
911 | sleep(1); | 983 | sleep(1); |
912 | 984 | ||
913 | /* Wait for any child process to exit */ | 985 | got_sigs |= check_delayed_sigs(); |
986 | |||
987 | /* Wait for any child process to exit. | ||
988 | * NB: "delayed" signals will also interrupt this wait(), | ||
989 | * bb_signals_recursive_norestart() set them up for that. | ||
990 | * This guarantees we won't be stuck here | ||
991 | * till next orphan dies. | ||
992 | */ | ||
993 | if (got_sigs) | ||
994 | goto dont_block; | ||
914 | wpid = wait(NULL); | 995 | wpid = wait(NULL); |
915 | while (wpid > 0) { | 996 | while (wpid > 0) { |
916 | /* Find out who died and clean up their corpse */ | 997 | struct init_action *a = mark_terminated(wpid); |
917 | for (a = init_action_list; a; a = a->next) { | 998 | if (a) { |
918 | if (a->pid == wpid) { | 999 | message(L_LOG, "process '%s' (pid %d) exited. " |
919 | /* Set the pid to 0 so that the process gets | 1000 | "Scheduling for restart.", |
920 | * restarted by run_actions() */ | 1001 | a->command, wpid); |
921 | a->pid = 0; | ||
922 | message(L_LOG, "process '%s' (pid %d) exited. " | ||
923 | "Scheduling for restart.", | ||
924 | a->command, wpid); | ||
925 | } | ||
926 | } | 1002 | } |
927 | /* see if anyone else is waiting to be reaped */ | 1003 | /* See if anyone else is waiting to be reaped */ |
1004 | dont_block: | ||
928 | wpid = wait_any_nohang(NULL); | 1005 | wpid = wait_any_nohang(NULL); |
929 | } | 1006 | } |
930 | } | 1007 | } /* while (1) */ |
931 | } | 1008 | } |