diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 01:05:03 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 01:05:03 +0000 |
| commit | 5c67e3ed90f559b61b02aa013ad4dd7d57fce772 (patch) | |
| tree | 65c9d248b9b3c05a11a4c88dec739e5c1c26c140 /shell | |
| parent | fe1f00a7a7fe19e330ad9c610e21823b93bed8ed (diff) | |
| download | busybox-w32-5c67e3ed90f559b61b02aa013ad4dd7d57fce772.tar.gz busybox-w32-5c67e3ed90f559b61b02aa013ad4dd7d57fce772.tar.bz2 busybox-w32-5c67e3ed90f559b61b02aa013ad4dd7d57fce772.zip | |
ash: cleanup part 5
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 903 |
1 files changed, 439 insertions, 464 deletions
diff --git a/shell/ash.c b/shell/ash.c index 7ffecf43d..54fc8ea48 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -175,6 +175,18 @@ static int exsig; | |||
| 175 | static volatile sig_atomic_t pendingsigs; | 175 | static volatile sig_atomic_t pendingsigs; |
| 176 | 176 | ||
| 177 | /* | 177 | /* |
| 178 | * Sigmode records the current value of the signal handlers for the various | ||
| 179 | * modes. A value of zero means that the current handler is not known. | ||
| 180 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | ||
| 181 | */ | ||
| 182 | |||
| 183 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | ||
| 184 | #define S_CATCH 2 /* signal is caught */ | ||
| 185 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | ||
| 186 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ | ||
| 187 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ | ||
| 188 | |||
| 189 | /* | ||
| 178 | * These macros allow the user to suspend the handling of interrupt signals | 190 | * These macros allow the user to suspend the handling of interrupt signals |
| 179 | * over a period of time. This is similar to SIGHOLD to or sigblock, but | 191 | * over a period of time. This is similar to SIGHOLD to or sigblock, but |
| 180 | * much more efficient and portable. (But hacking the kernel is so much | 192 | * much more efficient and portable. (But hacking the kernel is so much |
| @@ -285,6 +297,34 @@ force_int_on(void) | |||
| 285 | }) | 297 | }) |
| 286 | /* EXSIG is turned off by evalbltin(). */ | 298 | /* EXSIG is turned off by evalbltin(). */ |
| 287 | 299 | ||
| 300 | /* | ||
| 301 | * Ignore a signal. Only one usage site - in forkchild() | ||
| 302 | */ | ||
| 303 | static void | ||
| 304 | ignoresig(int signo) | ||
| 305 | { | ||
| 306 | if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { | ||
| 307 | signal(signo, SIG_IGN); | ||
| 308 | } | ||
| 309 | sigmode[signo - 1] = S_HARD_IGN; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Signal handler. Only one usage site - in setsignal() | ||
| 314 | */ | ||
| 315 | static void | ||
| 316 | onsig(int signo) | ||
| 317 | { | ||
| 318 | gotsig[signo - 1] = 1; | ||
| 319 | pendingsigs = signo; | ||
| 320 | |||
| 321 | if (exsig || (signo == SIGINT && !trap[SIGINT])) { | ||
| 322 | if (!suppressint) | ||
| 323 | raise_interrupt(); | ||
| 324 | intpending = 1; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 288 | 328 | ||
| 289 | /* ============ stdout/stderr output */ | 329 | /* ============ stdout/stderr output */ |
| 290 | 330 | ||
| @@ -3244,10 +3284,10 @@ static void unsetfunc(const char *); | |||
| 3244 | 3284 | ||
| 3245 | #if ENABLE_ASH_MATH_SUPPORT_64 | 3285 | #if ENABLE_ASH_MATH_SUPPORT_64 |
| 3246 | typedef int64_t arith_t; | 3286 | typedef int64_t arith_t; |
| 3247 | #define arith_t_type (long long) | 3287 | #define arith_t_type long long |
| 3248 | #else | 3288 | #else |
| 3249 | typedef long arith_t; | 3289 | typedef long arith_t; |
| 3250 | #define arith_t_type (long) | 3290 | #define arith_t_type long |
| 3251 | #endif | 3291 | #endif |
| 3252 | 3292 | ||
| 3253 | #if ENABLE_ASH_MATH_SUPPORT | 3293 | #if ENABLE_ASH_MATH_SUPPORT |
| @@ -3341,7 +3381,6 @@ static int jobctl; /* true if doing job control */ | |||
| 3341 | static struct job *makejob(union node *, int); | 3381 | static struct job *makejob(union node *, int); |
| 3342 | static int forkshell(struct job *, union node *, int); | 3382 | static int forkshell(struct job *, union node *, int); |
| 3343 | static int waitforjob(struct job *); | 3383 | static int waitforjob(struct job *); |
| 3344 | static int stoppedjobs(void); | ||
| 3345 | 3384 | ||
| 3346 | #if ! JOBS | 3385 | #if ! JOBS |
| 3347 | #define setjobctl(on) /* do nothing */ | 3386 | #define setjobctl(on) /* do nothing */ |
| @@ -3384,8 +3423,6 @@ static int redirectsafe(union node *, int); | |||
| 3384 | 3423 | ||
| 3385 | static void clear_traps(void); | 3424 | static void clear_traps(void); |
| 3386 | static void setsignal(int); | 3425 | static void setsignal(int); |
| 3387 | static void ignoresig(int); | ||
| 3388 | static void onsig(int); | ||
| 3389 | static int dotrap(void); | 3426 | static int dotrap(void); |
| 3390 | static void setinteractive(int); | 3427 | static void setinteractive(int); |
| 3391 | static void exitshell(void) ATTRIBUTE_NORETURN; | 3428 | static void exitshell(void) ATTRIBUTE_NORETURN; |
| @@ -7226,38 +7263,26 @@ closescript(void) | |||
| 7226 | #define DOWAIT_NORMAL 0 | 7263 | #define DOWAIT_NORMAL 0 |
| 7227 | #define DOWAIT_BLOCK 1 | 7264 | #define DOWAIT_BLOCK 1 |
| 7228 | 7265 | ||
| 7229 | /* array of jobs */ | ||
| 7230 | static struct job *jobtab; | ||
| 7231 | /* size of array */ | ||
| 7232 | static unsigned njobs; | ||
| 7233 | #if JOBS | 7266 | #if JOBS |
| 7234 | /* pgrp of shell on invocation */ | 7267 | /* pgrp of shell on invocation */ |
| 7235 | static int initialpgrp; | 7268 | static int initialpgrp; |
| 7236 | static int ttyfd = -1; | 7269 | static int ttyfd = -1; |
| 7237 | #endif | 7270 | #endif |
| 7271 | /* array of jobs */ | ||
| 7272 | static struct job *jobtab; | ||
| 7273 | /* size of array */ | ||
| 7274 | static unsigned njobs; | ||
| 7238 | /* current job */ | 7275 | /* current job */ |
| 7239 | static struct job *curjob; | 7276 | static struct job *curjob; |
| 7240 | /* number of presumed living untracked jobs */ | 7277 | /* number of presumed living untracked jobs */ |
| 7241 | static int jobless; | 7278 | static int jobless; |
| 7242 | 7279 | ||
| 7243 | static void set_curjob(struct job *, unsigned); | ||
| 7244 | #if JOBS | 7280 | #if JOBS |
| 7245 | static int restartjob(struct job *, int); | ||
| 7246 | static void xtcsetpgrp(int, pid_t); | ||
| 7247 | static char *commandtext(union node *); | 7281 | static char *commandtext(union node *); |
| 7248 | static void cmdlist(union node *, int); | 7282 | static void cmdlist(union node *, int); |
| 7249 | static void cmdtxt(union node *); | 7283 | static void cmdtxt(union node *); |
| 7250 | static void cmdputs(const char *); | 7284 | static void cmdputs(const char *); |
| 7251 | static void showpipe(struct job *, FILE *); | ||
| 7252 | #endif | 7285 | #endif |
| 7253 | static int sprint_status(char *, int, int); | ||
| 7254 | static void freejob(struct job *); | ||
| 7255 | static struct job *getjob(const char *, int); | ||
| 7256 | static struct job *growjobtab(void); | ||
| 7257 | static void forkchild(struct job *, union node *, int); | ||
| 7258 | static void forkparent(struct job *, union node *, int, pid_t); | ||
| 7259 | static int dowait(int, struct job *); | ||
| 7260 | static int getstatus(struct job *); | ||
| 7261 | 7286 | ||
| 7262 | static void | 7287 | static void |
| 7263 | set_curjob(struct job *jp, unsigned mode) | 7288 | set_curjob(struct job *jp, unsigned mode) |
| @@ -7307,7 +7332,126 @@ set_curjob(struct job *jp, unsigned mode) | |||
| 7307 | } | 7332 | } |
| 7308 | } | 7333 | } |
| 7309 | 7334 | ||
| 7335 | #if JOBS || DEBUG | ||
| 7336 | static int | ||
| 7337 | jobno(const struct job *jp) | ||
| 7338 | { | ||
| 7339 | return jp - jobtab + 1; | ||
| 7340 | } | ||
| 7341 | #endif | ||
| 7342 | |||
| 7343 | /* | ||
| 7344 | * Convert a job name to a job structure. | ||
| 7345 | */ | ||
| 7346 | static struct job * | ||
| 7347 | getjob(const char *name, int getctl) | ||
| 7348 | { | ||
| 7349 | struct job *jp; | ||
| 7350 | struct job *found; | ||
| 7351 | const char *err_msg = "No such job: %s"; | ||
| 7352 | unsigned num; | ||
| 7353 | int c; | ||
| 7354 | const char *p; | ||
| 7355 | char *(*match)(const char *, const char *); | ||
| 7356 | |||
| 7357 | jp = curjob; | ||
| 7358 | p = name; | ||
| 7359 | if (!p) | ||
| 7360 | goto currentjob; | ||
| 7361 | |||
| 7362 | if (*p != '%') | ||
| 7363 | goto err; | ||
| 7364 | |||
| 7365 | c = *++p; | ||
| 7366 | if (!c) | ||
| 7367 | goto currentjob; | ||
| 7368 | |||
| 7369 | if (!p[1]) { | ||
| 7370 | if (c == '+' || c == '%') { | ||
| 7371 | currentjob: | ||
| 7372 | err_msg = "No current job"; | ||
| 7373 | goto check; | ||
| 7374 | } | ||
| 7375 | if (c == '-') { | ||
| 7376 | if (jp) | ||
| 7377 | jp = jp->prev_job; | ||
| 7378 | err_msg = "No previous job"; | ||
| 7379 | check: | ||
| 7380 | if (!jp) | ||
| 7381 | goto err; | ||
| 7382 | goto gotit; | ||
| 7383 | } | ||
| 7384 | } | ||
| 7385 | |||
| 7386 | if (is_number(p)) { | ||
| 7387 | num = atoi(p); | ||
| 7388 | if (num < njobs) { | ||
| 7389 | jp = jobtab + num - 1; | ||
| 7390 | if (jp->used) | ||
| 7391 | goto gotit; | ||
| 7392 | goto err; | ||
| 7393 | } | ||
| 7394 | } | ||
| 7395 | |||
| 7396 | match = prefix; | ||
| 7397 | if (*p == '?') { | ||
| 7398 | match = strstr; | ||
| 7399 | p++; | ||
| 7400 | } | ||
| 7401 | |||
| 7402 | found = 0; | ||
| 7403 | while (1) { | ||
| 7404 | if (!jp) | ||
| 7405 | goto err; | ||
| 7406 | if (match(jp->ps[0].cmd, p)) { | ||
| 7407 | if (found) | ||
| 7408 | goto err; | ||
| 7409 | found = jp; | ||
| 7410 | err_msg = "%s: ambiguous"; | ||
| 7411 | } | ||
| 7412 | jp = jp->prev_job; | ||
| 7413 | } | ||
| 7414 | |||
| 7415 | gotit: | ||
| 7416 | #if JOBS | ||
| 7417 | err_msg = "job %s not created under job control"; | ||
| 7418 | if (getctl && jp->jobctl == 0) | ||
| 7419 | goto err; | ||
| 7420 | #endif | ||
| 7421 | return jp; | ||
| 7422 | err: | ||
| 7423 | ash_msg_and_raise_error(err_msg, name); | ||
| 7424 | } | ||
| 7425 | |||
| 7426 | /* | ||
| 7427 | * Mark a job structure as unused. | ||
| 7428 | */ | ||
| 7429 | static void | ||
| 7430 | freejob(struct job *jp) | ||
| 7431 | { | ||
| 7432 | struct procstat *ps; | ||
| 7433 | int i; | ||
| 7434 | |||
| 7435 | INT_OFF; | ||
| 7436 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | ||
| 7437 | if (ps->cmd != nullstr) | ||
| 7438 | free(ps->cmd); | ||
| 7439 | } | ||
| 7440 | if (jp->ps != &jp->ps0) | ||
| 7441 | free(jp->ps); | ||
| 7442 | jp->used = 0; | ||
| 7443 | set_curjob(jp, CUR_DELETE); | ||
| 7444 | INT_ON; | ||
| 7445 | } | ||
| 7446 | |||
| 7310 | #if JOBS | 7447 | #if JOBS |
| 7448 | static void | ||
| 7449 | xtcsetpgrp(int fd, pid_t pgrp) | ||
| 7450 | { | ||
| 7451 | if (tcsetpgrp(fd, pgrp)) | ||
| 7452 | ash_msg_and_raise_error("Cannot set tty process group (%m)"); | ||
| 7453 | } | ||
| 7454 | |||
| 7311 | /* | 7455 | /* |
| 7312 | * Turn job control on and off. | 7456 | * Turn job control on and off. |
| 7313 | * | 7457 | * |
| @@ -7401,7 +7545,7 @@ killcmd(int argc, char **argv) | |||
| 7401 | if (signo < 0) { | 7545 | if (signo < 0) { |
| 7402 | int c; | 7546 | int c; |
| 7403 | 7547 | ||
| 7404 | while ((c = nextopt("ls:")) != '\0') | 7548 | while ((c = nextopt("ls:")) != '\0') { |
| 7405 | switch (c) { | 7549 | switch (c) { |
| 7406 | default: | 7550 | default: |
| 7407 | #if DEBUG | 7551 | #if DEBUG |
| @@ -7420,6 +7564,7 @@ killcmd(int argc, char **argv) | |||
| 7420 | } | 7564 | } |
| 7421 | break; | 7565 | break; |
| 7422 | } | 7566 | } |
| 7567 | } | ||
| 7423 | argv = argptr; | 7568 | argv = argptr; |
| 7424 | } else | 7569 | } else |
| 7425 | argv++; | 7570 | argv++; |
| @@ -7467,42 +7612,21 @@ killcmd(int argc, char **argv) | |||
| 7467 | 7612 | ||
| 7468 | return i; | 7613 | return i; |
| 7469 | } | 7614 | } |
| 7470 | #endif /* JOBS */ | ||
| 7471 | |||
| 7472 | #if JOBS || DEBUG | ||
| 7473 | static int | ||
| 7474 | jobno(const struct job *jp) | ||
| 7475 | { | ||
| 7476 | return jp - jobtab + 1; | ||
| 7477 | } | ||
| 7478 | #endif | ||
| 7479 | 7615 | ||
| 7480 | #if JOBS | 7616 | static void |
| 7481 | static int | 7617 | showpipe(struct job *jp, FILE *out) |
| 7482 | fg_bgcmd(int argc, char **argv) | ||
| 7483 | { | 7618 | { |
| 7484 | struct job *jp; | 7619 | struct procstat *sp; |
| 7485 | FILE *out; | 7620 | struct procstat *spend; |
| 7486 | int mode; | ||
| 7487 | int retval; | ||
| 7488 | 7621 | ||
| 7489 | mode = (**argv == 'f') ? FORK_FG : FORK_BG; | 7622 | spend = jp->ps + jp->nprocs; |
| 7490 | nextopt(nullstr); | 7623 | for (sp = jp->ps + 1; sp < spend; sp++) |
| 7491 | argv = argptr; | 7624 | fprintf(out, " | %s", sp->cmd); |
| 7492 | out = stdout; | 7625 | outcslow('\n', out); |
| 7493 | do { | 7626 | flush_stdout_stderr(); |
| 7494 | jp = getjob(*argv, 1); | ||
| 7495 | if (mode == FORK_BG) { | ||
| 7496 | set_curjob(jp, CUR_RUNNING); | ||
| 7497 | fprintf(out, "[%d] ", jobno(jp)); | ||
| 7498 | } | ||
| 7499 | outstr(jp->ps->cmd, out); | ||
| 7500 | showpipe(jp, out); | ||
| 7501 | retval = restartjob(jp, mode); | ||
| 7502 | } while (*argv && *++argv); | ||
| 7503 | return retval; | ||
| 7504 | } | 7627 | } |
| 7505 | 7628 | ||
| 7629 | |||
| 7506 | static int | 7630 | static int |
| 7507 | restartjob(struct job *jp, int mode) | 7631 | restartjob(struct job *jp, int mode) |
| 7508 | { | 7632 | { |
| @@ -7531,6 +7655,31 @@ restartjob(struct job *jp, int mode) | |||
| 7531 | INT_ON; | 7655 | INT_ON; |
| 7532 | return status; | 7656 | return status; |
| 7533 | } | 7657 | } |
| 7658 | |||
| 7659 | static int | ||
| 7660 | fg_bgcmd(int argc, char **argv) | ||
| 7661 | { | ||
| 7662 | struct job *jp; | ||
| 7663 | FILE *out; | ||
| 7664 | int mode; | ||
| 7665 | int retval; | ||
| 7666 | |||
| 7667 | mode = (**argv == 'f') ? FORK_FG : FORK_BG; | ||
| 7668 | nextopt(nullstr); | ||
| 7669 | argv = argptr; | ||
| 7670 | out = stdout; | ||
| 7671 | do { | ||
| 7672 | jp = getjob(*argv, 1); | ||
| 7673 | if (mode == FORK_BG) { | ||
| 7674 | set_curjob(jp, CUR_RUNNING); | ||
| 7675 | fprintf(out, "[%d] ", jobno(jp)); | ||
| 7676 | } | ||
| 7677 | outstr(jp->ps->cmd, out); | ||
| 7678 | showpipe(jp, out); | ||
| 7679 | retval = restartjob(jp, mode); | ||
| 7680 | } while (*argv && *++argv); | ||
| 7681 | return retval; | ||
| 7682 | } | ||
| 7534 | #endif | 7683 | #endif |
| 7535 | 7684 | ||
| 7536 | static int | 7685 | static int |
| @@ -7571,6 +7720,137 @@ sprint_status(char *s, int status, int sigonly) | |||
| 7571 | return col; | 7720 | return col; |
| 7572 | } | 7721 | } |
| 7573 | 7722 | ||
| 7723 | /* | ||
| 7724 | * Do a wait system call. If job control is compiled in, we accept | ||
| 7725 | * stopped processes. If block is zero, we return a value of zero | ||
| 7726 | * rather than blocking. | ||
| 7727 | * | ||
| 7728 | * System V doesn't have a non-blocking wait system call. It does | ||
| 7729 | * have a SIGCLD signal that is sent to a process when one of it's | ||
| 7730 | * children dies. The obvious way to use SIGCLD would be to install | ||
| 7731 | * a handler for SIGCLD which simply bumped a counter when a SIGCLD | ||
| 7732 | * was received, and have waitproc bump another counter when it got | ||
| 7733 | * the status of a process. Waitproc would then know that a wait | ||
| 7734 | * system call would not block if the two counters were different. | ||
| 7735 | * This approach doesn't work because if a process has children that | ||
| 7736 | * have not been waited for, System V will send it a SIGCLD when it | ||
| 7737 | * installs a signal handler for SIGCLD. What this means is that when | ||
| 7738 | * a child exits, the shell will be sent SIGCLD signals continuously | ||
| 7739 | * until is runs out of stack space, unless it does a wait call before | ||
| 7740 | * restoring the signal handler. The code below takes advantage of | ||
| 7741 | * this (mis)feature by installing a signal handler for SIGCLD and | ||
| 7742 | * then checking to see whether it was called. If there are any | ||
| 7743 | * children to be waited for, it will be. | ||
| 7744 | * | ||
| 7745 | * If neither SYSV nor BSD is defined, we don't implement nonblocking | ||
| 7746 | * waits at all. In this case, the user will not be informed when | ||
| 7747 | * a background process until the next time she runs a real program | ||
| 7748 | * (as opposed to running a builtin command or just typing return), | ||
| 7749 | * and the jobs command may give out of date information. | ||
| 7750 | */ | ||
| 7751 | static int | ||
| 7752 | waitproc(int block, int *status) | ||
| 7753 | { | ||
| 7754 | int flags = 0; | ||
| 7755 | |||
| 7756 | #if JOBS | ||
| 7757 | if (jobctl) | ||
| 7758 | flags |= WUNTRACED; | ||
| 7759 | #endif | ||
| 7760 | if (block == 0) | ||
| 7761 | flags |= WNOHANG; | ||
| 7762 | return wait3(status, flags, (struct rusage *)NULL); | ||
| 7763 | } | ||
| 7764 | |||
| 7765 | /* | ||
| 7766 | * Wait for a process to terminate. | ||
| 7767 | */ | ||
| 7768 | static int | ||
| 7769 | dowait(int block, struct job *job) | ||
| 7770 | { | ||
| 7771 | int pid; | ||
| 7772 | int status; | ||
| 7773 | struct job *jp; | ||
| 7774 | struct job *thisjob; | ||
| 7775 | int state; | ||
| 7776 | |||
| 7777 | TRACE(("dowait(%d) called\n", block)); | ||
| 7778 | pid = waitproc(block, &status); | ||
| 7779 | TRACE(("wait returns pid %d, status=%d\n", pid, status)); | ||
| 7780 | if (pid <= 0) | ||
| 7781 | return pid; | ||
| 7782 | INT_OFF; | ||
| 7783 | thisjob = NULL; | ||
| 7784 | for (jp = curjob; jp; jp = jp->prev_job) { | ||
| 7785 | struct procstat *sp; | ||
| 7786 | struct procstat *spend; | ||
| 7787 | if (jp->state == JOBDONE) | ||
| 7788 | continue; | ||
| 7789 | state = JOBDONE; | ||
| 7790 | spend = jp->ps + jp->nprocs; | ||
| 7791 | sp = jp->ps; | ||
| 7792 | do { | ||
| 7793 | if (sp->pid == pid) { | ||
| 7794 | TRACE(("Job %d: changing status of proc %d " | ||
| 7795 | "from 0x%x to 0x%x\n", | ||
| 7796 | jobno(jp), pid, sp->status, status)); | ||
| 7797 | sp->status = status; | ||
| 7798 | thisjob = jp; | ||
| 7799 | } | ||
| 7800 | if (sp->status == -1) | ||
| 7801 | state = JOBRUNNING; | ||
| 7802 | #if JOBS | ||
| 7803 | if (state == JOBRUNNING) | ||
| 7804 | continue; | ||
| 7805 | if (WIFSTOPPED(sp->status)) { | ||
| 7806 | jp->stopstatus = sp->status; | ||
| 7807 | state = JOBSTOPPED; | ||
| 7808 | } | ||
| 7809 | #endif | ||
| 7810 | } while (++sp < spend); | ||
| 7811 | if (thisjob) | ||
| 7812 | goto gotjob; | ||
| 7813 | } | ||
| 7814 | #if JOBS | ||
| 7815 | if (!WIFSTOPPED(status)) | ||
| 7816 | #endif | ||
| 7817 | |||
| 7818 | jobless--; | ||
| 7819 | goto out; | ||
| 7820 | |||
| 7821 | gotjob: | ||
| 7822 | if (state != JOBRUNNING) { | ||
| 7823 | thisjob->changed = 1; | ||
| 7824 | |||
| 7825 | if (thisjob->state != state) { | ||
| 7826 | TRACE(("Job %d: changing state from %d to %d\n", | ||
| 7827 | jobno(thisjob), thisjob->state, state)); | ||
| 7828 | thisjob->state = state; | ||
| 7829 | #if JOBS | ||
| 7830 | if (state == JOBSTOPPED) { | ||
| 7831 | set_curjob(thisjob, CUR_STOPPED); | ||
| 7832 | } | ||
| 7833 | #endif | ||
| 7834 | } | ||
| 7835 | } | ||
| 7836 | |||
| 7837 | out: | ||
| 7838 | INT_ON; | ||
| 7839 | |||
| 7840 | if (thisjob && thisjob == job) { | ||
| 7841 | char s[48 + 1]; | ||
| 7842 | int len; | ||
| 7843 | |||
| 7844 | len = sprint_status(s, status, 1); | ||
| 7845 | if (len) { | ||
| 7846 | s[len] = '\n'; | ||
| 7847 | s[len + 1] = 0; | ||
| 7848 | out2str(s); | ||
| 7849 | } | ||
| 7850 | } | ||
| 7851 | return pid; | ||
| 7852 | } | ||
| 7853 | |||
| 7574 | #if JOBS | 7854 | #if JOBS |
| 7575 | static void | 7855 | static void |
| 7576 | showjob(FILE *out, struct job *jp, int mode) | 7856 | showjob(FILE *out, struct job *jp, int mode) |
| @@ -7641,7 +7921,6 @@ showjob(FILE *out, struct job *jp, int mode) | |||
| 7641 | } | 7921 | } |
| 7642 | } | 7922 | } |
| 7643 | 7923 | ||
| 7644 | |||
| 7645 | static int | 7924 | static int |
| 7646 | jobscmd(int argc, char **argv) | 7925 | jobscmd(int argc, char **argv) |
| 7647 | { | 7926 | { |
| @@ -7668,7 +7947,6 @@ jobscmd(int argc, char **argv) | |||
| 7668 | return 0; | 7947 | return 0; |
| 7669 | } | 7948 | } |
| 7670 | 7949 | ||
| 7671 | |||
| 7672 | /* | 7950 | /* |
| 7673 | * Print a list of jobs. If "change" is nonzero, only print jobs whose | 7951 | * Print a list of jobs. If "change" is nonzero, only print jobs whose |
| 7674 | * statuses have changed since the last call to showjobs. | 7952 | * statuses have changed since the last call to showjobs. |
| @@ -7691,29 +7969,34 @@ showjobs(FILE *out, int mode) | |||
| 7691 | } | 7969 | } |
| 7692 | #endif /* JOBS */ | 7970 | #endif /* JOBS */ |
| 7693 | 7971 | ||
| 7694 | 7972 | static int | |
| 7695 | /* | 7973 | getstatus(struct job *job) |
| 7696 | * Mark a job structure as unused. | ||
| 7697 | */ | ||
| 7698 | static void | ||
| 7699 | freejob(struct job *jp) | ||
| 7700 | { | 7974 | { |
| 7701 | struct procstat *ps; | 7975 | int status; |
| 7702 | int i; | 7976 | int retval; |
| 7703 | 7977 | ||
| 7704 | INT_OFF; | 7978 | status = job->ps[job->nprocs - 1].status; |
| 7705 | for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { | 7979 | retval = WEXITSTATUS(status); |
| 7706 | if (ps->cmd != nullstr) | 7980 | if (!WIFEXITED(status)) { |
| 7707 | free(ps->cmd); | 7981 | #if JOBS |
| 7982 | retval = WSTOPSIG(status); | ||
| 7983 | if (!WIFSTOPPED(status)) | ||
| 7984 | #endif | ||
| 7985 | { | ||
| 7986 | /* XXX: limits number of signals */ | ||
| 7987 | retval = WTERMSIG(status); | ||
| 7988 | #if JOBS | ||
| 7989 | if (retval == SIGINT) | ||
| 7990 | job->sigint = 1; | ||
| 7991 | #endif | ||
| 7992 | } | ||
| 7993 | retval += 128; | ||
| 7708 | } | 7994 | } |
| 7709 | if (jp->ps != &jp->ps0) | 7995 | TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", |
| 7710 | free(jp->ps); | 7996 | jobno(job), job->nprocs, status, retval)); |
| 7711 | jp->used = 0; | 7997 | return retval; |
| 7712 | set_curjob(jp, CUR_DELETE); | ||
| 7713 | INT_ON; | ||
| 7714 | } | 7998 | } |
| 7715 | 7999 | ||
| 7716 | |||
| 7717 | static int | 8000 | static int |
| 7718 | waitcmd(int argc, char **argv) | 8001 | waitcmd(int argc, char **argv) |
| 7719 | { | 8002 | { |
| @@ -7774,91 +8057,49 @@ waitcmd(int argc, char **argv) | |||
| 7774 | return retval; | 8057 | return retval; |
| 7775 | } | 8058 | } |
| 7776 | 8059 | ||
| 7777 | |||
| 7778 | /* | ||
| 7779 | * Convert a job name to a job structure. | ||
| 7780 | */ | ||
| 7781 | static struct job * | 8060 | static struct job * |
| 7782 | getjob(const char *name, int getctl) | 8061 | growjobtab(void) |
| 7783 | { | 8062 | { |
| 7784 | struct job *jp; | 8063 | size_t len; |
| 7785 | struct job *found; | 8064 | ptrdiff_t offset; |
| 7786 | const char *err_msg = "No such job: %s"; | 8065 | struct job *jp, *jq; |
| 7787 | unsigned num; | ||
| 7788 | int c; | ||
| 7789 | const char *p; | ||
| 7790 | char *(*match)(const char *, const char *); | ||
| 7791 | |||
| 7792 | jp = curjob; | ||
| 7793 | p = name; | ||
| 7794 | if (!p) | ||
| 7795 | goto currentjob; | ||
| 7796 | |||
| 7797 | if (*p != '%') | ||
| 7798 | goto err; | ||
| 7799 | |||
| 7800 | c = *++p; | ||
| 7801 | if (!c) | ||
| 7802 | goto currentjob; | ||
| 7803 | |||
| 7804 | if (!p[1]) { | ||
| 7805 | if (c == '+' || c == '%') { | ||
| 7806 | currentjob: | ||
| 7807 | err_msg = "No current job"; | ||
| 7808 | goto check; | ||
| 7809 | } | ||
| 7810 | if (c == '-') { | ||
| 7811 | if (jp) | ||
| 7812 | jp = jp->prev_job; | ||
| 7813 | err_msg = "No previous job"; | ||
| 7814 | check: | ||
| 7815 | if (!jp) | ||
| 7816 | goto err; | ||
| 7817 | goto gotit; | ||
| 7818 | } | ||
| 7819 | } | ||
| 7820 | 8066 | ||
| 7821 | if (is_number(p)) { | 8067 | len = njobs * sizeof(*jp); |
| 7822 | num = atoi(p); | 8068 | jq = jobtab; |
| 7823 | if (num < njobs) { | 8069 | jp = ckrealloc(jq, len + 4 * sizeof(*jp)); |
| 7824 | jp = jobtab + num - 1; | ||
| 7825 | if (jp->used) | ||
| 7826 | goto gotit; | ||
| 7827 | goto err; | ||
| 7828 | } | ||
| 7829 | } | ||
| 7830 | 8070 | ||
| 7831 | match = prefix; | 8071 | offset = (char *)jp - (char *)jq; |
| 7832 | if (*p == '?') { | 8072 | if (offset) { |
| 7833 | match = strstr; | 8073 | /* Relocate pointers */ |
| 7834 | p++; | 8074 | size_t l = len; |
| 7835 | } | ||
| 7836 | 8075 | ||
| 7837 | found = 0; | 8076 | jq = (struct job *)((char *)jq + l); |
| 7838 | while (1) { | 8077 | while (l) { |
| 7839 | if (!jp) | 8078 | l -= sizeof(*jp); |
| 7840 | goto err; | 8079 | jq--; |
| 7841 | if (match(jp->ps[0].cmd, p)) { | 8080 | #define joff(p) ((struct job *)((char *)(p) + l)) |
| 7842 | if (found) | 8081 | #define jmove(p) (p) = (void *)((char *)(p) + offset) |
| 7843 | goto err; | 8082 | if (xlikely(joff(jp)->ps == &jq->ps0)) |
| 7844 | found = jp; | 8083 | jmove(joff(jp)->ps); |
| 7845 | err_msg = "%s: ambiguous"; | 8084 | if (joff(jp)->prev_job) |
| 8085 | jmove(joff(jp)->prev_job); | ||
| 7846 | } | 8086 | } |
| 7847 | jp = jp->prev_job; | 8087 | if (curjob) |
| 8088 | jmove(curjob); | ||
| 8089 | #undef joff | ||
| 8090 | #undef jmove | ||
| 7848 | } | 8091 | } |
| 7849 | 8092 | ||
| 7850 | gotit: | 8093 | njobs += 4; |
| 7851 | #if JOBS | 8094 | jobtab = jp; |
| 7852 | err_msg = "job %s not created under job control"; | 8095 | jp = (struct job *)((char *)jp + len); |
| 7853 | if (getctl && jp->jobctl == 0) | 8096 | jq = jp + 3; |
| 7854 | goto err; | 8097 | do { |
| 7855 | #endif | 8098 | jq->used = 0; |
| 8099 | } while (--jq >= jp); | ||
| 7856 | return jp; | 8100 | return jp; |
| 7857 | err: | ||
| 7858 | ash_msg_and_raise_error(err_msg, name); | ||
| 7859 | } | 8101 | } |
| 7860 | 8102 | ||
| 7861 | |||
| 7862 | /* | 8103 | /* |
| 7863 | * Return a new job structure. | 8104 | * Return a new job structure. |
| 7864 | * Called with interrupts off. | 8105 | * Called with interrupts off. |
| @@ -7902,50 +8143,6 @@ makejob(union node *node, int nprocs) | |||
| 7902 | return jp; | 8143 | return jp; |
| 7903 | } | 8144 | } |
| 7904 | 8145 | ||
| 7905 | static struct job * | ||
| 7906 | growjobtab(void) | ||
| 7907 | { | ||
| 7908 | size_t len; | ||
| 7909 | ptrdiff_t offset; | ||
| 7910 | struct job *jp, *jq; | ||
| 7911 | |||
| 7912 | len = njobs * sizeof(*jp); | ||
| 7913 | jq = jobtab; | ||
| 7914 | jp = ckrealloc(jq, len + 4 * sizeof(*jp)); | ||
| 7915 | |||
| 7916 | offset = (char *)jp - (char *)jq; | ||
| 7917 | if (offset) { | ||
| 7918 | /* Relocate pointers */ | ||
| 7919 | size_t l = len; | ||
| 7920 | |||
| 7921 | jq = (struct job *)((char *)jq + l); | ||
| 7922 | while (l) { | ||
| 7923 | l -= sizeof(*jp); | ||
| 7924 | jq--; | ||
| 7925 | #define joff(p) ((struct job *)((char *)(p) + l)) | ||
| 7926 | #define jmove(p) (p) = (void *)((char *)(p) + offset) | ||
| 7927 | if (xlikely(joff(jp)->ps == &jq->ps0)) | ||
| 7928 | jmove(joff(jp)->ps); | ||
| 7929 | if (joff(jp)->prev_job) | ||
| 7930 | jmove(joff(jp)->prev_job); | ||
| 7931 | } | ||
| 7932 | if (curjob) | ||
| 7933 | jmove(curjob); | ||
| 7934 | #undef joff | ||
| 7935 | #undef jmove | ||
| 7936 | } | ||
| 7937 | |||
| 7938 | njobs += 4; | ||
| 7939 | jobtab = jp; | ||
| 7940 | jp = (struct job *)((char *)jp + len); | ||
| 7941 | jq = jp + 3; | ||
| 7942 | do { | ||
| 7943 | jq->used = 0; | ||
| 7944 | } while (--jq >= jp); | ||
| 7945 | return jp; | ||
| 7946 | } | ||
| 7947 | |||
| 7948 | |||
| 7949 | /* | 8146 | /* |
| 7950 | * Fork off a subshell. If we are doing job control, give the subshell its | 8147 | * Fork off a subshell. If we are doing job control, give the subshell its |
| 7951 | * own process group. Jp is a job structure that the job is to be added to. | 8148 | * own process group. Jp is a job structure that the job is to be added to. |
| @@ -7962,7 +8159,8 @@ growjobtab(void) | |||
| 7962 | * | 8159 | * |
| 7963 | * Called with interrupts off. | 8160 | * Called with interrupts off. |
| 7964 | */ | 8161 | */ |
| 7965 | static void forkchild(struct job *jp, union node *n, int mode) | 8162 | static void |
| 8163 | forkchild(struct job *jp, union node *n, int mode) | ||
| 7966 | { | 8164 | { |
| 7967 | int oldlvl; | 8165 | int oldlvl; |
| 7968 | 8166 | ||
| @@ -8009,7 +8207,8 @@ static void forkchild(struct job *jp, union node *n, int mode) | |||
| 8009 | jobless = 0; | 8207 | jobless = 0; |
| 8010 | } | 8208 | } |
| 8011 | 8209 | ||
| 8012 | static void forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 8210 | static void |
| 8211 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | ||
| 8013 | { | 8212 | { |
| 8014 | TRACE(("In parent shell: child = %d\n", pid)); | 8213 | TRACE(("In parent shell: child = %d\n", pid)); |
| 8015 | if (!jp) { | 8214 | if (!jp) { |
| @@ -8065,7 +8264,6 @@ forkshell(struct job *jp, union node *n, int mode) | |||
| 8065 | return pid; | 8264 | return pid; |
| 8066 | } | 8265 | } |
| 8067 | 8266 | ||
| 8068 | |||
| 8069 | /* | 8267 | /* |
| 8070 | * Wait for job to finish. | 8268 | * Wait for job to finish. |
| 8071 | * | 8269 | * |
| @@ -8116,144 +8314,10 @@ waitforjob(struct job *jp) | |||
| 8116 | return st; | 8314 | return st; |
| 8117 | } | 8315 | } |
| 8118 | 8316 | ||
| 8119 | |||
| 8120 | /* | ||
| 8121 | * Do a wait system call. If job control is compiled in, we accept | ||
| 8122 | * stopped processes. If block is zero, we return a value of zero | ||
| 8123 | * rather than blocking. | ||
| 8124 | * | ||
| 8125 | * System V doesn't have a non-blocking wait system call. It does | ||
| 8126 | * have a SIGCLD signal that is sent to a process when one of it's | ||
| 8127 | * children dies. The obvious way to use SIGCLD would be to install | ||
| 8128 | * a handler for SIGCLD which simply bumped a counter when a SIGCLD | ||
| 8129 | * was received, and have waitproc bump another counter when it got | ||
| 8130 | * the status of a process. Waitproc would then know that a wait | ||
| 8131 | * system call would not block if the two counters were different. | ||
| 8132 | * This approach doesn't work because if a process has children that | ||
| 8133 | * have not been waited for, System V will send it a SIGCLD when it | ||
| 8134 | * installs a signal handler for SIGCLD. What this means is that when | ||
| 8135 | * a child exits, the shell will be sent SIGCLD signals continuously | ||
| 8136 | * until is runs out of stack space, unless it does a wait call before | ||
| 8137 | * restoring the signal handler. The code below takes advantage of | ||
| 8138 | * this (mis)feature by installing a signal handler for SIGCLD and | ||
| 8139 | * then checking to see whether it was called. If there are any | ||
| 8140 | * children to be waited for, it will be. | ||
| 8141 | * | ||
| 8142 | * If neither SYSV nor BSD is defined, we don't implement nonblocking | ||
| 8143 | * waits at all. In this case, the user will not be informed when | ||
| 8144 | * a background process until the next time she runs a real program | ||
| 8145 | * (as opposed to running a builtin command or just typing return), | ||
| 8146 | * and the jobs command may give out of date information. | ||
| 8147 | */ | ||
| 8148 | static int | ||
| 8149 | waitproc(int block, int *status) | ||
| 8150 | { | ||
| 8151 | int flags = 0; | ||
| 8152 | |||
| 8153 | #if JOBS | ||
| 8154 | if (jobctl) | ||
| 8155 | flags |= WUNTRACED; | ||
| 8156 | #endif | ||
| 8157 | if (block == 0) | ||
| 8158 | flags |= WNOHANG; | ||
| 8159 | return wait3(status, flags, (struct rusage *)NULL); | ||
| 8160 | } | ||
| 8161 | |||
| 8162 | |||
| 8163 | /* | ||
| 8164 | * Wait for a process to terminate. | ||
| 8165 | */ | ||
| 8166 | static int | ||
| 8167 | dowait(int block, struct job *job) | ||
| 8168 | { | ||
| 8169 | int pid; | ||
| 8170 | int status; | ||
| 8171 | struct job *jp; | ||
| 8172 | struct job *thisjob; | ||
| 8173 | int state; | ||
| 8174 | |||
| 8175 | TRACE(("dowait(%d) called\n", block)); | ||
| 8176 | pid = waitproc(block, &status); | ||
| 8177 | TRACE(("wait returns pid %d, status=%d\n", pid, status)); | ||
| 8178 | if (pid <= 0) | ||
| 8179 | return pid; | ||
| 8180 | INT_OFF; | ||
| 8181 | thisjob = NULL; | ||
| 8182 | for (jp = curjob; jp; jp = jp->prev_job) { | ||
| 8183 | struct procstat *sp; | ||
| 8184 | struct procstat *spend; | ||
| 8185 | if (jp->state == JOBDONE) | ||
| 8186 | continue; | ||
| 8187 | state = JOBDONE; | ||
| 8188 | spend = jp->ps + jp->nprocs; | ||
| 8189 | sp = jp->ps; | ||
| 8190 | do { | ||
| 8191 | if (sp->pid == pid) { | ||
| 8192 | TRACE(("Job %d: changing status of proc %d " | ||
| 8193 | "from 0x%x to 0x%x\n", | ||
| 8194 | jobno(jp), pid, sp->status, status)); | ||
| 8195 | sp->status = status; | ||
| 8196 | thisjob = jp; | ||
| 8197 | } | ||
| 8198 | if (sp->status == -1) | ||
| 8199 | state = JOBRUNNING; | ||
| 8200 | #if JOBS | ||
| 8201 | if (state == JOBRUNNING) | ||
| 8202 | continue; | ||
| 8203 | if (WIFSTOPPED(sp->status)) { | ||
| 8204 | jp->stopstatus = sp->status; | ||
| 8205 | state = JOBSTOPPED; | ||
| 8206 | } | ||
| 8207 | #endif | ||
| 8208 | } while (++sp < spend); | ||
| 8209 | if (thisjob) | ||
| 8210 | goto gotjob; | ||
| 8211 | } | ||
| 8212 | #if JOBS | ||
| 8213 | if (!WIFSTOPPED(status)) | ||
| 8214 | #endif | ||
| 8215 | |||
| 8216 | jobless--; | ||
| 8217 | goto out; | ||
| 8218 | |||
| 8219 | gotjob: | ||
| 8220 | if (state != JOBRUNNING) { | ||
| 8221 | thisjob->changed = 1; | ||
| 8222 | |||
| 8223 | if (thisjob->state != state) { | ||
| 8224 | TRACE(("Job %d: changing state from %d to %d\n", | ||
| 8225 | jobno(thisjob), thisjob->state, state)); | ||
| 8226 | thisjob->state = state; | ||
| 8227 | #if JOBS | ||
| 8228 | if (state == JOBSTOPPED) { | ||
| 8229 | set_curjob(thisjob, CUR_STOPPED); | ||
| 8230 | } | ||
| 8231 | #endif | ||
| 8232 | } | ||
| 8233 | } | ||
| 8234 | |||
| 8235 | out: | ||
| 8236 | INT_ON; | ||
| 8237 | |||
| 8238 | if (thisjob && thisjob == job) { | ||
| 8239 | char s[48 + 1]; | ||
| 8240 | int len; | ||
| 8241 | |||
| 8242 | len = sprint_status(s, status, 1); | ||
| 8243 | if (len) { | ||
| 8244 | s[len] = '\n'; | ||
| 8245 | s[len + 1] = 0; | ||
| 8246 | out2str(s); | ||
| 8247 | } | ||
| 8248 | } | ||
| 8249 | return pid; | ||
| 8250 | } | ||
| 8251 | |||
| 8252 | |||
| 8253 | /* | 8317 | /* |
| 8254 | * return 1 if there are stopped jobs, otherwise 0 | 8318 | * return 1 if there are stopped jobs, otherwise 0 |
| 8255 | */ | 8319 | */ |
| 8256 | int | 8320 | static int |
| 8257 | stoppedjobs(void) | 8321 | stoppedjobs(void) |
| 8258 | { | 8322 | { |
| 8259 | struct job *jp; | 8323 | struct job *jp; |
| @@ -8289,7 +8353,7 @@ commandtext(union node *n) | |||
| 8289 | cmdtxt(n); | 8353 | cmdtxt(n); |
| 8290 | name = stackblock(); | 8354 | name = stackblock(); |
| 8291 | TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", | 8355 | TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", |
| 8292 | name, cmdnextc, cmdnextc)); | 8356 | name, cmdnextc, cmdnextc)); |
| 8293 | return ckstrdup(name); | 8357 | return ckstrdup(name); |
| 8294 | } | 8358 | } |
| 8295 | 8359 | ||
| @@ -8550,57 +8614,8 @@ cmdputs(const char *s) | |||
| 8550 | *nextc = 0; | 8614 | *nextc = 0; |
| 8551 | cmdnextc = nextc; | 8615 | cmdnextc = nextc; |
| 8552 | } | 8616 | } |
| 8553 | |||
| 8554 | |||
| 8555 | static void | ||
| 8556 | showpipe(struct job *jp, FILE *out) | ||
| 8557 | { | ||
| 8558 | struct procstat *sp; | ||
| 8559 | struct procstat *spend; | ||
| 8560 | |||
| 8561 | spend = jp->ps + jp->nprocs; | ||
| 8562 | for (sp = jp->ps + 1; sp < spend; sp++) | ||
| 8563 | fprintf(out, " | %s", sp->cmd); | ||
| 8564 | outcslow('\n', out); | ||
| 8565 | flush_stdout_stderr(); | ||
| 8566 | } | ||
| 8567 | |||
| 8568 | static void | ||
| 8569 | xtcsetpgrp(int fd, pid_t pgrp) | ||
| 8570 | { | ||
| 8571 | if (tcsetpgrp(fd, pgrp)) | ||
| 8572 | ash_msg_and_raise_error("Cannot set tty process group (%m)"); | ||
| 8573 | } | ||
| 8574 | #endif /* JOBS */ | 8617 | #endif /* JOBS */ |
| 8575 | 8618 | ||
| 8576 | static int | ||
| 8577 | getstatus(struct job *job) | ||
| 8578 | { | ||
| 8579 | int status; | ||
| 8580 | int retval; | ||
| 8581 | |||
| 8582 | status = job->ps[job->nprocs - 1].status; | ||
| 8583 | retval = WEXITSTATUS(status); | ||
| 8584 | if (!WIFEXITED(status)) { | ||
| 8585 | #if JOBS | ||
| 8586 | retval = WSTOPSIG(status); | ||
| 8587 | if (!WIFSTOPPED(status)) | ||
| 8588 | #endif | ||
| 8589 | { | ||
| 8590 | /* XXX: limits number of signals */ | ||
| 8591 | retval = WTERMSIG(status); | ||
| 8592 | #if JOBS | ||
| 8593 | if (retval == SIGINT) | ||
| 8594 | job->sigint = 1; | ||
| 8595 | #endif | ||
| 8596 | } | ||
| 8597 | retval += 128; | ||
| 8598 | } | ||
| 8599 | TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", | ||
| 8600 | jobno(job), job->nprocs, status, retval)); | ||
| 8601 | return retval; | ||
| 8602 | } | ||
| 8603 | |||
| 8604 | #if ENABLE_ASH_MAIL | 8619 | #if ENABLE_ASH_MAIL |
| 8605 | /* mail.c */ | 8620 | /* mail.c */ |
| 8606 | 8621 | ||
| @@ -11333,17 +11348,6 @@ redirectsafe(union node *redir, int flags) | |||
| 11333 | 11348 | ||
| 11334 | /* trap.c */ | 11349 | /* trap.c */ |
| 11335 | 11350 | ||
| 11336 | /* | ||
| 11337 | * Sigmode records the current value of the signal handlers for the various | ||
| 11338 | * modes. A value of zero means that the current handler is not known. | ||
| 11339 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | ||
| 11340 | */ | ||
| 11341 | |||
| 11342 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | ||
| 11343 | #define S_CATCH 2 /* signal is caught */ | ||
| 11344 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | ||
| 11345 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ | ||
| 11346 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ | ||
| 11347 | 11351 | ||
| 11348 | 11352 | ||
| 11349 | /* | 11353 | /* |
| @@ -11507,36 +11511,6 @@ setsignal(int signo) | |||
| 11507 | 11511 | ||
| 11508 | 11512 | ||
| 11509 | /* | 11513 | /* |
| 11510 | * Ignore a signal. | ||
| 11511 | */ | ||
| 11512 | static void | ||
| 11513 | ignoresig(int signo) | ||
| 11514 | { | ||
| 11515 | if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { | ||
| 11516 | signal(signo, SIG_IGN); | ||
| 11517 | } | ||
| 11518 | sigmode[signo - 1] = S_HARD_IGN; | ||
| 11519 | } | ||
| 11520 | |||
| 11521 | |||
| 11522 | /* | ||
| 11523 | * Signal handler. | ||
| 11524 | */ | ||
| 11525 | static void | ||
| 11526 | onsig(int signo) | ||
| 11527 | { | ||
| 11528 | gotsig[signo - 1] = 1; | ||
| 11529 | pendingsigs = signo; | ||
| 11530 | |||
| 11531 | if (exsig || (signo == SIGINT && !trap[SIGINT])) { | ||
| 11532 | if (!suppressint) | ||
| 11533 | raise_interrupt(); | ||
| 11534 | intpending = 1; | ||
| 11535 | } | ||
| 11536 | } | ||
| 11537 | |||
| 11538 | |||
| 11539 | /* | ||
| 11540 | * Called to execute a trap. Perhaps we should avoid entering new trap | 11514 | * Called to execute a trap. Perhaps we should avoid entering new trap |
| 11541 | * handlers while we are executing a trap handler. | 11515 | * handlers while we are executing a trap handler. |
| 11542 | */ | 11516 | */ |
| @@ -11587,7 +11561,7 @@ setinteractive(int on) | |||
| 11587 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | 11561 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET |
| 11588 | if (is_interactive > 1) { | 11562 | if (is_interactive > 1) { |
| 11589 | /* Looks like they want an interactive shell */ | 11563 | /* Looks like they want an interactive shell */ |
| 11590 | static int do_banner; | 11564 | static smallint do_banner; |
| 11591 | 11565 | ||
| 11592 | if (!do_banner) { | 11566 | if (!do_banner) { |
| 11593 | out1fmt( | 11567 | out1fmt( |
| @@ -11596,15 +11570,16 @@ setinteractive(int on) | |||
| 11596 | "Enter 'help' for a list of built-in commands." | 11570 | "Enter 'help' for a list of built-in commands." |
| 11597 | "\n\n", | 11571 | "\n\n", |
| 11598 | BB_BANNER); | 11572 | BB_BANNER); |
| 11599 | do_banner++; | 11573 | do_banner = 1; |
| 11600 | } | 11574 | } |
| 11601 | } | 11575 | } |
| 11602 | #endif | 11576 | #endif |
| 11603 | } | 11577 | } |
| 11604 | 11578 | ||
| 11605 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | 11579 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET |
| 11606 | /*** List the available builtins ***/ | 11580 | /* |
| 11607 | 11581 | * Lists available builtins | |
| 11582 | */ | ||
| 11608 | static int | 11583 | static int |
| 11609 | helpcmd(int argc, char **argv) | 11584 | helpcmd(int argc, char **argv) |
| 11610 | { | 11585 | { |
| @@ -11711,7 +11686,8 @@ exportcmd(int argc, char **argv) | |||
| 11711 | * will be restored when the shell function returns. We handle the name | 11686 | * will be restored when the shell function returns. We handle the name |
| 11712 | * "-" as a special case. | 11687 | * "-" as a special case. |
| 11713 | */ | 11688 | */ |
| 11714 | static void mklocal(char *name) | 11689 | static void |
| 11690 | mklocal(char *name) | ||
| 11715 | { | 11691 | { |
| 11716 | struct localvar *lvp; | 11692 | struct localvar *lvp; |
| 11717 | struct var **vpp; | 11693 | struct var **vpp; |
| @@ -11811,9 +11787,10 @@ static const unsigned char timescmd_str[] = { | |||
| 11811 | 0 | 11787 | 0 |
| 11812 | }; | 11788 | }; |
| 11813 | 11789 | ||
| 11814 | static int timescmd(int ac, char **av) | 11790 | static int |
| 11791 | timescmd(int ac, char **av) | ||
| 11815 | { | 11792 | { |
| 11816 | long int clk_tck, s, t; | 11793 | long clk_tck, s, t; |
| 11817 | const unsigned char *p; | 11794 | const unsigned char *p; |
| 11818 | struct tms buf; | 11795 | struct tms buf; |
| 11819 | 11796 | ||
| @@ -11845,12 +11822,11 @@ dash_arith(const char *s) | |||
| 11845 | if (errcode < 0) { | 11822 | if (errcode < 0) { |
| 11846 | if (errcode == -3) | 11823 | if (errcode == -3) |
| 11847 | ash_msg_and_raise_error("exponent less than 0"); | 11824 | ash_msg_and_raise_error("exponent less than 0"); |
| 11848 | else if (errcode == -2) | 11825 | if (errcode == -2) |
| 11849 | ash_msg_and_raise_error("divide by zero"); | 11826 | ash_msg_and_raise_error("divide by zero"); |
| 11850 | else if (errcode == -5) | 11827 | if (errcode == -5) |
| 11851 | ash_msg_and_raise_error("expression recursion loop detected"); | 11828 | ash_msg_and_raise_error("expression recursion loop detected"); |
| 11852 | else | 11829 | raise_error_syntax(s); |
| 11853 | raise_error_syntax(s); | ||
| 11854 | } | 11830 | } |
| 11855 | INT_ON; | 11831 | INT_ON; |
| 11856 | 11832 | ||
| @@ -12083,7 +12059,8 @@ readcmd(int argc, char **argv) | |||
| 12083 | } | 12059 | } |
| 12084 | 12060 | ||
| 12085 | 12061 | ||
| 12086 | static int umaskcmd(int argc, char **argv) | 12062 | static int |
| 12063 | umaskcmd(int argc, char **argv) | ||
| 12087 | { | 12064 | { |
| 12088 | static const char permuser[3] = "ugo"; | 12065 | static const char permuser[3] = "ugo"; |
| 12089 | static const char permmode[3] = "rwx"; | 12066 | static const char permmode[3] = "rwx"; |
| @@ -12201,12 +12178,13 @@ static const struct limits limits[] = { | |||
| 12201 | #ifdef RLIMIT_LOCKS | 12178 | #ifdef RLIMIT_LOCKS |
| 12202 | { "locks", RLIMIT_LOCKS, 1, 'w' }, | 12179 | { "locks", RLIMIT_LOCKS, 1, 'w' }, |
| 12203 | #endif | 12180 | #endif |
| 12204 | { (char *) 0, 0, 0, '\0' } | 12181 | { NULL, 0, 0, '\0' } |
| 12205 | }; | 12182 | }; |
| 12206 | 12183 | ||
| 12207 | enum limtype { SOFT = 0x1, HARD = 0x2 }; | 12184 | enum limtype { SOFT = 0x1, HARD = 0x2 }; |
| 12208 | 12185 | ||
| 12209 | static void printlim(enum limtype how, const struct rlimit *limit, | 12186 | static void |
| 12187 | printlim(enum limtype how, const struct rlimit *limit, | ||
| 12210 | const struct limits *l) | 12188 | const struct limits *l) |
| 12211 | { | 12189 | { |
| 12212 | rlim_t val; | 12190 | rlim_t val; |
| @@ -12223,16 +12201,16 @@ static void printlim(enum limtype how, const struct rlimit *limit, | |||
| 12223 | } | 12201 | } |
| 12224 | } | 12202 | } |
| 12225 | 12203 | ||
| 12226 | int | 12204 | static int |
| 12227 | ulimitcmd(int argc, char **argv) | 12205 | ulimitcmd(int argc, char **argv) |
| 12228 | { | 12206 | { |
| 12229 | int c; | 12207 | int c; |
| 12230 | rlim_t val = 0; | 12208 | rlim_t val = 0; |
| 12231 | enum limtype how = SOFT | HARD; | 12209 | enum limtype how = SOFT | HARD; |
| 12232 | const struct limits *l; | 12210 | const struct limits *l; |
| 12233 | int set, all = 0; | 12211 | int set, all = 0; |
| 12234 | int optc, what; | 12212 | int optc, what; |
| 12235 | struct rlimit limit; | 12213 | struct rlimit limit; |
| 12236 | 12214 | ||
| 12237 | what = 'f'; | 12215 | what = 'f'; |
| 12238 | while ((optc = nextopt("HSa" | 12216 | while ((optc = nextopt("HSa" |
| @@ -12428,11 +12406,9 @@ ulimitcmd(int argc, char **argv) | |||
| 12428 | * - always use special isspace(), see comment from bash ;-) | 12406 | * - always use special isspace(), see comment from bash ;-) |
| 12429 | */ | 12407 | */ |
| 12430 | 12408 | ||
| 12431 | |||
| 12432 | #define arith_isspace(arithval) \ | 12409 | #define arith_isspace(arithval) \ |
| 12433 | (arithval == ' ' || arithval == '\n' || arithval == '\t') | 12410 | (arithval == ' ' || arithval == '\n' || arithval == '\t') |
| 12434 | 12411 | ||
| 12435 | |||
| 12436 | typedef unsigned char operator; | 12412 | typedef unsigned char operator; |
| 12437 | 12413 | ||
| 12438 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the | 12414 | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the |
| @@ -12524,7 +12500,8 @@ typedef unsigned char operator; | |||
| 12524 | 12500 | ||
| 12525 | #define NUMPTR (*numstackptr) | 12501 | #define NUMPTR (*numstackptr) |
| 12526 | 12502 | ||
| 12527 | static int tok_have_assign(operator op) | 12503 | static int |
| 12504 | tok_have_assign(operator op) | ||
| 12528 | { | 12505 | { |
| 12529 | operator prec = PREC(op); | 12506 | operator prec = PREC(op); |
| 12530 | 12507 | ||
| @@ -12533,13 +12510,13 @@ static int tok_have_assign(operator op) | |||
| 12533 | prec == PREC_PRE || prec == PREC_POST); | 12510 | prec == PREC_PRE || prec == PREC_POST); |
| 12534 | } | 12511 | } |
| 12535 | 12512 | ||
| 12536 | static int is_right_associativity(operator prec) | 12513 | static int |
| 12514 | is_right_associativity(operator prec) | ||
| 12537 | { | 12515 | { |
| 12538 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) | 12516 | return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) |
| 12539 | || prec == PREC(TOK_CONDITIONAL)); | 12517 | || prec == PREC(TOK_CONDITIONAL)); |
| 12540 | } | 12518 | } |
| 12541 | 12519 | ||
| 12542 | |||
| 12543 | typedef struct ARITCH_VAR_NUM { | 12520 | typedef struct ARITCH_VAR_NUM { |
| 12544 | arith_t val; | 12521 | arith_t val; |
| 12545 | arith_t contidional_second_val; | 12522 | arith_t contidional_second_val; |
| @@ -12548,7 +12525,6 @@ typedef struct ARITCH_VAR_NUM { | |||
| 12548 | else is variable name */ | 12525 | else is variable name */ |
| 12549 | } v_n_t; | 12526 | } v_n_t; |
| 12550 | 12527 | ||
| 12551 | |||
| 12552 | typedef struct CHK_VAR_RECURSIVE_LOOPED { | 12528 | typedef struct CHK_VAR_RECURSIVE_LOOPED { |
| 12553 | const char *var; | 12529 | const char *var; |
| 12554 | struct CHK_VAR_RECURSIVE_LOOPED *next; | 12530 | struct CHK_VAR_RECURSIVE_LOOPED *next; |
| @@ -12556,8 +12532,8 @@ typedef struct CHK_VAR_RECURSIVE_LOOPED { | |||
| 12556 | 12532 | ||
| 12557 | static chk_var_recursive_looped_t *prev_chk_var_recursive; | 12533 | static chk_var_recursive_looped_t *prev_chk_var_recursive; |
| 12558 | 12534 | ||
| 12559 | 12535 | static int | |
| 12560 | static int arith_lookup_val(v_n_t *t) | 12536 | arith_lookup_val(v_n_t *t) |
| 12561 | { | 12537 | { |
| 12562 | if (t->var) { | 12538 | if (t->var) { |
| 12563 | const char * p = lookupvar(t->var); | 12539 | const char * p = lookupvar(t->var); |
| @@ -12595,7 +12571,8 @@ static int arith_lookup_val(v_n_t *t) | |||
| 12595 | /* "applying" a token means performing it on the top elements on the integer | 12571 | /* "applying" a token means performing it on the top elements on the integer |
| 12596 | * stack. For a unary operator it will only change the top element, but a | 12572 | * stack. For a unary operator it will only change the top element, but a |
| 12597 | * binary operator will pop two arguments and push a result */ | 12573 | * binary operator will pop two arguments and push a result */ |
| 12598 | static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | 12574 | static int |
| 12575 | arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | ||
| 12599 | { | 12576 | { |
| 12600 | v_n_t *numptr_m1; | 12577 | v_n_t *numptr_m1; |
| 12601 | arith_t numptr_val, rez; | 12578 | arith_t numptr_val, rez; |
| @@ -12692,12 +12669,10 @@ static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | |||
| 12692 | } | 12669 | } |
| 12693 | numptr_m1->contidional_second_val_initialized = op; | 12670 | numptr_m1->contidional_second_val_initialized = op; |
| 12694 | numptr_m1->contidional_second_val = numptr_val; | 12671 | numptr_m1->contidional_second_val = numptr_val; |
| 12695 | } | 12672 | } else if (op == TOK_CONDITIONAL) { |
| 12696 | else if (op == TOK_CONDITIONAL) { | ||
| 12697 | rez = rez ? | 12673 | rez = rez ? |
| 12698 | numptr_val : numptr_m1->contidional_second_val; | 12674 | numptr_val : numptr_m1->contidional_second_val; |
| 12699 | } | 12675 | } else if (op == TOK_EXPONENT) { |
| 12700 | else if (op == TOK_EXPONENT) { | ||
| 12701 | if (numptr_val < 0) | 12676 | if (numptr_val < 0) |
| 12702 | return -3; /* exponent less than 0 */ | 12677 | return -3; /* exponent less than 0 */ |
| 12703 | else { | 12678 | else { |
| @@ -12708,8 +12683,7 @@ static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | |||
| 12708 | c *= rez; | 12683 | c *= rez; |
| 12709 | rez = c; | 12684 | rez = c; |
| 12710 | } | 12685 | } |
| 12711 | } | 12686 | } else if (numptr_val==0) /* zero divisor check */ |
| 12712 | else if (numptr_val==0) /* zero divisor check */ | ||
| 12713 | return -2; | 12687 | return -2; |
| 12714 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) | 12688 | else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) |
| 12715 | rez /= numptr_val; | 12689 | rez /= numptr_val; |
| @@ -12717,7 +12691,7 @@ static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | |||
| 12717 | rez %= numptr_val; | 12691 | rez %= numptr_val; |
| 12718 | } | 12692 | } |
| 12719 | if (tok_have_assign(op)) { | 12693 | if (tok_have_assign(op)) { |
| 12720 | char buf[32]; | 12694 | char buf[sizeof(arith_t_type)*3 + 2]; |
| 12721 | 12695 | ||
| 12722 | if (numptr_m1->var == NULL) { | 12696 | if (numptr_m1->var == NULL) { |
| 12723 | /* Hmm, 1=2 ? */ | 12697 | /* Hmm, 1=2 ? */ |
| @@ -12725,9 +12699,9 @@ static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | |||
| 12725 | } | 12699 | } |
| 12726 | /* save to shell variable */ | 12700 | /* save to shell variable */ |
| 12727 | #if ENABLE_ASH_MATH_SUPPORT_64 | 12701 | #if ENABLE_ASH_MATH_SUPPORT_64 |
| 12728 | snprintf(buf, sizeof(buf), "%lld", arith_t_type rez); | 12702 | snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); |
| 12729 | #else | 12703 | #else |
| 12730 | snprintf(buf, sizeof(buf), "%ld", arith_t_type rez); | 12704 | snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); |
| 12731 | #endif | 12705 | #endif |
| 12732 | setvar(numptr_m1->var, buf, 0); | 12706 | setvar(numptr_m1->var, buf, 0); |
| 12733 | /* after saving, make previous value for v++ or v-- */ | 12707 | /* after saving, make previous value for v++ or v-- */ |
| @@ -12744,7 +12718,7 @@ static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) | |||
| 12744 | return -1; | 12718 | return -1; |
| 12745 | } | 12719 | } |
| 12746 | 12720 | ||
| 12747 | /* longest must first */ | 12721 | /* longest must be first */ |
| 12748 | static const char op_tokens[] = { | 12722 | static const char op_tokens[] = { |
| 12749 | '<','<','=',0, TOK_LSHIFT_ASSIGN, | 12723 | '<','<','=',0, TOK_LSHIFT_ASSIGN, |
| 12750 | '>','>','=',0, TOK_RSHIFT_ASSIGN, | 12724 | '>','>','=',0, TOK_RSHIFT_ASSIGN, |
| @@ -12792,7 +12766,8 @@ static const char op_tokens[] = { | |||
| 12792 | #define endexpression &op_tokens[sizeof(op_tokens)-7] | 12766 | #define endexpression &op_tokens[sizeof(op_tokens)-7] |
| 12793 | 12767 | ||
| 12794 | 12768 | ||
| 12795 | static arith_t arith(const char *expr, int *perrcode) | 12769 | static arith_t |
| 12770 | arith(const char *expr, int *perrcode) | ||
| 12796 | { | 12771 | { |
| 12797 | char arithval; /* Current character under analysis */ | 12772 | char arithval; /* Current character under analysis */ |
| 12798 | operator lasttok, op; | 12773 | operator lasttok, op; |
| @@ -12990,8 +12965,8 @@ static arith_t arith(const char *expr, int *perrcode) | |||
| 12990 | * exception occurs. When an exception occurs the variable "state" | 12965 | * exception occurs. When an exception occurs the variable "state" |
| 12991 | * is used to figure out how far we had gotten. | 12966 | * is used to figure out how far we had gotten. |
| 12992 | */ | 12967 | */ |
| 12993 | 12968 | static void | |
| 12994 | static void init(void) | 12969 | init(void) |
| 12995 | { | 12970 | { |
| 12996 | /* from input.c: */ | 12971 | /* from input.c: */ |
| 12997 | basepf.nextc = basepf.buf = basebuf; | 12972 | basepf.nextc = basepf.buf = basebuf; |
| @@ -13002,7 +12977,7 @@ static void init(void) | |||
| 13002 | /* from var.c: */ | 12977 | /* from var.c: */ |
| 13003 | { | 12978 | { |
| 13004 | char **envp; | 12979 | char **envp; |
| 13005 | char ppid[32]; | 12980 | char ppid[sizeof(int)*3 + 1]; |
| 13006 | const char *p; | 12981 | const char *p; |
| 13007 | struct stat st1, st2; | 12982 | struct stat st1, st2; |
| 13008 | 12983 | ||
| @@ -13013,7 +12988,7 @@ static void init(void) | |||
| 13013 | } | 12988 | } |
| 13014 | } | 12989 | } |
| 13015 | 12990 | ||
| 13016 | snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); | 12991 | snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); |
| 13017 | setvar("PPID", ppid, 0); | 12992 | setvar("PPID", ppid, 0); |
| 13018 | 12993 | ||
| 13019 | p = lookupvar("PWD"); | 12994 | p = lookupvar("PWD"); |
