diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:05:03 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:05:03 +0000 |
commit | 5b7579bbbaf369e6de72e5f063560f54b2637b08 (patch) | |
tree | 65c9d248b9b3c05a11a4c88dec739e5c1c26c140 /shell/ash.c | |
parent | 487a5f166d47cbc76877bb58240c1609bfcd8319 (diff) | |
download | busybox-w32-5b7579bbbaf369e6de72e5f063560f54b2637b08.tar.gz busybox-w32-5b7579bbbaf369e6de72e5f063560f54b2637b08.tar.bz2 busybox-w32-5b7579bbbaf369e6de72e5f063560f54b2637b08.zip |
ash: cleanup part 5
git-svn-id: svn://busybox.net/trunk/busybox@17957 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell/ash.c')
-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"); |