diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-21 23:27:30 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-21 23:27:30 +0000 |
commit | 1359da6ac7f7f44f82d224e61cc2c6ecb58baeef (patch) | |
tree | 0fce9fa95cef2293e24a5626a88b60c59b11a865 /shell/hush.c | |
parent | 762d35c75fe7001847adf85b5cf8279d53f627d7 (diff) | |
download | busybox-w32-1359da6ac7f7f44f82d224e61cc2c6ecb58baeef.tar.gz busybox-w32-1359da6ac7f7f44f82d224e61cc2c6ecb58baeef.tar.bz2 busybox-w32-1359da6ac7f7f44f82d224e61cc2c6ecb58baeef.zip |
hush: make Ctrl-Z work (at least sometimes)
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 400 |
1 files changed, 224 insertions, 176 deletions
diff --git a/shell/hush.c b/shell/hush.c index b367a08b2..e2ce3676d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -82,7 +82,9 @@ | |||
82 | #include <getopt.h> /* should be pretty obvious */ | 82 | #include <getopt.h> /* should be pretty obvious */ |
83 | 83 | ||
84 | /* #include <dmalloc.h> */ | 84 | /* #include <dmalloc.h> */ |
85 | /* #define DEBUG_SHELL */ | 85 | //#define DEBUG_SHELL |
86 | /* Finer-grained debug switch */ | ||
87 | //#define DEBUG_SHELL_JOBS | ||
86 | 88 | ||
87 | 89 | ||
88 | #define SPECIAL_VAR_SYMBOL 03 | 90 | #define SPECIAL_VAR_SYMBOL 03 |
@@ -274,9 +276,9 @@ struct in_str { | |||
274 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" | 276 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" |
275 | 277 | ||
276 | struct built_in_command { | 278 | struct built_in_command { |
277 | const char *cmd; /* name */ | 279 | const char *cmd; /* name */ |
278 | const char *descr; /* description */ | 280 | const char *descr; /* description */ |
279 | int (*function) (struct child_prog *); /* function ptr */ | 281 | int (*function) (char **argv); /* function ptr */ |
280 | }; | 282 | }; |
281 | 283 | ||
282 | /* belongs in busybox.h */ | 284 | /* belongs in busybox.h */ |
@@ -285,24 +287,24 @@ static int max(int a, int b) | |||
285 | return (a > b) ? a : b; | 287 | return (a > b) ? a : b; |
286 | } | 288 | } |
287 | 289 | ||
288 | /* This should be in utility.c */ | ||
289 | #ifdef DEBUG_SHELL | 290 | #ifdef DEBUG_SHELL |
290 | static void debug_printf(const char *format, ...) | 291 | #define debug_printf(...) fprintf(stderr, __VA_ARGS__) |
291 | { | ||
292 | va_list args; | ||
293 | va_start(args, format); | ||
294 | vfprintf(stderr, format, args); | ||
295 | va_end(args); | ||
296 | } | ||
297 | /* broken, of course, but OK for testing */ | 292 | /* broken, of course, but OK for testing */ |
298 | static char *indenter(int i) | 293 | static char *indenter(int i) |
299 | { | 294 | { |
300 | static char blanks[] = " "; | 295 | static char blanks[] = " "; |
301 | return &blanks[sizeof(blanks)-i-1]; | 296 | return &blanks[sizeof(blanks) - i - 1]; |
302 | } | 297 | } |
303 | #else | 298 | #else |
304 | #define debug_printf(...) do {} while (0) | 299 | #define debug_printf(...) do {} while (0) |
305 | #endif | 300 | #endif |
301 | |||
302 | #ifdef DEBUG_SHELL_JOBS | ||
303 | #define debug_jobs_printf(...) fprintf(stderr, __VA_ARGS__) | ||
304 | #else | ||
305 | #define debug_jobs_printf(...) do {} while (0) | ||
306 | #endif | ||
307 | |||
306 | #define final_printf debug_printf | 308 | #define final_printf debug_printf |
307 | 309 | ||
308 | static void __syntax(const char *file, int line) | 310 | static void __syntax(const char *file, int line) |
@@ -314,23 +316,23 @@ static void __syntax(const char *file, int line) | |||
314 | 316 | ||
315 | /* Index of subroutines: */ | 317 | /* Index of subroutines: */ |
316 | /* function prototypes for builtins */ | 318 | /* function prototypes for builtins */ |
317 | static int builtin_cd(struct child_prog *child); | 319 | static int builtin_cd(char **argv); |
318 | static int builtin_env(struct child_prog *child); | 320 | static int builtin_env(char **argv); |
319 | static int builtin_eval(struct child_prog *child); | 321 | static int builtin_eval(char **argv); |
320 | static int builtin_exec(struct child_prog *child); | 322 | static int builtin_exec(char **argv); |
321 | static int builtin_exit(struct child_prog *child); | 323 | static int builtin_exit(char **argv); |
322 | static int builtin_export(struct child_prog *child); | 324 | static int builtin_export(char **argv); |
323 | static int builtin_fg_bg(struct child_prog *child); | 325 | static int builtin_fg_bg(char **argv); |
324 | static int builtin_help(struct child_prog *child); | 326 | static int builtin_help(char **argv); |
325 | static int builtin_jobs(struct child_prog *child); | 327 | static int builtin_jobs(char **argv); |
326 | static int builtin_pwd(struct child_prog *child); | 328 | static int builtin_pwd(char **argv); |
327 | static int builtin_read(struct child_prog *child); | 329 | static int builtin_read(char **argv); |
328 | static int builtin_set(struct child_prog *child); | 330 | static int builtin_set(char **argv); |
329 | static int builtin_shift(struct child_prog *child); | 331 | static int builtin_shift(char **argv); |
330 | static int builtin_source(struct child_prog *child); | 332 | static int builtin_source(char **argv); |
331 | static int builtin_umask(struct child_prog *child); | 333 | static int builtin_umask(char **argv); |
332 | static int builtin_unset(struct child_prog *child); | 334 | static int builtin_unset(char **argv); |
333 | static int builtin_not_written(struct child_prog *child); | 335 | static int builtin_not_written(char **argv); |
334 | /* o_string manipulation: */ | 336 | /* o_string manipulation: */ |
335 | static int b_check_space(o_string *o, int len); | 337 | static int b_check_space(o_string *o, int len); |
336 | static int b_addchr(o_string *o, int ch); | 338 | static int b_addchr(o_string *o, int ch); |
@@ -354,6 +356,7 @@ static int free_pipe(struct pipe *pi, int indent); | |||
354 | /* really run the final data structures: */ | 356 | /* really run the final data structures: */ |
355 | static int setup_redirects(struct child_prog *prog, int squirrel[]); | 357 | static int setup_redirects(struct child_prog *prog, int squirrel[]); |
356 | static int run_list_real(struct pipe *pi); | 358 | static int run_list_real(struct pipe *pi); |
359 | static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; | ||
357 | static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; | 360 | static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; |
358 | static int run_pipe_real(struct pipe *pi); | 361 | static int run_pipe_real(struct pipe *pi); |
359 | /* extended glob support: */ | 362 | /* extended glob support: */ |
@@ -387,6 +390,7 @@ static int checkjobs(struct pipe* fg_pipe); | |||
387 | static int checkjobs_and_fg_shell(struct pipe* fg_pipe); | 390 | static int checkjobs_and_fg_shell(struct pipe* fg_pipe); |
388 | static void insert_bg_job(struct pipe *pi); | 391 | static void insert_bg_job(struct pipe *pi); |
389 | static void remove_bg_job(struct pipe *pi); | 392 | static void remove_bg_job(struct pipe *pi); |
393 | static void delete_finished_bg_job(struct pipe *pi); | ||
390 | /* local variable support */ | 394 | /* local variable support */ |
391 | static char **make_list_in(char **inp, char *name); | 395 | static char **make_list_in(char **inp, char *name); |
392 | static char *insert_var_value(char *inp); | 396 | static char *insert_var_value(char *inp); |
@@ -503,18 +507,14 @@ static const char *set_cwd(void) | |||
503 | return cwd; | 507 | return cwd; |
504 | } | 508 | } |
505 | 509 | ||
506 | // It seems ALL built-ins ever use *only* child->argv in child param. | ||
507 | // Passing argv directly may make 'child->argv += n' modifications | ||
508 | // unneeded on vfork codepaths. | ||
509 | |||
510 | /* built-in 'eval' handler */ | 510 | /* built-in 'eval' handler */ |
511 | static int builtin_eval(struct child_prog *child) | 511 | static int builtin_eval(char **argv) |
512 | { | 512 | { |
513 | char *str = NULL; | 513 | char *str = NULL; |
514 | int rcode = EXIT_SUCCESS; | 514 | int rcode = EXIT_SUCCESS; |
515 | 515 | ||
516 | if (child->argv[1]) { | 516 | if (argv[1]) { |
517 | str = make_string(child->argv + 1); | 517 | str = make_string(argv + 1); |
518 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | | 518 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | |
519 | FLAG_PARSE_SEMICOLON); | 519 | FLAG_PARSE_SEMICOLON); |
520 | free(str); | 520 | free(str); |
@@ -524,13 +524,13 @@ static int builtin_eval(struct child_prog *child) | |||
524 | } | 524 | } |
525 | 525 | ||
526 | /* built-in 'cd <path>' handler */ | 526 | /* built-in 'cd <path>' handler */ |
527 | static int builtin_cd(struct child_prog *child) | 527 | static int builtin_cd(char **argv) |
528 | { | 528 | { |
529 | char *newdir; | 529 | char *newdir; |
530 | if (child->argv[1] == NULL) | 530 | if (argv[1] == NULL) |
531 | newdir = getenv("HOME"); | 531 | newdir = getenv("HOME"); |
532 | else | 532 | else |
533 | newdir = child->argv[1]; | 533 | newdir = argv[1]; |
534 | if (chdir(newdir)) { | 534 | if (chdir(newdir)) { |
535 | printf("cd: %s: %s\n", newdir, strerror(errno)); | 535 | printf("cd: %s: %s\n", newdir, strerror(errno)); |
536 | return EXIT_FAILURE; | 536 | return EXIT_FAILURE; |
@@ -540,7 +540,7 @@ static int builtin_cd(struct child_prog *child) | |||
540 | } | 540 | } |
541 | 541 | ||
542 | /* built-in 'env' handler */ | 542 | /* built-in 'env' handler */ |
543 | static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED) | 543 | static int builtin_env(char **argv ATTRIBUTE_UNUSED) |
544 | { | 544 | { |
545 | /* TODO: call env applet's code instead */ | 545 | /* TODO: call env applet's code instead */ |
546 | char **e = environ; | 546 | char **e = environ; |
@@ -553,37 +553,36 @@ static int builtin_env(struct child_prog *dummy ATTRIBUTE_UNUSED) | |||
553 | } | 553 | } |
554 | 554 | ||
555 | /* built-in 'exec' handler */ | 555 | /* built-in 'exec' handler */ |
556 | static int builtin_exec(struct child_prog *child) | 556 | static int builtin_exec(char **argv) |
557 | { | 557 | { |
558 | if (child->argv[1] == NULL) | 558 | if (argv[1] == NULL) |
559 | return EXIT_SUCCESS; /* Really? */ | 559 | return EXIT_SUCCESS; /* Really? */ |
560 | child->argv++; | 560 | pseudo_exec_argv(argv + 1); |
561 | pseudo_exec(child); | ||
562 | /* never returns */ | 561 | /* never returns */ |
563 | } | 562 | } |
564 | 563 | ||
565 | /* built-in 'exit' handler */ | 564 | /* built-in 'exit' handler */ |
566 | static int builtin_exit(struct child_prog *child) | 565 | static int builtin_exit(char **argv) |
567 | { | 566 | { |
568 | // TODO: bash does it ONLY on top-level sh exit (+interacive only?) | 567 | // TODO: bash does it ONLY on top-level sh exit (+interacive only?) |
569 | //puts("exit"); /* bash does it */ | 568 | //puts("exit"); /* bash does it */ |
570 | 569 | ||
571 | if (child->argv[1] == NULL) | 570 | if (argv[1] == NULL) |
572 | hush_exit(last_return_code); | 571 | hush_exit(last_return_code); |
573 | /* mimic bash: exit 123abc == exit 255 + error msg */ | 572 | /* mimic bash: exit 123abc == exit 255 + error msg */ |
574 | xfunc_error_retval = 255; | 573 | xfunc_error_retval = 255; |
575 | /* bash: exit -2 == exit 254, no error msg */ | 574 | /* bash: exit -2 == exit 254, no error msg */ |
576 | hush_exit(xatoi(child->argv[1])); | 575 | hush_exit(xatoi(argv[1])); |
577 | } | 576 | } |
578 | 577 | ||
579 | /* built-in 'export VAR=value' handler */ | 578 | /* built-in 'export VAR=value' handler */ |
580 | static int builtin_export(struct child_prog *child) | 579 | static int builtin_export(char **argv) |
581 | { | 580 | { |
582 | int res = 0; | 581 | int res = 0; |
583 | char *name = child->argv[1]; | 582 | char *name = argv[1]; |
584 | 583 | ||
585 | if (name == NULL) { | 584 | if (name == NULL) { |
586 | return builtin_env(child); | 585 | return builtin_env(argv); |
587 | } | 586 | } |
588 | 587 | ||
589 | name = strdup(name); | 588 | name = strdup(name); |
@@ -624,7 +623,7 @@ static int builtin_export(struct child_prog *child) | |||
624 | } | 623 | } |
625 | 624 | ||
626 | /* built-in 'fg' and 'bg' handler */ | 625 | /* built-in 'fg' and 'bg' handler */ |
627 | static int builtin_fg_bg(struct child_prog *child) | 626 | static int builtin_fg_bg(char **argv) |
628 | { | 627 | { |
629 | int i, jobnum; | 628 | int i, jobnum; |
630 | struct pipe *pi; | 629 | struct pipe *pi; |
@@ -632,17 +631,17 @@ static int builtin_fg_bg(struct child_prog *child) | |||
632 | if (!interactive_fd) | 631 | if (!interactive_fd) |
633 | return EXIT_FAILURE; | 632 | return EXIT_FAILURE; |
634 | /* If they gave us no args, assume they want the last backgrounded task */ | 633 | /* If they gave us no args, assume they want the last backgrounded task */ |
635 | if (!child->argv[1]) { | 634 | if (!argv[1]) { |
636 | for (pi = job_list; pi; pi = pi->next) { | 635 | for (pi = job_list; pi; pi = pi->next) { |
637 | if (pi->jobid == last_jobid) { | 636 | if (pi->jobid == last_jobid) { |
638 | goto found; | 637 | goto found; |
639 | } | 638 | } |
640 | } | 639 | } |
641 | bb_error_msg("%s: no current job", child->argv[0]); | 640 | bb_error_msg("%s: no current job", argv[0]); |
642 | return EXIT_FAILURE; | 641 | return EXIT_FAILURE; |
643 | } | 642 | } |
644 | if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { | 643 | if (sscanf(argv[1], "%%%d", &jobnum) != 1) { |
645 | bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); | 644 | bb_error_msg("%s: bad argument '%s'", argv[0], argv[1]); |
646 | return EXIT_FAILURE; | 645 | return EXIT_FAILURE; |
647 | } | 646 | } |
648 | for (pi = job_list; pi; pi = pi->next) { | 647 | for (pi = job_list; pi; pi = pi->next) { |
@@ -650,37 +649,42 @@ static int builtin_fg_bg(struct child_prog *child) | |||
650 | goto found; | 649 | goto found; |
651 | } | 650 | } |
652 | } | 651 | } |
653 | bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); | 652 | bb_error_msg("%s: %d: no such job", argv[0], jobnum); |
654 | return EXIT_FAILURE; | 653 | return EXIT_FAILURE; |
655 | found: | 654 | found: |
656 | // TODO: bash prints a string representation | 655 | // TODO: bash prints a string representation |
657 | // of job being foregrounded (like "sleep 1 | cat") | 656 | // of job being foregrounded (like "sleep 1 | cat") |
658 | if (*child->argv[0] == 'f') { | 657 | if (*argv[0] == 'f') { |
659 | /* Put the job into the foreground. */ | 658 | /* Put the job into the foreground. */ |
660 | tcsetpgrp(interactive_fd, pi->pgrp); | 659 | tcsetpgrp(interactive_fd, pi->pgrp); |
661 | } | 660 | } |
662 | 661 | ||
663 | /* Restart the processes in the job */ | 662 | /* Restart the processes in the job */ |
664 | for (i = 0; i < pi->num_progs; i++) | 663 | debug_jobs_printf("reviving %d procs, pgrp %d\n", pi->num_progs, pi->pgrp); |
664 | for (i = 0; i < pi->num_progs; i++) { | ||
665 | debug_jobs_printf("reviving pid %d\n", pi->progs[i].pid); | ||
665 | pi->progs[i].is_stopped = 0; | 666 | pi->progs[i].is_stopped = 0; |
667 | } | ||
668 | pi->stopped_progs = 0; | ||
666 | 669 | ||
667 | i = kill(- pi->pgrp, SIGCONT); | 670 | i = kill(- pi->pgrp, SIGCONT); |
668 | pi->stopped_progs = 0; | ||
669 | if (i < 0) { | 671 | if (i < 0) { |
670 | if (errno == ESRCH) { | 672 | if (errno == ESRCH) { |
671 | remove_bg_job(pi); | 673 | delete_finished_bg_job(pi); |
672 | } else { | 674 | } else { |
673 | bb_perror_msg("kill (SIGCONT)"); | 675 | bb_perror_msg("kill (SIGCONT)"); |
674 | } | 676 | } |
675 | } | 677 | } |
676 | 678 | ||
677 | if (*child->argv[0] == 'f') | 679 | if (*argv[0] == 'f') { |
680 | remove_bg_job(pi); | ||
678 | return checkjobs_and_fg_shell(pi); | 681 | return checkjobs_and_fg_shell(pi); |
682 | } | ||
679 | return EXIT_SUCCESS; | 683 | return EXIT_SUCCESS; |
680 | } | 684 | } |
681 | 685 | ||
682 | /* built-in 'help' handler */ | 686 | /* built-in 'help' handler */ |
683 | static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED) | 687 | static int builtin_help(char **argv ATTRIBUTE_UNUSED) |
684 | { | 688 | { |
685 | const struct built_in_command *x; | 689 | const struct built_in_command *x; |
686 | 690 | ||
@@ -696,7 +700,7 @@ static int builtin_help(struct child_prog *dummy ATTRIBUTE_UNUSED) | |||
696 | } | 700 | } |
697 | 701 | ||
698 | /* built-in 'jobs' handler */ | 702 | /* built-in 'jobs' handler */ |
699 | static int builtin_jobs(struct child_prog *child ATTRIBUTE_UNUSED) | 703 | static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) |
700 | { | 704 | { |
701 | struct pipe *job; | 705 | struct pipe *job; |
702 | const char *status_string; | 706 | const char *status_string; |
@@ -713,18 +717,18 @@ static int builtin_jobs(struct child_prog *child ATTRIBUTE_UNUSED) | |||
713 | } | 717 | } |
714 | 718 | ||
715 | /* built-in 'pwd' handler */ | 719 | /* built-in 'pwd' handler */ |
716 | static int builtin_pwd(struct child_prog *dummy ATTRIBUTE_UNUSED) | 720 | static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) |
717 | { | 721 | { |
718 | puts(set_cwd()); | 722 | puts(set_cwd()); |
719 | return EXIT_SUCCESS; | 723 | return EXIT_SUCCESS; |
720 | } | 724 | } |
721 | 725 | ||
722 | /* built-in 'read VAR' handler */ | 726 | /* built-in 'read VAR' handler */ |
723 | static int builtin_read(struct child_prog *child) | 727 | static int builtin_read(char **argv) |
724 | { | 728 | { |
725 | int res; | 729 | int res; |
726 | 730 | ||
727 | if (child->argv[1]) { | 731 | if (argv[1]) { |
728 | char string[BUFSIZ]; | 732 | char string[BUFSIZ]; |
729 | char *var = NULL; | 733 | char *var = NULL; |
730 | 734 | ||
@@ -732,9 +736,9 @@ static int builtin_read(struct child_prog *child) | |||
732 | /* read string */ | 736 | /* read string */ |
733 | fgets(string, sizeof(string), stdin); | 737 | fgets(string, sizeof(string), stdin); |
734 | chomp(string); | 738 | chomp(string); |
735 | var = malloc(strlen(child->argv[1]) + strlen(string) + 2); | 739 | var = malloc(strlen(argv[1]) + strlen(string) + 2); |
736 | if (var) { | 740 | if (var) { |
737 | sprintf(var, "%s=%s", child->argv[1], string); | 741 | sprintf(var, "%s=%s", argv[1], string); |
738 | res = set_local_var(var, 0); | 742 | res = set_local_var(var, 0); |
739 | } else | 743 | } else |
740 | res = -1; | 744 | res = -1; |
@@ -748,9 +752,9 @@ static int builtin_read(struct child_prog *child) | |||
748 | } | 752 | } |
749 | 753 | ||
750 | /* built-in 'set VAR=value' handler */ | 754 | /* built-in 'set VAR=value' handler */ |
751 | static int builtin_set(struct child_prog *child) | 755 | static int builtin_set(char **argv) |
752 | { | 756 | { |
753 | char *temp = child->argv[1]; | 757 | char *temp = argv[1]; |
754 | struct variables *e; | 758 | struct variables *e; |
755 | 759 | ||
756 | if (temp == NULL) | 760 | if (temp == NULL) |
@@ -764,11 +768,11 @@ static int builtin_set(struct child_prog *child) | |||
764 | 768 | ||
765 | 769 | ||
766 | /* Built-in 'shift' handler */ | 770 | /* Built-in 'shift' handler */ |
767 | static int builtin_shift(struct child_prog *child) | 771 | static int builtin_shift(char **argv) |
768 | { | 772 | { |
769 | int n = 1; | 773 | int n = 1; |
770 | if (child->argv[1]) { | 774 | if (argv[1]) { |
771 | n = atoi(child->argv[1]); | 775 | n = atoi(argv[1]); |
772 | } | 776 | } |
773 | if (n >= 0 && n < global_argc) { | 777 | if (n >= 0 && n < global_argc) { |
774 | /* XXX This probably breaks $0 */ | 778 | /* XXX This probably breaks $0 */ |
@@ -780,25 +784,25 @@ static int builtin_shift(struct child_prog *child) | |||
780 | } | 784 | } |
781 | 785 | ||
782 | /* Built-in '.' handler (read-in and execute commands from file) */ | 786 | /* Built-in '.' handler (read-in and execute commands from file) */ |
783 | static int builtin_source(struct child_prog *child) | 787 | static int builtin_source(char **argv) |
784 | { | 788 | { |
785 | FILE *input; | 789 | FILE *input; |
786 | int status; | 790 | int status; |
787 | 791 | ||
788 | if (child->argv[1] == NULL) | 792 | if (argv[1] == NULL) |
789 | return EXIT_FAILURE; | 793 | return EXIT_FAILURE; |
790 | 794 | ||
791 | /* XXX search through $PATH is missing */ | 795 | /* XXX search through $PATH is missing */ |
792 | input = fopen(child->argv[1], "r"); | 796 | input = fopen(argv[1], "r"); |
793 | if (!input) { | 797 | if (!input) { |
794 | bb_error_msg("cannot open '%s'", child->argv[1]); | 798 | bb_error_msg("cannot open '%s'", argv[1]); |
795 | return EXIT_FAILURE; | 799 | return EXIT_FAILURE; |
796 | } | 800 | } |
797 | 801 | ||
798 | /* Now run the file */ | 802 | /* Now run the file */ |
799 | /* XXX argv and argc are broken; need to save old global_argv | 803 | /* XXX argv and argc are broken; need to save old global_argv |
800 | * (pointer only is OK!) on this stack frame, | 804 | * (pointer only is OK!) on this stack frame, |
801 | * set global_argv=child->argv+1, recurse, and restore. */ | 805 | * set global_argv=argv+1, recurse, and restore. */ |
802 | mark_open(fileno(input)); | 806 | mark_open(fileno(input)); |
803 | status = parse_file_outer(input); | 807 | status = parse_file_outer(input); |
804 | mark_closed(fileno(input)); | 808 | mark_closed(fileno(input)); |
@@ -806,10 +810,10 @@ static int builtin_source(struct child_prog *child) | |||
806 | return status; | 810 | return status; |
807 | } | 811 | } |
808 | 812 | ||
809 | static int builtin_umask(struct child_prog *child) | 813 | static int builtin_umask(char **argv) |
810 | { | 814 | { |
811 | mode_t new_umask; | 815 | mode_t new_umask; |
812 | const char *arg = child->argv[1]; | 816 | const char *arg = argv[1]; |
813 | char *end; | 817 | char *end; |
814 | if (arg) { | 818 | if (arg) { |
815 | new_umask = strtoul(arg, &end, 8); | 819 | new_umask = strtoul(arg, &end, 8); |
@@ -825,16 +829,16 @@ static int builtin_umask(struct child_prog *child) | |||
825 | } | 829 | } |
826 | 830 | ||
827 | /* built-in 'unset VAR' handler */ | 831 | /* built-in 'unset VAR' handler */ |
828 | static int builtin_unset(struct child_prog *child) | 832 | static int builtin_unset(char **argv) |
829 | { | 833 | { |
830 | /* bash returned already true */ | 834 | /* bash returned already true */ |
831 | unset_local_var(child->argv[1]); | 835 | unset_local_var(argv[1]); |
832 | return EXIT_SUCCESS; | 836 | return EXIT_SUCCESS; |
833 | } | 837 | } |
834 | 838 | ||
835 | static int builtin_not_written(struct child_prog *child) | 839 | static int builtin_not_written(char **argv) |
836 | { | 840 | { |
837 | printf("builtin_%s not written\n", child->argv[0]); | 841 | printf("builtin_%s not written\n", argv[0]); |
838 | return EXIT_FAILURE; | 842 | return EXIT_FAILURE; |
839 | } | 843 | } |
840 | 844 | ||
@@ -1132,68 +1136,71 @@ static void restore_redirects(int squirrel[]) | |||
1132 | /* XXX no exit() here. If you don't exec, use _exit instead. | 1136 | /* XXX no exit() here. If you don't exec, use _exit instead. |
1133 | * The at_exit handlers apparently confuse the calling process, | 1137 | * The at_exit handlers apparently confuse the calling process, |
1134 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ | 1138 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ |
1135 | static void pseudo_exec(struct child_prog *child) | 1139 | static void pseudo_exec_argv(char **argv) |
1136 | { | 1140 | { |
1137 | int i, rcode; | 1141 | int i, rcode; |
1138 | char *p; | 1142 | char *p; |
1139 | const struct built_in_command *x; | 1143 | const struct built_in_command *x; |
1140 | 1144 | ||
1141 | if (child->argv) { | 1145 | for (i = 0; is_assignment(argv[i]); i++) { |
1142 | for (i = 0; is_assignment(child->argv[i]); i++) { | 1146 | debug_printf("pid %d environment modification: %s\n", |
1143 | debug_printf("pid %d environment modification: %s\n", | 1147 | getpid(), argv[i]); |
1144 | getpid(), child->argv[i]); | 1148 | // FIXME: vfork case?? |
1145 | // FIXME: vfork case?? | 1149 | p = insert_var_value(argv[i]); |
1146 | p = insert_var_value(child->argv[i]); | 1150 | putenv(strdup(p)); |
1147 | putenv(strdup(p)); | 1151 | if (p != argv[i]) |
1148 | if (p != child->argv[i]) | 1152 | free(p); |
1149 | free(p); | 1153 | } |
1150 | } | 1154 | argv += i; |
1151 | child->argv += i; /* XXX this hack isn't so horrible, since we are about | 1155 | /* If a variable is assigned in a forest, and nobody listens, |
1152 | to exit, and therefore don't need to keep data | 1156 | * was it ever really set? |
1153 | structures consistent for free() use. */ | 1157 | */ |
1154 | // FIXME: ...unless we have _vforked_! Think NOMMU! | 1158 | if (argv[0] == NULL) { |
1155 | 1159 | _exit(EXIT_SUCCESS); | |
1156 | /* If a variable is assigned in a forest, and nobody listens, | 1160 | } |
1157 | * was it ever really set? | ||
1158 | */ | ||
1159 | if (child->argv[0] == NULL) { | ||
1160 | _exit(EXIT_SUCCESS); | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * Check if the command matches any of the builtins. | ||
1165 | * Depending on context, this might be redundant. But it's | ||
1166 | * easier to waste a few CPU cycles than it is to figure out | ||
1167 | * if this is one of those cases. | ||
1168 | */ | ||
1169 | for (x = bltins; x->cmd; x++) { | ||
1170 | if (strcmp(child->argv[0], x->cmd) == 0) { | ||
1171 | debug_printf("builtin exec %s\n", child->argv[0]); | ||
1172 | rcode = x->function(child); | ||
1173 | fflush(stdout); | ||
1174 | _exit(rcode); | ||
1175 | } | ||
1176 | } | ||
1177 | 1161 | ||
1178 | /* Check if the command matches any busybox internal commands | 1162 | /* |
1179 | * ("applets") here. | 1163 | * Check if the command matches any of the builtins. |
1180 | * FIXME: This feature is not 100% safe, since | 1164 | * Depending on context, this might be redundant. But it's |
1181 | * BusyBox is not fully reentrant, so we have no guarantee the things | 1165 | * easier to waste a few CPU cycles than it is to figure out |
1182 | * from the .bss are still zeroed, or that things from .data are still | 1166 | * if this is one of those cases. |
1183 | * at their defaults. We could exec ourself from /proc/self/exe, but I | 1167 | */ |
1184 | * really dislike relying on /proc for things. We could exec ourself | 1168 | for (x = bltins; x->cmd; x++) { |
1185 | * from global_argv[0], but if we are in a chroot, we may not be able | 1169 | if (strcmp(argv[0], x->cmd) == 0) { |
1186 | * to find ourself... */ | 1170 | debug_printf("builtin exec %s\n", argv[0]); |
1171 | rcode = x->function(argv); | ||
1172 | fflush(stdout); | ||
1173 | _exit(rcode); | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | /* Check if the command matches any busybox internal commands | ||
1178 | * ("applets") here. | ||
1179 | * FIXME: This feature is not 100% safe, since | ||
1180 | * BusyBox is not fully reentrant, so we have no guarantee the things | ||
1181 | * from the .bss are still zeroed, or that things from .data are still | ||
1182 | * at their defaults. We could exec ourself from /proc/self/exe, but I | ||
1183 | * really dislike relying on /proc for things. We could exec ourself | ||
1184 | * from global_argv[0], but if we are in a chroot, we may not be able | ||
1185 | * to find ourself... */ | ||
1187 | #if ENABLE_FEATURE_SH_STANDALONE | 1186 | #if ENABLE_FEATURE_SH_STANDALONE |
1188 | debug_printf("running applet %s\n", child->argv[0]); | 1187 | debug_printf("running applet %s\n", argv[0]); |
1189 | run_applet_and_exit(child->argv[0], child->argv); | 1188 | run_applet_and_exit(argv[0], argv); |
1190 | // is it ok that run_applet_and_exit() does exit(), not _exit()? | 1189 | // is it ok that run_applet_and_exit() does exit(), not _exit()? |
1191 | // NB: IIRC on NOMMU we are after _vfork_, not fork! | 1190 | // NB: IIRC on NOMMU we are after _vfork_, not fork! |
1192 | #endif | 1191 | #endif |
1193 | debug_printf("exec of %s\n", child->argv[0]); | 1192 | debug_printf("exec of %s\n", argv[0]); |
1194 | execvp(child->argv[0], child->argv); | 1193 | execvp(argv[0], argv); |
1195 | bb_perror_msg("cannot exec '%s'", child->argv[0]); | 1194 | bb_perror_msg("cannot exec '%s'", argv[0]); |
1196 | _exit(1); | 1195 | _exit(1); |
1196 | } | ||
1197 | |||
1198 | static void pseudo_exec(struct child_prog *child) | ||
1199 | { | ||
1200 | int rcode; | ||
1201 | |||
1202 | if (child->argv) { | ||
1203 | pseudo_exec_argv(child->argv); | ||
1197 | } | 1204 | } |
1198 | 1205 | ||
1199 | if (child->group) { | 1206 | if (child->group) { |
@@ -1233,13 +1240,17 @@ static void insert_bg_job(struct pipe *pi) | |||
1233 | 1240 | ||
1234 | /* physically copy the struct job */ | 1241 | /* physically copy the struct job */ |
1235 | memcpy(thejob, pi, sizeof(struct pipe)); | 1242 | memcpy(thejob, pi, sizeof(struct pipe)); |
1243 | // (pi->num_progs+1) is one-too-many I think? | ||
1244 | thejob->progs = xmalloc(sizeof(pi->progs[0]) * (pi->num_progs+1)); | ||
1245 | memcpy(thejob->progs, pi->progs, sizeof(pi->progs[0]) * (pi->num_progs+1)); | ||
1236 | thejob->next = NULL; | 1246 | thejob->next = NULL; |
1237 | thejob->running_progs = thejob->num_progs; | 1247 | /*seems to be wrong:*/ |
1238 | thejob->stopped_progs = 0; | 1248 | /*thejob->running_progs = thejob->num_progs;*/ |
1249 | /*thejob->stopped_progs = 0;*/ | ||
1239 | thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ | 1250 | thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ |
1240 | |||
1241 | //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) | 1251 | //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) |
1242 | { | 1252 | { |
1253 | // FIXME: overflow check? and also trim the size, BUFSIZ can be 4K! | ||
1243 | char *bar = thejob->text; | 1254 | char *bar = thejob->text; |
1244 | char **foo = pi->progs[0].argv; | 1255 | char **foo = pi->progs[0].argv; |
1245 | if (foo) | 1256 | if (foo) |
@@ -1254,7 +1265,6 @@ static void insert_bg_job(struct pipe *pi) | |||
1254 | last_jobid = thejob->jobid; | 1265 | last_jobid = thejob->jobid; |
1255 | } | 1266 | } |
1256 | 1267 | ||
1257 | /* remove a backgrounded job */ | ||
1258 | static void remove_bg_job(struct pipe *pi) | 1268 | static void remove_bg_job(struct pipe *pi) |
1259 | { | 1269 | { |
1260 | struct pipe *prev_pipe; | 1270 | struct pipe *prev_pipe; |
@@ -1271,7 +1281,12 @@ static void remove_bg_job(struct pipe *pi) | |||
1271 | last_jobid = job_list->jobid; | 1281 | last_jobid = job_list->jobid; |
1272 | else | 1282 | else |
1273 | last_jobid = 0; | 1283 | last_jobid = 0; |
1284 | } | ||
1274 | 1285 | ||
1286 | /* remove a backgrounded job */ | ||
1287 | static void delete_finished_bg_job(struct pipe *pi) | ||
1288 | { | ||
1289 | remove_bg_job(pi); | ||
1275 | pi->stopped_progs = 0; | 1290 | pi->stopped_progs = 0; |
1276 | free_pipe(pi, 0); | 1291 | free_pipe(pi, 0); |
1277 | free(pi); | 1292 | free(pi); |
@@ -1289,36 +1304,67 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1289 | int rcode = 0; | 1304 | int rcode = 0; |
1290 | 1305 | ||
1291 | attributes = WUNTRACED; | 1306 | attributes = WUNTRACED; |
1292 | //WUNTRACED?? huh, what will happed on Ctrl-Z? fg waiting code | ||
1293 | //doesn't seem to be ready for stopped children! (only exiting ones)... | ||
1294 | if (fg_pipe == NULL) { | 1307 | if (fg_pipe == NULL) { |
1295 | attributes |= WNOHANG; | 1308 | attributes |= WNOHANG; |
1296 | } | 1309 | } |
1297 | 1310 | ||
1311 | /* Do we do this right? | ||
1312 | * bash-3.00# sleep 20 | false | ||
1313 | * <Ctrl-Z pressed> | ||
1314 | * [3]+ Stopped sleep 20 | false | ||
1315 | * bash-3.00# echo $? | ||
1316 | * 1 <========== bg pipe is not fully done, but exitcode is already known! | ||
1317 | */ | ||
1318 | |||
1298 | wait_more: | 1319 | wait_more: |
1299 | while ((childpid = waitpid(-1, &status, attributes)) > 0) { | 1320 | while ((childpid = waitpid(-1, &status, attributes)) > 0) { |
1321 | const int dead = WIFEXITED(status) || WIFSIGNALED(status); | ||
1322 | |||
1323 | #ifdef DEBUG_SHELL_JOBS | ||
1324 | if (WIFSTOPPED(status)) | ||
1325 | debug_jobs_printf("pid %d stopped by sig %d (exitcode %d)\n", | ||
1326 | childpid, WSTOPSIG(status), WEXITSTATUS(status)); | ||
1327 | if (WIFSIGNALED(status)) | ||
1328 | debug_jobs_printf("pid %d killed by sig %d (exitcode %d)\n", | ||
1329 | childpid, WTERMSIG(status), WEXITSTATUS(status)); | ||
1330 | if (WIFEXITED(status)) | ||
1331 | debug_jobs_printf("pid %d exited, exitcode %d\n", | ||
1332 | childpid, WEXITSTATUS(status)); | ||
1333 | #endif | ||
1300 | /* Were we asked to wait for fg pipe? */ | 1334 | /* Were we asked to wait for fg pipe? */ |
1301 | if (fg_pipe) { | 1335 | if (fg_pipe) { |
1302 | int i; | 1336 | int i; |
1303 | for (i = 0; i < fg_pipe->num_progs; i++) { | 1337 | for (i = 0; i < fg_pipe->num_progs; i++) { |
1338 | debug_jobs_printf("check pid %d\n", fg_pipe->progs[i].pid); | ||
1304 | if (fg_pipe->progs[i].pid == childpid) { | 1339 | if (fg_pipe->progs[i].pid == childpid) { |
1305 | /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ | 1340 | /* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */ |
1306 | fg_pipe->progs[i].pid = 0; | 1341 | if (dead) { |
1307 | if (i == fg_pipe->num_progs-1) | 1342 | fg_pipe->progs[i].pid = 0; |
1308 | /* last process gives overall exitstatus */ | 1343 | fg_pipe->running_progs--; |
1309 | rcode = WEXITSTATUS(status); | 1344 | if (i == fg_pipe->num_progs-1) |
1310 | if (--fg_pipe->running_progs <= 0) | 1345 | /* last process gives overall exitstatus */ |
1311 | /* All processes in fg pipe have exited */ | 1346 | rcode = WEXITSTATUS(status); |
1347 | } else { | ||
1348 | fg_pipe->progs[i].is_stopped = 1; | ||
1349 | fg_pipe->stopped_progs++; | ||
1350 | } | ||
1351 | debug_jobs_printf("fg_pipe: running_progs %d stopped_progs %d\n", | ||
1352 | fg_pipe->running_progs, fg_pipe->stopped_progs); | ||
1353 | if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) { | ||
1354 | /* All processes in fg pipe have exited/stopped */ | ||
1355 | if (fg_pipe->running_progs) | ||
1356 | insert_bg_job(fg_pipe); | ||
1312 | return rcode; | 1357 | return rcode; |
1358 | } | ||
1313 | /* There are still running processes in the fg pipe */ | 1359 | /* There are still running processes in the fg pipe */ |
1314 | goto wait_more; | 1360 | goto wait_more; |
1315 | } | 1361 | } |
1316 | } | 1362 | } |
1363 | /* fall through to searching process in bg pipes */ | ||
1317 | } | 1364 | } |
1318 | 1365 | ||
1319 | /* We asked to wait for bg or orphaned children */ | 1366 | /* We asked to wait for bg or orphaned children */ |
1320 | /* No need to remember exitcode in this case */ | 1367 | /* No need to remember exitcode in this case */ |
1321 | |||
1322 | for (pi = job_list; pi; pi = pi->next) { | 1368 | for (pi = job_list; pi; pi = pi->next) { |
1323 | prognum = 0; | 1369 | prognum = 0; |
1324 | while (prognum < pi->num_progs) { | 1370 | while (prognum < pi->num_progs) { |
@@ -1330,18 +1376,17 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1330 | 1376 | ||
1331 | /* Happens when shell is used as init process (init=/bin/sh) */ | 1377 | /* Happens when shell is used as init process (init=/bin/sh) */ |
1332 | debug_printf("checkjobs: pid %d was not in our list!\n", childpid); | 1378 | debug_printf("checkjobs: pid %d was not in our list!\n", childpid); |
1333 | continue; | 1379 | goto wait_more; |
1334 | 1380 | ||
1335 | found_pi_and_prognum: | 1381 | found_pi_and_prognum: |
1336 | if (WIFEXITED(status) || WIFSIGNALED(status)) { | 1382 | if (dead) { |
1337 | /* child exited */ | 1383 | /* child exited */ |
1338 | pi->running_progs--; | ||
1339 | pi->progs[prognum].pid = 0; | 1384 | pi->progs[prognum].pid = 0; |
1340 | 1385 | pi->running_progs--; | |
1341 | if (!pi->running_progs) { | 1386 | if (!pi->running_progs) { |
1342 | printf(JOB_STATUS_FORMAT, pi->jobid, | 1387 | printf(JOB_STATUS_FORMAT, pi->jobid, |
1343 | "Done", pi->text); | 1388 | "Done", pi->text); |
1344 | remove_bg_job(pi); | 1389 | delete_finished_bg_job(pi); |
1345 | } | 1390 | } |
1346 | } else { | 1391 | } else { |
1347 | /* child stopped */ | 1392 | /* child stopped */ |
@@ -1350,7 +1395,9 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1350 | } | 1395 | } |
1351 | } | 1396 | } |
1352 | 1397 | ||
1353 | if (childpid == -1 && errno != ECHILD) | 1398 | /* wait found no children or failed */ |
1399 | |||
1400 | if (childpid && errno != ECHILD) | ||
1354 | bb_perror_msg("waitpid"); | 1401 | bb_perror_msg("waitpid"); |
1355 | 1402 | ||
1356 | /* move the shell to the foreground */ | 1403 | /* move the shell to the foreground */ |
@@ -1402,6 +1449,8 @@ static int run_pipe_real(struct pipe *pi) | |||
1402 | 1449 | ||
1403 | nextin = 0; | 1450 | nextin = 0; |
1404 | pi->pgrp = -1; | 1451 | pi->pgrp = -1; |
1452 | pi->running_progs = 0; | ||
1453 | pi->stopped_progs = 0; | ||
1405 | 1454 | ||
1406 | /* Check if this is a simple builtin (not part of a pipe). | 1455 | /* Check if this is a simple builtin (not part of a pipe). |
1407 | * Builtins within pipes have to fork anyway, and are handled in | 1456 | * Builtins within pipes have to fork anyway, and are handled in |
@@ -1418,12 +1467,14 @@ static int run_pipe_real(struct pipe *pi) | |||
1418 | return rcode; | 1467 | return rcode; |
1419 | } | 1468 | } |
1420 | 1469 | ||
1421 | if (single_fg && pi->progs[0].argv != NULL) { | 1470 | if (single_fg && child->argv != NULL) { |
1422 | for (i = 0; is_assignment(child->argv[i]); i++) | 1471 | char **argv = child->argv; |
1472 | |||
1473 | for (i = 0; is_assignment(argv[i]); i++) | ||
1423 | continue; | 1474 | continue; |
1424 | if (i != 0 && child->argv[i] == NULL) { | 1475 | if (i != 0 && argv[i] == NULL) { |
1425 | /* assignments, but no command: set the local environment */ | 1476 | /* assignments, but no command: set the local environment */ |
1426 | for (i = 0; child->argv[i] != NULL; i++) { | 1477 | for (i = 0; argv[i] != NULL; i++) { |
1427 | /* Ok, this case is tricky. We have to decide if this is a | 1478 | /* Ok, this case is tricky. We have to decide if this is a |
1428 | * local variable, or an already exported variable. If it is | 1479 | * local variable, or an already exported variable. If it is |
1429 | * already exported, we have to export the new value. If it is | 1480 | * already exported, we have to export the new value. If it is |
@@ -1432,7 +1483,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1432 | * variable. */ | 1483 | * variable. */ |
1433 | int export_me = 0; | 1484 | int export_me = 0; |
1434 | char *name, *value; | 1485 | char *name, *value; |
1435 | name = xstrdup(child->argv[i]); | 1486 | name = xstrdup(argv[i]); |
1436 | debug_printf("Local environment set: %s\n", name); | 1487 | debug_printf("Local environment set: %s\n", name); |
1437 | value = strchr(name, '='); | 1488 | value = strchr(name, '='); |
1438 | if (value) | 1489 | if (value) |
@@ -1441,17 +1492,17 @@ static int run_pipe_real(struct pipe *pi) | |||
1441 | export_me = 1; | 1492 | export_me = 1; |
1442 | } | 1493 | } |
1443 | free(name); | 1494 | free(name); |
1444 | p = insert_var_value(child->argv[i]); | 1495 | p = insert_var_value(argv[i]); |
1445 | set_local_var(p, export_me); | 1496 | set_local_var(p, export_me); |
1446 | if (p != child->argv[i]) | 1497 | if (p != argv[i]) |
1447 | free(p); | 1498 | free(p); |
1448 | } | 1499 | } |
1449 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ | 1500 | return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ |
1450 | } | 1501 | } |
1451 | for (i = 0; is_assignment(child->argv[i]); i++) { | 1502 | for (i = 0; is_assignment(argv[i]); i++) { |
1452 | p = insert_var_value(child->argv[i]); | 1503 | p = insert_var_value(argv[i]); |
1453 | putenv(strdup(p)); | 1504 | putenv(strdup(p)); |
1454 | if (p != child->argv[i]) { | 1505 | if (p != argv[i]) { |
1455 | child->sp--; | 1506 | child->sp--; |
1456 | free(p); | 1507 | free(p); |
1457 | } | 1508 | } |
@@ -1459,27 +1510,25 @@ static int run_pipe_real(struct pipe *pi) | |||
1459 | if (child->sp) { | 1510 | if (child->sp) { |
1460 | char *str; | 1511 | char *str; |
1461 | 1512 | ||
1462 | str = make_string(child->argv + i); | 1513 | str = make_string(argv + i); |
1463 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); | 1514 | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); |
1464 | free(str); | 1515 | free(str); |
1465 | return last_return_code; | 1516 | return last_return_code; |
1466 | } | 1517 | } |
1467 | for (x = bltins; x->cmd; x++) { | 1518 | for (x = bltins; x->cmd; x++) { |
1468 | if (strcmp(child->argv[i], x->cmd) == 0) { | 1519 | if (strcmp(argv[i], x->cmd) == 0) { |
1469 | if (x->function == builtin_exec && child->argv[i+1] == NULL) { | 1520 | if (x->function == builtin_exec && argv[i+1] == NULL) { |
1470 | debug_printf("magic exec\n"); | 1521 | debug_printf("magic exec\n"); |
1471 | setup_redirects(child, NULL); | 1522 | setup_redirects(child, NULL); |
1472 | return EXIT_SUCCESS; | 1523 | return EXIT_SUCCESS; |
1473 | } | 1524 | } |
1474 | debug_printf("builtin inline %s\n", child->argv[0]); | 1525 | debug_printf("builtin inline %s\n", argv[0]); |
1475 | /* XXX setup_redirects acts on file descriptors, not FILEs. | 1526 | /* XXX setup_redirects acts on file descriptors, not FILEs. |
1476 | * This is perfect for work that comes after exec(). | 1527 | * This is perfect for work that comes after exec(). |
1477 | * Is it really safe for inline use? Experimentally, | 1528 | * Is it really safe for inline use? Experimentally, |
1478 | * things seem to work with glibc. */ | 1529 | * things seem to work with glibc. */ |
1479 | setup_redirects(child, squirrel); | 1530 | setup_redirects(child, squirrel); |
1480 | child->argv += i; /* XXX horrible hack */ | 1531 | rcode = x->function(argv + i); |
1481 | rcode = x->function(child); | ||
1482 | child->argv -= i; /* XXX restore hack so free() can work right */ | ||
1483 | restore_redirects(squirrel); | 1532 | restore_redirects(squirrel); |
1484 | return rcode; | 1533 | return rcode; |
1485 | } | 1534 | } |
@@ -1488,10 +1537,10 @@ static int run_pipe_real(struct pipe *pi) | |||
1488 | { | 1537 | { |
1489 | // FIXME: applet runs like part of shell - for example, it ignores | 1538 | // FIXME: applet runs like part of shell - for example, it ignores |
1490 | // SIGINT! Try to Ctrl-C out of "rm -i"... doesn't work | 1539 | // SIGINT! Try to Ctrl-C out of "rm -i"... doesn't work |
1491 | const struct bb_applet *a = find_applet_by_name(child->argv[i]); | 1540 | const struct bb_applet *a = find_applet_by_name(argv[i]); |
1492 | if (a && a->nofork) { | 1541 | if (a && a->nofork) { |
1493 | setup_redirects(child, squirrel); | 1542 | setup_redirects(child, squirrel); |
1494 | rcode = run_nofork_applet(a, child->argv + i); | 1543 | rcode = run_nofork_applet(a, argv + i); |
1495 | restore_redirects(squirrel); | 1544 | restore_redirects(squirrel); |
1496 | return rcode; | 1545 | return rcode; |
1497 | } | 1546 | } |
@@ -1503,7 +1552,6 @@ static int run_pipe_real(struct pipe *pi) | |||
1503 | * for initial child code after fork */ | 1552 | * for initial child code after fork */ |
1504 | set_jobctrl_sighandler(SIG_IGN); | 1553 | set_jobctrl_sighandler(SIG_IGN); |
1505 | 1554 | ||
1506 | pi->running_progs = 0; | ||
1507 | for (i = 0; i < pi->num_progs; i++) { | 1555 | for (i = 0; i < pi->num_progs; i++) { |
1508 | child = &(pi->progs[i]); | 1556 | child = &(pi->progs[i]); |
1509 | 1557 | ||