1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-06-06 15:26:04 +02:00

users/11807: fix some job display bugs

This commit is contained in:
Peter Stephenson 2007-09-04 20:43:52 +00:00
parent 40e70b0419
commit e85760e05e
3 changed files with 167 additions and 109 deletions

View File

@ -1,3 +1,8 @@
2007-09-04 Peter Stephenson <p.w.stephenson@ntlworld.com>
* users/11807: Src/exec.c, Src/jobs.c: display of jobs in
subshells and occasionally in the main shell was screwy.
2007-08-31 Peter Stephenson <pws@csr.com>
* 23812: Src/exec.c: ( command & ) caused core dump after 23460.

View File

@ -804,6 +804,105 @@ hashcmd(char *arg0, char **pp)
return cn;
}
/**/
int
forklevel;
/* Arguments to entersubsh() */
enum {
/* Subshell is to be run asynchronously (else synchronously) */
ESUB_ASYNC = 0x01,
/*
* Perform process group and tty handling and clear the
* (real) job table, since it won't be any longer valid
*/
ESUB_PGRP = 0x02,
/* Don't unset traps */
ESUB_KEEPTRAP = 0x04,
/* This is only a fake entry to a subshell */
ESUB_FAKE = 0x08,
/* Release the process group if pid is the shell's process group */
ESUB_REVERTPGRP = 0x10,
/* Don't handle the MONITOR option even if previously set */
ESUB_NOMONITOR = 0x20
};
/**/
static void
entersubsh(int flags)
{
int sig, monitor;
if (!(flags & ESUB_KEEPTRAP))
for (sig = 0; sig < VSIGCOUNT; sig++)
if (!(sigtrapped[sig] & ZSIG_FUNC))
unsettrap(sig);
monitor = isset(MONITOR);
if (flags & ESUB_NOMONITOR)
opts[MONITOR] = 0;
if (!isset(MONITOR)) {
if (flags & ESUB_ASYNC) {
settrap(SIGINT, NULL, 0);
settrap(SIGQUIT, NULL, 0);
if (isatty(0)) {
close(0);
if (open("/dev/null", O_RDWR | O_NOCTTY)) {
zerr("can't open /dev/null: %e", errno);
_exit(1);
}
}
}
} else if (thisjob != -1 && (flags & ESUB_PGRP)) {
if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) {
if (setpgrp(0L, jobtab[list_pipe_job].gleader) == -1 ||
killpg(jobtab[list_pipe_job].gleader, 0) == -1) {
jobtab[list_pipe_job].gleader =
jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid());
setpgrp(0L, jobtab[list_pipe_job].gleader);
if (!(flags & ESUB_ASYNC))
attachtty(jobtab[thisjob].gleader);
}
}
else if (!jobtab[thisjob].gleader ||
setpgrp(0L, jobtab[thisjob].gleader) == -1) {
jobtab[thisjob].gleader = getpid();
if (list_pipe_job != thisjob &&
!jobtab[list_pipe_job].gleader)
jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader;
setpgrp(0L, jobtab[thisjob].gleader);
if (!(flags & ESUB_ASYNC))
attachtty(jobtab[thisjob].gleader);
}
}
if (!(flags & ESUB_FAKE))
subsh = 1;
if ((flags & ESUB_REVERTPGRP) && getpid() == mypgrp)
release_pgrp();
if (SHTTY != -1) {
shout = NULL;
zclose(SHTTY);
SHTTY = -1;
}
if (isset(MONITOR)) {
signal_default(SIGTTOU);
signal_default(SIGTTIN);
signal_default(SIGTSTP);
}
if (interact) {
signal_default(SIGTERM);
if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
signal_default(SIGINT);
}
if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
signal_default(SIGQUIT);
opts[MONITOR] = opts[USEZLE] = 0;
zleactive = 0;
if (flags & ESUB_PGRP)
clearjobtab(monitor);
get_usage();
forklevel = locallevel;
}
/* execute a string */
/**/
@ -1301,7 +1400,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
}
else {
close(synch[0]);
entersubsh(Z_ASYNC, 0, 0, 0);
entersubsh(ESUB_ASYNC);
if (jobtab[list_pipe_job].procs) {
if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader)
== -1) {
@ -1413,7 +1512,8 @@ execpline2(Estate state, wordcode pcode,
} else {
zclose(pipes[0]);
close(synch[0]);
entersubsh(how, 2, 0, 0);
entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0)
| ESUB_PGRP | ESUB_KEEPTRAP);
close(synch[1]);
execcmd(state, input, pipes[1], how, 0);
_exit(lastval);
@ -2419,7 +2519,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
(!is_cursh && (last1 != 1 || nsigtrapped || havefiles()))))) {
pid_t pid;
int synch[2];
int synch[2], flags;
char dummy;
struct timeval bgtime;
@ -2432,7 +2532,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
if (oautocont >= 0)
opts[AUTOCONTINUE] = oautocont;
return;
} if (pid) {
}
if (pid) {
close(synch[1]);
read(synch[0], &dummy, 1);
close(synch[0]);
@ -2462,7 +2564,10 @@ execcmd(Estate state, int input, int output, int how, int last1)
}
/* pid == 0 */
close(synch[0]);
entersubsh(how, (type != WC_SUBSH) && !(how & Z_ASYNC) ? 2 : 1, 0, 0);
flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP;
if ((type != WC_SUBSH) && !(how & Z_ASYNC))
flags |= ESUB_KEEPTRAP;
entersubsh(flags);
close(synch[1]);
forked = 1;
if (sigtrapped[SIGINT] & ZSIG_IGNORED)
@ -2737,10 +2842,16 @@ execcmd(Estate state, int input, int output, int how, int last1)
* the current shell (including a fake exec to run a builtin then
* exit) in case there is an error return.
*/
if (is_exec)
entersubsh(how, (type != WC_SUBSH) ? 2 : 1, 1,
(do_exec || (type >= WC_CURSH && last1 == 1))
&& !forked);
if (is_exec) {
int flags = ((how & Z_ASYNC) ? ESUB_ASYNC : 0) |
ESUB_PGRP | ESUB_FAKE;
if (type != WC_SUBSH)
flags |= ESUB_KEEPTRAP;
if ((do_exec || (type >= WC_CURSH && last1 == 1))
&& !forked)
flags |= ESUB_REVERTPGRP;
entersubsh(flags);
}
if (type >= WC_CURSH) {
if (last1 == 1)
do_exec = 1;
@ -3037,83 +3148,6 @@ fixfds(int *save)
errno = old_errno;
}
/**/
int
forklevel;
/**/
static void
entersubsh(int how, int cl, int fake, int revertpgrp)
{
int sig, monitor;
if (cl != 2)
for (sig = 0; sig < VSIGCOUNT; sig++)
if (!(sigtrapped[sig] & ZSIG_FUNC))
unsettrap(sig);
if (!(monitor = isset(MONITOR))) {
if (how & Z_ASYNC) {
settrap(SIGINT, NULL, 0);
settrap(SIGQUIT, NULL, 0);
if (isatty(0)) {
close(0);
if (open("/dev/null", O_RDWR | O_NOCTTY)) {
zerr("can't open /dev/null: %e", errno);
_exit(1);
}
}
}
} else if (thisjob != -1 && cl) {
if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) {
if (setpgrp(0L, jobtab[list_pipe_job].gleader) == -1 ||
killpg(jobtab[list_pipe_job].gleader, 0) == -1) {
jobtab[list_pipe_job].gleader =
jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid());
setpgrp(0L, jobtab[list_pipe_job].gleader);
if (how & Z_SYNC)
attachtty(jobtab[thisjob].gleader);
}
}
else if (!jobtab[thisjob].gleader ||
setpgrp(0L, jobtab[thisjob].gleader) == -1) {
jobtab[thisjob].gleader = getpid();
if (list_pipe_job != thisjob &&
!jobtab[list_pipe_job].gleader)
jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader;
setpgrp(0L, jobtab[thisjob].gleader);
if (how & Z_SYNC)
attachtty(jobtab[thisjob].gleader);
}
}
if (!fake)
subsh = 1;
if (revertpgrp && getpid() == mypgrp)
release_pgrp();
if (SHTTY != -1) {
shout = NULL;
zclose(SHTTY);
SHTTY = -1;
}
if (isset(MONITOR)) {
signal_default(SIGTTOU);
signal_default(SIGTTIN);
signal_default(SIGTSTP);
}
if (interact) {
signal_default(SIGTERM);
if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
signal_default(SIGINT);
}
if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
signal_default(SIGQUIT);
opts[MONITOR] = opts[USEZLE] = 0;
zleactive = 0;
if (cl)
clearjobtab(monitor);
get_usage();
forklevel = locallevel;
}
/*
* Close internal shell fds.
*
@ -3307,8 +3341,7 @@ getoutput(char *cmd, int qt)
child_unblock();
zclose(pipes[0]);
redup(pipes[1], 1);
opts[MONITOR] = 0;
entersubsh(Z_SYNC, 1, 0, 0);
entersubsh(ESUB_PGRP|ESUB_NOMONITOR);
cmdpush(CS_CMDSUBST);
execode(prog, 0, 1);
cmdpop();
@ -3460,8 +3493,7 @@ getoutputfile(char *cmd)
/* pid == 0 */
redup(fd, 1);
opts[MONITOR] = 0;
entersubsh(Z_SYNC, 1, 0, 0);
entersubsh(ESUB_PGRP|ESUB_NOMONITOR);
cmdpush(CS_CMDSUBST);
execode(prog, 0, 1);
cmdpop();
@ -3532,7 +3564,7 @@ getproc(char *cmd)
zerr("can't open %s: %e", pnam, errno);
_exit(1);
}
entersubsh(Z_ASYNC, 1, 0, 0);
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(fd, out);
#else /* PATH_DEV_FD */
int pipes[2];
@ -3558,7 +3590,7 @@ getproc(char *cmd)
}
return pnam;
}
entersubsh(Z_ASYNC, 1, 0, 0);
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(pipes[out], out);
closem(FDT_UNUSED); /* this closes pipes[!out] as well */
#endif /* PATH_DEV_FD */
@ -3602,7 +3634,7 @@ getpipe(char *cmd, int nullexec)
addproc(pid, NULL, 1, &bgtime);
return pipes[!out];
}
entersubsh(Z_ASYNC, 1, 0, 0);
entersubsh(ESUB_ASYNC|ESUB_PGRP);
redup(pipes[out], out);
closem(FDT_UNUSED); /* this closes pipes[!out] as well */
cmdpush(CS_CMDSUBST);

View File

@ -821,10 +821,7 @@ printjob(Job jn, int lng, int synch)
int doneprint = 0;
FILE *fout = (synch == 2) ? stdout : shout;
/*
* Wow, what a hack. Did I really write this? --- pws
*/
if (jn < jobtab || jn >= jobtab + jobtabsize)
if (oldjobtab != NULL)
job = jn - oldjobtab;
else
job = jn - jobtab;
@ -1286,6 +1283,7 @@ clearjobtab(int monitor)
if (monitor && oldmaxjob) {
int sz = oldmaxjob * sizeof(struct job);
DPUTS(oldjobtab != NULL, "BUG: saving job table twice\n");
oldjobtab = (struct job *)zalloc(sz);
memcpy(oldjobtab, jobtab, sz);
@ -1473,7 +1471,16 @@ setcurjob(void)
static int
getjob(char *s, char *prog)
{
int jobnum, returnval;
int jobnum, returnval, mymaxjob;
Job myjobtab;
if (oldjobtab) {
myjobtab = oldjobtab;
mymaxjob = oldmaxjob;
} else {
myjobtab= jobtab;
mymaxjob = maxjob;
}
/* if there is no %, treat as a name */
if (*s != '%')
@ -1502,8 +1509,15 @@ getjob(char *s, char *prog)
/* a digit here means we have a job number */
if (idigit(*s)) {
jobnum = atoi(s);
if (jobnum && jobnum <= maxjob && jobtab[jobnum].stat &&
!(jobtab[jobnum].stat & STAT_SUBJOB) && jobnum != thisjob) {
if (jobnum && jobnum <= mymaxjob && myjobtab[jobnum].stat &&
!(myjobtab[jobnum].stat & STAT_SUBJOB) &&
/*
* If running jobs in a subshell, we are allowed to
* refer to the "current" job (it's not really the
* current job in the subshell). It's possible we
* should reset thisjob to -1 on entering the subshell.
*/
(myjobtab == oldjobtab || jobnum != thisjob)) {
returnval = jobnum;
goto done;
}
@ -1515,10 +1529,11 @@ getjob(char *s, char *prog)
if (*s == '?') {
struct process *pn;
for (jobnum = maxjob; jobnum >= 0; jobnum--)
if (jobtab[jobnum].stat && !(jobtab[jobnum].stat & STAT_SUBJOB) &&
for (jobnum = mymaxjob; jobnum >= 0; jobnum--)
if (myjobtab[jobnum].stat &&
!(myjobtab[jobnum].stat & STAT_SUBJOB) &&
jobnum != thisjob)
for (pn = jobtab[jobnum].procs; pn; pn = pn->next)
for (pn = myjobtab[jobnum].procs; pn; pn = pn->next)
if (strstr(pn->text, s + 1)) {
returnval = jobnum;
goto done;
@ -1772,7 +1787,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
In the default case for bg, fg and disown, the argument will be provided by
the above routine. We now loop over the arguments. */
for (; (firstjob != -1) || *argv; (void)(*argv && argv++)) {
int stopped, ocj = thisjob;
int stopped, ocj = thisjob, jstat;
func = ofunc;
@ -1798,6 +1813,11 @@ bin_fg(char *name, char **argv, Options ops, int func)
thisjob = ocj;
continue;
}
if (func != BIN_JOBS && oldjobtab != NULL) {
zwarnnam(name, "can't manipulate jobs in subshell");
unqueue_signals();
return 1;
}
/* The only type of argument allowed now is a job spec. Check it. */
job = (*argv) ? getjob(*argv, name) : firstjob;
firstjob = -1;
@ -1805,9 +1825,10 @@ bin_fg(char *name, char **argv, Options ops, int func)
retval = 1;
break;
}
if (!(jobtab[job].stat & STAT_INUSE) ||
(jobtab[job].stat & STAT_NOPRINT)) {
zwarnnam(name, "%%%d: no such job", job);
jstat = oldjobtab ? oldjobtab[job].stat : jobtab[job].stat;
if (!(jstat & STAT_INUSE) ||
(jstat & STAT_NOPRINT)) {
zwarnnam(name, "%s: no such job", *argv);
unqueue_signals();
return 1;
}
@ -1815,7 +1836,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
* on disown), we actually do a bg and then delete the job table entry. */
if (isset(AUTOCONTINUE) && func == BIN_DISOWN &&
jobtab[job].stat & STAT_STOPPED)
jstat & STAT_STOPPED)
func = BIN_BG;
/* We have a job number. Now decide what to do with it. */
@ -1905,7 +1926,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
deletejob(jobtab + job);
break;
case BIN_JOBS:
printjob(job + jobtab, lng, 2);
printjob(job + (oldjobtab ? oldjobtab : jobtab), lng, 2);
break;
case BIN_DISOWN:
if (jobtab[job].stat & STAT_STOPPED) {