summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 02:57:07 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-19 02:57:07 +0000
commita37e7134f76b7661b86bb9cc926f28f81b1e1109 (patch)
tree88c511c1f1094c3c4207523e31db5fdf7bda6069
parent92657d484f4f95ce4579ad095c9caf596a737e5b (diff)
downloadbusybox-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
-rw-r--r--init/Config.in15
-rw-r--r--init/init.c189
2 files changed, 96 insertions, 108 deletions
diff --git a/init/Config.in b/init/Config.in
index 4c5610246..f525abc8a 100644
--- a/init/Config.in
+++ b/init/Config.in
@@ -47,15 +47,18 @@ config FEATURE_KILL_DELAY
47 wrong process!) 47 wrong process!)
48 48
49config FEATURE_INIT_SCTTY 49config FEATURE_INIT_SCTTY
50 bool "Support running commands with a controlling-tty" 50 bool "Run commands with leading dash with controlling tty"
51 default n 51 default n
52 depends on INIT 52 depends on INIT
53 help 53 help
54 If this option is enabled a command starting with hyphen (-) 54 If this option is enabled, init will try to give a controlling
55 is run in its own session (setsid(2)) and possibly with a 55 tty to any command which has leading hyphen (often it's "-/bin/sh").
56 controlling tty (TIOCSCTTY). This is not the traditional init 56 More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
57 behavour, but is often what you want in an embedded system where 57 If device attached to STDIN_FILENO can be a ctty but is not yet
58 the console is only accessed during development or for maintenance. 58 a ctty for other session, it will become this process' ctty.
59 This is not the traditional init behavour, but is often what you want
60 in an embedded system where the console is only accessed during
61 development or for maintenance.
59 NB: using cttyhack applet may work better. 62 NB: using cttyhack applet may work better.
60 63
61config FEATURE_INIT_SYSLOG 64config FEATURE_INIT_SYSLOG
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 @@
55struct init_action { 55struct 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 */
302static 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 */
298static pid_t run(const struct init_action *a) 345static 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 */
484static void run_actions(int action) 472static 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 */
594static void exec_restart_action(int sig ATTRIBUTE_UNUSED) 582static 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
657static void new_init_action(uint8_t action, const char *command, const char *cons) 641static 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
690static void delete_init_action(struct init_action *action) 675static void delete_init_action(struct init_action *action)
@@ -714,7 +699,7 @@ static void delete_init_action(struct init_action *action)
714static void parse_inittab(void) 699static 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 }