diff options
author | Ron Yorston <rmy@pobox.com> | 2016-11-02 10:19:18 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-11-02 10:19:18 +0000 |
commit | e45ff573dc9707b1ea71f490ef16cd9d08feaaf2 (patch) | |
tree | 09980b02b9c8efc8d772c7379abdcd4eef4ddad8 /shell/ash.c | |
parent | 7bc3efa4f0c7608723d301bda5ee006a0f6141fe (diff) | |
parent | 2e6af549715f5d7b4c2ab204e46c8b8f6f057045 (diff) | |
download | busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.tar.gz busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.tar.bz2 busybox-w32-e45ff573dc9707b1ea71f490ef16cd9d08feaaf2.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 122 |
1 files changed, 81 insertions, 41 deletions
diff --git a/shell/ash.c b/shell/ash.c index dd320355e..a709c3602 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -362,8 +362,7 @@ struct globals_misc { | |||
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 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ |
365 | /* last pending signal */ | 365 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
366 | volatile /*sig_atomic_t*/ smallint pending_sig; | ||
367 | smallint exception_type; /* kind of exception (0..5) */ | 366 | smallint exception_type; /* kind of exception (0..5) */ |
368 | /* exceptions */ | 367 | /* exceptions */ |
369 | #define EXINT 0 /* SIGINT received */ | 368 | #define EXINT 0 /* SIGINT received */ |
@@ -915,13 +914,8 @@ trace_vprintf(const char *fmt, va_list va) | |||
915 | { | 914 | { |
916 | if (debug != 1) | 915 | if (debug != 1) |
917 | return; | 916 | return; |
918 | if (DEBUG_TIME) | ||
919 | fprintf(tracefile, "%u ", (int) time(NULL)); | ||
920 | if (DEBUG_PID) | ||
921 | fprintf(tracefile, "[%u] ", (int) getpid()); | ||
922 | if (DEBUG_SIG) | ||
923 | fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int); | ||
924 | vfprintf(tracefile, fmt, va); | 917 | vfprintf(tracefile, fmt, va); |
918 | fprintf(tracefile, "\n"); | ||
925 | } | 919 | } |
926 | 920 | ||
927 | static void | 921 | static void |
@@ -1314,11 +1308,10 @@ ash_vmsg_and_raise(int cond, const char *msg, va_list ap) | |||
1314 | { | 1308 | { |
1315 | #if DEBUG | 1309 | #if DEBUG |
1316 | if (msg) { | 1310 | if (msg) { |
1317 | TRACE(("ash_vmsg_and_raise(%d, \"", cond)); | 1311 | TRACE(("ash_vmsg_and_raise(%d):", cond)); |
1318 | TRACEV((msg, ap)); | 1312 | TRACEV((msg, ap)); |
1319 | TRACE(("\") pid=%d\n", getpid())); | ||
1320 | } else | 1313 | } else |
1321 | TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid())); | 1314 | TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond)); |
1322 | if (msg) | 1315 | if (msg) |
1323 | #endif | 1316 | #endif |
1324 | ash_vmsg(msg, ap); | 1317 | ash_vmsg(msg, ap); |
@@ -2250,6 +2243,7 @@ setvareq(char *s, int flags) | |||
2250 | if (flags & VNOSAVE) | 2243 | if (flags & VNOSAVE) |
2251 | free(s); | 2244 | free(s); |
2252 | n = vp->var_text; | 2245 | n = vp->var_text; |
2246 | exitstatus = 1; | ||
2253 | ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); | 2247 | ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); |
2254 | } | 2248 | } |
2255 | 2249 | ||
@@ -3715,11 +3709,6 @@ setsignal(int signo) | |||
3715 | #define CUR_RUNNING 1 | 3709 | #define CUR_RUNNING 1 |
3716 | #define CUR_STOPPED 0 | 3710 | #define CUR_STOPPED 0 |
3717 | 3711 | ||
3718 | /* mode flags for dowait */ | ||
3719 | #define DOWAIT_NONBLOCK 0 | ||
3720 | #define DOWAIT_BLOCK 1 | ||
3721 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
3722 | |||
3723 | #if JOBS | 3712 | #if JOBS |
3724 | /* pgrp of shell on invocation */ | 3713 | /* pgrp of shell on invocation */ |
3725 | static int initialpgrp; //references:2 | 3714 | static int initialpgrp; //references:2 |
@@ -4231,24 +4220,30 @@ waitpid_child(int *status, int wait_flags) | |||
4231 | #else | 4220 | #else |
4232 | 4221 | ||
4233 | static int | 4222 | static int |
4234 | wait_block_or_sig(int *status, int wait_flags) | 4223 | wait_block_or_sig(int *status) |
4235 | { | 4224 | { |
4236 | sigset_t mask; | ||
4237 | int pid; | 4225 | int pid; |
4238 | 4226 | ||
4239 | do { | 4227 | do { |
4240 | /* Poll all children for changes in their state */ | 4228 | /* Poll all children for changes in their state */ |
4241 | got_sigchld = 0; | 4229 | got_sigchld = 0; |
4242 | pid = waitpid(-1, status, wait_flags | WNOHANG); | 4230 | /* if job control is active, accept stopped processes too */ |
4231 | pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG); | ||
4243 | if (pid != 0) | 4232 | if (pid != 0) |
4244 | break; /* Error (e.g. EINTR) or pid */ | 4233 | break; /* Error (e.g. EINTR, ECHILD) or pid */ |
4245 | 4234 | ||
4246 | /* No child is ready. Sleep until interesting signal is received */ | 4235 | /* Children exist, but none are ready. Sleep until interesting signal */ |
4236 | #if 0 /* dash does this */ | ||
4237 | sigset_t mask; | ||
4247 | sigfillset(&mask); | 4238 | sigfillset(&mask); |
4248 | sigprocmask(SIG_SETMASK, &mask, &mask); | 4239 | sigprocmask(SIG_SETMASK, &mask, &mask); |
4249 | while (!got_sigchld && !pending_sig) | 4240 | while (!got_sigchld && !pending_sig) |
4250 | sigsuspend(&mask); | 4241 | sigsuspend(&mask); |
4251 | sigprocmask(SIG_SETMASK, &mask, NULL); | 4242 | sigprocmask(SIG_SETMASK, &mask, NULL); |
4243 | #else | ||
4244 | while (!got_sigchld && !pending_sig) | ||
4245 | pause(); | ||
4246 | #endif | ||
4252 | 4247 | ||
4253 | /* If it was SIGCHLD, poll children again */ | 4248 | /* If it was SIGCHLD, poll children again */ |
4254 | } while (got_sigchld); | 4249 | } while (got_sigchld); |
@@ -4257,11 +4252,13 @@ wait_block_or_sig(int *status, int wait_flags) | |||
4257 | } | 4252 | } |
4258 | #endif | 4253 | #endif |
4259 | 4254 | ||
4255 | #define DOWAIT_NONBLOCK 0 | ||
4256 | #define DOWAIT_BLOCK 1 | ||
4257 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
4260 | 4258 | ||
4261 | static int | 4259 | static int |
4262 | dowait(int block, struct job *job) | 4260 | dowait(int block, struct job *job) |
4263 | { | 4261 | { |
4264 | int wait_flags; | ||
4265 | int pid; | 4262 | int pid; |
4266 | int status; | 4263 | int status; |
4267 | struct job *jp; | 4264 | struct job *jp; |
@@ -4269,13 +4266,6 @@ dowait(int block, struct job *job) | |||
4269 | 4266 | ||
4270 | TRACE(("dowait(0x%x) called\n", block)); | 4267 | TRACE(("dowait(0x%x) called\n", block)); |
4271 | 4268 | ||
4272 | wait_flags = 0; | ||
4273 | if (block == DOWAIT_NONBLOCK) | ||
4274 | wait_flags = WNOHANG; | ||
4275 | /* If job control is compiled in, we accept stopped processes too. */ | ||
4276 | if (doing_jobctl) | ||
4277 | wait_flags |= WUNTRACED; | ||
4278 | |||
4279 | /* It's wrong to call waitpid() outside of INT_OFF region: | 4269 | /* It's wrong to call waitpid() outside of INT_OFF region: |
4280 | * signal can arrive just after syscall return and handler can | 4270 | * signal can arrive just after syscall return and handler can |
4281 | * longjmp away, losing stop/exit notification processing. | 4271 | * longjmp away, losing stop/exit notification processing. |
@@ -4286,17 +4276,27 @@ dowait(int block, struct job *job) | |||
4286 | * in INT_OFF region: "wait" needs to wait for any running job | 4276 | * in INT_OFF region: "wait" needs to wait for any running job |
4287 | * to change state, but should exit on any trap too. | 4277 | * to change state, but should exit on any trap too. |
4288 | * In INT_OFF region, a signal just before syscall entry can set | 4278 | * In INT_OFF region, a signal just before syscall entry can set |
4289 | * pending_sig valiables, but we can't check them, and we would | 4279 | * pending_sig variables, but we can't check them, and we would |
4290 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. | 4280 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. |
4281 | * | ||
4291 | * Because of this, we run inside INT_OFF, but use a special routine | 4282 | * Because of this, we run inside INT_OFF, but use a special routine |
4292 | * which combines waitpid() and sigsuspend(). | 4283 | * which combines waitpid() and pause(). |
4284 | * This is the reason why we need to have a handler for SIGCHLD: | ||
4285 | * SIG_DFL handler does not wake pause(). | ||
4293 | */ | 4286 | */ |
4294 | INT_OFF; | 4287 | INT_OFF; |
4295 | if (block == DOWAIT_BLOCK_OR_SIG) | 4288 | if (block == DOWAIT_BLOCK_OR_SIG) { |
4296 | pid = wait_block_or_sig(&status, wait_flags); | 4289 | pid = wait_block_or_sig(&status); |
4297 | else | 4290 | } else { |
4298 | /* NB: _not_ safe_waitpid, we need to detect EINTR. */ | 4291 | int wait_flags = 0; |
4292 | if (block == DOWAIT_NONBLOCK) | ||
4293 | wait_flags = WNOHANG; | ||
4294 | /* if job control is active, accept stopped processes too */ | ||
4295 | if (doing_jobctl) | ||
4296 | wait_flags |= WUNTRACED; | ||
4297 | /* NB: _not_ safe_waitpid, we need to detect EINTR */ | ||
4299 | pid = waitpid(-1, &status, wait_flags); | 4298 | pid = waitpid(-1, &status, wait_flags); |
4299 | } | ||
4300 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4300 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
4301 | pid, status, errno, strerror(errno))); | 4301 | pid, status, errno, strerror(errno))); |
4302 | if (pid <= 0) | 4302 | if (pid <= 0) |
@@ -7410,6 +7410,21 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7410 | 7410 | ||
7411 | if (fflag) | 7411 | if (fflag) |
7412 | goto nometa; | 7412 | goto nometa; |
7413 | |||
7414 | /* Avoid glob() (and thus, stat() et al) for words like "echo" */ | ||
7415 | p = str->text; | ||
7416 | while (*p) { | ||
7417 | if (*p == '*') | ||
7418 | goto need_glob; | ||
7419 | if (*p == '?') | ||
7420 | goto need_glob; | ||
7421 | if (*p == '[') | ||
7422 | goto need_glob; | ||
7423 | p++; | ||
7424 | } | ||
7425 | goto nometa; | ||
7426 | |||
7427 | need_glob: | ||
7413 | INT_OFF; | 7428 | INT_OFF; |
7414 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); | 7429 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
7415 | // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match | 7430 | // GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match |
@@ -10064,7 +10079,7 @@ evalcommand(union node *cmd, int flags) | |||
10064 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { | 10079 | if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { |
10065 | if (exception_type == EXERROR && spclbltin <= 0) { | 10080 | if (exception_type == EXERROR && spclbltin <= 0) { |
10066 | FORCE_INT_ON; | 10081 | FORCE_INT_ON; |
10067 | break; | 10082 | goto readstatus; |
10068 | } | 10083 | } |
10069 | raise: | 10084 | raise: |
10070 | longjmp(exception_handler->loc, 1); | 10085 | longjmp(exception_handler->loc, 1); |
@@ -10584,6 +10599,9 @@ popfile(void) | |||
10584 | { | 10599 | { |
10585 | struct parsefile *pf = g_parsefile; | 10600 | struct parsefile *pf = g_parsefile; |
10586 | 10601 | ||
10602 | if (pf == &basepf) | ||
10603 | return; | ||
10604 | |||
10587 | INT_OFF; | 10605 | INT_OFF; |
10588 | if (pf->pf_fd >= 0) | 10606 | if (pf->pf_fd >= 0) |
10589 | close(pf->pf_fd); | 10607 | close(pf->pf_fd); |
@@ -12747,6 +12765,10 @@ expandstr(const char *ps) | |||
12747 | static int | 12765 | static int |
12748 | evalstring(char *s, int flags) | 12766 | evalstring(char *s, int flags) |
12749 | { | 12767 | { |
12768 | struct jmploc *volatile savehandler; | ||
12769 | struct jmploc jmploc; | ||
12770 | int ex; | ||
12771 | |||
12750 | union node *n; | 12772 | union node *n; |
12751 | struct stackmark smark; | 12773 | struct stackmark smark; |
12752 | int status; | 12774 | int status; |
@@ -12756,6 +12778,19 @@ evalstring(char *s, int flags) | |||
12756 | setstackmark(&smark); | 12778 | setstackmark(&smark); |
12757 | 12779 | ||
12758 | status = 0; | 12780 | status = 0; |
12781 | /* On exception inside execution loop, we must popfile(). | ||
12782 | * Try interactively: | ||
12783 | * readonly a=a | ||
12784 | * command eval "a=b" # throws "is read only" error | ||
12785 | * "command BLTIN" is not supposed to abort (even in non-interactive use). | ||
12786 | * But if we skip popfile(), we hit EOF in eval's string, and exit. | ||
12787 | */ | ||
12788 | savehandler = exception_handler; | ||
12789 | ex = setjmp(jmploc.loc); | ||
12790 | if (ex) | ||
12791 | goto out; | ||
12792 | exception_handler = &jmploc; | ||
12793 | |||
12759 | while ((n = parsecmd(0)) != NODE_EOF) { | 12794 | while ((n = parsecmd(0)) != NODE_EOF) { |
12760 | int i; | 12795 | int i; |
12761 | 12796 | ||
@@ -12766,10 +12801,15 @@ evalstring(char *s, int flags) | |||
12766 | if (evalskip) | 12801 | if (evalskip) |
12767 | break; | 12802 | break; |
12768 | } | 12803 | } |
12804 | out: | ||
12769 | popstackmark(&smark); | 12805 | popstackmark(&smark); |
12770 | popfile(); | 12806 | popfile(); |
12771 | stunalloc(s); | 12807 | stunalloc(s); |
12772 | 12808 | ||
12809 | exception_handler = savehandler; | ||
12810 | if (ex) | ||
12811 | longjmp(exception_handler->loc, ex); | ||
12812 | |||
12773 | return status; | 12813 | return status; |
12774 | } | 12814 | } |
12775 | 12815 | ||
@@ -13982,11 +14022,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
13982 | goto state4; | 14022 | goto state4; |
13983 | } | 14023 | } |
13984 | exception_handler = &jmploc; | 14024 | exception_handler = &jmploc; |
13985 | #if DEBUG | ||
13986 | opentrace(); | ||
13987 | TRACE(("Shell args: ")); | ||
13988 | trace_puts_args(argv); | ||
13989 | #endif | ||
13990 | rootpid = getpid(); | 14025 | rootpid = getpid(); |
13991 | 14026 | ||
13992 | init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0)); | 14027 | init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0)); |
@@ -14003,6 +14038,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14003 | } | 14038 | } |
14004 | #endif | 14039 | #endif |
14005 | procargs(argv); | 14040 | procargs(argv); |
14041 | #if DEBUG | ||
14042 | TRACE(("Shell args: ")); | ||
14043 | trace_puts_args(argv); | ||
14044 | #endif | ||
14045 | |||
14006 | #if ENABLE_PLATFORM_MINGW32 | 14046 | #if ENABLE_PLATFORM_MINGW32 |
14007 | if ( noconsole ) { | 14047 | if ( noconsole ) { |
14008 | DWORD dummy; | 14048 | DWORD dummy; |