diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/exec.c | 218 | ||||
-rw-r--r-- | Src/jobs.c | 53 |
2 files changed, 162 insertions, 109 deletions
diff --git a/Src/exec.c b/Src/exec.c index 6d45f7452..cf79ea88b 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -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); diff --git a/Src/jobs.c b/Src/jobs.c index 129da7d57..e50a235f3 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -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) { |