diff options
Diffstat (limited to 'bin/sh')
-rw-r--r-- | bin/sh/jobs.c | 197 | ||||
-rw-r--r-- | bin/sh/sh.1 | 25 |
2 files changed, 136 insertions, 86 deletions
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index 8722f67..de813c2 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -100,7 +100,8 @@ static void setcurjob(struct job *); static void deljob(struct job *); static struct job *getcurjob(struct job *); #endif -static void showjob(struct job *, pid_t, int); +static void printjobcmd(struct job *); +static void showjob(struct job *, int); /* @@ -205,8 +206,7 @@ fgcmd(int argc __unused, char **argv) jp = getjob(argv[1]); if (jp->jobctl == 0) error("job not created under job control"); - out1str(jp->ps[0].cmd); - out1c('\n'); + printjobcmd(jp); flushout(&output); pgrp = jp->ps[0].pid; tcsetpgrp(ttyfd, pgrp); @@ -235,8 +235,7 @@ bgcmd(int argc, char **argv) jp->foreground = 0; fmtstr(s, 64, "[%td] ", jp - jobtab + 1); out1str(s); - out1str(jp->ps[0].cmd); - out1c('\n'); + printjobcmd(jp); } while (--argc > 1); return 0; } @@ -296,19 +295,33 @@ jobscmd(int argc, char *argv[]) showjobs(0, mode); else while ((id = *argv++) != NULL) - showjob(getjob(id), 0, mode); + showjob(getjob(id), mode); return (0); } static void -showjob(struct job *jp, pid_t pid, int mode) +printjobcmd(struct job *jp) +{ + struct procstat *ps; + int i; + + for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { + out1str(ps->cmd); + if (i > 0) + out1str(" | "); + } + out1c('\n'); +} + +static void +showjob(struct job *jp, int mode) { char s[64]; + char statestr[64]; struct procstat *ps; struct job *j; int col, curr, i, jobno, prev, procno; - pid_t ppid; char c; procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs; @@ -321,16 +334,44 @@ showjob(struct job *jp, pid_t pid, int mode) prev = j - jobtab + 1; } #endif + ps = jp->ps + jp->nprocs - 1; + if (jp->state == 0) { + strcpy(statestr, "Running"); +#if JOBS + } else if (jp->state == JOBSTOPPED) { + while (!WIFSTOPPED(ps->status) && ps > jp->ps) + ps--; + if (WIFSTOPPED(ps->status)) + i = WSTOPSIG(ps->status); + else + i = -1; + if (i > 0 && i < sys_nsig && sys_siglist[i]) + strcpy(statestr, sys_siglist[i]); + else + strcpy(statestr, "Suspended"); +#endif + } else if (WIFEXITED(ps->status)) { + if (WEXITSTATUS(ps->status) == 0) + strcpy(statestr, "Done"); + else + fmtstr(statestr, 64, "Done(%d)", + WEXITSTATUS(ps->status)); + } else { + i = WTERMSIG(ps->status); + if (i > 0 && i < sys_nsig && sys_siglist[i]) + strcpy(statestr, sys_siglist[i]); + else + fmtstr(statestr, 64, "Signal %d", i); + if (WCOREDUMP(ps->status)) + strcat(statestr, " (core dumped)"); + } + for (ps = jp->ps ; ; ps++) { /* for each process */ if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) { - ppid = (mode == SHOWJOBS_PIDS) ? ps->pid : - getpgid(ps->pid); - out1fmt("%d\n", (int)ppid); + out1fmt("%d\n", (int)ps->pid); goto skip; } - if (mode != SHOWJOBS_VERBOSE && ps != jp->ps && pid == 0) - goto skip; - if (pid != 0 && pid != ps->pid) + if (mode != SHOWJOBS_VERBOSE && ps != jp->ps) goto skip; if (jobno == curr && ps == jp->ps) c = '+'; @@ -349,39 +390,19 @@ showjob(struct job *jp, pid_t pid, int mode) out1str(s); col += strlen(s); } - s[0] = '\0'; - if (ps != jp->ps) { - *s = '\0'; - } else if (ps->status == -1) { - strcpy(s, "Running"); - } else if (WIFEXITED(ps->status)) { - if (WEXITSTATUS(ps->status) == 0) - strcpy(s, "Done"); - else - fmtstr(s, 64, "Done (%d)", - WEXITSTATUS(ps->status)); - } else { -#if JOBS - if (WIFSTOPPED(ps->status)) - i = WSTOPSIG(ps->status); - else -#endif - i = WTERMSIG(ps->status); - if ((i & 0x7F) < sys_nsig && sys_siglist[i & 0x7F]) - scopy(sys_siglist[i & 0x7F], s); - else - fmtstr(s, 64, "Signal %d", i & 0x7F); - if (WCOREDUMP(ps->status)) - strcat(s, " (core dumped)"); + if (ps == jp->ps) { + out1str(statestr); + col += strlen(statestr); } - out1str(s); - col += strlen(s); do { out1c(' '); col++; } while (col < 30); - out1str(ps->cmd); - out1c('\n'); + if (mode == SHOWJOBS_VERBOSE) { + out1str(ps->cmd); + out1c('\n'); + } else + printjobcmd(jp); skip: if (--procno <= 0) break; } @@ -413,7 +434,7 @@ showjobs(int change, int mode) } if (change && ! jp->changed) continue; - showjob(jp, 0, mode); + showjob(jp, mode); jp->changed = 0; /* Hack: discard jobs for which $! has not been referenced * in interactive mode when they terminate. @@ -769,7 +790,7 @@ forkshell(struct job *jp, union node *n, int mode) TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n, mode)); INTOFF; - if (mode == FORK_BG) + if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0)) checkzombies(); flushall(); pid = fork(); @@ -961,7 +982,7 @@ dowait(int block, struct job *job) int done; int stopped; int sig; - int i; + int coredump; in_dowait++; TRACE(("dowait(%d) called\n", block)); @@ -983,7 +1004,7 @@ dowait(int block, struct job *job) INTOFF; thisjob = NULL; for (jp = jobtab ; jp < jobtab + njobs ; jp++) { - if (jp->used) { + if (jp->used && jp->nprocs > 0) { done = 1; stopped = 1; for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { @@ -1020,36 +1041,29 @@ dowait(int block, struct job *job) } } INTON; - if (! rootshell || ! iflag || (job && thisjob == job)) { -#if JOBS - if (WIFSTOPPED(status)) - sig = WSTOPSIG(status); - else -#endif - { - if (WIFEXITED(status)) - sig = 0; + if (!thisjob || thisjob->state == 0) + ; + else if ((!rootshell || !iflag || thisjob == job) && + thisjob->foreground && thisjob->state != JOBSTOPPED) { + sig = 0; + coredump = 0; + for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++) + if (WIFSIGNALED(sp->status)) { + sig = WTERMSIG(sp->status); + coredump = WCOREDUMP(sp->status); + } + if (sig > 0 && sig != SIGINT && sig != SIGPIPE) { + if (sig < sys_nsig && sys_siglist[sig]) + out1str(sys_siglist[sig]); else - sig = WTERMSIG(status); - } - if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { - if (!mflag || - (thisjob->foreground && !WIFSTOPPED(status))) { - i = WTERMSIG(status); - if ((i & 0x7F) < sys_nsig && sys_siglist[i & 0x7F]) - out1str(sys_siglist[i & 0x7F]); - else - out1fmt("Signal %d", i & 0x7F); - if (WCOREDUMP(status)) - out1str(" (core dumped)"); - out1c('\n'); - } else - showjob(thisjob, pid, SHOWJOBS_DEFAULT); + out1fmt("Signal %d", sig); + if (coredump) + out1str(" (core dumped)"); + out1c('\n'); } } else { TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job)); - if (thisjob) - thisjob->changed = 1; + thisjob->changed = 1; } return pid; } @@ -1300,13 +1314,46 @@ cmdputs(const char *s) if (--cmdnleft > 0) *q++ = '{'; subtype = *p++; + if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0) + *q++ = '#'; } else if (c == '=' && subtype != 0) { - *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; + *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL]; + if (*q) + q++; + else + cmdnleft++; + if (((subtype & VSTYPE) == VSTRIMLEFTMAX || + (subtype & VSTYPE) == VSTRIMRIGHTMAX) && + --cmdnleft > 0) + *q = q[-1], q++; subtype = 0; } else if (c == CTLENDVAR) { *q++ = '}'; - } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) - cmdnleft++; /* ignore it */ + } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) { + cmdnleft -= 5; + if (cmdnleft > 0) { + *q++ = '$'; + *q++ = '('; + *q++ = '.'; + *q++ = '.'; + *q++ = '.'; + *q++ = ')'; + } + } else if (c == CTLARI) { + cmdnleft -= 2; + if (cmdnleft > 0) { + *q++ = '$'; + *q++ = '('; + *q++ = '('; + } + p++; + } else if (c == CTLENDARI) { + if (--cmdnleft > 0) { + *q++ = ')'; + *q++ = ')'; + } + } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND) + cmdnleft++; /* ignore */ else *q++ = c; if (--cmdnleft <= 0) { diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 16f431e..a6fd7be 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -32,7 +32,7 @@ .\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95 .\" $FreeBSD$ .\" -.Dd December 1, 2010 +.Dd December 3, 2010 .Dt SH 1 .Os .Sh NAME @@ -1593,12 +1593,7 @@ To include a .Ql - , make it the first or last character listed. .Ss Built-in Commands -This section lists the commands which -are built-in because they need to perform some operation -that cannot be performed by a separate process. -In addition to -these, built-in versions of essential utilities -are provided for efficiency. +This section lists the built-in commands. .Bl -tag -width indent .It Ic \&: A null command that returns a 0 (true) exit value. @@ -1649,15 +1644,19 @@ subsection. Continue the specified jobs (or the current job if no jobs are given) in the background. +.It Ic bind Oo Fl aeklrsv Oc Oo Ar key Oo Ar command Oc Oc +List or alter key bindings for the line editor. +This command is documented in +.Xr editrc 5 . +.It Ic break Op Ar num +See the +.Sx Flow-Control Constructs +subsection. .It Ic builtin Ar cmd Op Ar arg ... Execute the specified built-in command, .Ar cmd . This is useful when the user wishes to override a shell function with the same name as a built-in command. -.It Ic bind Oo Fl aeklrsv Oc Oo Ar key Oo Ar command Oc Oc -List or alter key bindings for the line editor. -This command is documented in -.Xr editrc 5 . .It Ic cd Oo Fl L | P Oc Op Ar directory Switch to the specified .Ar directory , @@ -1759,6 +1758,10 @@ a shell keyword or an alias for .Ar value . +.It Ic continue Op Ar num +See the +.Sx Flow-Control Constructs +subsection. .It Ic echo Oo Fl e | n Oc Op Ar string ... Print a space-separated list of the arguments to the standard output and append a newline character. |