diff options
| author | Ron Yorston <rmy@pobox.com> | 2016-10-28 12:42:38 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2016-10-28 12:42:38 +0100 |
| commit | d3b0f5df93a7955ff1b9a56d2d5ebd7bc2ef5708 (patch) | |
| tree | 6b5e1eee412b8980d714f16c2aa70e399be07ff7 /shell | |
| parent | 687f98b0ba79aeb85b73c4ab06b661fb17bf4e23 (diff) | |
| parent | 458c1f218bb6a6bd0325f0b0cedea5ab0980dbc3 (diff) | |
| download | busybox-w32-d3b0f5df93a7955ff1b9a56d2d5ebd7bc2ef5708.tar.gz busybox-w32-d3b0f5df93a7955ff1b9a56d2d5ebd7bc2ef5708.tar.bz2 busybox-w32-d3b0f5df93a7955ff1b9a56d2d5ebd7bc2ef5708.zip | |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 467 | ||||
| -rw-r--r-- | shell/hush.c | 1 |
2 files changed, 242 insertions, 226 deletions
diff --git a/shell/ash.c b/shell/ash.c index 9c73760f0..abbc0cd78 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -361,6 +361,7 @@ struct globals_misc { | |||
| 361 | 361 | ||
| 362 | volatile int suppress_int; /* counter */ | 362 | volatile int suppress_int; /* counter */ |
| 363 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 363 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
| 364 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ | ||
| 364 | /* last pending signal */ | 365 | /* last pending signal */ |
| 365 | volatile /*sig_atomic_t*/ smallint pending_sig; | 366 | volatile /*sig_atomic_t*/ smallint pending_sig; |
| 366 | smallint exception_type; /* kind of exception (0..5) */ | 367 | smallint exception_type; /* kind of exception (0..5) */ |
| @@ -368,7 +369,6 @@ struct globals_misc { | |||
| 368 | #define EXINT 0 /* SIGINT received */ | 369 | #define EXINT 0 /* SIGINT received */ |
| 369 | #define EXERROR 1 /* a generic error */ | 370 | #define EXERROR 1 /* a generic error */ |
| 370 | #define EXEXIT 4 /* exit the shell */ | 371 | #define EXEXIT 4 /* exit the shell */ |
| 371 | #define EXSIG 5 /* trapped signal in wait(1) */ | ||
| 372 | 372 | ||
| 373 | smallint isloginsh; | 373 | smallint isloginsh; |
| 374 | char nullstr[1]; /* zero length string */ | 374 | char nullstr[1]; /* zero length string */ |
| @@ -441,6 +441,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc; | |||
| 441 | #define exception_type (G_misc.exception_type ) | 441 | #define exception_type (G_misc.exception_type ) |
| 442 | #define suppress_int (G_misc.suppress_int ) | 442 | #define suppress_int (G_misc.suppress_int ) |
| 443 | #define pending_int (G_misc.pending_int ) | 443 | #define pending_int (G_misc.pending_int ) |
| 444 | #define got_sigchld (G_misc.got_sigchld ) | ||
| 444 | #define pending_sig (G_misc.pending_sig ) | 445 | #define pending_sig (G_misc.pending_sig ) |
| 445 | #define isloginsh (G_misc.isloginsh ) | 446 | #define isloginsh (G_misc.isloginsh ) |
| 446 | #define nullstr (G_misc.nullstr ) | 447 | #define nullstr (G_misc.nullstr ) |
| @@ -552,26 +553,20 @@ static void raise_interrupt(void) NORETURN; | |||
| 552 | static void | 553 | static void |
| 553 | raise_interrupt(void) | 554 | raise_interrupt(void) |
| 554 | { | 555 | { |
| 555 | int ex_type; | ||
| 556 | |||
| 557 | pending_int = 0; | 556 | pending_int = 0; |
| 558 | /* Signal is not automatically unmasked after it is raised, | 557 | /* Signal is not automatically unmasked after it is raised, |
| 559 | * do it ourself - unmask all signals */ | 558 | * do it ourself - unmask all signals */ |
| 560 | sigprocmask_allsigs(SIG_UNBLOCK); | 559 | sigprocmask_allsigs(SIG_UNBLOCK); |
| 561 | /* pending_sig = 0; - now done in signal_handler() */ | 560 | /* pending_sig = 0; - now done in signal_handler() */ |
| 562 | 561 | ||
| 563 | ex_type = EXSIG; | 562 | if (!(rootshell && iflag)) { |
| 564 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { | 563 | /* Kill ourself with SIGINT */ |
| 565 | if (!(rootshell && iflag)) { | 564 | signal(SIGINT, SIG_DFL); |
| 566 | /* Kill ourself with SIGINT */ | 565 | raise(SIGINT); |
| 567 | signal(SIGINT, SIG_DFL); | ||
| 568 | raise(SIGINT); | ||
| 569 | } | ||
| 570 | ex_type = EXINT; | ||
| 571 | } | 566 | } |
| 572 | /* bash: ^C even on empty command line sets $? */ | 567 | /* bash: ^C even on empty command line sets $? */ |
| 573 | exitstatus = SIGINT + 128; | 568 | exitstatus = SIGINT + 128; |
| 574 | raise_exception(ex_type); | 569 | raise_exception(EXINT); |
| 575 | /* NOTREACHED */ | 570 | /* NOTREACHED */ |
| 576 | } | 571 | } |
| 577 | #if DEBUG | 572 | #if DEBUG |
| @@ -3592,7 +3587,14 @@ ignoresig(int signo) | |||
| 3592 | static void | 3587 | static void |
| 3593 | signal_handler(int signo) | 3588 | signal_handler(int signo) |
| 3594 | { | 3589 | { |
| 3590 | if (signo == SIGCHLD) { | ||
| 3591 | got_sigchld = 1; | ||
| 3592 | if (!trap[SIGCHLD]) | ||
| 3593 | return; | ||
| 3594 | } | ||
| 3595 | |||
| 3595 | gotsig[signo - 1] = 1; | 3596 | gotsig[signo - 1] = 1; |
| 3597 | pending_sig = signo; | ||
| 3596 | 3598 | ||
| 3597 | if (signo == SIGINT && !trap[SIGINT]) { | 3599 | if (signo == SIGINT && !trap[SIGINT]) { |
| 3598 | if (!suppress_int) { | 3600 | if (!suppress_int) { |
| @@ -3600,8 +3602,6 @@ signal_handler(int signo) | |||
| 3600 | raise_interrupt(); /* does not return */ | 3602 | raise_interrupt(); /* does not return */ |
| 3601 | } | 3603 | } |
| 3602 | pending_int = 1; | 3604 | pending_int = 1; |
| 3603 | } else { | ||
| 3604 | pending_sig = signo; | ||
| 3605 | } | 3605 | } |
| 3606 | } | 3606 | } |
| 3607 | 3607 | ||
| @@ -3661,6 +3661,9 @@ setsignal(int signo) | |||
| 3661 | //whereas we have to restore it to what shell got on entry | 3661 | //whereas we have to restore it to what shell got on entry |
| 3662 | //from the parent. See comment above | 3662 | //from the parent. See comment above |
| 3663 | 3663 | ||
| 3664 | if (signo == SIGCHLD) | ||
| 3665 | new_act = S_CATCH; | ||
| 3666 | |||
| 3664 | t = &sigmode[signo - 1]; | 3667 | t = &sigmode[signo - 1]; |
| 3665 | cur_act = *t; | 3668 | cur_act = *t; |
| 3666 | if (cur_act == 0) { | 3669 | if (cur_act == 0) { |
| @@ -3711,8 +3714,9 @@ setsignal(int signo) | |||
| 3711 | #define CUR_STOPPED 0 | 3714 | #define CUR_STOPPED 0 |
| 3712 | 3715 | ||
| 3713 | /* mode flags for dowait */ | 3716 | /* mode flags for dowait */ |
| 3714 | #define DOWAIT_NONBLOCK WNOHANG | 3717 | #define DOWAIT_NONBLOCK 0 |
| 3715 | #define DOWAIT_BLOCK 0 | 3718 | #define DOWAIT_BLOCK 1 |
| 3719 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
| 3716 | 3720 | ||
| 3717 | #if JOBS | 3721 | #if JOBS |
| 3718 | /* pgrp of shell on invocation */ | 3722 | /* pgrp of shell on invocation */ |
| @@ -4223,27 +4227,76 @@ waitpid_child(int *status, int wait_flags) | |||
| 4223 | #endif | 4227 | #endif |
| 4224 | 4228 | ||
| 4225 | static int | 4229 | static int |
| 4226 | dowait(int wait_flags, struct job *job) | 4230 | wait_block_or_sig(int *status, int wait_flags) |
| 4227 | { | 4231 | { |
| 4232 | sigset_t mask; | ||
| 4233 | int pid; | ||
| 4234 | |||
| 4235 | do { | ||
| 4236 | /* Poll all children for changes in their state */ | ||
| 4237 | got_sigchld = 0; | ||
| 4238 | pid = waitpid(-1, status, wait_flags | WNOHANG); | ||
| 4239 | if (pid != 0) | ||
| 4240 | break; /* Error (e.g. EINTR) or pid */ | ||
| 4241 | |||
| 4242 | /* No child is ready. Sleep until interesting signal is received */ | ||
| 4243 | sigfillset(&mask); | ||
| 4244 | sigprocmask(SIG_SETMASK, &mask, &mask); | ||
| 4245 | while (!got_sigchld && !pending_sig) | ||
| 4246 | sigsuspend(&mask); | ||
| 4247 | sigprocmask(SIG_SETMASK, &mask, NULL); | ||
| 4248 | |||
| 4249 | /* If it was SIGCHLD, poll children again */ | ||
| 4250 | } while (got_sigchld); | ||
| 4251 | |||
| 4252 | return pid; | ||
| 4253 | } | ||
| 4254 | |||
| 4255 | |||
| 4256 | static int | ||
| 4257 | dowait(int block, struct job *job) | ||
| 4258 | { | ||
| 4259 | int wait_flags; | ||
| 4228 | int pid; | 4260 | int pid; |
| 4229 | int status; | 4261 | int status; |
| 4230 | struct job *jp; | 4262 | struct job *jp; |
| 4231 | struct job *thisjob; | 4263 | struct job *thisjob = NULL; |
| 4232 | 4264 | ||
| 4233 | TRACE(("dowait(0x%x) called\n", wait_flags)); | 4265 | TRACE(("dowait(0x%x) called\n", block)); |
| 4234 | 4266 | ||
| 4235 | /* Do a wait system call. If job control is compiled in, we accept | 4267 | wait_flags = 0; |
| 4236 | * stopped processes. wait_flags may have WNOHANG, preventing blocking. | 4268 | if (block == DOWAIT_NONBLOCK) |
| 4237 | * NB: _not_ safe_waitpid, we need to detect EINTR */ | 4269 | wait_flags = WNOHANG; |
| 4270 | /* If job control is compiled in, we accept stopped processes too. */ | ||
| 4238 | if (doing_jobctl) | 4271 | if (doing_jobctl) |
| 4239 | wait_flags |= WUNTRACED; | 4272 | wait_flags |= WUNTRACED; |
| 4240 | pid = waitpid(-1, &status, wait_flags); | 4273 | |
| 4274 | /* It's wrong to call waitpid() outside of INT_OFF region: | ||
| 4275 | * signal can arrive just after syscall return and handler can | ||
| 4276 | * longjmp away, losing stop/exit notification processing. | ||
| 4277 | * Thus, for "jobs" builtin, and for waiting for a fg job, | ||
| 4278 | * we call waitpid() (blocking or non-blocking) inside INT_OFF. | ||
| 4279 | * | ||
| 4280 | * However, for "wait" builtin it is wrong to simply call waitpid() | ||
| 4281 | * in INT_OFF region: "wait" needs to wait for any running job | ||
| 4282 | * to change state, but should exit on any trap too. | ||
| 4283 | * In INT_OFF region, a signal just before syscall entry can set | ||
| 4284 | * pending_sig valiables, but we can't check them, and we would | ||
| 4285 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. | ||
| 4286 | * Because of this, we run inside INT_OFF, but use a special routine | ||
| 4287 | * which combines waitpid() and sigsuspend(). | ||
| 4288 | */ | ||
| 4289 | INT_OFF; | ||
| 4290 | if (block == DOWAIT_BLOCK_OR_SIG) | ||
| 4291 | pid = wait_block_or_sig(&status, wait_flags); | ||
| 4292 | else | ||
| 4293 | /* NB: _not_ safe_waitpid, we need to detect EINTR. */ | ||
| 4294 | pid = waitpid(-1, &status, wait_flags); | ||
| 4241 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4295 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
| 4242 | pid, status, errno, strerror(errno))); | 4296 | pid, status, errno, strerror(errno))); |
| 4243 | if (pid <= 0) | 4297 | if (pid <= 0) |
| 4244 | return pid; | 4298 | goto out; |
| 4245 | 4299 | ||
| 4246 | INT_OFF; | ||
| 4247 | thisjob = NULL; | 4300 | thisjob = NULL; |
| 4248 | for (jp = curjob; jp; jp = jp->prev_job) { | 4301 | for (jp = curjob; jp; jp = jp->prev_job) { |
| 4249 | int jobstate; | 4302 | int jobstate; |
| @@ -4320,15 +4373,6 @@ dowait(int wait_flags, struct job *job) | |||
| 4320 | return pid; | 4373 | return pid; |
| 4321 | } | 4374 | } |
| 4322 | 4375 | ||
| 4323 | static int | ||
| 4324 | blocking_wait_with_raise_on_sig(void) | ||
| 4325 | { | ||
| 4326 | pid_t pid = dowait(DOWAIT_BLOCK, NULL); | ||
| 4327 | if (pid <= 0 && pending_sig) | ||
| 4328 | raise_exception(EXSIG); | ||
| 4329 | return pid; | ||
| 4330 | } | ||
| 4331 | |||
| 4332 | #if JOBS | 4376 | #if JOBS |
| 4333 | static void | 4377 | static void |
| 4334 | showjob(struct job *jp, int mode) | 4378 | showjob(struct job *jp, int mode) |
| @@ -4498,9 +4542,6 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4498 | int retval; | 4542 | int retval; |
| 4499 | struct job *jp; | 4543 | struct job *jp; |
| 4500 | 4544 | ||
| 4501 | if (pending_sig) | ||
| 4502 | raise_exception(EXSIG); | ||
| 4503 | |||
| 4504 | nextopt(nullstr); | 4545 | nextopt(nullstr); |
| 4505 | retval = 0; | 4546 | retval = 0; |
| 4506 | 4547 | ||
| @@ -4517,21 +4558,20 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4517 | jp->waited = 1; | 4558 | jp->waited = 1; |
| 4518 | jp = jp->prev_job; | 4559 | jp = jp->prev_job; |
| 4519 | } | 4560 | } |
| 4520 | blocking_wait_with_raise_on_sig(); | ||
| 4521 | /* man bash: | 4561 | /* man bash: |
| 4522 | * "When bash is waiting for an asynchronous command via | 4562 | * "When bash is waiting for an asynchronous command via |
| 4523 | * the wait builtin, the reception of a signal for which a trap | 4563 | * the wait builtin, the reception of a signal for which a trap |
| 4524 | * has been set will cause the wait builtin to return immediately | 4564 | * has been set will cause the wait builtin to return immediately |
| 4525 | * with an exit status greater than 128, immediately after which | 4565 | * with an exit status greater than 128, immediately after which |
| 4526 | * the trap is executed." | 4566 | * the trap is executed." |
| 4527 | * | 4567 | */ |
| 4528 | * blocking_wait_with_raise_on_sig raises signal handlers | 4568 | dowait(DOWAIT_BLOCK_OR_SIG, NULL); |
| 4529 | * if it gets no pid (pid < 0). However, | 4569 | /* if child sends us a signal *and immediately exits*, |
| 4530 | * if child sends us a signal *and immediately exits*, | 4570 | * dowait() returns pid > 0. Check this case, |
| 4531 | * blocking_wait_with_raise_on_sig gets pid > 0 | 4571 | * not "if (dowait() < 0)"! |
| 4532 | * and does not handle pending_sig. Check this case: */ | 4572 | */ |
| 4533 | if (pending_sig) | 4573 | if (pending_sig) |
| 4534 | raise_exception(EXSIG); | 4574 | goto sigout; |
| 4535 | } | 4575 | } |
| 4536 | } | 4576 | } |
| 4537 | 4577 | ||
| @@ -4551,8 +4591,11 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4551 | job = getjob(*argv, 0); | 4591 | job = getjob(*argv, 0); |
| 4552 | } | 4592 | } |
| 4553 | /* loop until process terminated or stopped */ | 4593 | /* loop until process terminated or stopped */ |
| 4554 | while (job->state == JOBRUNNING) | 4594 | while (job->state == JOBRUNNING) { |
| 4555 | blocking_wait_with_raise_on_sig(); | 4595 | dowait(DOWAIT_BLOCK_OR_SIG, NULL); |
| 4596 | if (pending_sig) | ||
| 4597 | goto sigout; | ||
| 4598 | } | ||
| 4556 | job->waited = 1; | 4599 | job->waited = 1; |
| 4557 | retval = getstatus(job); | 4600 | retval = getstatus(job); |
| 4558 | repeat: ; | 4601 | repeat: ; |
| @@ -4560,6 +4603,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 4560 | 4603 | ||
| 4561 | ret: | 4604 | ret: |
| 4562 | return retval; | 4605 | return retval; |
| 4606 | sigout: | ||
| 4607 | retval = 128 + pending_sig; | ||
| 4608 | return retval; | ||
| 4563 | } | 4609 | } |
| 4564 | 4610 | ||
| 4565 | static struct job * | 4611 | static struct job * |
| @@ -4954,19 +5000,19 @@ clear_traps(void) | |||
| 4954 | { | 5000 | { |
| 4955 | char **tp; | 5001 | char **tp; |
| 4956 | 5002 | ||
| 5003 | INT_OFF; | ||
| 4957 | for (tp = trap; tp < &trap[NSIG]; tp++) { | 5004 | for (tp = trap; tp < &trap[NSIG]; tp++) { |
| 4958 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ | 5005 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ |
| 4959 | INT_OFF; | ||
| 4960 | if (trap_ptr == trap) | 5006 | if (trap_ptr == trap) |
| 4961 | free(*tp); | 5007 | free(*tp); |
| 4962 | /* else: it "belongs" to trap_ptr vector, don't free */ | 5008 | /* else: it "belongs" to trap_ptr vector, don't free */ |
| 4963 | *tp = NULL; | 5009 | *tp = NULL; |
| 4964 | if ((tp - trap) != 0) | 5010 | if ((tp - trap) != 0) |
| 4965 | setsignal(tp - trap); | 5011 | setsignal(tp - trap); |
| 4966 | INT_ON; | ||
| 4967 | } | 5012 | } |
| 4968 | } | 5013 | } |
| 4969 | may_have_traps = 0; | 5014 | may_have_traps = 0; |
| 5015 | INT_ON; | ||
| 4970 | } | 5016 | } |
| 4971 | 5017 | ||
| 4972 | /* Lives far away from here, needed for forkchild */ | 5018 | /* Lives far away from here, needed for forkchild */ |
| @@ -5914,6 +5960,119 @@ cvtnum(arith_t num) | |||
| 5914 | return len; | 5960 | return len; |
| 5915 | } | 5961 | } |
| 5916 | 5962 | ||
| 5963 | /* | ||
| 5964 | * Break the argument string into pieces based upon IFS and add the | ||
| 5965 | * strings to the argument list. The regions of the string to be | ||
| 5966 | * searched for IFS characters have been stored by recordregion. | ||
| 5967 | */ | ||
| 5968 | static void | ||
| 5969 | ifsbreakup(char *string, struct arglist *arglist) | ||
| 5970 | { | ||
| 5971 | struct ifsregion *ifsp; | ||
| 5972 | struct strlist *sp; | ||
| 5973 | char *start; | ||
| 5974 | char *p; | ||
| 5975 | char *q; | ||
| 5976 | const char *ifs, *realifs; | ||
| 5977 | int ifsspc; | ||
| 5978 | int nulonly; | ||
| 5979 | |||
| 5980 | start = string; | ||
| 5981 | if (ifslastp != NULL) { | ||
| 5982 | ifsspc = 0; | ||
| 5983 | nulonly = 0; | ||
| 5984 | realifs = ifsset() ? ifsval() : defifs; | ||
| 5985 | ifsp = &ifsfirst; | ||
| 5986 | do { | ||
| 5987 | p = string + ifsp->begoff; | ||
| 5988 | nulonly = ifsp->nulonly; | ||
| 5989 | ifs = nulonly ? nullstr : realifs; | ||
| 5990 | ifsspc = 0; | ||
| 5991 | while (p < string + ifsp->endoff) { | ||
| 5992 | q = p; | ||
| 5993 | if ((unsigned char)*p == CTLESC) | ||
| 5994 | p++; | ||
| 5995 | if (!strchr(ifs, *p)) { | ||
| 5996 | p++; | ||
| 5997 | continue; | ||
| 5998 | } | ||
| 5999 | if (!nulonly) | ||
| 6000 | ifsspc = (strchr(defifs, *p) != NULL); | ||
| 6001 | /* Ignore IFS whitespace at start */ | ||
| 6002 | if (q == start && ifsspc) { | ||
| 6003 | p++; | ||
| 6004 | start = p; | ||
| 6005 | continue; | ||
| 6006 | } | ||
| 6007 | *q = '\0'; | ||
| 6008 | sp = stzalloc(sizeof(*sp)); | ||
| 6009 | sp->text = start; | ||
| 6010 | *arglist->lastp = sp; | ||
| 6011 | arglist->lastp = &sp->next; | ||
| 6012 | p++; | ||
| 6013 | if (!nulonly) { | ||
| 6014 | for (;;) { | ||
| 6015 | if (p >= string + ifsp->endoff) { | ||
| 6016 | break; | ||
| 6017 | } | ||
| 6018 | q = p; | ||
| 6019 | if ((unsigned char)*p == CTLESC) | ||
| 6020 | p++; | ||
| 6021 | if (strchr(ifs, *p) == NULL) { | ||
| 6022 | p = q; | ||
| 6023 | break; | ||
| 6024 | } | ||
| 6025 | if (strchr(defifs, *p) == NULL) { | ||
| 6026 | if (ifsspc) { | ||
| 6027 | p++; | ||
| 6028 | ifsspc = 0; | ||
| 6029 | } else { | ||
| 6030 | p = q; | ||
| 6031 | break; | ||
| 6032 | } | ||
| 6033 | } else | ||
| 6034 | p++; | ||
| 6035 | } | ||
| 6036 | } | ||
| 6037 | start = p; | ||
| 6038 | } /* while */ | ||
| 6039 | ifsp = ifsp->next; | ||
| 6040 | } while (ifsp != NULL); | ||
| 6041 | if (nulonly) | ||
| 6042 | goto add; | ||
| 6043 | } | ||
| 6044 | |||
| 6045 | if (!*start) | ||
| 6046 | return; | ||
| 6047 | |||
| 6048 | add: | ||
| 6049 | sp = stzalloc(sizeof(*sp)); | ||
| 6050 | sp->text = start; | ||
| 6051 | *arglist->lastp = sp; | ||
| 6052 | arglist->lastp = &sp->next; | ||
| 6053 | } | ||
| 6054 | |||
| 6055 | static void | ||
| 6056 | ifsfree(void) | ||
| 6057 | { | ||
| 6058 | struct ifsregion *p = ifsfirst.next; | ||
| 6059 | |||
| 6060 | if (!p) | ||
| 6061 | goto out; | ||
| 6062 | |||
| 6063 | INT_OFF; | ||
| 6064 | do { | ||
| 6065 | struct ifsregion *ifsp; | ||
| 6066 | ifsp = p->next; | ||
| 6067 | free(p); | ||
| 6068 | p = ifsp; | ||
| 6069 | } while (p); | ||
| 6070 | ifsfirst.next = NULL; | ||
| 6071 | INT_ON; | ||
| 6072 | out: | ||
| 6073 | ifslastp = NULL; | ||
| 6074 | } | ||
| 6075 | |||
| 5917 | static size_t | 6076 | static size_t |
| 5918 | esclen(const char *start, const char *p) | 6077 | esclen(const char *start, const char *p) |
| 5919 | { | 6078 | { |
| @@ -6235,6 +6394,7 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
| 6235 | * For now, preserve bash-like behavior, it seems to be somewhat more useful: | 6394 | * For now, preserve bash-like behavior, it seems to be somewhat more useful: |
| 6236 | */ | 6395 | */ |
| 6237 | eflag = 0; | 6396 | eflag = 0; |
| 6397 | ifsfree(); | ||
| 6238 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ | 6398 | evaltree(n, EV_EXIT); /* actually evaltreenr... */ |
| 6239 | /* NOTREACHED */ | 6399 | /* NOTREACHED */ |
| 6240 | } | 6400 | } |
| @@ -7207,116 +7367,6 @@ evalvar(char *p, int flag, struct strlist *var_str_list) | |||
| 7207 | } | 7367 | } |
| 7208 | 7368 | ||
| 7209 | /* | 7369 | /* |
| 7210 | * Break the argument string into pieces based upon IFS and add the | ||
| 7211 | * strings to the argument list. The regions of the string to be | ||
| 7212 | * searched for IFS characters have been stored by recordregion. | ||
| 7213 | */ | ||
| 7214 | static void | ||
| 7215 | ifsbreakup(char *string, struct arglist *arglist) | ||
| 7216 | { | ||
| 7217 | struct ifsregion *ifsp; | ||
| 7218 | struct strlist *sp; | ||
| 7219 | char *start; | ||
| 7220 | char *p; | ||
| 7221 | char *q; | ||
| 7222 | const char *ifs, *realifs; | ||
| 7223 | int ifsspc; | ||
| 7224 | int nulonly; | ||
| 7225 | |||
| 7226 | start = string; | ||
| 7227 | if (ifslastp != NULL) { | ||
| 7228 | ifsspc = 0; | ||
| 7229 | nulonly = 0; | ||
| 7230 | realifs = ifsset() ? ifsval() : defifs; | ||
| 7231 | ifsp = &ifsfirst; | ||
| 7232 | do { | ||
| 7233 | p = string + ifsp->begoff; | ||
| 7234 | nulonly = ifsp->nulonly; | ||
| 7235 | ifs = nulonly ? nullstr : realifs; | ||
| 7236 | ifsspc = 0; | ||
| 7237 | while (p < string + ifsp->endoff) { | ||
| 7238 | q = p; | ||
| 7239 | if ((unsigned char)*p == CTLESC) | ||
| 7240 | p++; | ||
| 7241 | if (!strchr(ifs, *p)) { | ||
| 7242 | p++; | ||
| 7243 | continue; | ||
| 7244 | } | ||
| 7245 | if (!nulonly) | ||
| 7246 | ifsspc = (strchr(defifs, *p) != NULL); | ||
| 7247 | /* Ignore IFS whitespace at start */ | ||
| 7248 | if (q == start && ifsspc) { | ||
| 7249 | p++; | ||
| 7250 | start = p; | ||
| 7251 | continue; | ||
| 7252 | } | ||
| 7253 | *q = '\0'; | ||
| 7254 | sp = stzalloc(sizeof(*sp)); | ||
| 7255 | sp->text = start; | ||
| 7256 | *arglist->lastp = sp; | ||
| 7257 | arglist->lastp = &sp->next; | ||
| 7258 | p++; | ||
| 7259 | if (!nulonly) { | ||
| 7260 | for (;;) { | ||
| 7261 | if (p >= string + ifsp->endoff) { | ||
| 7262 | break; | ||
| 7263 | } | ||
| 7264 | q = p; | ||
| 7265 | if ((unsigned char)*p == CTLESC) | ||
| 7266 | p++; | ||
| 7267 | if (strchr(ifs, *p) == NULL) { | ||
| 7268 | p = q; | ||
| 7269 | break; | ||
| 7270 | } | ||
| 7271 | if (strchr(defifs, *p) == NULL) { | ||
| 7272 | if (ifsspc) { | ||
| 7273 | p++; | ||
| 7274 | ifsspc = 0; | ||
| 7275 | } else { | ||
| 7276 | p = q; | ||
| 7277 | break; | ||
| 7278 | } | ||
| 7279 | } else | ||
| 7280 | p++; | ||
| 7281 | } | ||
| 7282 | } | ||
| 7283 | start = p; | ||
| 7284 | } /* while */ | ||
| 7285 | ifsp = ifsp->next; | ||
| 7286 | } while (ifsp != NULL); | ||
| 7287 | if (nulonly) | ||
| 7288 | goto add; | ||
| 7289 | } | ||
| 7290 | |||
| 7291 | if (!*start) | ||
| 7292 | return; | ||
| 7293 | |||
| 7294 | add: | ||
| 7295 | sp = stzalloc(sizeof(*sp)); | ||
| 7296 | sp->text = start; | ||
| 7297 | *arglist->lastp = sp; | ||
| 7298 | arglist->lastp = &sp->next; | ||
| 7299 | } | ||
| 7300 | |||
| 7301 | static void | ||
| 7302 | ifsfree(void) | ||
| 7303 | { | ||
| 7304 | struct ifsregion *p; | ||
| 7305 | |||
| 7306 | INT_OFF; | ||
| 7307 | p = ifsfirst.next; | ||
| 7308 | do { | ||
| 7309 | struct ifsregion *ifsp; | ||
| 7310 | ifsp = p->next; | ||
| 7311 | free(p); | ||
| 7312 | p = ifsp; | ||
| 7313 | } while (p); | ||
| 7314 | ifslastp = NULL; | ||
| 7315 | ifsfirst.next = NULL; | ||
| 7316 | INT_ON; | ||
| 7317 | } | ||
| 7318 | |||
| 7319 | /* | ||
| 7320 | * Add a file name to the list. | 7370 | * Add a file name to the list. |
| 7321 | */ | 7371 | */ |
| 7322 | static void | 7372 | static void |
| @@ -7654,15 +7704,14 @@ expandarg(union node *arg, struct arglist *arglist, int flag) | |||
| 7654 | 7704 | ||
| 7655 | argbackq = arg->narg.backquote; | 7705 | argbackq = arg->narg.backquote; |
| 7656 | STARTSTACKSTR(expdest); | 7706 | STARTSTACKSTR(expdest); |
| 7657 | ifsfirst.next = NULL; | ||
| 7658 | ifslastp = NULL; | ||
| 7659 | TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); | 7707 | TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); |
| 7660 | argstr(arg->narg.text, flag, | 7708 | argstr(arg->narg.text, flag, |
| 7661 | /* var_str_list: */ arglist ? arglist->list : NULL); | 7709 | /* var_str_list: */ arglist ? arglist->list : NULL); |
| 7662 | p = _STPUTC('\0', expdest); | 7710 | p = _STPUTC('\0', expdest); |
| 7663 | expdest = p - 1; | 7711 | expdest = p - 1; |
| 7664 | if (arglist == NULL) { | 7712 | if (arglist == NULL) { |
| 7665 | return; /* here document expanded */ | 7713 | /* here document expanded */ |
| 7714 | goto out; | ||
| 7666 | } | 7715 | } |
| 7667 | p = grabstackstr(p); | 7716 | p = grabstackstr(p); |
| 7668 | TRACE(("expandarg: p:'%s'\n", p)); | 7717 | TRACE(("expandarg: p:'%s'\n", p)); |
| @@ -7685,13 +7734,14 @@ expandarg(union node *arg, struct arglist *arglist, int flag) | |||
| 7685 | *exparg.lastp = sp; | 7734 | *exparg.lastp = sp; |
| 7686 | exparg.lastp = &sp->next; | 7735 | exparg.lastp = &sp->next; |
| 7687 | } | 7736 | } |
| 7688 | if (ifsfirst.next) | ||
| 7689 | ifsfree(); | ||
| 7690 | *exparg.lastp = NULL; | 7737 | *exparg.lastp = NULL; |
| 7691 | if (exparg.list) { | 7738 | if (exparg.list) { |
| 7692 | *arglist->lastp = exparg.list; | 7739 | *arglist->lastp = exparg.list; |
| 7693 | arglist->lastp = exparg.lastp; | 7740 | arglist->lastp = exparg.lastp; |
| 7694 | } | 7741 | } |
| 7742 | |||
| 7743 | out: | ||
| 7744 | ifsfree(); | ||
| 7695 | } | 7745 | } |
| 7696 | 7746 | ||
| 7697 | /* | 7747 | /* |
| @@ -7725,10 +7775,10 @@ casematch(union node *pattern, char *val) | |||
| 7725 | setstackmark(&smark); | 7775 | setstackmark(&smark); |
| 7726 | argbackq = pattern->narg.backquote; | 7776 | argbackq = pattern->narg.backquote; |
| 7727 | STARTSTACKSTR(expdest); | 7777 | STARTSTACKSTR(expdest); |
| 7728 | ifslastp = NULL; | ||
| 7729 | argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, | 7778 | argstr(pattern->narg.text, EXP_TILDE | EXP_CASE, |
| 7730 | /* var_str_list: */ NULL); | 7779 | /* var_str_list: */ NULL); |
| 7731 | STACKSTRNUL(expdest); | 7780 | STACKSTRNUL(expdest); |
| 7781 | ifsfree(); | ||
| 7732 | result = patmatch(stackblock(), val); | 7782 | result = patmatch(stackblock(), val); |
| 7733 | popstackmark(&smark); | 7783 | popstackmark(&smark); |
| 7734 | return result; | 7784 | return result; |
| @@ -8890,41 +8940,18 @@ static void prehash(union node *); | |||
| 8890 | static int | 8940 | static int |
| 8891 | evaltree(union node *n, int flags) | 8941 | evaltree(union node *n, int flags) |
| 8892 | { | 8942 | { |
| 8893 | struct jmploc *volatile savehandler = exception_handler; | ||
| 8894 | struct jmploc jmploc; | ||
| 8895 | int checkexit = 0; | 8943 | int checkexit = 0; |
| 8896 | int (*evalfn)(union node *, int); | 8944 | int (*evalfn)(union node *, int); |
| 8897 | int status = 0; | 8945 | int status = 0; |
| 8898 | int int_level; | ||
| 8899 | |||
| 8900 | SAVE_INT(int_level); | ||
| 8901 | 8946 | ||
| 8902 | if (n == NULL) { | 8947 | if (n == NULL) { |
| 8903 | TRACE(("evaltree(NULL) called\n")); | 8948 | TRACE(("evaltree(NULL) called\n")); |
| 8904 | goto out1; | 8949 | goto out; |
| 8905 | } | 8950 | } |
| 8906 | TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); | 8951 | TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags)); |
| 8907 | 8952 | ||
| 8908 | dotrap(); | 8953 | dotrap(); |
| 8909 | 8954 | ||
| 8910 | exception_handler = &jmploc; | ||
| 8911 | { | ||
| 8912 | int err = setjmp(jmploc.loc); | ||
| 8913 | if (err) { | ||
| 8914 | /* if it was a signal, check for trap handlers */ | ||
| 8915 | if (exception_type == EXSIG) { | ||
| 8916 | TRACE(("exception %d (EXSIG) in evaltree, err=%d\n", | ||
| 8917 | exception_type, err)); | ||
| 8918 | goto out; | ||
| 8919 | } | ||
| 8920 | /* continue on the way out */ | ||
| 8921 | TRACE(("exception %d in evaltree, propagating err=%d\n", | ||
| 8922 | exception_type, err)); | ||
| 8923 | exception_handler = savehandler; | ||
| 8924 | longjmp(exception_handler->loc, err); | ||
| 8925 | } | ||
| 8926 | } | ||
| 8927 | |||
| 8928 | switch (n->type) { | 8955 | switch (n->type) { |
| 8929 | default: | 8956 | default: |
| 8930 | #if DEBUG | 8957 | #if DEBUG |
| @@ -9015,11 +9042,7 @@ evaltree(union node *n, int flags) | |||
| 9015 | exitstatus = status; | 9042 | exitstatus = status; |
| 9016 | break; | 9043 | break; |
| 9017 | } | 9044 | } |
| 9018 | |||
| 9019 | out: | 9045 | out: |
| 9020 | exception_handler = savehandler; | ||
| 9021 | |||
| 9022 | out1: | ||
| 9023 | /* Order of checks below is important: | 9046 | /* Order of checks below is important: |
| 9024 | * signal handlers trigger before exit caused by "set -e". | 9047 | * signal handlers trigger before exit caused by "set -e". |
| 9025 | */ | 9048 | */ |
| @@ -9030,9 +9053,7 @@ evaltree(union node *n, int flags) | |||
| 9030 | if (flags & EV_EXIT) | 9053 | if (flags & EV_EXIT) |
| 9031 | raise_exception(EXEXIT); | 9054 | raise_exception(EXEXIT); |
| 9032 | 9055 | ||
| 9033 | RESTORE_INT(int_level); | ||
| 9034 | TRACE(("leaving evaltree (no interrupts)\n")); | 9056 | TRACE(("leaving evaltree (no interrupts)\n")); |
| 9035 | |||
| 9036 | return exitstatus; | 9057 | return exitstatus; |
| 9037 | } | 9058 | } |
| 9038 | 9059 | ||
| @@ -10036,21 +10057,12 @@ evalcommand(union node *cmd, int flags) | |||
| 10036 | dowait(DOWAIT_NONBLOCK, NULL); | 10057 | dowait(DOWAIT_NONBLOCK, NULL); |
| 10037 | 10058 | ||
| 10038 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { | 10059 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { |
| 10039 | int exit_status; | 10060 | if (exception_type == EXERROR && spclbltin <= 0) { |
| 10040 | int i = exception_type; | 10061 | FORCE_INT_ON; |
| 10041 | if (i == EXEXIT) | 10062 | break; |
| 10042 | goto raise; | ||
| 10043 | exit_status = 2; | ||
| 10044 | if (i == EXINT) | ||
| 10045 | exit_status = 128 + SIGINT; | ||
| 10046 | if (i == EXSIG) | ||
| 10047 | exit_status = 128 + pending_sig; | ||
| 10048 | exitstatus = exit_status; | ||
| 10049 | if (i == EXINT || spclbltin > 0) { | ||
| 10050 | raise: | ||
| 10051 | longjmp(exception_handler->loc, 1); | ||
| 10052 | } | 10063 | } |
| 10053 | FORCE_INT_ON; | 10064 | raise: |
| 10065 | longjmp(exception_handler->loc, 1); | ||
| 10054 | } | 10066 | } |
| 10055 | goto readstatus; | 10067 | goto readstatus; |
| 10056 | 10068 | ||
| @@ -13255,12 +13267,13 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 13255 | if (action) { | 13267 | if (action) { |
| 13256 | if (LONE_DASH(action)) | 13268 | if (LONE_DASH(action)) |
| 13257 | action = NULL; | 13269 | action = NULL; |
| 13258 | else | 13270 | else { |
| 13271 | if (action[0]) /* not NULL and not "" and not "-" */ | ||
| 13272 | may_have_traps = 1; | ||
| 13259 | action = ckstrdup(action); | 13273 | action = ckstrdup(action); |
| 13274 | } | ||
| 13260 | } | 13275 | } |
| 13261 | free(trap[signo]); | 13276 | free(trap[signo]); |
| 13262 | if (action) | ||
| 13263 | may_have_traps = 1; | ||
| 13264 | trap[signo] = action; | 13277 | trap[signo] = action; |
| 13265 | if (signo != 0) | 13278 | if (signo != 0) |
| 13266 | setsignal(signo); | 13279 | setsignal(signo); |
| @@ -13661,7 +13674,9 @@ init(void) | |||
| 13661 | /* we will never free this */ | 13674 | /* we will never free this */ |
| 13662 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 13675 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
| 13663 | 13676 | ||
| 13664 | signal(SIGCHLD, SIG_DFL); | 13677 | sigmode[SIGCHLD - 1] = S_DFL; |
| 13678 | setsignal(SIGCHLD); | ||
| 13679 | |||
| 13665 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. | 13680 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. |
| 13666 | * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" | 13681 | * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" |
| 13667 | */ | 13682 | */ |
| @@ -13863,11 +13878,12 @@ procargs(char **argv) | |||
| 13863 | } | 13878 | } |
| 13864 | 13879 | ||
| 13865 | /* | 13880 | /* |
| 13866 | * Read /etc/profile or .profile. | 13881 | * Read /etc/profile, ~/.profile, $ENV. |
| 13867 | */ | 13882 | */ |
| 13868 | static void | 13883 | static void |
| 13869 | read_profile(const char *name) | 13884 | read_profile(const char *name) |
| 13870 | { | 13885 | { |
| 13886 | name = expandstr(name); | ||
| 13871 | if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) | 13887 | if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) |
| 13872 | return; | 13888 | return; |
| 13873 | cmdloop(0); | 13889 | cmdloop(0); |
| @@ -13877,6 +13893,7 @@ read_profile(const char *name) | |||
| 13877 | /* | 13893 | /* |
| 13878 | * This routine is called when an error or an interrupt occurs in an | 13894 | * This routine is called when an error or an interrupt occurs in an |
| 13879 | * interactive shell and control is returned to the main command loop. | 13895 | * interactive shell and control is returned to the main command loop. |
| 13896 | * (In dash, this function is auto-generated by build machinery). | ||
| 13880 | */ | 13897 | */ |
| 13881 | static void | 13898 | static void |
| 13882 | reset(void) | 13899 | reset(void) |
| @@ -13884,13 +13901,15 @@ reset(void) | |||
| 13884 | /* from eval.c: */ | 13901 | /* from eval.c: */ |
| 13885 | evalskip = 0; | 13902 | evalskip = 0; |
| 13886 | loopnest = 0; | 13903 | loopnest = 0; |
| 13904 | |||
| 13905 | /* from expand.c: */ | ||
| 13906 | ifsfree(); | ||
| 13907 | |||
| 13887 | /* from input.c: */ | 13908 | /* from input.c: */ |
| 13888 | g_parsefile->left_in_buffer = 0; | 13909 | g_parsefile->left_in_buffer = 0; |
| 13889 | g_parsefile->left_in_line = 0; /* clear input buffer */ | 13910 | g_parsefile->left_in_line = 0; /* clear input buffer */ |
| 13890 | popallfiles(); | 13911 | popallfiles(); |
| 13891 | /* from parser.c: */ | 13912 | |
| 13892 | tokpushback = 0; | ||
| 13893 | checkkwd = 0; | ||
| 13894 | /* from redir.c: */ | 13913 | /* from redir.c: */ |
| 13895 | while (redirlist) | 13914 | while (redirlist) |
| 13896 | popredir(/*drop:*/ 0, /*restore:*/ 0); | 13915 | popredir(/*drop:*/ 0, /*restore:*/ 0); |
| @@ -13911,7 +13930,6 @@ extern int etext(); | |||
| 13911 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 13930 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 13912 | int ash_main(int argc UNUSED_PARAM, char **argv) | 13931 | int ash_main(int argc UNUSED_PARAM, char **argv) |
| 13913 | { | 13932 | { |
| 13914 | const char *shinit; | ||
| 13915 | volatile smallint state; | 13933 | volatile smallint state; |
| 13916 | struct jmploc jmploc; | 13934 | struct jmploc jmploc; |
| 13917 | struct stackmark smark; | 13935 | struct stackmark smark; |
| @@ -14005,11 +14023,8 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14005 | state1: | 14023 | state1: |
| 14006 | state = 2; | 14024 | state = 2; |
| 14007 | hp = lookupvar("HOME"); | 14025 | hp = lookupvar("HOME"); |
| 14008 | if (hp) { | 14026 | if (hp) |
| 14009 | hp = concat_path_file(hp, ".profile"); | 14027 | read_profile("$HOME/.profile"); |
| 14010 | read_profile(hp); | ||
| 14011 | free((char*)hp); | ||
| 14012 | } | ||
| 14013 | } | 14028 | } |
| 14014 | state2: | 14029 | state2: |
| 14015 | state = 3; | 14030 | state = 3; |
| @@ -14019,11 +14034,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
| 14019 | #endif | 14034 | #endif |
| 14020 | iflag | 14035 | iflag |
| 14021 | ) { | 14036 | ) { |
| 14022 | shinit = lookupvar("ENV"); | 14037 | const char *shinit = lookupvar("ENV"); |
| 14023 | if (shinit != NULL && *shinit != '\0') { | 14038 | if (shinit != NULL && *shinit != '\0') |
| 14024 | read_profile(shinit); | 14039 | read_profile(shinit); |
| 14025 | } | ||
| 14026 | } | 14040 | } |
| 14041 | popstackmark(&smark); | ||
| 14027 | state3: | 14042 | state3: |
| 14028 | state = 4; | 14043 | state = 4; |
| 14029 | if (minusc) { | 14044 | if (minusc) { |
diff --git a/shell/hush.c b/shell/hush.c index d7a0d761e..c80429d5c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -8405,6 +8405,7 @@ int hush_main(int argc, char **argv) | |||
| 8405 | * "bash <script>" (which is never interactive (unless -i?)) | 8405 | * "bash <script>" (which is never interactive (unless -i?)) |
| 8406 | * sources $BASH_ENV here (without scanning $PATH). | 8406 | * sources $BASH_ENV here (without scanning $PATH). |
| 8407 | * If called as sh, does the same but with $ENV. | 8407 | * If called as sh, does the same but with $ENV. |
| 8408 | * Also NB, per POSIX, $ENV should undergo parameter expansion. | ||
| 8408 | */ | 8409 | */ |
| 8409 | G.global_argc--; | 8410 | G.global_argc--; |
| 8410 | G.global_argv++; | 8411 | G.global_argv++; |
