diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-19 02:57:07 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-19 02:57:07 +0000 |
commit | a37e7134f76b7661b86bb9cc926f28f81b1e1109 (patch) | |
tree | 88c511c1f1094c3c4207523e31db5fdf7bda6069 /init/init.c | |
parent | 92657d484f4f95ce4579ad095c9caf596a737e5b (diff) | |
download | busybox-w32-a37e7134f76b7661b86bb9cc926f28f81b1e1109.tar.gz busybox-w32-a37e7134f76b7661b86bb9cc926f28f81b1e1109.tar.bz2 busybox-w32-a37e7134f76b7661b86bb9cc926f28f81b1e1109.zip |
init: fix bug 1111: restart actions were not splitting words:
::restart:/sbin/rc restart
resulted in:
exec of '/sbin/rc restart' failed: No such file or directory
Diffstat (limited to 'init/init.c')
-rw-r--r-- | init/init.c | 189 |
1 files changed, 87 insertions, 102 deletions
diff --git a/init/init.c b/init/init.c index 080c5b3af..8d706fe1f 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <paths.h> | 14 | #include <paths.h> |
15 | #include <sys/reboot.h> | 15 | #include <sys/reboot.h> |
16 | 16 | ||
17 | #define INIT_BUFFS_SIZE 256 | 17 | #define COMMAND_SIZE 256 |
18 | #define CONSOLE_NAME_SIZE 32 | 18 | #define CONSOLE_NAME_SIZE 32 |
19 | #define MAXENV 16 /* Number of env. vars */ | 19 | #define MAXENV 16 /* Number of env. vars */ |
20 | 20 | ||
@@ -55,9 +55,9 @@ | |||
55 | struct init_action { | 55 | struct init_action { |
56 | struct init_action *next; | 56 | struct init_action *next; |
57 | pid_t pid; | 57 | pid_t pid; |
58 | uint8_t action; | 58 | uint8_t action_type; |
59 | char terminal[CONSOLE_NAME_SIZE]; | 59 | char terminal[CONSOLE_NAME_SIZE]; |
60 | char command[INIT_BUFFS_SIZE]; | 60 | char command[COMMAND_SIZE]; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | /* Static variables */ | 63 | /* Static variables */ |
@@ -294,14 +294,57 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | |||
294 | set_sane_term(); | 294 | set_sane_term(); |
295 | } | 295 | } |
296 | 296 | ||
297 | /* wrapper around exec: | ||
298 | * takes string (max COMMAND_SIZE chars) | ||
299 | * runs [-]/bin/sh -c "exec ......." if '>' etc detected. | ||
300 | * otherwise splits words on whitespace and deals with leading dash. | ||
301 | */ | ||
302 | static void init_exec(const char *command) | ||
303 | { | ||
304 | char *cmd[COMMAND_SIZE / 2]; | ||
305 | char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ | ||
306 | int dash = (command[0] == '-'); | ||
307 | |||
308 | /* See if any special /bin/sh requiring characters are present */ | ||
309 | if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { | ||
310 | strcpy(buf, "exec "); | ||
311 | strcpy(buf + 5, command + dash); /* excluding "-" */ | ||
312 | /* LIBBB_DEFAULT_LOGIN_SHELL has leading dash */ | ||
313 | cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); | ||
314 | cmd[1] = (char*)"-c"; | ||
315 | cmd[2] = buf; | ||
316 | cmd[3] = NULL; | ||
317 | } else { | ||
318 | /* Convert command (char*) into cmd (char**, one word per string) */ | ||
319 | char *word, *next; | ||
320 | int i = 0; | ||
321 | next = strcpy(buf, command); /* including "-" */ | ||
322 | while ((word = strsep(&next, " \t")) != NULL) { | ||
323 | if (*word != '\0') { /* not two spaces/tabs together? */ | ||
324 | cmd[i] = word; | ||
325 | i++; | ||
326 | } | ||
327 | } | ||
328 | cmd[i] = NULL; | ||
329 | } | ||
330 | /* If we saw leading "-", it is interactive shell. | ||
331 | * Try harder to give it a controlling tty. | ||
332 | * And skip "-" in actual exec call. */ | ||
333 | if (dash) { | ||
334 | /* _Attempt_ to make stdin a controlling tty. */ | ||
335 | if (ENABLE_FEATURE_INIT_SCTTY) | ||
336 | ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); | ||
337 | } | ||
338 | BB_EXECVP(cmd[0] + dash, cmd); | ||
339 | message(L_LOG | L_CONSOLE, "Cannot run '%s': %s", | ||
340 | cmd[0], strerror(errno)); | ||
341 | /* returns if execvp fails */ | ||
342 | } | ||
343 | |||
297 | /* Used only by run_actions */ | 344 | /* Used only by run_actions */ |
298 | static pid_t run(const struct init_action *a) | 345 | static pid_t run(const struct init_action *a) |
299 | { | 346 | { |
300 | int i; | ||
301 | pid_t pid; | 347 | pid_t pid; |
302 | char *s, *tmpCmd, *cmdpath; | ||
303 | char *cmd[INIT_BUFFS_SIZE]; | ||
304 | char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */ | ||
305 | sigset_t nmask, omask; | 348 | sigset_t nmask, omask; |
306 | 349 | ||
307 | /* Block sigchild while forking (why?) */ | 350 | /* Block sigchild while forking (why?) */ |
@@ -341,7 +384,7 @@ static pid_t run(const struct init_action *a) | |||
341 | #ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING | 384 | #ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING |
342 | /* If the init Action requires us to wait, then force the | 385 | /* If the init Action requires us to wait, then force the |
343 | * supplied terminal to be the controlling tty. */ | 386 | * supplied terminal to be the controlling tty. */ |
344 | if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { | 387 | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { |
345 | /* Now fork off another process to just hang around */ | 388 | /* Now fork off another process to just hang around */ |
346 | pid = fork(); | 389 | pid = fork(); |
347 | if (pid < 0) { | 390 | if (pid < 0) { |
@@ -381,58 +424,7 @@ static pid_t run(const struct init_action *a) | |||
381 | /* Child - fall though to actually execute things */ | 424 | /* Child - fall though to actually execute things */ |
382 | } | 425 | } |
383 | #endif | 426 | #endif |
384 | 427 | if (a->action_type & ASKFIRST) { | |
385 | /* See if any special /bin/sh requiring characters are present */ | ||
386 | if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { | ||
387 | cmd[0] = (char*)DEFAULT_SHELL; | ||
388 | cmd[1] = (char*)"-c"; | ||
389 | cmd[2] = strcat(strcpy(buf, "exec "), a->command); | ||
390 | cmd[3] = NULL; | ||
391 | } else { | ||
392 | /* Convert command (char*) into cmd (char**, one word per string) */ | ||
393 | strcpy(buf, a->command); | ||
394 | s = buf; | ||
395 | for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) { | ||
396 | if (*tmpCmd != '\0') { | ||
397 | cmd[i] = tmpCmd; | ||
398 | i++; | ||
399 | } | ||
400 | } | ||
401 | cmd[i] = NULL; | ||
402 | } | ||
403 | |||
404 | cmdpath = cmd[0]; | ||
405 | |||
406 | /* | ||
407 | * Interactive shells want to see a dash in argv[0]. This | ||
408 | * typically is handled by login, argv will be setup this | ||
409 | * way if a dash appears at the front of the command path | ||
410 | * (like "-/bin/sh"). | ||
411 | */ | ||
412 | if (*cmdpath == '-') { | ||
413 | /* skip over the dash */ | ||
414 | ++cmdpath; | ||
415 | |||
416 | #ifdef WHY_WE_DO_THIS_SHELL_MUST_HANDLE_THIS_ITSELF | ||
417 | /* find the last component in the command pathname */ | ||
418 | s = bb_get_last_path_component_nostrip(cmdpath); | ||
419 | /* make a new argv[0] */ | ||
420 | cmd[0] = malloc(strlen(s) + 2); | ||
421 | if (cmd[0] == NULL) { | ||
422 | message(L_LOG | L_CONSOLE, bb_msg_memory_exhausted); | ||
423 | cmd[0] = cmdpath; | ||
424 | } else { | ||
425 | cmd[0][0] = '-'; | ||
426 | strcpy(cmd[0] + 1, s); | ||
427 | } | ||
428 | #endif | ||
429 | |||
430 | /* _Attempt_ to make stdin a controlling tty. */ | ||
431 | if (ENABLE_FEATURE_INIT_SCTTY) | ||
432 | ioctl(0, TIOCSCTTY, 0 /*only try, don't steal*/); | ||
433 | } | ||
434 | |||
435 | if (a->action & ASKFIRST) { | ||
436 | static const char press_enter[] ALIGN1 = | 428 | static const char press_enter[] ALIGN1 = |
437 | #ifdef CUSTOMIZED_BANNER | 429 | #ifdef CUSTOMIZED_BANNER |
438 | #include CUSTOMIZED_BANNER | 430 | #include CUSTOMIZED_BANNER |
@@ -449,58 +441,54 @@ static pid_t run(const struct init_action *a) | |||
449 | */ | 441 | */ |
450 | messageD(L_LOG, "waiting for enter to start '%s'" | 442 | messageD(L_LOG, "waiting for enter to start '%s'" |
451 | "(pid %d, tty '%s')\n", | 443 | "(pid %d, tty '%s')\n", |
452 | cmdpath, getpid(), a->terminal); | 444 | a->command, getpid(), a->terminal); |
453 | full_write(1, press_enter, sizeof(press_enter) - 1); | 445 | full_write(1, press_enter, sizeof(press_enter) - 1); |
454 | while (safe_read(0, &c, 1) == 1 && c != '\n') | 446 | while (safe_read(0, &c, 1) == 1 && c != '\n') |
455 | continue; | 447 | continue; |
456 | } | 448 | } |
457 | 449 | ||
458 | /* Log the process name and args */ | ||
459 | message(L_LOG, "starting pid %d, tty '%s': '%s'", | ||
460 | getpid(), a->terminal, cmdpath); | ||
461 | |||
462 | if (ENABLE_FEATURE_INIT_COREDUMPS) { | 450 | if (ENABLE_FEATURE_INIT_COREDUMPS) { |
463 | struct stat sb; | 451 | struct stat sb; |
464 | if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) { | 452 | if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) { |
465 | struct rlimit limit; | 453 | struct rlimit limit; |
466 | |||
467 | limit.rlim_cur = RLIM_INFINITY; | 454 | limit.rlim_cur = RLIM_INFINITY; |
468 | limit.rlim_max = RLIM_INFINITY; | 455 | limit.rlim_max = RLIM_INFINITY; |
469 | setrlimit(RLIMIT_CORE, &limit); | 456 | setrlimit(RLIMIT_CORE, &limit); |
470 | } | 457 | } |
471 | } | 458 | } |
472 | 459 | ||
460 | /* Log the process name and args */ | ||
461 | message(L_LOG, "starting pid %d, tty '%s': '%s'", | ||
462 | getpid(), a->terminal, a->command); | ||
463 | |||
473 | /* Now run it. The new program will take over this PID, | 464 | /* Now run it. The new program will take over this PID, |
474 | * so nothing further in init.c should be run. */ | 465 | * so nothing further in init.c should be run. */ |
475 | BB_EXECVP(cmdpath, cmd); | 466 | init_exec(a->command); |
476 | |||
477 | /* We're still here? Some error happened. */ | 467 | /* We're still here? Some error happened. */ |
478 | message(L_LOG | L_CONSOLE, "Cannot run '%s': %s", | ||
479 | cmdpath, strerror(errno)); | ||
480 | _exit(-1); | 468 | _exit(-1); |
481 | } | 469 | } |
482 | 470 | ||
483 | /* Run all commands of a particular type */ | 471 | /* Run all commands of a particular type */ |
484 | static void run_actions(int action) | 472 | static void run_actions(int action_type) |
485 | { | 473 | { |
486 | struct init_action *a, *tmp; | 474 | struct init_action *a, *tmp; |
487 | 475 | ||
488 | for (a = init_action_list; a; a = tmp) { | 476 | for (a = init_action_list; a; a = tmp) { |
489 | tmp = a->next; | 477 | tmp = a->next; |
490 | if (a->action == action) { | 478 | if (a->action_type == action_type) { |
491 | // Pointless: run() will error out if open of device fails. | 479 | // Pointless: run() will error out if open of device fails. |
492 | ///* a->terminal of "" means "init's console" */ | 480 | ///* a->terminal of "" means "init's console" */ |
493 | //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) { | 481 | //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) { |
494 | // //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/); | 482 | // //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/); |
495 | // delete_init_action(a); | 483 | // delete_init_action(a); |
496 | //} else | 484 | //} else |
497 | if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { | 485 | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { |
498 | waitfor(run(a)); | 486 | waitfor(run(a)); |
499 | delete_init_action(a); | 487 | delete_init_action(a); |
500 | } else if (a->action & ONCE) { | 488 | } else if (a->action_type & ONCE) { |
501 | run(a); | 489 | run(a); |
502 | delete_init_action(a); | 490 | delete_init_action(a); |
503 | } else if (a->action & (RESPAWN | ASKFIRST)) { | 491 | } else if (a->action_type & (RESPAWN | ASKFIRST)) { |
504 | /* Only run stuff with pid==0. If they have | 492 | /* Only run stuff with pid==0. If they have |
505 | * a pid, that means it is still running */ | 493 | * a pid, that means it is still running */ |
506 | if (a->pid == 0) { | 494 | if (a->pid == 0) { |
@@ -593,12 +581,11 @@ static void halt_reboot_pwoff(int sig) | |||
593 | * else (no such action defined) do nothing */ | 581 | * else (no such action defined) do nothing */ |
594 | static void exec_restart_action(int sig ATTRIBUTE_UNUSED) | 582 | static void exec_restart_action(int sig ATTRIBUTE_UNUSED) |
595 | { | 583 | { |
596 | struct init_action *a, *tmp; | 584 | struct init_action *a; |
597 | sigset_t unblock_signals; | 585 | sigset_t unblock_signals; |
598 | 586 | ||
599 | for (a = init_action_list; a; a = tmp) { | 587 | for (a = init_action_list; a; a = a->next) { |
600 | tmp = a->next; | 588 | if (a->action_type & RESTART) { |
601 | if (a->action & RESTART) { | ||
602 | kill_all_processes(); | 589 | kill_all_processes(); |
603 | 590 | ||
604 | /* unblock all signals (blocked in kill_all_processes()) */ | 591 | /* unblock all signals (blocked in kill_all_processes()) */ |
@@ -620,10 +607,7 @@ static void exec_restart_action(int sig ATTRIBUTE_UNUSED) | |||
620 | open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); | 607 | open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); |
621 | 608 | ||
622 | messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); | 609 | messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); |
623 | BB_EXECLP(a->command, a->command, NULL); | 610 | init_exec(a->command); |
624 | |||
625 | message(L_CONSOLE | L_LOG, "Cannot run '%s': %s", | ||
626 | a->command, strerror(errno)); | ||
627 | sleep(2); | 611 | sleep(2); |
628 | init_reboot(RB_HALT_SYSTEM); | 612 | init_reboot(RB_HALT_SYSTEM); |
629 | loop_forever(); | 613 | loop_forever(); |
@@ -654,12 +638,13 @@ static void cont_handler(int sig ATTRIBUTE_UNUSED) | |||
654 | got_cont = 1; | 638 | got_cont = 1; |
655 | } | 639 | } |
656 | 640 | ||
657 | static void new_init_action(uint8_t action, const char *command, const char *cons) | 641 | static void new_init_action(uint8_t action_type, const char *command, const char *cons) |
658 | { | 642 | { |
659 | struct init_action *new_action, *a, *last; | 643 | struct init_action *a, *last; |
660 | 644 | ||
661 | if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) | 645 | // Why? |
662 | return; | 646 | // if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) |
647 | // return; | ||
663 | 648 | ||
664 | /* Append to the end of the list */ | 649 | /* Append to the end of the list */ |
665 | for (a = last = init_action_list; a; a = a->next) { | 650 | for (a = last = init_action_list; a; a = a->next) { |
@@ -668,23 +653,23 @@ static void new_init_action(uint8_t action, const char *command, const char *con | |||
668 | if ((strcmp(a->command, command) == 0) | 653 | if ((strcmp(a->command, command) == 0) |
669 | && (strcmp(a->terminal, cons) == 0) | 654 | && (strcmp(a->terminal, cons) == 0) |
670 | ) { | 655 | ) { |
671 | a->action = action; | 656 | a->action_type = action_type; |
672 | return; | 657 | return; |
673 | } | 658 | } |
674 | last = a; | 659 | last = a; |
675 | } | 660 | } |
676 | 661 | ||
677 | new_action = xzalloc(sizeof(struct init_action)); | 662 | a = xzalloc(sizeof(*a)); |
678 | if (last) { | 663 | if (last) { |
679 | last->next = new_action; | 664 | last->next = a; |
680 | } else { | 665 | } else { |
681 | init_action_list = new_action; | 666 | init_action_list = a; |
682 | } | 667 | } |
683 | strcpy(new_action->command, command); | 668 | a->action_type = action_type; |
684 | new_action->action = action; | 669 | safe_strncpy(a->command, command, sizeof(a->command)); |
685 | strcpy(new_action->terminal, cons); | 670 | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); |
686 | messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", | 671 | messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", |
687 | new_action->command, new_action->action, new_action->terminal); | 672 | a->command, a->action_type, a->terminal); |
688 | } | 673 | } |
689 | 674 | ||
690 | static void delete_init_action(struct init_action *action) | 675 | static void delete_init_action(struct init_action *action) |
@@ -714,7 +699,7 @@ static void delete_init_action(struct init_action *action) | |||
714 | static void parse_inittab(void) | 699 | static void parse_inittab(void) |
715 | { | 700 | { |
716 | FILE *file; | 701 | FILE *file; |
717 | char buf[INIT_BUFFS_SIZE]; | 702 | char buf[COMMAND_SIZE]; |
718 | 703 | ||
719 | if (ENABLE_FEATURE_USE_INITTAB) | 704 | if (ENABLE_FEATURE_USE_INITTAB) |
720 | file = fopen(INITTAB, "r"); | 705 | file = fopen(INITTAB, "r"); |
@@ -743,7 +728,7 @@ static void parse_inittab(void) | |||
743 | return; | 728 | return; |
744 | } | 729 | } |
745 | 730 | ||
746 | while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { | 731 | while (fgets(buf, COMMAND_SIZE, file) != NULL) { |
747 | static const char actions[] = | 732 | static const char actions[] = |
748 | STR_SYSINIT "sysinit\0" | 733 | STR_SYSINIT "sysinit\0" |
749 | STR_RESPAWN "respawn\0" | 734 | STR_RESPAWN "respawn\0" |
@@ -810,7 +795,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |||
810 | 795 | ||
811 | /* disable old entrys */ | 796 | /* disable old entrys */ |
812 | for (a = init_action_list; a; a = a->next) { | 797 | for (a = init_action_list; a; a = a->next) { |
813 | a->action = ONCE; | 798 | a->action_type = ONCE; |
814 | } | 799 | } |
815 | 800 | ||
816 | parse_inittab(); | 801 | parse_inittab(); |
@@ -819,7 +804,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |||
819 | /* Be nice and send SIGTERM first */ | 804 | /* Be nice and send SIGTERM first */ |
820 | for (a = init_action_list; a; a = a->next) { | 805 | for (a = init_action_list; a; a = a->next) { |
821 | pid_t pid = a->pid; | 806 | pid_t pid = a->pid; |
822 | if ((a->action & ONCE) && pid != 0) { | 807 | if ((a->action_type & ONCE) && pid != 0) { |
823 | kill(pid, SIGTERM); | 808 | kill(pid, SIGTERM); |
824 | } | 809 | } |
825 | } | 810 | } |
@@ -828,7 +813,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |||
828 | sleep(CONFIG_FEATURE_KILL_DELAY); | 813 | sleep(CONFIG_FEATURE_KILL_DELAY); |
829 | for (a = init_action_list; a; a = a->next) { | 814 | for (a = init_action_list; a; a = a->next) { |
830 | pid_t pid = a->pid; | 815 | pid_t pid = a->pid; |
831 | if ((a->action & ONCE) && pid != 0) { | 816 | if ((a->action_type & ONCE) && pid != 0) { |
832 | kill(pid, SIGKILL); | 817 | kill(pid, SIGKILL); |
833 | } | 818 | } |
834 | } | 819 | } |
@@ -840,7 +825,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |||
840 | /* remove unused entrys */ | 825 | /* remove unused entrys */ |
841 | for (a = init_action_list; a; a = tmp) { | 826 | for (a = init_action_list; a; a = tmp) { |
842 | tmp = a->next; | 827 | tmp = a->next; |
843 | if ((a->action & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { | 828 | if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { |
844 | delete_init_action(a); | 829 | delete_init_action(a); |
845 | } | 830 | } |
846 | } | 831 | } |
@@ -998,7 +983,7 @@ int init_main(int argc, char **argv) | |||
998 | * restarted by run_actions() */ | 983 | * restarted by run_actions() */ |
999 | a->pid = 0; | 984 | a->pid = 0; |
1000 | message(L_LOG, "process '%s' (pid %d) exited. " | 985 | message(L_LOG, "process '%s' (pid %d) exited. " |
1001 | "Scheduling it for restart.", | 986 | "Scheduling for restart.", |
1002 | a->command, wpid); | 987 | a->command, wpid); |
1003 | } | 988 | } |
1004 | } | 989 | } |