sh: Improve jobs output of pipelines.
If describing the status of a pipeline, write all elements of the pipeline and show the status of the last process (which would also end up in $?). Only write one report per job, not one for every process that exits. To keep some earlier behaviour, if any process started by the shell in a foreground job terminates because of a signal, write a message about the signal (at most one message per job, however). Also, do not write messages about signals in the wait builtin in non-interactive shells. Only true foreground jobs now write such messages (for example, "Terminated").
This commit is contained in:
parent
dc5e1d528e
commit
1bb49f9524
149
bin/sh/jobs.c
149
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,15 +295,30 @@ 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;
|
||||
@ -320,14 +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) {
|
||||
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 = '+';
|
||||
@ -346,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;
|
||||
}
|
||||
@ -410,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.
|
||||
@ -958,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));
|
||||
@ -1017,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user