aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-02-10 19:02:53 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-02-10 19:02:53 +0000
commit991a1da14806eefd1c6fc8fc1c0c3d2b90af6f24 (patch)
tree4397962a82c1b4c161ee3b9af88943d64c5b993b /shell/ash.c
parent0ef240d979b0ffcad104a6844cee4c72640844f5 (diff)
downloadbusybox-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.c103
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;