diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 111 |
1 files changed, 69 insertions, 42 deletions
diff --git a/shell/ash.c b/shell/ash.c index 5d8415a79..16a331bb0 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -257,6 +257,7 @@ struct globals_misc { | |||
257 | 257 | ||
258 | /* indicates specified signal received */ | 258 | /* indicates specified signal received */ |
259 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 259 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
260 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | ||
260 | char *trap[NSIG]; | 261 | char *trap[NSIG]; |
261 | char **trap_ptr; /* used only by "trap hack" */ | 262 | char **trap_ptr; /* used only by "trap hack" */ |
262 | 263 | ||
@@ -285,6 +286,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | |||
285 | #define optlist (G_misc.optlist ) | 286 | #define optlist (G_misc.optlist ) |
286 | #define sigmode (G_misc.sigmode ) | 287 | #define sigmode (G_misc.sigmode ) |
287 | #define gotsig (G_misc.gotsig ) | 288 | #define gotsig (G_misc.gotsig ) |
289 | #define may_have_traps (G_misc.may_have_traps ) | ||
288 | #define trap (G_misc.trap ) | 290 | #define trap (G_misc.trap ) |
289 | #define trap_ptr (G_misc.trap_ptr ) | 291 | #define trap_ptr (G_misc.trap_ptr ) |
290 | #define random_gen (G_misc.random_gen ) | 292 | #define random_gen (G_misc.random_gen ) |
@@ -382,7 +384,7 @@ raise_interrupt(void) | |||
382 | /* Signal is not automatically unmasked after it is raised, | 384 | /* Signal is not automatically unmasked after it is raised, |
383 | * do it ourself - unmask all signals */ | 385 | * do it ourself - unmask all signals */ |
384 | sigprocmask_allsigs(SIG_UNBLOCK); | 386 | sigprocmask_allsigs(SIG_UNBLOCK); |
385 | /* pending_sig = 0; - now done in onsig() */ | 387 | /* pending_sig = 0; - now done in signal_handler() */ |
386 | 388 | ||
387 | ex_type = EXSIG; | 389 | ex_type = EXSIG; |
388 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { | 390 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { |
@@ -2743,9 +2745,7 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
2743 | /* ============ ... */ | 2745 | /* ============ ... */ |
2744 | 2746 | ||
2745 | 2747 | ||
2746 | #define IBUFSIZ COMMON_BUFSIZE | 2748 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) |
2747 | /* buffer for top level input file */ | ||
2748 | #define basebuf bb_common_bufsiz1 | ||
2749 | 2749 | ||
2750 | /* Syntax classes */ | 2750 | /* Syntax classes */ |
2751 | #define CWORD 0 /* character is nothing special */ | 2751 | #define CWORD 0 /* character is nothing special */ |
@@ -3424,10 +3424,10 @@ ignoresig(int signo) | |||
3424 | } | 3424 | } |
3425 | 3425 | ||
3426 | /* | 3426 | /* |
3427 | * Signal handler. Only one usage site - in setsignal() | 3427 | * Only one usage site - in setsignal() |
3428 | */ | 3428 | */ |
3429 | static void | 3429 | static void |
3430 | onsig(int signo) | 3430 | signal_handler(int signo) |
3431 | { | 3431 | { |
3432 | gotsig[signo - 1] = 1; | 3432 | gotsig[signo - 1] = 1; |
3433 | 3433 | ||
@@ -3524,7 +3524,7 @@ setsignal(int signo) | |||
3524 | act.sa_handler = SIG_DFL; | 3524 | act.sa_handler = SIG_DFL; |
3525 | switch (new_act) { | 3525 | switch (new_act) { |
3526 | case S_CATCH: | 3526 | case S_CATCH: |
3527 | act.sa_handler = onsig; | 3527 | act.sa_handler = signal_handler; |
3528 | act.sa_flags = 0; /* matters only if !DFL and !IGN */ | 3528 | act.sa_flags = 0; /* matters only if !DFL and !IGN */ |
3529 | sigfillset(&act.sa_mask); /* ditto */ | 3529 | sigfillset(&act.sa_mask); /* ditto */ |
3530 | break; | 3530 | break; |
@@ -4083,9 +4083,9 @@ dowait(int wait_flags, struct job *job) | |||
4083 | } | 4083 | } |
4084 | 4084 | ||
4085 | static int | 4085 | static int |
4086 | blocking_wait_with_raise_on_sig(struct job *job) | 4086 | blocking_wait_with_raise_on_sig(void) |
4087 | { | 4087 | { |
4088 | pid_t pid = dowait(DOWAIT_BLOCK, job); | 4088 | pid_t pid = dowait(DOWAIT_BLOCK, NULL); |
4089 | if (pid <= 0 && pending_sig) | 4089 | if (pid <= 0 && pending_sig) |
4090 | raise_exception(EXSIG); | 4090 | raise_exception(EXSIG); |
4091 | return pid; | 4091 | return pid; |
@@ -4281,14 +4281,21 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4281 | jp->waited = 1; | 4281 | jp->waited = 1; |
4282 | jp = jp->prev_job; | 4282 | jp = jp->prev_job; |
4283 | } | 4283 | } |
4284 | blocking_wait_with_raise_on_sig(); | ||
4284 | /* man bash: | 4285 | /* man bash: |
4285 | * "When bash is waiting for an asynchronous command via | 4286 | * "When bash is waiting for an asynchronous command via |
4286 | * the wait builtin, the reception of a signal for which a trap | 4287 | * the wait builtin, the reception of a signal for which a trap |
4287 | * has been set will cause the wait builtin to return immediately | 4288 | * has been set will cause the wait builtin to return immediately |
4288 | * with an exit status greater than 128, immediately after which | 4289 | * with an exit status greater than 128, immediately after which |
4289 | * the trap is executed." | 4290 | * the trap is executed." |
4290 | * Do we do it that way? */ | 4291 | * |
4291 | blocking_wait_with_raise_on_sig(NULL); | 4292 | * blocking_wait_with_raise_on_sig raises signal handlers |
4293 | * if it gets no pid (pid < 0). However, | ||
4294 | * if child sends us a signal *and immediately exits*, | ||
4295 | * blocking_wait_with_raise_on_sig gets pid > 0 | ||
4296 | * and does not handle pending_sig. Check this case: */ | ||
4297 | if (pending_sig) | ||
4298 | raise_exception(EXSIG); | ||
4292 | } | 4299 | } |
4293 | } | 4300 | } |
4294 | 4301 | ||
@@ -4308,7 +4315,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
4308 | job = getjob(*argv, 0); | 4315 | job = getjob(*argv, 0); |
4309 | /* loop until process terminated or stopped */ | 4316 | /* loop until process terminated or stopped */ |
4310 | while (job->state == JOBRUNNING) | 4317 | while (job->state == JOBRUNNING) |
4311 | blocking_wait_with_raise_on_sig(NULL); | 4318 | blocking_wait_with_raise_on_sig(); |
4312 | job->waited = 1; | 4319 | job->waited = 1; |
4313 | retval = getstatus(job); | 4320 | retval = getstatus(job); |
4314 | repeat: ; | 4321 | repeat: ; |
@@ -5715,7 +5722,11 @@ rmescapes(char *str, int flag) | |||
5715 | size_t fulllen = len + strlen(p) + 1; | 5722 | size_t fulllen = len + strlen(p) + 1; |
5716 | 5723 | ||
5717 | if (flag & RMESCAPE_GROW) { | 5724 | if (flag & RMESCAPE_GROW) { |
5725 | int strloc = str - (char *)stackblock(); | ||
5718 | r = makestrspace(fulllen, expdest); | 5726 | r = makestrspace(fulllen, expdest); |
5727 | /* p and str may be invalidated by makestrspace */ | ||
5728 | str = (char *)stackblock() + strloc; | ||
5729 | p = str + len; | ||
5719 | } else if (flag & RMESCAPE_HEAP) { | 5730 | } else if (flag & RMESCAPE_HEAP) { |
5720 | r = ckmalloc(fulllen); | 5731 | r = ckmalloc(fulllen); |
5721 | } else { | 5732 | } else { |
@@ -8819,7 +8830,7 @@ evalsubshell(union node *n, int flags) | |||
8819 | int status; | 8830 | int status; |
8820 | 8831 | ||
8821 | expredir(n->nredir.redirect); | 8832 | expredir(n->nredir.redirect); |
8822 | if (!backgnd && flags & EV_EXIT && !trap[0]) | 8833 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
8823 | goto nofork; | 8834 | goto nofork; |
8824 | INT_OFF; | 8835 | INT_OFF; |
8825 | jp = makejob(/*n,*/ 1); | 8836 | jp = makejob(/*n,*/ 1); |
@@ -8832,10 +8843,11 @@ evalsubshell(union node *n, int flags) | |||
8832 | ash_msg_and_raise_error("unable to spawn shell"); | 8843 | ash_msg_and_raise_error("unable to spawn shell"); |
8833 | #endif | 8844 | #endif |
8834 | if (forkshell(jp, n, backgnd) == 0) { | 8845 | if (forkshell(jp, n, backgnd) == 0) { |
8846 | /* child */ | ||
8835 | INT_ON; | 8847 | INT_ON; |
8836 | flags |= EV_EXIT; | 8848 | flags |= EV_EXIT; |
8837 | if (backgnd) | 8849 | if (backgnd) |
8838 | flags &=~ EV_TESTED; | 8850 | flags &= ~EV_TESTED; |
8839 | nofork: | 8851 | nofork: |
8840 | redirect(n->nredir.redirect, 0); | 8852 | redirect(n->nredir.redirect, 0); |
8841 | evaltreenr(n->nredir.n, flags); | 8853 | evaltreenr(n->nredir.n, flags); |
@@ -9365,7 +9377,9 @@ static const struct builtincmd builtintab[] = { | |||
9365 | { BUILTIN_SPEC_REG "return" , returncmd }, | 9377 | { BUILTIN_SPEC_REG "return" , returncmd }, |
9366 | { BUILTIN_SPEC_REG "set" , setcmd }, | 9378 | { BUILTIN_SPEC_REG "set" , setcmd }, |
9367 | { BUILTIN_SPEC_REG "shift" , shiftcmd }, | 9379 | { BUILTIN_SPEC_REG "shift" , shiftcmd }, |
9380 | #if ENABLE_ASH_BASH_COMPAT | ||
9368 | { BUILTIN_SPEC_REG "source" , dotcmd }, | 9381 | { BUILTIN_SPEC_REG "source" , dotcmd }, |
9382 | #endif | ||
9369 | #if ENABLE_ASH_BUILTIN_TEST | 9383 | #if ENABLE_ASH_BUILTIN_TEST |
9370 | { BUILTIN_REGULAR "test" , testcmd }, | 9384 | { BUILTIN_REGULAR "test" , testcmd }, |
9371 | #endif | 9385 | #endif |
@@ -9646,16 +9660,19 @@ evalcommand(union node *cmd, int flags) | |||
9646 | /* goes through to shellexec() */ | 9660 | /* goes through to shellexec() */ |
9647 | #endif | 9661 | #endif |
9648 | /* Fork off a child process if necessary. */ | 9662 | /* Fork off a child process if necessary. */ |
9649 | if (!(flags & EV_EXIT) || trap[0]) { | 9663 | if (!(flags & EV_EXIT) || may_have_traps) { |
9650 | INT_OFF; | 9664 | INT_OFF; |
9651 | jp = makejob(/*cmd,*/ 1); | 9665 | jp = makejob(/*cmd,*/ 1); |
9652 | if (forkshell(jp, cmd, FORK_FG) != 0) { | 9666 | if (forkshell(jp, cmd, FORK_FG) != 0) { |
9667 | /* parent */ | ||
9653 | exitstatus = waitforjob(jp); | 9668 | exitstatus = waitforjob(jp); |
9654 | INT_ON; | 9669 | INT_ON; |
9655 | TRACE(("forked child exited with %d\n", exitstatus)); | 9670 | TRACE(("forked child exited with %d\n", exitstatus)); |
9656 | break; | 9671 | break; |
9657 | } | 9672 | } |
9673 | /* child */ | ||
9658 | FORCE_INT_ON; | 9674 | FORCE_INT_ON; |
9675 | /* fall through to exec'ing external program */ | ||
9659 | } | 9676 | } |
9660 | listsetvar(varlist.list, VEXPORT|VSTACK); | 9677 | listsetvar(varlist.list, VEXPORT|VSTACK); |
9661 | shellexec(argv, path, cmdentry.u.index); | 9678 | shellexec(argv, path, cmdentry.u.index); |
@@ -9900,12 +9917,12 @@ preadfd(void) | |||
9900 | #if ENABLE_FEATURE_EDITING | 9917 | #if ENABLE_FEATURE_EDITING |
9901 | retry: | 9918 | retry: |
9902 | if (!iflag || g_parsefile->fd != STDIN_FILENO) | 9919 | if (!iflag || g_parsefile->fd != STDIN_FILENO) |
9903 | nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); | 9920 | nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1); |
9904 | else { | 9921 | else { |
9905 | #if ENABLE_FEATURE_TAB_COMPLETION | 9922 | #if ENABLE_FEATURE_TAB_COMPLETION |
9906 | line_input_state->path_lookup = pathval(); | 9923 | line_input_state->path_lookup = pathval(); |
9907 | #endif | 9924 | #endif |
9908 | nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); | 9925 | nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); |
9909 | if (nr == 0) { | 9926 | if (nr == 0) { |
9910 | /* Ctrl+C pressed */ | 9927 | /* Ctrl+C pressed */ |
9911 | if (trap[SIGINT]) { | 9928 | if (trap[SIGINT]) { |
@@ -9922,7 +9939,7 @@ preadfd(void) | |||
9922 | } | 9939 | } |
9923 | } | 9940 | } |
9924 | #else | 9941 | #else |
9925 | nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); | 9942 | nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1); |
9926 | #endif | 9943 | #endif |
9927 | 9944 | ||
9928 | #if 0 | 9945 | #if 0 |
@@ -12484,36 +12501,43 @@ find_dot_file(char *name) | |||
12484 | static int FAST_FUNC | 12501 | static int FAST_FUNC |
12485 | dotcmd(int argc, char **argv) | 12502 | dotcmd(int argc, char **argv) |
12486 | { | 12503 | { |
12504 | char *fullname; | ||
12487 | struct strlist *sp; | 12505 | struct strlist *sp; |
12488 | volatile struct shparam saveparam; | 12506 | volatile struct shparam saveparam; |
12489 | int status = 0; | ||
12490 | 12507 | ||
12491 | for (sp = cmdenviron; sp; sp = sp->next) | 12508 | for (sp = cmdenviron; sp; sp = sp->next) |
12492 | setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); | 12509 | setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); |
12493 | 12510 | ||
12494 | if (argv[1]) { /* That's what SVR2 does */ | 12511 | if (!argv[1]) { |
12495 | char *fullname = find_dot_file(argv[1]); | 12512 | /* bash says: "bash: .: filename argument required" */ |
12496 | argv += 2; | 12513 | return 2; /* bash compat */ |
12497 | argc -= 2; | ||
12498 | if (argc) { /* argc > 0, argv[0] != NULL */ | ||
12499 | saveparam = shellparam; | ||
12500 | shellparam.malloced = 0; | ||
12501 | shellparam.nparam = argc; | ||
12502 | shellparam.p = argv; | ||
12503 | }; | ||
12504 | |||
12505 | setinputfile(fullname, INPUT_PUSH_FILE); | ||
12506 | commandname = fullname; | ||
12507 | cmdloop(0); | ||
12508 | popfile(); | ||
12509 | |||
12510 | if (argc) { | ||
12511 | freeparam(&shellparam); | ||
12512 | shellparam = saveparam; | ||
12513 | }; | ||
12514 | status = exitstatus; | ||
12515 | } | 12514 | } |
12516 | return status; | 12515 | |
12516 | /* "false; . empty_file; echo $?" should print 0, not 1: */ | ||
12517 | exitstatus = 0; | ||
12518 | |||
12519 | fullname = find_dot_file(argv[1]); | ||
12520 | |||
12521 | argv += 2; | ||
12522 | argc -= 2; | ||
12523 | if (argc) { /* argc > 0, argv[0] != NULL */ | ||
12524 | saveparam = shellparam; | ||
12525 | shellparam.malloced = 0; | ||
12526 | shellparam.nparam = argc; | ||
12527 | shellparam.p = argv; | ||
12528 | }; | ||
12529 | |||
12530 | setinputfile(fullname, INPUT_PUSH_FILE); | ||
12531 | commandname = fullname; | ||
12532 | cmdloop(0); | ||
12533 | popfile(); | ||
12534 | |||
12535 | if (argc) { | ||
12536 | freeparam(&shellparam); | ||
12537 | shellparam = saveparam; | ||
12538 | }; | ||
12539 | |||
12540 | return exitstatus; | ||
12517 | } | 12541 | } |
12518 | 12542 | ||
12519 | static int FAST_FUNC | 12543 | static int FAST_FUNC |
@@ -12824,6 +12848,8 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12824 | action = ckstrdup(action); | 12848 | action = ckstrdup(action); |
12825 | } | 12849 | } |
12826 | free(trap[signo]); | 12850 | free(trap[signo]); |
12851 | if (action) | ||
12852 | may_have_traps = 1; | ||
12827 | trap[signo] = action; | 12853 | trap[signo] = action; |
12828 | if (signo != 0) | 12854 | if (signo != 0) |
12829 | setsignal(signo); | 12855 | setsignal(signo); |
@@ -13219,7 +13245,8 @@ static void | |||
13219 | init(void) | 13245 | init(void) |
13220 | { | 13246 | { |
13221 | /* from input.c: */ | 13247 | /* from input.c: */ |
13222 | basepf.next_to_pgetc = basepf.buf = basebuf; | 13248 | /* we will never free this */ |
13249 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | ||
13223 | 13250 | ||
13224 | /* from trap.c: */ | 13251 | /* from trap.c: */ |
13225 | signal(SIGCHLD, SIG_DFL); | 13252 | signal(SIGCHLD, SIG_DFL); |