147121Sbostic /*- 247121Sbostic * Copyright (c) 1991 The Regents of the University of California. 347121Sbostic * All rights reserved. 447121Sbostic * 547121Sbostic * This code is derived from software contributed to Berkeley by 647121Sbostic * Kenneth Almquist. 747121Sbostic * 855297Smarc * Redistribution and use in source and binary forms, with or without 955297Smarc * modification, are permitted provided that the following conditions 1055297Smarc * are met: 1155297Smarc * 1. Redistributions of source code must retain the above copyright 1255297Smarc * notice, this list of conditions and the following disclaimer. 1355297Smarc * 2. Redistributions in binary form must reproduce the above copyright 1455297Smarc * notice, this list of conditions and the following disclaimer in the 1555297Smarc * documentation and/or other materials provided with the distribution. 1655297Smarc * 3. All advertising materials mentioning features or use of this software 1755297Smarc * must display the following acknowledgement: 1855297Smarc * This product includes software developed by the University of 1955297Smarc * California, Berkeley and its contributors. 2055297Smarc * 4. Neither the name of the University nor the names of its contributors 2155297Smarc * may be used to endorse or promote products derived from this software 2255297Smarc * without specific prior written permission. 2355297Smarc * 2455297Smarc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2555297Smarc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2655297Smarc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2755297Smarc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2855297Smarc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2955297Smarc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3055297Smarc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3155297Smarc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3255297Smarc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3355297Smarc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3455297Smarc * SUCH DAMAGE. 3547121Sbostic */ 3647121Sbostic 3747121Sbostic #ifndef lint 3855297Smarc static char sccsid[] = "@(#)jobs.c 5.4 (Berkeley) 7/15/92"; 3947121Sbostic #endif /* not lint */ 4047121Sbostic 4147121Sbostic #include "shell.h" 4247121Sbostic #if JOBS 4347121Sbostic #include "sgtty.h" 4447121Sbostic #undef CEOF /* syntax.h redefines this */ 4547121Sbostic #endif 4647121Sbostic #include "main.h" 4747121Sbostic #include "parser.h" 4847121Sbostic #include "nodes.h" 4947121Sbostic #include "jobs.h" 5047121Sbostic #include "options.h" 5147121Sbostic #include "trap.h" 5247121Sbostic #include "signames.h" 5347121Sbostic #include "syntax.h" 5447121Sbostic #include "input.h" 5547121Sbostic #include "output.h" 5647121Sbostic #include "memalloc.h" 5747121Sbostic #include "error.h" 5847121Sbostic #include "mystring.h" 5947121Sbostic #include <fcntl.h> 6047121Sbostic #include <signal.h> 6147121Sbostic #include <errno.h> 6247121Sbostic #ifdef BSD 6347121Sbostic #include <sys/types.h> 6447121Sbostic #include <sys/wait.h> 6547121Sbostic #include <sys/time.h> 6647121Sbostic #include <sys/resource.h> 6747121Sbostic #endif 6847121Sbostic 6947121Sbostic 7047121Sbostic 7147121Sbostic struct job *jobtab; /* array of jobs */ 7247121Sbostic int njobs; /* size of array */ 7347121Sbostic MKINIT short backgndpid = -1; /* pid of last background process */ 7447121Sbostic #if JOBS 7547121Sbostic int initialpgrp; /* pgrp of shell on invocation */ 7647121Sbostic short curjob; /* current job */ 7747121Sbostic #endif 7847121Sbostic 7947121Sbostic #ifdef __STDC__ 8047121Sbostic STATIC void restartjob(struct job *); 8147121Sbostic STATIC struct job *getjob(char *); 8247121Sbostic STATIC void freejob(struct job *); 8347121Sbostic STATIC int procrunning(int); 8447121Sbostic STATIC int dowait(int, struct job *); 8547121Sbostic STATIC int waitproc(int, int *); 8647121Sbostic #else 8747121Sbostic STATIC void restartjob(); 8847121Sbostic STATIC struct job *getjob(); 8947121Sbostic STATIC void freejob(); 9047121Sbostic STATIC int procrunning(); 9147121Sbostic STATIC int dowait(); 9247121Sbostic STATIC int waitproc(); 9347121Sbostic #endif 9447121Sbostic 9547121Sbostic 9647121Sbostic 9747121Sbostic /* 9847121Sbostic * Turn job control on and off. 9947121Sbostic * 10047121Sbostic * Note: This code assumes that the third arg to ioctl is a character 10147121Sbostic * pointer, which is true on Berkeley systems but not System V. Since 10247121Sbostic * System V doesn't have job control yet, this isn't a problem now. 10347121Sbostic */ 10447121Sbostic 10547121Sbostic MKINIT int jobctl; 10647121Sbostic 10747121Sbostic void 10847121Sbostic setjobctl(on) { 109*56563Smarc #ifdef OLD_TTY_DRIVER 11047121Sbostic int ldisc; 111*56563Smarc #endif 11247121Sbostic 11347121Sbostic if (on == jobctl || rootshell == 0) 11447121Sbostic return; 11547121Sbostic if (on) { 11647121Sbostic do { /* while we are in the background */ 11747121Sbostic if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { 11855230Smarc out2str("sh: can't access tty; job control turned off\n"); 11955230Smarc mflag = 0; 12047121Sbostic return; 12147121Sbostic } 12247121Sbostic if (initialpgrp == -1) 12347121Sbostic initialpgrp = getpgrp(0); 12447121Sbostic else if (initialpgrp != getpgrp(0)) { 12547121Sbostic killpg(initialpgrp, SIGTTIN); 12647121Sbostic continue; 12747121Sbostic } 12847121Sbostic } while (0); 12955230Smarc #ifdef OLD_TTY_DRIVER 13047121Sbostic if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { 13155230Smarc out2str("sh: need new tty driver to run job control; job control turned off\n"); 13255230Smarc mflag = 0; 13347121Sbostic return; 13447121Sbostic } 13555230Smarc #endif 13647121Sbostic setsignal(SIGTSTP); 13747121Sbostic setsignal(SIGTTOU); 13854318Smarc setsignal(SIGTTIN); 13947121Sbostic setpgrp(0, rootpid); 14047121Sbostic ioctl(2, TIOCSPGRP, (char *)&rootpid); 14147121Sbostic } else { /* turning job control off */ 14247121Sbostic setpgrp(0, initialpgrp); 14347121Sbostic ioctl(2, TIOCSPGRP, (char *)&initialpgrp); 14447121Sbostic setsignal(SIGTSTP); 14547121Sbostic setsignal(SIGTTOU); 14654318Smarc setsignal(SIGTTIN); 14747121Sbostic } 14847121Sbostic jobctl = on; 14947121Sbostic } 15047121Sbostic 15147121Sbostic 15247121Sbostic #ifdef mkinit 15347121Sbostic 15447121Sbostic SHELLPROC { 15547121Sbostic backgndpid = -1; 15647121Sbostic #if JOBS 15747121Sbostic jobctl = 0; 15847121Sbostic #endif 15947121Sbostic } 16047121Sbostic 16147121Sbostic #endif 16247121Sbostic 16347121Sbostic 16447121Sbostic 16547121Sbostic #if JOBS 16647121Sbostic fgcmd(argc, argv) char **argv; { 16747121Sbostic struct job *jp; 16847121Sbostic int pgrp; 16947121Sbostic int status; 17047121Sbostic 17147121Sbostic jp = getjob(argv[1]); 17247121Sbostic if (jp->jobctl == 0) 17347121Sbostic error("job not created under job control"); 17447121Sbostic pgrp = jp->ps[0].pid; 17547121Sbostic ioctl(2, TIOCSPGRP, (char *)&pgrp); 17647121Sbostic restartjob(jp); 17747121Sbostic INTOFF; 17847121Sbostic status = waitforjob(jp); 17947121Sbostic INTON; 18047121Sbostic return status; 18147121Sbostic } 18247121Sbostic 18347121Sbostic 18447121Sbostic bgcmd(argc, argv) char **argv; { 18547121Sbostic struct job *jp; 18647121Sbostic 18747121Sbostic do { 18847121Sbostic jp = getjob(*++argv); 18947121Sbostic if (jp->jobctl == 0) 19047121Sbostic error("job not created under job control"); 19147121Sbostic restartjob(jp); 19247121Sbostic } while (--argc > 1); 19347121Sbostic return 0; 19447121Sbostic } 19547121Sbostic 19647121Sbostic 19747121Sbostic STATIC void 19847121Sbostic restartjob(jp) 19947121Sbostic struct job *jp; 20047121Sbostic { 20147121Sbostic struct procstat *ps; 20247121Sbostic int i; 20347121Sbostic 20447121Sbostic if (jp->state == JOBDONE) 20547121Sbostic return; 20647121Sbostic INTOFF; 20747121Sbostic killpg(jp->ps[0].pid, SIGCONT); 20847121Sbostic for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { 20947121Sbostic if ((ps->status & 0377) == 0177) { 21047121Sbostic ps->status = -1; 21147121Sbostic jp->state = 0; 21247121Sbostic } 21347121Sbostic } 21447121Sbostic INTON; 21547121Sbostic } 21647121Sbostic #endif 21747121Sbostic 21847121Sbostic 21947121Sbostic int 22047121Sbostic jobscmd(argc, argv) char **argv; { 22147121Sbostic showjobs(0); 22247121Sbostic return 0; 22347121Sbostic } 22447121Sbostic 22547121Sbostic 22647121Sbostic /* 22747121Sbostic * Print a list of jobs. If "change" is nonzero, only print jobs whose 22847121Sbostic * statuses have changed since the last call to showjobs. 22947121Sbostic * 23047121Sbostic * If the shell is interrupted in the process of creating a job, the 23147121Sbostic * result may be a job structure containing zero processes. Such structures 23247121Sbostic * will be freed here. 23347121Sbostic */ 23447121Sbostic 23547121Sbostic void 23647121Sbostic showjobs(change) { 23747121Sbostic int jobno; 23847121Sbostic int procno; 23947121Sbostic int i; 24047121Sbostic struct job *jp; 24147121Sbostic struct procstat *ps; 24247121Sbostic int col; 24347121Sbostic char s[64]; 24447121Sbostic 24547121Sbostic TRACE(("showjobs(%d) called\n", change)); 24647121Sbostic while (dowait(0, (struct job *)NULL) > 0); 24747121Sbostic for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { 24847121Sbostic if (! jp->used) 24947121Sbostic continue; 25047121Sbostic if (jp->nprocs == 0) { 25147121Sbostic freejob(jp); 25247121Sbostic continue; 25347121Sbostic } 25447121Sbostic if (change && ! jp->changed) 25547121Sbostic continue; 25647121Sbostic procno = jp->nprocs; 25747121Sbostic for (ps = jp->ps ; ; ps++) { /* for each process */ 25847121Sbostic if (ps == jp->ps) 25947121Sbostic fmtstr(s, 64, "[%d] %d ", jobno, ps->pid); 26047121Sbostic else 26147121Sbostic fmtstr(s, 64, " %d ", ps->pid); 26247121Sbostic out1str(s); 26347121Sbostic col = strlen(s); 26447121Sbostic s[0] = '\0'; 26547121Sbostic if (ps->status == -1) { 26647121Sbostic /* don't print anything */ 26747121Sbostic } else if ((ps->status & 0xFF) == 0) { 26847121Sbostic fmtstr(s, 64, "Exit %d", ps->status >> 8); 26947121Sbostic } else { 27047121Sbostic i = ps->status; 27147121Sbostic #if JOBS 27247121Sbostic if ((i & 0xFF) == 0177) 27347121Sbostic i >>= 8; 27447121Sbostic #endif 27547121Sbostic if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F]) 27647121Sbostic scopy(sigmesg[i & 0x7F], s); 27747121Sbostic else 27847121Sbostic fmtstr(s, 64, "Signal %d", i & 0x7F); 27947121Sbostic if (i & 0x80) 28047121Sbostic strcat(s, " (core dumped)"); 28147121Sbostic } 28247121Sbostic out1str(s); 28347121Sbostic col += strlen(s); 28447121Sbostic do { 28547121Sbostic out1c(' '); 28647121Sbostic col++; 28747121Sbostic } while (col < 30); 28847121Sbostic out1str(ps->cmd); 28947121Sbostic out1c('\n'); 29047121Sbostic if (--procno <= 0) 29147121Sbostic break; 29247121Sbostic } 29347121Sbostic jp->changed = 0; 29447121Sbostic if (jp->state == JOBDONE) { 29547121Sbostic freejob(jp); 29647121Sbostic } 29747121Sbostic } 29847121Sbostic } 29947121Sbostic 30047121Sbostic 30147121Sbostic /* 30247121Sbostic * Mark a job structure as unused. 30347121Sbostic */ 30447121Sbostic 30547121Sbostic STATIC void 30647121Sbostic freejob(jp) 30747121Sbostic struct job *jp; 30847121Sbostic { 30947121Sbostic struct procstat *ps; 31047121Sbostic int i; 31147121Sbostic 31247121Sbostic INTOFF; 31347121Sbostic for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { 31447121Sbostic if (ps->cmd != nullstr) 31547121Sbostic ckfree(ps->cmd); 31647121Sbostic } 31747121Sbostic if (jp->ps != &jp->ps0) 31847121Sbostic ckfree(jp->ps); 31947121Sbostic jp->used = 0; 32047121Sbostic #if JOBS 32147121Sbostic if (curjob == jp - jobtab + 1) 32247121Sbostic curjob = 0; 32347121Sbostic #endif 32447121Sbostic INTON; 32547121Sbostic } 32647121Sbostic 32747121Sbostic 32847121Sbostic 32947121Sbostic int 33047121Sbostic waitcmd(argc, argv) char **argv; { 33147121Sbostic struct job *job; 33247121Sbostic int status; 33347121Sbostic struct job *jp; 33447121Sbostic 33547121Sbostic if (argc > 1) { 33647121Sbostic job = getjob(argv[1]); 33747121Sbostic } else { 33847121Sbostic job = NULL; 33947121Sbostic } 34047121Sbostic for (;;) { /* loop until process terminated or stopped */ 34147121Sbostic if (job != NULL) { 34247121Sbostic if (job->state) { 34347121Sbostic status = job->ps[job->nprocs - 1].status; 34447121Sbostic if ((status & 0xFF) == 0) 34547121Sbostic status = status >> 8 & 0xFF; 34647121Sbostic #if JOBS 34747121Sbostic else if ((status & 0xFF) == 0177) 34847121Sbostic status = (status >> 8 & 0x7F) + 128; 34947121Sbostic #endif 35047121Sbostic else 35147121Sbostic status = (status & 0x7F) + 128; 35247121Sbostic if (! iflag) 35347121Sbostic freejob(job); 35447121Sbostic return status; 35547121Sbostic } 35647121Sbostic } else { 35747121Sbostic for (jp = jobtab ; ; jp++) { 35847121Sbostic if (jp >= jobtab + njobs) { /* no running procs */ 35947121Sbostic return 0; 36047121Sbostic } 36147121Sbostic if (jp->used && jp->state == 0) 36247121Sbostic break; 36347121Sbostic } 36447121Sbostic } 36547121Sbostic dowait(1, (struct job *)NULL); 36647121Sbostic } 36747121Sbostic } 36847121Sbostic 36947121Sbostic 37047121Sbostic 37147121Sbostic jobidcmd(argc, argv) char **argv; { 37247121Sbostic struct job *jp; 37347121Sbostic int i; 37447121Sbostic 37547121Sbostic jp = getjob(argv[1]); 37647121Sbostic for (i = 0 ; i < jp->nprocs ; ) { 37747121Sbostic out1fmt("%d", jp->ps[i].pid); 37847121Sbostic out1c(++i < jp->nprocs? ' ' : '\n'); 37947121Sbostic } 38047121Sbostic return 0; 38147121Sbostic } 38247121Sbostic 38347121Sbostic 38447121Sbostic 38547121Sbostic /* 38647121Sbostic * Convert a job name to a job structure. 38747121Sbostic */ 38847121Sbostic 38947121Sbostic STATIC struct job * 39047121Sbostic getjob(name) 39147121Sbostic char *name; 39247121Sbostic { 39347121Sbostic int jobno; 39447121Sbostic register struct job *jp; 39547121Sbostic int pid; 39647121Sbostic int i; 39747121Sbostic 39847121Sbostic if (name == NULL) { 39947121Sbostic #if JOBS 40047121Sbostic currentjob: 40147121Sbostic if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) 40247121Sbostic error("No current job"); 40347121Sbostic return &jobtab[jobno - 1]; 40447121Sbostic #else 40547121Sbostic error("No current job"); 40647121Sbostic #endif 40747121Sbostic } else if (name[0] == '%') { 40847121Sbostic if (is_digit(name[1])) { 40947121Sbostic jobno = number(name + 1); 41047121Sbostic if (jobno > 0 && jobno <= njobs 41147121Sbostic && jobtab[jobno - 1].used != 0) 41247121Sbostic return &jobtab[jobno - 1]; 41347121Sbostic #if JOBS 41447121Sbostic } else if (name[1] == '%' && name[2] == '\0') { 41547121Sbostic goto currentjob; 41647121Sbostic #endif 41747121Sbostic } else { 41847121Sbostic register struct job *found = NULL; 41947121Sbostic for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 42047121Sbostic if (jp->used && jp->nprocs > 0 42147121Sbostic && prefix(name + 1, jp->ps[0].cmd)) { 42247121Sbostic if (found) 42347121Sbostic error("%s: ambiguous", name); 42447121Sbostic found = jp; 42547121Sbostic } 42647121Sbostic } 42747121Sbostic if (found) 42847121Sbostic return found; 42947121Sbostic } 43047121Sbostic } else if (is_number(name)) { 43147121Sbostic pid = number(name); 43247121Sbostic for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { 43347121Sbostic if (jp->used && jp->nprocs > 0 43447121Sbostic && jp->ps[jp->nprocs - 1].pid == pid) 43547121Sbostic return jp; 43647121Sbostic } 43747121Sbostic } 43847121Sbostic error("No such job: %s", name); 43947121Sbostic } 44047121Sbostic 44147121Sbostic 44247121Sbostic 44347121Sbostic /* 44447121Sbostic * Return a new job structure, 44547121Sbostic */ 44647121Sbostic 44747121Sbostic struct job * 44847121Sbostic makejob(node, nprocs) 44947121Sbostic union node *node; 45047121Sbostic { 45147121Sbostic int i; 45247121Sbostic struct job *jp; 45347121Sbostic 45447121Sbostic for (i = njobs, jp = jobtab ; ; jp++) { 45547121Sbostic if (--i < 0) { 45647121Sbostic INTOFF; 45747121Sbostic if (njobs == 0) { 45847121Sbostic jobtab = ckmalloc(4 * sizeof jobtab[0]); 45947121Sbostic } else { 46047121Sbostic jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); 46147121Sbostic bcopy(jobtab, jp, njobs * sizeof jp[0]); 46247121Sbostic ckfree(jobtab); 46347121Sbostic jobtab = jp; 46447121Sbostic } 46547121Sbostic jp = jobtab + njobs; 46647121Sbostic for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); 46747121Sbostic INTON; 46847121Sbostic break; 46947121Sbostic } 47047121Sbostic if (jp->used == 0) 47147121Sbostic break; 47247121Sbostic } 47347121Sbostic INTOFF; 47447121Sbostic jp->state = 0; 47547121Sbostic jp->used = 1; 47647121Sbostic jp->changed = 0; 47747121Sbostic jp->nprocs = 0; 47847121Sbostic #if JOBS 47947121Sbostic jp->jobctl = jobctl; 48047121Sbostic #endif 48147121Sbostic if (nprocs > 1) { 48247121Sbostic jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); 48347121Sbostic } else { 48447121Sbostic jp->ps = &jp->ps0; 48547121Sbostic } 48647121Sbostic INTON; 48747121Sbostic TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1)); 48847121Sbostic return jp; 48947121Sbostic } 49047121Sbostic 49147121Sbostic 49247121Sbostic /* 49347121Sbostic * Fork of a subshell. If we are doing job control, give the subshell its 49447121Sbostic * own process group. Jp is a job structure that the job is to be added to. 49547121Sbostic * N is the command that will be evaluated by the child. Both jp and n may 49647121Sbostic * be NULL. The mode parameter can be one of the following: 49747121Sbostic * FORK_FG - Fork off a foreground process. 49847121Sbostic * FORK_BG - Fork off a background process. 49947121Sbostic * FORK_NOJOB - Like FORK_FG, but don't give the process its own 50047121Sbostic * process group even if job control is on. 50147121Sbostic * 50247121Sbostic * When job control is turned off, background processes have their standard 50347121Sbostic * input redirected to /dev/null (except for the second and later processes 50447121Sbostic * in a pipeline). 50547121Sbostic */ 50647121Sbostic 50747121Sbostic int 50847121Sbostic forkshell(jp, n, mode) 50947121Sbostic union node *n; 51047121Sbostic struct job *jp; 51147121Sbostic { 51247121Sbostic int pid; 51347121Sbostic int pgrp; 51447121Sbostic 51547121Sbostic TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode)); 51647121Sbostic INTOFF; 51747121Sbostic pid = fork(); 51847121Sbostic if (pid == -1) { 51947121Sbostic TRACE(("Fork failed, errno=%d\n", errno)); 52047121Sbostic INTON; 52147121Sbostic error("Cannot fork"); 52247121Sbostic } 52347121Sbostic if (pid == 0) { 52447121Sbostic struct job *p; 52547121Sbostic int wasroot; 52647121Sbostic int i; 52747121Sbostic 52847121Sbostic TRACE(("Child shell %d\n", getpid())); 52947121Sbostic wasroot = rootshell; 53047121Sbostic rootshell = 0; 53147121Sbostic for (i = njobs, p = jobtab ; --i >= 0 ; p++) 53247121Sbostic if (p->used) 53347121Sbostic freejob(p); 53447121Sbostic closescript(); 53547121Sbostic INTON; 53647121Sbostic clear_traps(); 53747121Sbostic #if JOBS 53847121Sbostic jobctl = 0; /* do job control only in root shell */ 53955230Smarc if (wasroot && mode != FORK_NOJOB && mflag) { 54047121Sbostic if (jp == NULL || jp->nprocs == 0) 54147121Sbostic pgrp = getpid(); 54247121Sbostic else 54347121Sbostic pgrp = jp->ps[0].pid; 54447121Sbostic setpgrp(0, pgrp); 54547121Sbostic if (mode == FORK_FG) { 54647121Sbostic /*** this causes superfluous TIOCSPGRPS ***/ 54747121Sbostic if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) 54847121Sbostic error("TIOCSPGRP failed, errno=%d\n", errno); 54947121Sbostic } 55047121Sbostic setsignal(SIGTSTP); 55147121Sbostic setsignal(SIGTTOU); 55247121Sbostic } else if (mode == FORK_BG) { 55347121Sbostic ignoresig(SIGINT); 55447121Sbostic ignoresig(SIGQUIT); 55547121Sbostic if (jp == NULL || jp->nprocs == 0) { 55647121Sbostic close(0); 55747121Sbostic if (open("/dev/null", O_RDONLY) != 0) 55847121Sbostic error("Can't open /dev/null"); 55947121Sbostic } 56047121Sbostic } 56147121Sbostic #else 56247121Sbostic if (mode == FORK_BG) { 56347121Sbostic ignoresig(SIGINT); 56447121Sbostic ignoresig(SIGQUIT); 56547121Sbostic if (jp == NULL || jp->nprocs == 0) { 56647121Sbostic close(0); 56747121Sbostic if (open("/dev/null", O_RDONLY) != 0) 56847121Sbostic error("Can't open /dev/null"); 56947121Sbostic } 57047121Sbostic } 57147121Sbostic #endif 57247121Sbostic if (wasroot && iflag) { 57347121Sbostic setsignal(SIGINT); 57447121Sbostic setsignal(SIGQUIT); 57547121Sbostic setsignal(SIGTERM); 57647121Sbostic } 57747121Sbostic return pid; 57847121Sbostic } 57955230Smarc if (rootshell && mode != FORK_NOJOB && mflag) { 58047121Sbostic if (jp == NULL || jp->nprocs == 0) 58147121Sbostic pgrp = pid; 58247121Sbostic else 58347121Sbostic pgrp = jp->ps[0].pid; 58447121Sbostic setpgrp(pid, pgrp); 58547121Sbostic } 58647121Sbostic if (mode == FORK_BG) 58747121Sbostic backgndpid = pid; /* set $! */ 58847121Sbostic if (jp) { 58947121Sbostic struct procstat *ps = &jp->ps[jp->nprocs++]; 59047121Sbostic ps->pid = pid; 59147121Sbostic ps->status = -1; 59247121Sbostic ps->cmd = nullstr; 59347121Sbostic if (iflag && rootshell && n) 59447121Sbostic ps->cmd = commandtext(n); 59547121Sbostic } 59647121Sbostic INTON; 59747121Sbostic TRACE(("In parent shell: child = %d\n", pid)); 59847121Sbostic return pid; 59947121Sbostic } 60047121Sbostic 60147121Sbostic 60247121Sbostic 60347121Sbostic /* 60447121Sbostic * Wait for job to finish. 60547121Sbostic * 60647121Sbostic * Under job control we have the problem that while a child process is 60747121Sbostic * running interrupts generated by the user are sent to the child but not 60847121Sbostic * to the shell. This means that an infinite loop started by an inter- 60947121Sbostic * active user may be hard to kill. With job control turned off, an 61047121Sbostic * interactive user may place an interactive program inside a loop. If 61147121Sbostic * the interactive program catches interrupts, the user doesn't want 61247121Sbostic * these interrupts to also abort the loop. The approach we take here 61347121Sbostic * is to have the shell ignore interrupt signals while waiting for a 61447121Sbostic * forground process to terminate, and then send itself an interrupt 61547121Sbostic * signal if the child process was terminated by an interrupt signal. 61647121Sbostic * Unfortunately, some programs want to do a bit of cleanup and then 61747121Sbostic * exit on interrupt; unless these processes terminate themselves by 61847121Sbostic * sending a signal to themselves (instead of calling exit) they will 61947121Sbostic * confuse this approach. 62047121Sbostic */ 62147121Sbostic 62247121Sbostic int 62347121Sbostic waitforjob(jp) 62447121Sbostic register struct job *jp; 62547121Sbostic { 62647121Sbostic #if JOBS 62747121Sbostic int mypgrp = getpgrp(0); 62847121Sbostic #endif 62947121Sbostic int status; 63047121Sbostic int st; 63147121Sbostic 63247121Sbostic INTOFF; 63347121Sbostic TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); 63447121Sbostic while (jp->state == 0) { 63547121Sbostic dowait(1, jp); 63647121Sbostic } 63747121Sbostic #if JOBS 63847121Sbostic if (jp->jobctl) { 63947121Sbostic if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) 64047121Sbostic error("TIOCSPGRP failed, errno=%d\n", errno); 64147121Sbostic } 64247121Sbostic if (jp->state == JOBSTOPPED) 64347121Sbostic curjob = jp - jobtab + 1; 64447121Sbostic #endif 64547121Sbostic status = jp->ps[jp->nprocs - 1].status; 64647121Sbostic /* convert to 8 bits */ 64747121Sbostic if ((status & 0xFF) == 0) 64847121Sbostic st = status >> 8 & 0xFF; 64947121Sbostic #if JOBS 65047121Sbostic else if ((status & 0xFF) == 0177) 65147121Sbostic st = (status >> 8 & 0x7F) + 128; 65247121Sbostic #endif 65347121Sbostic else 65447121Sbostic st = (status & 0x7F) + 128; 65547121Sbostic if (! JOBS || jp->state == JOBDONE) 65647121Sbostic freejob(jp); 65747121Sbostic CLEAR_PENDING_INT; 65847121Sbostic if ((status & 0x7F) == SIGINT) 65947121Sbostic kill(getpid(), SIGINT); 66047121Sbostic INTON; 66147121Sbostic return st; 66247121Sbostic } 66347121Sbostic 66447121Sbostic 66547121Sbostic 66647121Sbostic /* 66747121Sbostic * Wait for a process to terminate. 66847121Sbostic */ 66947121Sbostic 67047121Sbostic STATIC int 67147121Sbostic dowait(block, job) 67247121Sbostic struct job *job; 67347121Sbostic { 67447121Sbostic int pid; 67547121Sbostic int status; 67647121Sbostic struct procstat *sp; 67747121Sbostic struct job *jp; 67847121Sbostic struct job *thisjob; 67947121Sbostic int done; 68047121Sbostic int stopped; 68147121Sbostic int core; 68247121Sbostic 68347121Sbostic TRACE(("dowait(%d) called\n", block)); 68447121Sbostic do { 68547121Sbostic pid = waitproc(block, &status); 68647121Sbostic TRACE(("wait returns %d, status=%d\n", pid, status)); 68747121Sbostic } while (pid == -1 && errno == EINTR); 68847121Sbostic if (pid <= 0) 68947121Sbostic return pid; 69047121Sbostic INTOFF; 69147121Sbostic thisjob = NULL; 69247121Sbostic for (jp = jobtab ; jp < jobtab + njobs ; jp++) { 69347121Sbostic if (jp->used) { 69447121Sbostic done = 1; 69547121Sbostic stopped = 1; 69647121Sbostic for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { 69747121Sbostic if (sp->pid == -1) 69847121Sbostic continue; 69947121Sbostic if (sp->pid == pid) { 70047121Sbostic TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status)); 70147121Sbostic sp->status = status; 70247121Sbostic thisjob = jp; 70347121Sbostic } 70447121Sbostic if (sp->status == -1) 70547121Sbostic stopped = 0; 70647121Sbostic else if ((sp->status & 0377) == 0177) 70747121Sbostic done = 0; 70847121Sbostic } 70947121Sbostic if (stopped) { /* stopped or done */ 71047121Sbostic int state = done? JOBDONE : JOBSTOPPED; 71147121Sbostic if (jp->state != state) { 71247121Sbostic TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); 71347121Sbostic jp->state = state; 71447121Sbostic #if JOBS 71547121Sbostic if (done && curjob == jp - jobtab + 1) 71647121Sbostic curjob = 0; /* no current job */ 71747121Sbostic #endif 71847121Sbostic } 71947121Sbostic } 72047121Sbostic } 72147121Sbostic } 72247121Sbostic INTON; 72347121Sbostic if (! rootshell || ! iflag || (job && thisjob == job)) { 72447121Sbostic #if JOBS 72547121Sbostic if ((status & 0xFF) == 0177) 72647121Sbostic status >>= 8; 72747121Sbostic #endif 72847121Sbostic core = status & 0x80; 72947121Sbostic status &= 0x7F; 73047121Sbostic if (status != 0 && status != SIGINT && status != SIGPIPE) { 73147121Sbostic if (thisjob != job) 73247121Sbostic outfmt(out2, "%d: ", pid); 73347121Sbostic #if JOBS 73447121Sbostic if (status == SIGTSTP && rootshell && iflag) 73547121Sbostic outfmt(out2, "%%%d ", job - jobtab + 1); 73647121Sbostic #endif 73747121Sbostic if (status <= MAXSIG && sigmesg[status]) 73847121Sbostic out2str(sigmesg[status]); 73947121Sbostic else 74047121Sbostic outfmt(out2, "Signal %d", status); 74147121Sbostic if (core) 74247121Sbostic out2str(" - core dumped"); 74347121Sbostic out2c('\n'); 74447121Sbostic flushout(&errout); 74547121Sbostic } else { 74647121Sbostic TRACE(("Not printing status: status=%d\n", status)); 74747121Sbostic } 74847121Sbostic } else { 74947121Sbostic TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); 75047121Sbostic if (thisjob) 75147121Sbostic thisjob->changed = 1; 75247121Sbostic } 75347121Sbostic return pid; 75447121Sbostic } 75547121Sbostic 75647121Sbostic 75747121Sbostic 75847121Sbostic /* 75947121Sbostic * Do a wait system call. If job control is compiled in, we accept 76047121Sbostic * stopped processes. If block is zero, we return a value of zero 76147121Sbostic * rather than blocking. 76247121Sbostic * 76347121Sbostic * System V doesn't have a non-blocking wait system call. It does 76447121Sbostic * have a SIGCLD signal that is sent to a process when one of it's 76547121Sbostic * children dies. The obvious way to use SIGCLD would be to install 76647121Sbostic * a handler for SIGCLD which simply bumped a counter when a SIGCLD 76747121Sbostic * was received, and have waitproc bump another counter when it got 76847121Sbostic * the status of a process. Waitproc would then know that a wait 76947121Sbostic * system call would not block if the two counters were different. 77047121Sbostic * This approach doesn't work because if a process has children that 77147121Sbostic * have not been waited for, System V will send it a SIGCLD when it 77247121Sbostic * installs a signal handler for SIGCLD. What this means is that when 77347121Sbostic * a child exits, the shell will be sent SIGCLD signals continuously 77447121Sbostic * until is runs out of stack space, unless it does a wait call before 77547121Sbostic * restoring the signal handler. The code below takes advantage of 77647121Sbostic * this (mis)feature by installing a signal handler for SIGCLD and 77747121Sbostic * then checking to see whether it was called. If there are any 77847121Sbostic * children to be waited for, it will be. 77947121Sbostic * 78047121Sbostic * If neither SYSV nor BSD is defined, we don't implement nonblocking 78147121Sbostic * waits at all. In this case, the user will not be informed when 78247121Sbostic * a background process until the next time she runs a real program 78347121Sbostic * (as opposed to running a builtin command or just typing return), 78447121Sbostic * and the jobs command may give out of date information. 78547121Sbostic */ 78647121Sbostic 78747121Sbostic #ifdef SYSV 78847121Sbostic STATIC int gotsigchild; 78947121Sbostic 79047121Sbostic STATIC int onsigchild() { 79147121Sbostic gotsigchild = 1; 79247121Sbostic } 79347121Sbostic #endif 79447121Sbostic 79547121Sbostic 79647121Sbostic STATIC int 79747121Sbostic waitproc(block, status) 79847121Sbostic int *status; 79947121Sbostic { 80047121Sbostic #ifdef BSD 80147121Sbostic int flags; 80247121Sbostic 80347121Sbostic #if JOBS 80447121Sbostic flags = WUNTRACED; 80547121Sbostic #else 80647121Sbostic flags = 0; 80747121Sbostic #endif 80847121Sbostic if (block == 0) 80947121Sbostic flags |= WNOHANG; 81055230Smarc return wait3(status, flags, (struct rusage *)NULL); 81147121Sbostic #else 81247121Sbostic #ifdef SYSV 81347121Sbostic int (*save)(); 81447121Sbostic 81547121Sbostic if (block == 0) { 81647121Sbostic gotsigchild = 0; 81747121Sbostic save = signal(SIGCLD, onsigchild); 81847121Sbostic signal(SIGCLD, save); 81947121Sbostic if (gotsigchild == 0) 82047121Sbostic return 0; 82147121Sbostic } 82247121Sbostic return wait(status); 82347121Sbostic #else 82447121Sbostic if (block == 0) 82547121Sbostic return 0; 82647121Sbostic return wait(status); 82747121Sbostic #endif 82847121Sbostic #endif 82947121Sbostic } 83047121Sbostic 83155277Smarc /* 83255277Smarc * return 1 if there are stopped jobs, otherwise 0 83355277Smarc */ 83455277Smarc int job_warning = 0; 83555277Smarc int 83655277Smarc stoppedjobs() 83755277Smarc { 838*56563Smarc register int jobno; 839*56563Smarc register struct job *jp; 84047121Sbostic 84155277Smarc if (job_warning) 84255277Smarc return (0); 843*56563Smarc for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { 844*56563Smarc if (jp->used == 0) 84555277Smarc continue; 846*56563Smarc if (jp->state == JOBSTOPPED) { 84755277Smarc out2str("You have stopped jobs.\n"); 84855277Smarc job_warning = 2; 84955277Smarc return (1); 85055277Smarc } 85155277Smarc } 85247121Sbostic 85355277Smarc return (0); 85455277Smarc } 85555277Smarc 85647121Sbostic /* 85747121Sbostic * Return a string identifying a command (to be printed by the 85847121Sbostic * jobs command. 85947121Sbostic */ 86047121Sbostic 86147121Sbostic STATIC char *cmdnextc; 86247121Sbostic STATIC int cmdnleft; 86347121Sbostic STATIC void cmdtxt(), cmdputs(); 86455297Smarc #define MAXCMDTEXT 200 86547121Sbostic 86655297Smarc char * 86747121Sbostic commandtext(n) 86847121Sbostic union node *n; 86947121Sbostic { 87047121Sbostic char *name; 87147121Sbostic 87255297Smarc cmdnextc = name = ckmalloc(MAXCMDTEXT); 87355297Smarc cmdnleft = MAXCMDTEXT - 4; 87447121Sbostic cmdtxt(n); 87547121Sbostic *cmdnextc = '\0'; 87647121Sbostic return name; 87747121Sbostic } 87847121Sbostic 87947121Sbostic 88047121Sbostic STATIC void 88147121Sbostic cmdtxt(n) 88247121Sbostic union node *n; 88347121Sbostic { 88447121Sbostic union node *np; 88547121Sbostic struct nodelist *lp; 88647121Sbostic char *p; 88747121Sbostic int i; 88847121Sbostic char s[2]; 88947121Sbostic 89055230Smarc if (n == NULL) 89155230Smarc return; 89247121Sbostic switch (n->type) { 89347121Sbostic case NSEMI: 89447121Sbostic cmdtxt(n->nbinary.ch1); 89547121Sbostic cmdputs("; "); 89647121Sbostic cmdtxt(n->nbinary.ch2); 89747121Sbostic break; 89847121Sbostic case NAND: 89947121Sbostic cmdtxt(n->nbinary.ch1); 90047121Sbostic cmdputs(" && "); 90147121Sbostic cmdtxt(n->nbinary.ch2); 90247121Sbostic break; 90347121Sbostic case NOR: 90447121Sbostic cmdtxt(n->nbinary.ch1); 90547121Sbostic cmdputs(" || "); 90647121Sbostic cmdtxt(n->nbinary.ch2); 90747121Sbostic break; 90847121Sbostic case NPIPE: 90947121Sbostic for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 91047121Sbostic cmdtxt(lp->n); 91147121Sbostic if (lp->next) 91247121Sbostic cmdputs(" | "); 91347121Sbostic } 91447121Sbostic break; 91547121Sbostic case NSUBSHELL: 91647121Sbostic cmdputs("("); 91747121Sbostic cmdtxt(n->nredir.n); 91847121Sbostic cmdputs(")"); 91947121Sbostic break; 92047121Sbostic case NREDIR: 92147121Sbostic case NBACKGND: 92247121Sbostic cmdtxt(n->nredir.n); 92347121Sbostic break; 92447121Sbostic case NIF: 92547121Sbostic cmdputs("if "); 92647121Sbostic cmdtxt(n->nif.test); 92747121Sbostic cmdputs("; then "); 92847121Sbostic cmdtxt(n->nif.ifpart); 92947121Sbostic cmdputs("..."); 93047121Sbostic break; 93147121Sbostic case NWHILE: 93247121Sbostic cmdputs("while "); 93347121Sbostic goto until; 93447121Sbostic case NUNTIL: 93547121Sbostic cmdputs("until "); 93647121Sbostic until: 93747121Sbostic cmdtxt(n->nbinary.ch1); 93847121Sbostic cmdputs("; do "); 93947121Sbostic cmdtxt(n->nbinary.ch2); 94047121Sbostic cmdputs("; done"); 94147121Sbostic break; 94247121Sbostic case NFOR: 94347121Sbostic cmdputs("for "); 94447121Sbostic cmdputs(n->nfor.var); 94547121Sbostic cmdputs(" in ..."); 94647121Sbostic break; 94747121Sbostic case NCASE: 94847121Sbostic cmdputs("case "); 94947121Sbostic cmdputs(n->ncase.expr->narg.text); 95047121Sbostic cmdputs(" in ..."); 95147121Sbostic break; 95247121Sbostic case NDEFUN: 95347121Sbostic cmdputs(n->narg.text); 95447121Sbostic cmdputs("() ..."); 95547121Sbostic break; 95647121Sbostic case NCMD: 95747121Sbostic for (np = n->ncmd.args ; np ; np = np->narg.next) { 95847121Sbostic cmdtxt(np); 95947121Sbostic if (np->narg.next) 96047121Sbostic cmdputs(" "); 96147121Sbostic } 96247121Sbostic for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { 96347121Sbostic cmdputs(" "); 96447121Sbostic cmdtxt(np); 96547121Sbostic } 96647121Sbostic break; 96747121Sbostic case NARG: 96847121Sbostic cmdputs(n->narg.text); 96947121Sbostic break; 97047121Sbostic case NTO: 97147121Sbostic p = ">"; i = 1; goto redir; 97247121Sbostic case NAPPEND: 97347121Sbostic p = ">>"; i = 1; goto redir; 97447121Sbostic case NTOFD: 97547121Sbostic p = ">&"; i = 1; goto redir; 97647121Sbostic case NFROM: 97747121Sbostic p = "<"; i = 0; goto redir; 97847121Sbostic case NFROMFD: 97947121Sbostic p = "<&"; i = 0; goto redir; 98047121Sbostic redir: 98147121Sbostic if (n->nfile.fd != i) { 98247121Sbostic s[0] = n->nfile.fd + '0'; 98347121Sbostic s[1] = '\0'; 98447121Sbostic cmdputs(s); 98547121Sbostic } 98647121Sbostic cmdputs(p); 98747121Sbostic if (n->type == NTOFD || n->type == NFROMFD) { 98847121Sbostic s[0] = n->ndup.dupfd + '0'; 98947121Sbostic s[1] = '\0'; 99047121Sbostic cmdputs(s); 99147121Sbostic } else { 99247121Sbostic cmdtxt(n->nfile.fname); 99347121Sbostic } 99447121Sbostic break; 99547121Sbostic case NHERE: 99647121Sbostic case NXHERE: 99747121Sbostic cmdputs("<<..."); 99847121Sbostic break; 99947121Sbostic default: 100047121Sbostic cmdputs("???"); 100147121Sbostic break; 100247121Sbostic } 100347121Sbostic } 100447121Sbostic 100547121Sbostic 100647121Sbostic 100747121Sbostic STATIC void 100847121Sbostic cmdputs(s) 100947121Sbostic char *s; 101047121Sbostic { 101147121Sbostic register char *p, *q; 101247121Sbostic register char c; 101347121Sbostic int subtype = 0; 101447121Sbostic 101547121Sbostic if (cmdnleft <= 0) 101647121Sbostic return; 101747121Sbostic p = s; 101847121Sbostic q = cmdnextc; 101947121Sbostic while ((c = *p++) != '\0') { 102047121Sbostic if (c == CTLESC) 102147121Sbostic *q++ = *p++; 102247121Sbostic else if (c == CTLVAR) { 102347121Sbostic *q++ = '$'; 102447121Sbostic if (--cmdnleft > 0) 102547121Sbostic *q++ = '{'; 102647121Sbostic subtype = *p++; 102747121Sbostic } else if (c == '=' && subtype != 0) { 102847121Sbostic *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; 102947121Sbostic subtype = 0; 103047121Sbostic } else if (c == CTLENDVAR) { 103147121Sbostic *q++ = '}'; 103247121Sbostic } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE) 103347121Sbostic cmdnleft++; /* ignore it */ 103447121Sbostic else 103547121Sbostic *q++ = c; 103647121Sbostic if (--cmdnleft <= 0) { 103747121Sbostic *q++ = '.'; 103847121Sbostic *q++ = '.'; 103947121Sbostic *q++ = '.'; 104047121Sbostic break; 104147121Sbostic } 104247121Sbostic } 104347121Sbostic cmdnextc = q; 104447121Sbostic } 1045