Home | History | Annotate | Line # | Download | only in sh
jobs.c revision 1.1
      1 /*-
      2  * Copyright (c) 1991 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Kenneth Almquist.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 static char sccsid[] = "@(#)jobs.c	5.1 (Berkeley) 3/7/91";
     39 #endif /* not lint */
     40 
     41 #include "shell.h"
     42 #if JOBS
     43 #include "sgtty.h"
     44 #undef CEOF			/* syntax.h redefines this */
     45 #endif
     46 #include "main.h"
     47 #include "parser.h"
     48 #include "nodes.h"
     49 #include "jobs.h"
     50 #include "options.h"
     51 #include "trap.h"
     52 #include "signames.h"
     53 #include "syntax.h"
     54 #include "input.h"
     55 #include "output.h"
     56 #include "memalloc.h"
     57 #include "error.h"
     58 #include "mystring.h"
     59 #include <fcntl.h>
     60 #include <signal.h>
     61 #include <errno.h>
     62 #ifdef BSD
     63 #include <sys/types.h>
     64 #include <sys/wait.h>
     65 #include <sys/time.h>
     66 #include <sys/resource.h>
     67 #endif
     68 
     69 
     70 
     71 struct job *jobtab;		/* array of jobs */
     72 int njobs;			/* size of array */
     73 MKINIT short backgndpid = -1;	/* pid of last background process */
     74 #if JOBS
     75 int initialpgrp;		/* pgrp of shell on invocation */
     76 short curjob;			/* current job */
     77 #endif
     78 
     79 #ifdef __STDC__
     80 STATIC void restartjob(struct job *);
     81 STATIC struct job *getjob(char *);
     82 STATIC void freejob(struct job *);
     83 STATIC int procrunning(int);
     84 STATIC int dowait(int, struct job *);
     85 STATIC int waitproc(int, int *);
     86 STATIC char *commandtext(union node *);
     87 #else
     88 STATIC void restartjob();
     89 STATIC struct job *getjob();
     90 STATIC void freejob();
     91 STATIC int procrunning();
     92 STATIC int dowait();
     93 STATIC int waitproc();
     94 STATIC char *commandtext();
     95 #endif
     96 
     97 
     98 
     99 #if JOBS
    100 /*
    101  * Turn job control on and off.
    102  *
    103  * Note:  This code assumes that the third arg to ioctl is a character
    104  * pointer, which is true on Berkeley systems but not System V.  Since
    105  * System V doesn't have job control yet, this isn't a problem now.
    106  */
    107 
    108 MKINIT int jobctl;
    109 
    110 void
    111 setjobctl(on) {
    112 	int ldisc;
    113 
    114 	if (on == jobctl || rootshell == 0)
    115 		return;
    116 	if (on) {
    117 		do { /* while we are in the background */
    118 			if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
    119 				out2str("ash: can't access tty; job control turned off\n");
    120 				jflag = 0;
    121 				return;
    122 			}
    123 			if (initialpgrp == -1)
    124 				initialpgrp = getpgrp(0);
    125 			else if (initialpgrp != getpgrp(0)) {
    126 				killpg(initialpgrp, SIGTTIN);
    127 				continue;
    128 			}
    129 		} while (0);
    130 		if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
    131 			out2str("ash: need new tty driver to run job control; job control turned off\n");
    132 			jflag = 0;
    133 			return;
    134 		}
    135 		setsignal(SIGTSTP);
    136 		setsignal(SIGTTOU);
    137 		setpgrp(0, rootpid);
    138 		ioctl(2, TIOCSPGRP, (char *)&rootpid);
    139 	} else { /* turning job control off */
    140 		setpgrp(0, initialpgrp);
    141 		ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
    142 		setsignal(SIGTSTP);
    143 		setsignal(SIGTTOU);
    144 	}
    145 	jobctl = on;
    146 }
    147 #endif
    148 
    149 
    150 #ifdef mkinit
    151 
    152 SHELLPROC {
    153 	backgndpid = -1;
    154 #if JOBS
    155 	jobctl = 0;
    156 #endif
    157 }
    158 
    159 #endif
    160 
    161 
    162 
    163 #if JOBS
    164 fgcmd(argc, argv)  char **argv; {
    165 	struct job *jp;
    166 	int pgrp;
    167 	int status;
    168 
    169 	jp = getjob(argv[1]);
    170 	if (jp->jobctl == 0)
    171 		error("job not created under job control");
    172 	pgrp = jp->ps[0].pid;
    173 	ioctl(2, TIOCSPGRP, (char *)&pgrp);
    174 	restartjob(jp);
    175 	INTOFF;
    176 	status = waitforjob(jp);
    177 	INTON;
    178 	return status;
    179 }
    180 
    181 
    182 bgcmd(argc, argv)  char **argv; {
    183 	struct job *jp;
    184 
    185 	do {
    186 		jp = getjob(*++argv);
    187 		if (jp->jobctl == 0)
    188 			error("job not created under job control");
    189 		restartjob(jp);
    190 	} while (--argc > 1);
    191 	return 0;
    192 }
    193 
    194 
    195 STATIC void
    196 restartjob(jp)
    197 	struct job *jp;
    198 	{
    199 	struct procstat *ps;
    200 	int i;
    201 
    202 	if (jp->state == JOBDONE)
    203 		return;
    204 	INTOFF;
    205 	killpg(jp->ps[0].pid, SIGCONT);
    206 	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
    207 		if ((ps->status & 0377) == 0177) {
    208 			ps->status = -1;
    209 			jp->state = 0;
    210 		}
    211 	}
    212 	INTON;
    213 }
    214 #endif
    215 
    216 
    217 int
    218 jobscmd(argc, argv)  char **argv; {
    219 	showjobs(0);
    220 	return 0;
    221 }
    222 
    223 
    224 /*
    225  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
    226  * statuses have changed since the last call to showjobs.
    227  *
    228  * If the shell is interrupted in the process of creating a job, the
    229  * result may be a job structure containing zero processes.  Such structures
    230  * will be freed here.
    231  */
    232 
    233 void
    234 showjobs(change) {
    235 	int jobno;
    236 	int procno;
    237 	int i;
    238 	struct job *jp;
    239 	struct procstat *ps;
    240 	int col;
    241 	char s[64];
    242 
    243 	TRACE(("showjobs(%d) called\n", change));
    244 	while (dowait(0, (struct job *)NULL) > 0);
    245 	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
    246 		if (! jp->used)
    247 			continue;
    248 		if (jp->nprocs == 0) {
    249 			freejob(jp);
    250 			continue;
    251 		}
    252 		if (change && ! jp->changed)
    253 			continue;
    254 		procno = jp->nprocs;
    255 		for (ps = jp->ps ; ; ps++) {	/* for each process */
    256 			if (ps == jp->ps)
    257 				fmtstr(s, 64, "[%d] %d ", jobno, ps->pid);
    258 			else
    259 				fmtstr(s, 64, "    %d ", ps->pid);
    260 			out1str(s);
    261 			col = strlen(s);
    262 			s[0] = '\0';
    263 			if (ps->status == -1) {
    264 				/* don't print anything */
    265 			} else if ((ps->status & 0xFF) == 0) {
    266 				fmtstr(s, 64, "Exit %d", ps->status >> 8);
    267 			} else {
    268 				i = ps->status;
    269 #if JOBS
    270 				if ((i & 0xFF) == 0177)
    271 					i >>= 8;
    272 #endif
    273 				if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F])
    274 					scopy(sigmesg[i & 0x7F], s);
    275 				else
    276 					fmtstr(s, 64, "Signal %d", i & 0x7F);
    277 				if (i & 0x80)
    278 					strcat(s, " (core dumped)");
    279 			}
    280 			out1str(s);
    281 			col += strlen(s);
    282 			do {
    283 				out1c(' ');
    284 				col++;
    285 			} while (col < 30);
    286 			out1str(ps->cmd);
    287 			out1c('\n');
    288 			if (--procno <= 0)
    289 				break;
    290 		}
    291 		jp->changed = 0;
    292 		if (jp->state == JOBDONE) {
    293 			freejob(jp);
    294 		}
    295 	}
    296 }
    297 
    298 
    299 /*
    300  * Mark a job structure as unused.
    301  */
    302 
    303 STATIC void
    304 freejob(jp)
    305 	struct job *jp;
    306 	{
    307 	struct procstat *ps;
    308 	int i;
    309 
    310 	INTOFF;
    311 	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
    312 		if (ps->cmd != nullstr)
    313 			ckfree(ps->cmd);
    314 	}
    315 	if (jp->ps != &jp->ps0)
    316 		ckfree(jp->ps);
    317 	jp->used = 0;
    318 #if JOBS
    319 	if (curjob == jp - jobtab + 1)
    320 		curjob = 0;
    321 #endif
    322 	INTON;
    323 }
    324 
    325 
    326 
    327 int
    328 waitcmd(argc, argv)  char **argv; {
    329 	struct job *job;
    330 	int status;
    331 	struct job *jp;
    332 
    333 	if (argc > 1) {
    334 		job = getjob(argv[1]);
    335 	} else {
    336 		job = NULL;
    337 	}
    338 	for (;;) {	/* loop until process terminated or stopped */
    339 		if (job != NULL) {
    340 			if (job->state) {
    341 				status = job->ps[job->nprocs - 1].status;
    342 				if ((status & 0xFF) == 0)
    343 					status = status >> 8 & 0xFF;
    344 #if JOBS
    345 				else if ((status & 0xFF) == 0177)
    346 					status = (status >> 8 & 0x7F) + 128;
    347 #endif
    348 				else
    349 					status = (status & 0x7F) + 128;
    350 				if (! iflag)
    351 					freejob(job);
    352 				return status;
    353 			}
    354 		} else {
    355 			for (jp = jobtab ; ; jp++) {
    356 				if (jp >= jobtab + njobs) {	/* no running procs */
    357 					return 0;
    358 				}
    359 				if (jp->used && jp->state == 0)
    360 					break;
    361 			}
    362 		}
    363 		dowait(1, (struct job *)NULL);
    364 	}
    365 }
    366 
    367 
    368 
    369 jobidcmd(argc, argv)  char **argv; {
    370 	struct job *jp;
    371 	int i;
    372 
    373 	jp = getjob(argv[1]);
    374 	for (i = 0 ; i < jp->nprocs ; ) {
    375 		out1fmt("%d", jp->ps[i].pid);
    376 		out1c(++i < jp->nprocs? ' ' : '\n');
    377 	}
    378 	return 0;
    379 }
    380 
    381 
    382 
    383 /*
    384  * Convert a job name to a job structure.
    385  */
    386 
    387 STATIC struct job *
    388 getjob(name)
    389 	char *name;
    390 	{
    391 	int jobno;
    392 	register struct job *jp;
    393 	int pid;
    394 	int i;
    395 
    396 	if (name == NULL) {
    397 #if JOBS
    398 currentjob:
    399 		if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
    400 			error("No current job");
    401 		return &jobtab[jobno - 1];
    402 #else
    403 		error("No current job");
    404 #endif
    405 	} else if (name[0] == '%') {
    406 		if (is_digit(name[1])) {
    407 			jobno = number(name + 1);
    408 			if (jobno > 0 && jobno <= njobs
    409 			 && jobtab[jobno - 1].used != 0)
    410 				return &jobtab[jobno - 1];
    411 #if JOBS
    412 		} else if (name[1] == '%' && name[2] == '\0') {
    413 			goto currentjob;
    414 #endif
    415 		} else {
    416 			register struct job *found = NULL;
    417 			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
    418 				if (jp->used && jp->nprocs > 0
    419 				 && prefix(name + 1, jp->ps[0].cmd)) {
    420 					if (found)
    421 						error("%s: ambiguous", name);
    422 					found = jp;
    423 				}
    424 			}
    425 			if (found)
    426 				return found;
    427 		}
    428 	} else if (is_number(name)) {
    429 		pid = number(name);
    430 		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
    431 			if (jp->used && jp->nprocs > 0
    432 			 && jp->ps[jp->nprocs - 1].pid == pid)
    433 				return jp;
    434 		}
    435 	}
    436 	error("No such job: %s", name);
    437 }
    438 
    439 
    440 
    441 /*
    442  * Return a new job structure,
    443  */
    444 
    445 struct job *
    446 makejob(node, nprocs)
    447 	union node *node;
    448 	{
    449 	int i;
    450 	struct job *jp;
    451 
    452 	for (i = njobs, jp = jobtab ; ; jp++) {
    453 		if (--i < 0) {
    454 			INTOFF;
    455 			if (njobs == 0) {
    456 				jobtab = ckmalloc(4 * sizeof jobtab[0]);
    457 			} else {
    458 				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
    459 				bcopy(jobtab, jp, njobs * sizeof jp[0]);
    460 				ckfree(jobtab);
    461 				jobtab = jp;
    462 			}
    463 			jp = jobtab + njobs;
    464 			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
    465 			INTON;
    466 			break;
    467 		}
    468 		if (jp->used == 0)
    469 			break;
    470 	}
    471 	INTOFF;
    472 	jp->state = 0;
    473 	jp->used = 1;
    474 	jp->changed = 0;
    475 	jp->nprocs = 0;
    476 #if JOBS
    477 	jp->jobctl = jobctl;
    478 #endif
    479 	if (nprocs > 1) {
    480 		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
    481 	} else {
    482 		jp->ps = &jp->ps0;
    483 	}
    484 	INTON;
    485 	TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1));
    486 	return jp;
    487 }
    488 
    489 
    490 /*
    491  * Fork of a subshell.  If we are doing job control, give the subshell its
    492  * own process group.  Jp is a job structure that the job is to be added to.
    493  * N is the command that will be evaluated by the child.  Both jp and n may
    494  * be NULL.  The mode parameter can be one of the following:
    495  *	FORK_FG - Fork off a foreground process.
    496  *	FORK_BG - Fork off a background process.
    497  *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
    498  *		     process group even if job control is on.
    499  *
    500  * When job control is turned off, background processes have their standard
    501  * input redirected to /dev/null (except for the second and later processes
    502  * in a pipeline).
    503  */
    504 
    505 int
    506 forkshell(jp, n, mode)
    507 	union node *n;
    508 	struct job *jp;
    509 	{
    510 	int pid;
    511 	int pgrp;
    512 
    513 	TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode));
    514 	INTOFF;
    515 	pid = fork();
    516 	if (pid == -1) {
    517 		TRACE(("Fork failed, errno=%d\n", errno));
    518 		INTON;
    519 		error("Cannot fork");
    520 	}
    521 	if (pid == 0) {
    522 		struct job *p;
    523 		int wasroot;
    524 		int i;
    525 
    526 		TRACE(("Child shell %d\n", getpid()));
    527 		wasroot = rootshell;
    528 		rootshell = 0;
    529 		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
    530 			if (p->used)
    531 				freejob(p);
    532 		closescript();
    533 		INTON;
    534 		clear_traps();
    535 #if JOBS
    536 		jobctl = 0;		/* do job control only in root shell */
    537 		if (wasroot && mode != FORK_NOJOB && jflag) {
    538 			if (jp == NULL || jp->nprocs == 0)
    539 				pgrp = getpid();
    540 			else
    541 				pgrp = jp->ps[0].pid;
    542 			setpgrp(0, pgrp);
    543 			if (mode == FORK_FG) {
    544 				/*** this causes superfluous TIOCSPGRPS ***/
    545 				if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
    546 					error("TIOCSPGRP failed, errno=%d\n", errno);
    547 			}
    548 			setsignal(SIGTSTP);
    549 			setsignal(SIGTTOU);
    550 		} else if (mode == FORK_BG) {
    551 			ignoresig(SIGINT);
    552 			ignoresig(SIGQUIT);
    553 			if (jp == NULL || jp->nprocs == 0) {
    554 				close(0);
    555 				if (open("/dev/null", O_RDONLY) != 0)
    556 					error("Can't open /dev/null");
    557 			}
    558 		}
    559 #else
    560 		if (mode == FORK_BG) {
    561 			ignoresig(SIGINT);
    562 			ignoresig(SIGQUIT);
    563 			if (jp == NULL || jp->nprocs == 0) {
    564 				close(0);
    565 				if (open("/dev/null", O_RDONLY) != 0)
    566 					error("Can't open /dev/null");
    567 			}
    568 		}
    569 #endif
    570 		if (wasroot && iflag) {
    571 			setsignal(SIGINT);
    572 			setsignal(SIGQUIT);
    573 			setsignal(SIGTERM);
    574 		}
    575 		return pid;
    576 	}
    577 	if (rootshell && mode != FORK_NOJOB && jflag) {
    578 		if (jp == NULL || jp->nprocs == 0)
    579 			pgrp = pid;
    580 		else
    581 			pgrp = jp->ps[0].pid;
    582 		setpgrp(pid, pgrp);
    583 	}
    584 	if (mode == FORK_BG)
    585 		backgndpid = pid;		/* set $! */
    586 	if (jp) {
    587 		struct procstat *ps = &jp->ps[jp->nprocs++];
    588 		ps->pid = pid;
    589 		ps->status = -1;
    590 		ps->cmd = nullstr;
    591 		if (iflag && rootshell && n)
    592 			ps->cmd = commandtext(n);
    593 	}
    594 	INTON;
    595 	TRACE(("In parent shell:  child = %d\n", pid));
    596 	return pid;
    597 }
    598 
    599 
    600 
    601 /*
    602  * Wait for job to finish.
    603  *
    604  * Under job control we have the problem that while a child process is
    605  * running interrupts generated by the user are sent to the child but not
    606  * to the shell.  This means that an infinite loop started by an inter-
    607  * active user may be hard to kill.  With job control turned off, an
    608  * interactive user may place an interactive program inside a loop.  If
    609  * the interactive program catches interrupts, the user doesn't want
    610  * these interrupts to also abort the loop.  The approach we take here
    611  * is to have the shell ignore interrupt signals while waiting for a
    612  * forground process to terminate, and then send itself an interrupt
    613  * signal if the child process was terminated by an interrupt signal.
    614  * Unfortunately, some programs want to do a bit of cleanup and then
    615  * exit on interrupt; unless these processes terminate themselves by
    616  * sending a signal to themselves (instead of calling exit) they will
    617  * confuse this approach.
    618  */
    619 
    620 int
    621 waitforjob(jp)
    622 	register struct job *jp;
    623 	{
    624 #if JOBS
    625 	int mypgrp = getpgrp(0);
    626 #endif
    627 	int status;
    628 	int st;
    629 
    630 	INTOFF;
    631 	TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
    632 	while (jp->state == 0) {
    633 		dowait(1, jp);
    634 	}
    635 #if JOBS
    636 	if (jp->jobctl) {
    637 		if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
    638 			error("TIOCSPGRP failed, errno=%d\n", errno);
    639 	}
    640 	if (jp->state == JOBSTOPPED)
    641 		curjob = jp - jobtab + 1;
    642 #endif
    643 	status = jp->ps[jp->nprocs - 1].status;
    644 	/* convert to 8 bits */
    645 	if ((status & 0xFF) == 0)
    646 		st = status >> 8 & 0xFF;
    647 #if JOBS
    648 	else if ((status & 0xFF) == 0177)
    649 		st = (status >> 8 & 0x7F) + 128;
    650 #endif
    651 	else
    652 		st = (status & 0x7F) + 128;
    653 	if (! JOBS || jp->state == JOBDONE)
    654 		freejob(jp);
    655 	CLEAR_PENDING_INT;
    656 	if ((status & 0x7F) == SIGINT)
    657 		kill(getpid(), SIGINT);
    658 	INTON;
    659 	return st;
    660 }
    661 
    662 
    663 
    664 /*
    665  * Wait for a process to terminate.
    666  */
    667 
    668 STATIC int
    669 dowait(block, job)
    670 	struct job *job;
    671 	{
    672 	int pid;
    673 	int status;
    674 	struct procstat *sp;
    675 	struct job *jp;
    676 	struct job *thisjob;
    677 	int done;
    678 	int stopped;
    679 	int core;
    680 
    681 	TRACE(("dowait(%d) called\n", block));
    682 	do {
    683 		pid = waitproc(block, &status);
    684 		TRACE(("wait returns %d, status=%d\n", pid, status));
    685 	} while (pid == -1 && errno == EINTR);
    686 	if (pid <= 0)
    687 		return pid;
    688 	INTOFF;
    689 	thisjob = NULL;
    690 	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
    691 		if (jp->used) {
    692 			done = 1;
    693 			stopped = 1;
    694 			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
    695 				if (sp->pid == -1)
    696 					continue;
    697 				if (sp->pid == pid) {
    698 					TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
    699 					sp->status = status;
    700 					thisjob = jp;
    701 				}
    702 				if (sp->status == -1)
    703 					stopped = 0;
    704 				else if ((sp->status & 0377) == 0177)
    705 					done = 0;
    706 			}
    707 			if (stopped) {		/* stopped or done */
    708 				int state = done? JOBDONE : JOBSTOPPED;
    709 				if (jp->state != state) {
    710 					TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
    711 					jp->state = state;
    712 #if JOBS
    713 					if (done && curjob == jp - jobtab + 1)
    714 						curjob = 0;		/* no current job */
    715 #endif
    716 				}
    717 			}
    718 		}
    719 	}
    720 	INTON;
    721 	if (! rootshell || ! iflag || (job && thisjob == job)) {
    722 #if JOBS
    723 		if ((status & 0xFF) == 0177)
    724 			status >>= 8;
    725 #endif
    726 		core = status & 0x80;
    727 		status &= 0x7F;
    728 		if (status != 0 && status != SIGINT && status != SIGPIPE) {
    729 			if (thisjob != job)
    730 				outfmt(out2, "%d: ", pid);
    731 #if JOBS
    732 			if (status == SIGTSTP && rootshell && iflag)
    733 				outfmt(out2, "%%%d ", job - jobtab + 1);
    734 #endif
    735 			if (status <= MAXSIG && sigmesg[status])
    736 				out2str(sigmesg[status]);
    737 			else
    738 				outfmt(out2, "Signal %d", status);
    739 			if (core)
    740 				out2str(" - core dumped");
    741 			out2c('\n');
    742 			flushout(&errout);
    743 		} else {
    744 			TRACE(("Not printing status: status=%d\n", status));
    745 		}
    746 	} else {
    747 		TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
    748 		if (thisjob)
    749 			thisjob->changed = 1;
    750 	}
    751 	return pid;
    752 }
    753 
    754 
    755 
    756 /*
    757  * Do a wait system call.  If job control is compiled in, we accept
    758  * stopped processes.  If block is zero, we return a value of zero
    759  * rather than blocking.
    760  *
    761  * System V doesn't have a non-blocking wait system call.  It does
    762  * have a SIGCLD signal that is sent to a process when one of it's
    763  * children dies.  The obvious way to use SIGCLD would be to install
    764  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
    765  * was received, and have waitproc bump another counter when it got
    766  * the status of a process.  Waitproc would then know that a wait
    767  * system call would not block if the two counters were different.
    768  * This approach doesn't work because if a process has children that
    769  * have not been waited for, System V will send it a SIGCLD when it
    770  * installs a signal handler for SIGCLD.  What this means is that when
    771  * a child exits, the shell will be sent SIGCLD signals continuously
    772  * until is runs out of stack space, unless it does a wait call before
    773  * restoring the signal handler.  The code below takes advantage of
    774  * this (mis)feature by installing a signal handler for SIGCLD and
    775  * then checking to see whether it was called.  If there are any
    776  * children to be waited for, it will be.
    777  *
    778  * If neither SYSV nor BSD is defined, we don't implement nonblocking
    779  * waits at all.  In this case, the user will not be informed when
    780  * a background process until the next time she runs a real program
    781  * (as opposed to running a builtin command or just typing return),
    782  * and the jobs command may give out of date information.
    783  */
    784 
    785 #ifdef SYSV
    786 STATIC int gotsigchild;
    787 
    788 STATIC int onsigchild() {
    789 	gotsigchild = 1;
    790 }
    791 #endif
    792 
    793 
    794 STATIC int
    795 waitproc(block, status)
    796 	int *status;
    797 	{
    798 #ifdef BSD
    799 	int flags;
    800 
    801 #if JOBS
    802 	flags = WUNTRACED;
    803 #else
    804 	flags = 0;
    805 #endif
    806 	if (block == 0)
    807 		flags |= WNOHANG;
    808 	return wait3((union wait *)status, flags, (struct rusage *)NULL);
    809 #else
    810 #ifdef SYSV
    811 	int (*save)();
    812 
    813 	if (block == 0) {
    814 		gotsigchild = 0;
    815 		save = signal(SIGCLD, onsigchild);
    816 		signal(SIGCLD, save);
    817 		if (gotsigchild == 0)
    818 			return 0;
    819 	}
    820 	return wait(status);
    821 #else
    822 	if (block == 0)
    823 		return 0;
    824 	return wait(status);
    825 #endif
    826 #endif
    827 }
    828 
    829 
    830 
    831 /*
    832  * Return a string identifying a command (to be printed by the
    833  * jobs command.
    834  */
    835 
    836 STATIC char *cmdnextc;
    837 STATIC int cmdnleft;
    838 STATIC void cmdtxt(), cmdputs();
    839 
    840 STATIC char *
    841 commandtext(n)
    842 	union node *n;
    843 	{
    844 	char *name;
    845 
    846 	cmdnextc = name = ckmalloc(50);
    847 	cmdnleft = 50 - 4;
    848 	cmdtxt(n);
    849 	*cmdnextc = '\0';
    850 	return name;
    851 }
    852 
    853 
    854 STATIC void
    855 cmdtxt(n)
    856 	union node *n;
    857 	{
    858 	union node *np;
    859 	struct nodelist *lp;
    860 	char *p;
    861 	int i;
    862 	char s[2];
    863 
    864 	switch (n->type) {
    865 	case NSEMI:
    866 		cmdtxt(n->nbinary.ch1);
    867 		cmdputs("; ");
    868 		cmdtxt(n->nbinary.ch2);
    869 		break;
    870 	case NAND:
    871 		cmdtxt(n->nbinary.ch1);
    872 		cmdputs(" && ");
    873 		cmdtxt(n->nbinary.ch2);
    874 		break;
    875 	case NOR:
    876 		cmdtxt(n->nbinary.ch1);
    877 		cmdputs(" || ");
    878 		cmdtxt(n->nbinary.ch2);
    879 		break;
    880 	case NPIPE:
    881 		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
    882 			cmdtxt(lp->n);
    883 			if (lp->next)
    884 				cmdputs(" | ");
    885 		}
    886 		break;
    887 	case NSUBSHELL:
    888 		cmdputs("(");
    889 		cmdtxt(n->nredir.n);
    890 		cmdputs(")");
    891 		break;
    892 	case NREDIR:
    893 	case NBACKGND:
    894 		cmdtxt(n->nredir.n);
    895 		break;
    896 	case NIF:
    897 		cmdputs("if ");
    898 		cmdtxt(n->nif.test);
    899 		cmdputs("; then ");
    900 		cmdtxt(n->nif.ifpart);
    901 		cmdputs("...");
    902 		break;
    903 	case NWHILE:
    904 		cmdputs("while ");
    905 		goto until;
    906 	case NUNTIL:
    907 		cmdputs("until ");
    908 until:
    909 		cmdtxt(n->nbinary.ch1);
    910 		cmdputs("; do ");
    911 		cmdtxt(n->nbinary.ch2);
    912 		cmdputs("; done");
    913 		break;
    914 	case NFOR:
    915 		cmdputs("for ");
    916 		cmdputs(n->nfor.var);
    917 		cmdputs(" in ...");
    918 		break;
    919 	case NCASE:
    920 		cmdputs("case ");
    921 		cmdputs(n->ncase.expr->narg.text);
    922 		cmdputs(" in ...");
    923 		break;
    924 	case NDEFUN:
    925 		cmdputs(n->narg.text);
    926 		cmdputs("() ...");
    927 		break;
    928 	case NCMD:
    929 		for (np = n->ncmd.args ; np ; np = np->narg.next) {
    930 			cmdtxt(np);
    931 			if (np->narg.next)
    932 				cmdputs(" ");
    933 		}
    934 		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
    935 			cmdputs(" ");
    936 			cmdtxt(np);
    937 		}
    938 		break;
    939 	case NARG:
    940 		cmdputs(n->narg.text);
    941 		break;
    942 	case NTO:
    943 		p = ">";  i = 1;  goto redir;
    944 	case NAPPEND:
    945 		p = ">>";  i = 1;  goto redir;
    946 	case NTOFD:
    947 		p = ">&";  i = 1;  goto redir;
    948 	case NFROM:
    949 		p = "<";  i = 0;  goto redir;
    950 	case NFROMFD:
    951 		p = "<&";  i = 0;  goto redir;
    952 redir:
    953 		if (n->nfile.fd != i) {
    954 			s[0] = n->nfile.fd + '0';
    955 			s[1] = '\0';
    956 			cmdputs(s);
    957 		}
    958 		cmdputs(p);
    959 		if (n->type == NTOFD || n->type == NFROMFD) {
    960 			s[0] = n->ndup.dupfd + '0';
    961 			s[1] = '\0';
    962 			cmdputs(s);
    963 		} else {
    964 			cmdtxt(n->nfile.fname);
    965 		}
    966 		break;
    967 	case NHERE:
    968 	case NXHERE:
    969 		cmdputs("<<...");
    970 		break;
    971 	default:
    972 		cmdputs("???");
    973 		break;
    974 	}
    975 }
    976 
    977 
    978 
    979 STATIC void
    980 cmdputs(s)
    981 	char *s;
    982 	{
    983 	register char *p, *q;
    984 	register char c;
    985 	int subtype = 0;
    986 
    987 	if (cmdnleft <= 0)
    988 		return;
    989 	p = s;
    990 	q = cmdnextc;
    991 	while ((c = *p++) != '\0') {
    992 		if (c == CTLESC)
    993 			*q++ = *p++;
    994 		else if (c == CTLVAR) {
    995 			*q++ = '$';
    996 			if (--cmdnleft > 0)
    997 				*q++ = '{';
    998 			subtype = *p++;
    999 		} else if (c == '=' && subtype != 0) {
   1000 			*q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
   1001 			subtype = 0;
   1002 		} else if (c == CTLENDVAR) {
   1003 			*q++ = '}';
   1004 		} else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE)
   1005 			cmdnleft++;		/* ignore it */
   1006 		else
   1007 			*q++ = c;
   1008 		if (--cmdnleft <= 0) {
   1009 			*q++ = '.';
   1010 			*q++ = '.';
   1011 			*q++ = '.';
   1012 			break;
   1013 		}
   1014 	}
   1015 	cmdnextc = q;
   1016 }
   1017