summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c111
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 */
3429static void 3429static void
3430onsig(int signo) 3430signal_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
4085static int 4085static int
4086blocking_wait_with_raise_on_sig(struct job *job) 4086blocking_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)
12484static int FAST_FUNC 12501static int FAST_FUNC
12485dotcmd(int argc, char **argv) 12502dotcmd(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
12519static int FAST_FUNC 12543static 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
13219init(void) 13245init(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);