diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-10 19:02:53 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-10 19:02:53 +0000 |
commit | 991a1da14806eefd1c6fc8fc1c0c3d2b90af6f24 (patch) | |
tree | 4397962a82c1b4c161ee3b9af88943d64c5b993b /shell/ash.c | |
parent | 0ef240d979b0ffcad104a6844cee4c72640844f5 (diff) | |
download | busybox-w32-991a1da14806eefd1c6fc8fc1c0c3d2b90af6f24.tar.gz busybox-w32-991a1da14806eefd1c6fc8fc1c0c3d2b90af6f24.tar.bz2 busybox-w32-991a1da14806eefd1c6fc8fc1c0c3d2b90af6f24.zip |
ash: fix "orwell bug" 1984. Testcase:
trap_handler() {
echo trap
}
trap trap_handler USR1
sleep 3600 &
while true; do wait; done
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 103 |
1 files changed, 48 insertions, 55 deletions
diff --git a/shell/ash.c b/shell/ash.c index 8ff5f4c31..a877b5bab 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -164,7 +164,16 @@ struct globals_misc { | |||
164 | char *arg0; /* value of $0 */ | 164 | char *arg0; /* value of $0 */ |
165 | 165 | ||
166 | struct jmploc *exception_handler; | 166 | struct jmploc *exception_handler; |
167 | int exception; | 167 | |
168 | // disabled by vda: cannot understand how it was supposed to work - | ||
169 | // cannot fix bugs. That's why you have to explain your non-trivial designs! | ||
170 | // /* do we generate EXSIG events */ | ||
171 | // int exsig; /* counter */ | ||
172 | volatile int suppressint; /* counter */ | ||
173 | volatile /*sig_atomic_t*/ smallint intpending; /* 1 = got SIGINT */ | ||
174 | /* last pending signal */ | ||
175 | volatile /*sig_atomic_t*/ smallint pendingsig; | ||
176 | smallint exception; /* kind of exception (0..5) */ | ||
168 | /* exceptions */ | 177 | /* exceptions */ |
169 | #define EXINT 0 /* SIGINT received */ | 178 | #define EXINT 0 /* SIGINT received */ |
170 | #define EXERROR 1 /* a generic error */ | 179 | #define EXERROR 1 /* a generic error */ |
@@ -172,12 +181,6 @@ struct globals_misc { | |||
172 | #define EXEXEC 3 /* command execution failed */ | 181 | #define EXEXEC 3 /* command execution failed */ |
173 | #define EXEXIT 4 /* exit the shell */ | 182 | #define EXEXIT 4 /* exit the shell */ |
174 | #define EXSIG 5 /* trapped signal in wait(1) */ | 183 | #define EXSIG 5 /* trapped signal in wait(1) */ |
175 | volatile int suppressint; | ||
176 | volatile sig_atomic_t intpending; | ||
177 | /* do we generate EXSIG events */ | ||
178 | int exsig; | ||
179 | /* last pending signal */ | ||
180 | volatile sig_atomic_t pendingsig; | ||
181 | 184 | ||
182 | /* trap handler commands */ | 185 | /* trap handler commands */ |
183 | char *trap[NSIG]; | 186 | char *trap[NSIG]; |
@@ -211,7 +214,7 @@ static struct globals_misc *const ptr_to_globals_misc __attribute__ ((section (" | |||
211 | #define exception (G_misc.exception ) | 214 | #define exception (G_misc.exception ) |
212 | #define suppressint (G_misc.suppressint ) | 215 | #define suppressint (G_misc.suppressint ) |
213 | #define intpending (G_misc.intpending ) | 216 | #define intpending (G_misc.intpending ) |
214 | #define exsig (G_misc.exsig ) | 217 | //#define exsig (G_misc.exsig ) |
215 | #define pendingsig (G_misc.pendingsig ) | 218 | #define pendingsig (G_misc.pendingsig ) |
216 | #define trap (G_misc.trap ) | 219 | #define trap (G_misc.trap ) |
217 | #define isloginsh (G_misc.isloginsh) | 220 | #define isloginsh (G_misc.isloginsh) |
@@ -281,6 +284,7 @@ raise_interrupt(void) | |||
281 | i = EXSIG; | 284 | i = EXSIG; |
282 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { | 285 | if (gotsig[SIGINT - 1] && !trap[SIGINT]) { |
283 | if (!(rootshell && iflag)) { | 286 | if (!(rootshell && iflag)) { |
287 | /* Kill ourself with SIGINT */ | ||
284 | signal(SIGINT, SIG_DFL); | 288 | signal(SIGINT, SIG_DFL); |
285 | raise(SIGINT); | 289 | raise(SIGINT); |
286 | } | 290 | } |
@@ -333,15 +337,6 @@ force_int_on(void) | |||
333 | raise_interrupt(); \ | 337 | raise_interrupt(); \ |
334 | } while (0) | 338 | } while (0) |
335 | 339 | ||
336 | #define EXSIGON \ | ||
337 | do { \ | ||
338 | exsig++; \ | ||
339 | xbarrier(); \ | ||
340 | if (pendingsig) \ | ||
341 | raise_exception(EXSIG); \ | ||
342 | } while (0) | ||
343 | /* EXSIG is turned off by evalbltin(). */ | ||
344 | |||
345 | /* | 340 | /* |
346 | * Ignore a signal. Only one usage site - in forkchild() | 341 | * Ignore a signal. Only one usage site - in forkchild() |
347 | */ | 342 | */ |
@@ -363,10 +358,10 @@ onsig(int signo) | |||
363 | gotsig[signo - 1] = 1; | 358 | gotsig[signo - 1] = 1; |
364 | pendingsig = signo; | 359 | pendingsig = signo; |
365 | 360 | ||
366 | if (exsig || (signo == SIGINT && !trap[SIGINT])) { | 361 | if ( /* exsig || */ (signo == SIGINT && !trap[SIGINT])) { |
367 | if (!suppressint) { | 362 | if (!suppressint) { |
368 | pendingsig = 0; | 363 | pendingsig = 0; |
369 | raise_interrupt(); | 364 | raise_interrupt(); /* does not return */ |
370 | } | 365 | } |
371 | intpending = 1; | 366 | intpending = 1; |
372 | } | 367 | } |
@@ -3256,12 +3251,11 @@ setsignal(int signo) | |||
3256 | struct sigaction act; | 3251 | struct sigaction act; |
3257 | 3252 | ||
3258 | t = trap[signo]; | 3253 | t = trap[signo]; |
3254 | action = S_IGN; | ||
3259 | if (t == NULL) | 3255 | if (t == NULL) |
3260 | action = S_DFL; | 3256 | action = S_DFL; |
3261 | else if (*t != '\0') | 3257 | else if (*t != '\0') |
3262 | action = S_CATCH; | 3258 | action = S_CATCH; |
3263 | else | ||
3264 | action = S_IGN; | ||
3265 | if (rootshell && action == S_DFL) { | 3259 | if (rootshell && action == S_DFL) { |
3266 | switch (signo) { | 3260 | switch (signo) { |
3267 | case SIGINT: | 3261 | case SIGINT: |
@@ -3294,7 +3288,7 @@ setsignal(int signo) | |||
3294 | /* | 3288 | /* |
3295 | * current setting unknown | 3289 | * current setting unknown |
3296 | */ | 3290 | */ |
3297 | if (sigaction(signo, 0, &act) == -1) { | 3291 | if (sigaction(signo, NULL, &act) == -1) { |
3298 | /* | 3292 | /* |
3299 | * Pretend it worked; maybe we should give a warning | 3293 | * Pretend it worked; maybe we should give a warning |
3300 | * here, but other shells don't. We don't alter | 3294 | * here, but other shells don't. We don't alter |
@@ -3302,19 +3296,19 @@ setsignal(int signo) | |||
3302 | */ | 3296 | */ |
3303 | return; | 3297 | return; |
3304 | } | 3298 | } |
3299 | tsig = S_RESET; /* force to be set */ | ||
3305 | if (act.sa_handler == SIG_IGN) { | 3300 | if (act.sa_handler == SIG_IGN) { |
3301 | tsig = S_HARD_IGN; | ||
3306 | if (mflag | 3302 | if (mflag |
3307 | && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) | 3303 | && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) |
3308 | ) { | 3304 | ) { |
3309 | tsig = S_IGN; /* don't hard ignore these */ | 3305 | tsig = S_IGN; /* don't hard ignore these */ |
3310 | } else | 3306 | } |
3311 | tsig = S_HARD_IGN; | ||
3312 | } else { | ||
3313 | tsig = S_RESET; /* force to be set */ | ||
3314 | } | 3307 | } |
3315 | } | 3308 | } |
3316 | if (tsig == S_HARD_IGN || tsig == action) | 3309 | if (tsig == S_HARD_IGN || tsig == action) |
3317 | return; | 3310 | return; |
3311 | act.sa_handler = SIG_DFL; | ||
3318 | switch (action) { | 3312 | switch (action) { |
3319 | case S_CATCH: | 3313 | case S_CATCH: |
3320 | act.sa_handler = onsig; | 3314 | act.sa_handler = onsig; |
@@ -3322,13 +3316,11 @@ setsignal(int signo) | |||
3322 | case S_IGN: | 3316 | case S_IGN: |
3323 | act.sa_handler = SIG_IGN; | 3317 | act.sa_handler = SIG_IGN; |
3324 | break; | 3318 | break; |
3325 | default: | ||
3326 | act.sa_handler = SIG_DFL; | ||
3327 | } | 3319 | } |
3328 | *t = action; | 3320 | *t = action; |
3329 | act.sa_flags = 0; | 3321 | act.sa_flags = 0; |
3330 | sigfillset(&act.sa_mask); | 3322 | sigfillset(&act.sa_mask); |
3331 | sigaction(signo, &act, 0); | 3323 | sigaction(signo, &act, NULL); |
3332 | } | 3324 | } |
3333 | 3325 | ||
3334 | /* mode flags for set_curjob */ | 3326 | /* mode flags for set_curjob */ |
@@ -3763,7 +3755,8 @@ waitproc(int wait_flags, int *status) | |||
3763 | if (jobctl) | 3755 | if (jobctl) |
3764 | wait_flags |= WUNTRACED; | 3756 | wait_flags |= WUNTRACED; |
3765 | #endif | 3757 | #endif |
3766 | return waitpid(-1, status, wait_flags); // safe_waitpid? | 3758 | /* NB: _not_ safe_waitpid, we need to detect EINTR */ |
3759 | return waitpid(-1, status, wait_flags); | ||
3767 | } | 3760 | } |
3768 | 3761 | ||
3769 | /* | 3762 | /* |
@@ -3781,8 +3774,14 @@ dowait(int wait_flags, struct job *job) | |||
3781 | TRACE(("dowait(%d) called\n", wait_flags)); | 3774 | TRACE(("dowait(%d) called\n", wait_flags)); |
3782 | pid = waitproc(wait_flags, &status); | 3775 | pid = waitproc(wait_flags, &status); |
3783 | TRACE(("wait returns pid=%d, status=%d\n", pid, status)); | 3776 | TRACE(("wait returns pid=%d, status=%d\n", pid, status)); |
3784 | if (pid <= 0) | 3777 | if (pid <= 0) { |
3778 | /* If we were doing blocking wait and (probably) got EINTR, | ||
3779 | * check for pending sigs received while waiting. | ||
3780 | * (NB: can be moved into callers if needed) */ | ||
3781 | if (wait_flags == DOWAIT_BLOCK && pendingsig) | ||
3782 | raise_exception(EXSIG); | ||
3785 | return pid; | 3783 | return pid; |
3784 | } | ||
3786 | INT_OFF; | 3785 | INT_OFF; |
3787 | thisjob = NULL; | 3786 | thisjob = NULL; |
3788 | for (jp = curjob; jp; jp = jp->prev_job) { | 3787 | for (jp = curjob; jp; jp = jp->prev_job) { |
@@ -4004,7 +4003,10 @@ waitcmd(int argc, char **argv) | |||
4004 | int retval; | 4003 | int retval; |
4005 | struct job *jp; | 4004 | struct job *jp; |
4006 | 4005 | ||
4007 | EXSIGON; | 4006 | // exsig++; |
4007 | // xbarrier(); | ||
4008 | if (pendingsig) | ||
4009 | raise_exception(EXSIG); | ||
4008 | 4010 | ||
4009 | nextopt(nullstr); | 4011 | nextopt(nullstr); |
4010 | retval = 0; | 4012 | retval = 0; |
@@ -4015,10 +4017,8 @@ waitcmd(int argc, char **argv) | |||
4015 | for (;;) { | 4017 | for (;;) { |
4016 | jp = curjob; | 4018 | jp = curjob; |
4017 | while (1) { | 4019 | while (1) { |
4018 | if (!jp) { | 4020 | if (!jp) /* no running procs */ |
4019 | /* no running procs */ | 4021 | goto ret; |
4020 | goto out; | ||
4021 | } | ||
4022 | if (jp->state == JOBRUNNING) | 4022 | if (jp->state == JOBRUNNING) |
4023 | break; | 4023 | break; |
4024 | jp->waited = 1; | 4024 | jp->waited = 1; |
@@ -4051,7 +4051,7 @@ waitcmd(int argc, char **argv) | |||
4051 | ; | 4051 | ; |
4052 | } while (*++argv); | 4052 | } while (*++argv); |
4053 | 4053 | ||
4054 | out: | 4054 | ret: |
4055 | return retval; | 4055 | return retval; |
4056 | } | 4056 | } |
4057 | 4057 | ||
@@ -4450,7 +4450,7 @@ clear_traps(void) | |||
4450 | char **tp; | 4450 | char **tp; |
4451 | 4451 | ||
4452 | for (tp = trap; tp < &trap[NSIG]; tp++) { | 4452 | for (tp = trap; tp < &trap[NSIG]; tp++) { |
4453 | if (*tp && **tp) { /* trap not NULL or SIG_IGN */ | 4453 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ |
4454 | INT_OFF; | 4454 | INT_OFF; |
4455 | free(*tp); | 4455 | free(*tp); |
4456 | *tp = NULL; | 4456 | *tp = NULL; |
@@ -4613,8 +4613,8 @@ waitforjob(struct job *jp) | |||
4613 | * intuit from the subprocess exit status whether a SIGINT | 4613 | * intuit from the subprocess exit status whether a SIGINT |
4614 | * occurred, and if so interrupt ourselves. Yuck. - mycroft | 4614 | * occurred, and if so interrupt ourselves. Yuck. - mycroft |
4615 | */ | 4615 | */ |
4616 | if (jp->sigint) | 4616 | if (jp->sigint) /* TODO: do the same with all signals */ |
4617 | raise(SIGINT); | 4617 | raise(SIGINT); /* ... by raise(jp->sig) instead? */ |
4618 | } | 4618 | } |
4619 | if (jp->state == JOBDONE) | 4619 | if (jp->state == JOBDONE) |
4620 | #endif | 4620 | #endif |
@@ -6268,7 +6268,7 @@ expmeta(char *enddir, char *name) | |||
6268 | p++; | 6268 | p++; |
6269 | if (*p == '.') | 6269 | if (*p == '.') |
6270 | matchdot++; | 6270 | matchdot++; |
6271 | while (! intpending && (dp = readdir(dirp)) != NULL) { | 6271 | while (!intpending && (dp = readdir(dirp)) != NULL) { |
6272 | if (dp->d_name[0] == '.' && ! matchdot) | 6272 | if (dp->d_name[0] == '.' && ! matchdot) |
6273 | continue; | 6273 | continue; |
6274 | if (pmatch(start, dp->d_name)) { | 6274 | if (pmatch(start, dp->d_name)) { |
@@ -7437,7 +7437,7 @@ dotrap(void) | |||
7437 | char *q; | 7437 | char *q; |
7438 | int i; | 7438 | int i; |
7439 | int savestatus; | 7439 | int savestatus; |
7440 | int skip = 0; | 7440 | int skip; |
7441 | 7441 | ||
7442 | savestatus = exitstatus; | 7442 | savestatus = exitstatus; |
7443 | pendingsig = 0; | 7443 | pendingsig = 0; |
@@ -7454,10 +7454,10 @@ dotrap(void) | |||
7454 | skip = evalstring(p, SKIPEVAL); | 7454 | skip = evalstring(p, SKIPEVAL); |
7455 | exitstatus = savestatus; | 7455 | exitstatus = savestatus; |
7456 | if (skip) | 7456 | if (skip) |
7457 | break; | 7457 | return skip; |
7458 | } | 7458 | } |
7459 | 7459 | ||
7460 | return skip; | 7460 | return 0; |
7461 | } | 7461 | } |
7462 | 7462 | ||
7463 | /* forward declarations - evaluation is fairly recursive business... */ | 7463 | /* forward declarations - evaluation is fairly recursive business... */ |
@@ -8434,22 +8434,15 @@ evalcommand(union node *cmd, int flags) | |||
8434 | } | 8434 | } |
8435 | if (evalbltin(cmdentry.u.cmd, argc, argv)) { | 8435 | if (evalbltin(cmdentry.u.cmd, argc, argv)) { |
8436 | int exit_status; | 8436 | int exit_status; |
8437 | int i, j; | 8437 | int i = exception; |
8438 | |||
8439 | i = exception; | ||
8440 | if (i == EXEXIT) | 8438 | if (i == EXEXIT) |
8441 | goto raise; | 8439 | goto raise; |
8442 | |||
8443 | exit_status = 2; | 8440 | exit_status = 2; |
8444 | j = 0; | ||
8445 | if (i == EXINT) | 8441 | if (i == EXINT) |
8446 | j = SIGINT; | 8442 | exit_status = 128 + SIGINT; |
8447 | if (i == EXSIG) | 8443 | if (i == EXSIG) |
8448 | j = pendingsig; | 8444 | exit_status = 128 + pendingsig; |
8449 | if (j) | ||
8450 | exit_status = j + 128; | ||
8451 | exitstatus = exit_status; | 8445 | exitstatus = exit_status; |
8452 | |||
8453 | if (i == EXINT || spclbltin > 0) { | 8446 | if (i == EXINT || spclbltin > 0) { |
8454 | raise: | 8447 | raise: |
8455 | longjmp(exception_handler->loc, 1); | 8448 | longjmp(exception_handler->loc, 1); |
@@ -8499,7 +8492,7 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv) | |||
8499 | exitstatus |= ferror(stdout); | 8492 | exitstatus |= ferror(stdout); |
8500 | clearerr(stdout); | 8493 | clearerr(stdout); |
8501 | commandname = savecmdname; | 8494 | commandname = savecmdname; |
8502 | exsig = 0; | 8495 | // exsig = 0; |
8503 | exception_handler = savehandler; | 8496 | exception_handler = savehandler; |
8504 | 8497 | ||
8505 | return i; | 8498 | return i; |