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 | |
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
-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++; |