xref: /dragonfly/bin/sh/jobs.c (revision 3e3895bf)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: head/bin/sh/jobs.c 361112 2020-05-16 16:29:23Z jilles $");
40 
41 #include <sys/ioctl.h>
42 #include <sys/param.h>
43 #include <sys/resource.h>
44 #include <sys/time.h>
45 #include <sys/wait.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <paths.h>
49 #include <signal.h>
50 #include <stddef.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 
54 #include "shell.h"
55 #if JOBS
56 #include <termios.h>
57 #undef CEOF			/* syntax.h redefines this */
58 #endif
59 #include "redir.h"
60 #include "exec.h"
61 #include "show.h"
62 #include "main.h"
63 #include "parser.h"
64 #include "nodes.h"
65 #include "jobs.h"
66 #include "options.h"
67 #include "trap.h"
68 #include "syntax.h"
69 #include "input.h"
70 #include "output.h"
71 #include "memalloc.h"
72 #include "error.h"
73 #include "mystring.h"
74 #include "var.h"
75 #include "builtins.h"
76 #include "eval.h"
77 
78 
79 /*
80  * A job structure contains information about a job.  A job is either a
81  * single process or a set of processes contained in a pipeline.  In the
82  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
83  * array of pids.
84  */
85 
86 struct procstat {
87 	pid_t pid;		/* process id */
88 	int status;		/* status flags (defined above) */
89 	char *cmd;		/* text of command being run */
90 };
91 
92 
93 /* states */
94 #define JOBSTOPPED 1		/* all procs are stopped */
95 #define JOBDONE 2		/* all procs are completed */
96 
97 
98 struct job {
99 	struct procstat ps0;	/* status of process */
100 	struct procstat *ps;	/* status or processes when more than one */
101 	short nprocs;		/* number of processes */
102 	pid_t pgrp;		/* process group of this job */
103 	char state;		/* true if job is finished */
104 	char used;		/* true if this entry is in used */
105 	char changed;		/* true if status has changed */
106 	char foreground;	/* true if running in the foreground */
107 	char remembered;	/* true if $! referenced */
108 	char pipefail;		/* pass any non-zero status */
109 #if JOBS
110 	char jobctl;		/* job running under job control */
111 	struct job *next;	/* job used after this one */
112 #endif
113 };
114 
115 
116 static struct job *jobtab;	/* array of jobs */
117 static int njobs;		/* size of array */
118 static pid_t backgndpid = -1;	/* pid of last background process */
119 static struct job *bgjob = NULL; /* last background process */
120 #if JOBS
121 static struct job *jobmru;	/* most recently used job list */
122 static pid_t initialpgrp;	/* pgrp of shell on invocation */
123 #endif
124 static int ttyfd = -1;
125 
126 /* mode flags for dowait */
127 #define DOWAIT_BLOCK	0x1 /* wait until a child exits */
128 #define DOWAIT_SIG	0x2 /* if DOWAIT_BLOCK, abort on signal */
129 #define DOWAIT_SIG_TRAP	0x4 /* if DOWAIT_SIG, abort on trapped signal only */
130 
131 #if JOBS
132 static void restartjob(struct job *);
133 #endif
134 static void freejob(struct job *);
135 static int waitcmdloop(struct job *);
136 static struct job *getjob_nonotfound(const char *);
137 static struct job *getjob(const char *);
138 pid_t killjob(const char *, int);
139 static pid_t dowait(int, struct job *);
140 static void checkzombies(void);
141 static void cmdtxt(union node *);
142 static void cmdputs(const char *);
143 #if JOBS
144 static void setcurjob(struct job *);
145 static void deljob(struct job *);
146 static struct job *getcurjob(struct job *);
147 #endif
148 static int getjobstatus(const struct job *);
149 static void printjobcmd(struct job *);
150 static void showjob(struct job *, int);
151 
152 
153 /*
154  * Turn job control on and off.
155  */
156 
157 static int jobctl;
158 
159 #if JOBS
160 static void
jobctl_notty(void)161 jobctl_notty(void)
162 {
163 	if (ttyfd >= 0) {
164 		close(ttyfd);
165 		ttyfd = -1;
166 	}
167 	if (!iflag) {
168 		setsignal(SIGTSTP);
169 		setsignal(SIGTTOU);
170 		setsignal(SIGTTIN);
171 		jobctl = 1;
172 		return;
173 	}
174 	out2fmt_flush("sh: can't access tty; job control turned off\n");
175 	mflag = 0;
176 }
177 
178 void
setjobctl(int on)179 setjobctl(int on)
180 {
181 	int i;
182 
183 	if (on == jobctl || rootshell == 0)
184 		return;
185 	if (on) {
186 		if (ttyfd != -1)
187 			close(ttyfd);
188 		if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC_MAYBE)) < 0) {
189 			i = 0;
190 			while (i <= 2 && !isatty(i))
191 				i++;
192 			if (i > 2 ||
193 			    (ttyfd = fcntl(i, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) {
194 				jobctl_notty();
195 				return;
196 			}
197 		}
198 		if (ttyfd < 10) {
199 			/*
200 			 * Keep our TTY file descriptor out of the way of
201 			 * the user's redirections.
202 			 */
203 			if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC_MAYBE, 10)) < 0) {
204 				jobctl_notty();
205 				return;
206 			}
207 			close(ttyfd);
208 			ttyfd = i;
209 		}
210 #if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC)
211 		if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
212 			close(ttyfd);
213 			ttyfd = -1;
214 			goto out;
215 		}
216 #endif
217 		do { /* while we are in the background */
218 			initialpgrp = tcgetpgrp(ttyfd);
219 			if (initialpgrp < 0) {
220 #if !defined(O_CLOEXEC) || !defined(F_DUPFD_CLOEXEC)
221 out:
222 #endif
223 				jobctl_notty();
224 				return;
225 			}
226 			if (initialpgrp != getpgrp()) {
227 				if (!iflag) {
228 					initialpgrp = -1;
229 					jobctl_notty();
230 					return;
231 				}
232 				kill(0, SIGTTIN);
233 				continue;
234 			}
235 		} while (0);
236 		setsignal(SIGTSTP);
237 		setsignal(SIGTTOU);
238 		setsignal(SIGTTIN);
239 		setpgid(0, rootpid);
240 		tcsetpgrp(ttyfd, rootpid);
241 	} else { /* turning job control off */
242 		setpgid(0, initialpgrp);
243 		if (ttyfd >= 0) {
244 			tcsetpgrp(ttyfd, initialpgrp);
245 			close(ttyfd);
246 			ttyfd = -1;
247 		}
248 		setsignal(SIGTSTP);
249 		setsignal(SIGTTOU);
250 		setsignal(SIGTTIN);
251 	}
252 	jobctl = on;
253 }
254 #endif
255 
256 
257 #if JOBS
258 int
fgcmd(int argc __unused,char ** argv __unused)259 fgcmd(int argc __unused, char **argv __unused)
260 {
261 	struct job *jp;
262 	pid_t pgrp;
263 	int status;
264 
265 	nextopt("");
266 	jp = getjob(*argptr);
267 	if (jp->jobctl == 0)
268 		error("job not created under job control");
269 	printjobcmd(jp);
270 	flushout(&output);
271 	pgrp = jp->ps[0].pid;
272 	if (ttyfd >= 0)
273 		tcsetpgrp(ttyfd, pgrp);
274 	restartjob(jp);
275 	jp->foreground = 1;
276 	INTOFF;
277 	status = waitforjob(jp, (int *)NULL);
278 	INTON;
279 	return status;
280 }
281 
282 
283 int
bgcmd(int argc __unused,char ** argv __unused)284 bgcmd(int argc __unused, char **argv __unused)
285 {
286 	struct job *jp;
287 
288 	nextopt("");
289 	do {
290 		jp = getjob(*argptr);
291 		if (jp->jobctl == 0)
292 			error("job not created under job control");
293 		if (jp->state == JOBDONE)
294 			continue;
295 		restartjob(jp);
296 		jp->foreground = 0;
297 		out1fmt("[%td] ", jp - jobtab + 1);
298 		printjobcmd(jp);
299 	} while (*argptr != NULL && *++argptr != NULL);
300 	return 0;
301 }
302 
303 
304 static void
restartjob(struct job * jp)305 restartjob(struct job *jp)
306 {
307 	struct procstat *ps;
308 	int i;
309 
310 	if (jp->state == JOBDONE)
311 		return;
312 	setcurjob(jp);
313 	INTOFF;
314 	kill(-jp->ps[0].pid, SIGCONT);
315 	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
316 		if (WIFSTOPPED(ps->status)) {
317 			ps->status = -1;
318 			jp->state = 0;
319 		}
320 	}
321 	INTON;
322 }
323 #endif
324 
325 
326 int
jobscmd(int argc __unused,char * argv[]__unused)327 jobscmd(int argc __unused, char *argv[] __unused)
328 {
329 	char *id;
330 	int ch, mode;
331 
332 	mode = SHOWJOBS_DEFAULT;
333 	while ((ch = nextopt("lps")) != '\0') {
334 		switch (ch) {
335 		case 'l':
336 			mode = SHOWJOBS_VERBOSE;
337 			break;
338 		case 'p':
339 			mode = SHOWJOBS_PGIDS;
340 			break;
341 		case 's':
342 			mode = SHOWJOBS_PIDS;
343 			break;
344 		}
345 	}
346 
347 	if (*argptr == NULL)
348 		showjobs(0, mode);
349 	else
350 		while ((id = *argptr++) != NULL)
351 			showjob(getjob(id), mode);
352 
353 	return (0);
354 }
355 
getjobstatus(const struct job * jp)356 static int getjobstatus(const struct job *jp)
357 {
358 	int i, status;
359 
360 	if (!jp->pipefail)
361 		return (jp->ps[jp->nprocs - 1].status);
362 	for (i = jp->nprocs - 1; i >= 0; i--) {
363 		status = jp->ps[i].status;
364 		if (status != 0)
365 			return (status);
366 	}
367 	return (0);
368 }
369 
370 static void
printjobcmd(struct job * jp)371 printjobcmd(struct job *jp)
372 {
373 	struct procstat *ps;
374 	int i;
375 
376 	for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
377 		out1str(ps->cmd);
378 		if (i > 0)
379 			out1str(" | ");
380 	}
381 	out1c('\n');
382 }
383 
384 static void
showjob(struct job * jp,int mode)385 showjob(struct job *jp, int mode)
386 {
387 	char s[64];
388 	char statebuf[16];
389 	const char *statestr, *coredump;
390 	struct procstat *ps;
391 	struct job *j;
392 	int col, curr, i, jobno, prev, procno, status;
393 	char c;
394 
395 	procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
396 	jobno = jp - jobtab + 1;
397 	curr = prev = 0;
398 #if JOBS
399 	if ((j = getcurjob(NULL)) != NULL) {
400 		curr = j - jobtab + 1;
401 		if ((j = getcurjob(j)) != NULL)
402 			prev = j - jobtab + 1;
403 	}
404 #endif
405 	coredump = "";
406 	status = getjobstatus(jp);
407 	if (jp->state == 0) {
408 		statestr = "Running";
409 #if JOBS
410 	} else if (jp->state == JOBSTOPPED) {
411 		ps = jp->ps + jp->nprocs - 1;
412 		while (!WIFSTOPPED(ps->status) && ps > jp->ps)
413 			ps--;
414 		if (WIFSTOPPED(ps->status))
415 			i = WSTOPSIG(ps->status);
416 		else
417 			i = -1;
418 		statestr = strsignal(i);
419 		if (statestr == NULL)
420 			statestr = "Suspended";
421 #endif
422 	} else if (WIFEXITED(status)) {
423 		if (WEXITSTATUS(status) == 0)
424 			statestr = "Done";
425 		else {
426 			fmtstr(statebuf, sizeof(statebuf), "Done(%d)",
427 			    WEXITSTATUS(status));
428 			statestr = statebuf;
429 		}
430 	} else {
431 		i = WTERMSIG(status);
432 		statestr = strsignal(i);
433 		if (statestr == NULL)
434 			statestr = "Unknown signal";
435 		if (WCOREDUMP(status))
436 			coredump = " (core dumped)";
437 	}
438 
439 	for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
440 		if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
441 			out1fmt("%d\n", (int)ps->pid);
442 			continue;
443 		}
444 		if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
445 			continue;
446 		if (jobno == curr && ps == jp->ps)
447 			c = '+';
448 		else if (jobno == prev && ps == jp->ps)
449 			c = '-';
450 		else
451 			c = ' ';
452 		if (ps == jp->ps)
453 			fmtstr(s, 64, "[%d] %c ", jobno, c);
454 		else
455 			fmtstr(s, 64, "    %c ", c);
456 		out1str(s);
457 		col = strlen(s);
458 		if (mode == SHOWJOBS_VERBOSE) {
459 			fmtstr(s, 64, "%d ", (int)ps->pid);
460 			out1str(s);
461 			col += strlen(s);
462 		}
463 		if (ps == jp->ps) {
464 			out1str(statestr);
465 			out1str(coredump);
466 			col += strlen(statestr) + strlen(coredump);
467 		}
468 		do {
469 			out1c(' ');
470 			col++;
471 		} while (col < 30);
472 		if (mode == SHOWJOBS_VERBOSE) {
473 			out1str(ps->cmd);
474 			out1c('\n');
475 		} else
476 			printjobcmd(jp);
477 	}
478 }
479 
480 /*
481  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
482  * statuses have changed since the last call to showjobs.
483  *
484  * If the shell is interrupted in the process of creating a job, the
485  * result may be a job structure containing zero processes.  Such structures
486  * will be freed here.
487  */
488 
489 void
showjobs(int change,int mode)490 showjobs(int change, int mode)
491 {
492 	int jobno;
493 	struct job *jp;
494 
495 	TRACE(("showjobs(%d) called\n", change));
496 	checkzombies();
497 	for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
498 		if (! jp->used)
499 			continue;
500 		if (jp->nprocs == 0) {
501 			freejob(jp);
502 			continue;
503 		}
504 		if (change && ! jp->changed)
505 			continue;
506 		showjob(jp, mode);
507 		if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) {
508 			jp->changed = 0;
509 			/* Hack: discard jobs for which $! has not been
510 			 * referenced in interactive mode when they terminate.
511 			 */
512 			if (jp->state == JOBDONE && !jp->remembered &&
513 					(iflag || jp != bgjob)) {
514 				freejob(jp);
515 			}
516 		}
517 	}
518 }
519 
520 
521 /*
522  * Mark a job structure as unused.
523  */
524 
525 static void
freejob(struct job * jp)526 freejob(struct job *jp)
527 {
528 	struct procstat *ps;
529 	int i;
530 
531 	INTOFF;
532 	if (bgjob == jp)
533 		bgjob = NULL;
534 	for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
535 		if (ps->cmd != nullstr)
536 			ckfree(ps->cmd);
537 	}
538 	if (jp->ps != &jp->ps0)
539 		ckfree(jp->ps);
540 	jp->used = 0;
541 #if JOBS
542 	deljob(jp);
543 #endif
544 	INTON;
545 }
546 
547 
548 
549 int
waitcmd(int argc __unused,char ** argv __unused)550 waitcmd(int argc __unused, char **argv __unused)
551 {
552 	struct job *job;
553 	int retval;
554 
555 	nextopt("");
556 	if (*argptr == NULL)
557 		return (waitcmdloop(NULL));
558 
559 	do {
560 		job = getjob_nonotfound(*argptr);
561 		if (job == NULL)
562 			retval = 127;
563 		else
564 			retval = waitcmdloop(job);
565 		argptr++;
566 	} while (*argptr != NULL);
567 
568 	return (retval);
569 }
570 
571 static int
waitcmdloop(struct job * job)572 waitcmdloop(struct job *job)
573 {
574 	int status, retval, sig;
575 	struct job *jp;
576 
577 	/*
578 	 * Loop until a process is terminated or stopped, or a SIGINT is
579 	 * received.
580 	 */
581 
582 	do {
583 		if (job != NULL) {
584 			if (job->state == JOBDONE) {
585 				status = getjobstatus(job);
586 				if (WIFEXITED(status))
587 					retval = WEXITSTATUS(status);
588 				else
589 					retval = WTERMSIG(status) + 128;
590 				if (! iflag || ! job->changed)
591 					freejob(job);
592 				else {
593 					job->remembered = 0;
594 					if (job == bgjob)
595 						bgjob = NULL;
596 				}
597 				return retval;
598 			}
599 		} else {
600 			for (jp = jobtab ; jp < jobtab + njobs; jp++)
601 				if (jp->used && jp->state == JOBDONE) {
602 					if (! iflag || ! jp->changed)
603 						freejob(jp);
604 					else {
605 						jp->remembered = 0;
606 						if (jp == bgjob)
607 							bgjob = NULL;
608 					}
609 				}
610 			for (jp = jobtab ; ; jp++) {
611 				if (jp >= jobtab + njobs) {	/* no running procs */
612 					return 0;
613 				}
614 				if (jp->used && jp->state == 0)
615 					break;
616 			}
617 		}
618 	} while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
619 
620 	sig = pendingsig_waitcmd;
621 	pendingsig_waitcmd = 0;
622 	return sig + 128;
623 }
624 
625 
626 
627 int
jobidcmd(int argc __unused,char ** argv __unused)628 jobidcmd(int argc __unused, char **argv __unused)
629 {
630 	struct job *jp;
631 	int i;
632 
633 	nextopt("");
634 	jp = getjob(*argptr);
635 	for (i = 0 ; i < jp->nprocs ; ) {
636 		out1fmt("%d", (int)jp->ps[i].pid);
637 		out1c(++i < jp->nprocs? ' ' : '\n');
638 	}
639 	return 0;
640 }
641 
642 
643 
644 /*
645  * Convert a job name to a job structure.
646  */
647 
648 static struct job *
getjob_nonotfound(const char * name)649 getjob_nonotfound(const char *name)
650 {
651 	int jobno;
652 	struct job *found, *jp;
653 	size_t namelen;
654 	pid_t pid;
655 	int i;
656 
657 	if (name == NULL) {
658 #if JOBS
659 		name = "%+";
660 #else
661 		error("No current job");
662 #endif
663 	}
664 	if (name[0] == '%') {
665 		if (is_digit(name[1])) {
666 			jobno = number(name + 1);
667 			if (jobno > 0 && jobno <= njobs
668 			 && jobtab[jobno - 1].used != 0)
669 				return &jobtab[jobno - 1];
670 #if JOBS
671 		} else if ((name[1] == '%' || name[1] == '+') &&
672 		    name[2] == '\0') {
673 			if ((jp = getcurjob(NULL)) == NULL)
674 				error("No current job");
675 			return (jp);
676 		} else if (name[1] == '-' && name[2] == '\0') {
677 			if ((jp = getcurjob(NULL)) == NULL ||
678 			    (jp = getcurjob(jp)) == NULL)
679 				error("No previous job");
680 			return (jp);
681 #endif
682 		} else if (name[1] == '?') {
683 			found = NULL;
684 			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
685 				if (jp->used && jp->nprocs > 0
686 				 && strstr(jp->ps[0].cmd, name + 2) != NULL) {
687 					if (found)
688 						error("%s: ambiguous", name);
689 					found = jp;
690 				}
691 			}
692 			if (found != NULL)
693 				return (found);
694 		} else {
695 			namelen = strlen(name);
696 			found = NULL;
697 			for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
698 				if (jp->used && jp->nprocs > 0
699 				 && strncmp(jp->ps[0].cmd, name + 1,
700 				 namelen - 1) == 0) {
701 					if (found)
702 						error("%s: ambiguous", name);
703 					found = jp;
704 				}
705 			}
706 			if (found)
707 				return found;
708 		}
709 	} else if (is_number(name)) {
710 		pid = (pid_t)number(name);
711 		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
712 			if (jp->used && jp->nprocs > 0
713 			 && jp->ps[jp->nprocs - 1].pid == pid)
714 				return jp;
715 		}
716 	}
717 	return NULL;
718 }
719 
720 
721 static struct job *
getjob(const char * name)722 getjob(const char *name)
723 {
724 	struct job *jp;
725 
726 	jp = getjob_nonotfound(name);
727 	if (jp == NULL)
728 		error("No such job: %s", name);
729 	return (jp);
730 }
731 
732 
733 int
killjob(const char * name,int sig)734 killjob(const char *name, int sig)
735 {
736 	struct job *jp;
737 	int i, ret;
738 
739 	jp = getjob(name);
740 	if (jp->state == JOBDONE)
741 		return 0;
742 	if (jp->jobctl)
743 		return kill(-jp->ps[0].pid, sig);
744 	ret = -1;
745 	errno = ESRCH;
746 	for (i = 0; i < jp->nprocs; i++)
747 		if (jp->ps[i].status == -1 || WIFSTOPPED(jp->ps[i].status)) {
748 			if (kill(jp->ps[i].pid, sig) == 0)
749 				ret = 0;
750 		} else
751 			ret = 0;
752 	return ret;
753 }
754 
755 /*
756  * Return a new job structure,
757  */
758 
759 struct job *
makejob(union node * node __unused,int nprocs)760 makejob(union node *node __unused, int nprocs)
761 {
762 	int i;
763 	struct job *jp;
764 
765 	for (i = njobs, jp = jobtab ; ; jp++) {
766 		if (--i < 0) {
767 			INTOFF;
768 			if (njobs == 0) {
769 				jobtab = ckmalloc(4 * sizeof jobtab[0]);
770 #if JOBS
771 				jobmru = NULL;
772 #endif
773 			} else {
774 				jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
775 				memcpy(jp, jobtab, njobs * sizeof jp[0]);
776 #if JOBS
777 				/* Relocate `next' pointers and list head */
778 				if (jobmru != NULL)
779 					jobmru = &jp[jobmru - jobtab];
780 				for (i = 0; i < njobs; i++)
781 					if (jp[i].next != NULL)
782 						jp[i].next = &jp[jp[i].next -
783 						    jobtab];
784 #endif
785 				if (bgjob != NULL)
786 					bgjob = &jp[bgjob - jobtab];
787 				/* Relocate `ps' pointers */
788 				for (i = 0; i < njobs; i++)
789 					if (jp[i].ps == &jobtab[i].ps0)
790 						jp[i].ps = &jp[i].ps0;
791 				ckfree(jobtab);
792 				jobtab = jp;
793 			}
794 			jp = jobtab + njobs;
795 			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0)
796 				;
797 			INTON;
798 			break;
799 		}
800 		if (jp->used == 0)
801 			break;
802 	}
803 	INTOFF;
804 	jp->state = 0;
805 	jp->used = 1;
806 	jp->changed = 0;
807 	jp->nprocs = 0;
808 	jp->foreground = 0;
809 	jp->remembered = 0;
810 	jp->pipefail = pipefailflag;
811 #if JOBS
812 	jp->jobctl = jobctl;
813 	jp->next = NULL;
814 #endif
815 	if (nprocs > 1) {
816 		jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
817 	} else {
818 		jp->ps = &jp->ps0;
819 	}
820 	INTON;
821 	TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
822 	    jp - jobtab + 1));
823 	return jp;
824 }
825 
826 #if JOBS
827 static void
setcurjob(struct job * cj)828 setcurjob(struct job *cj)
829 {
830 	struct job *jp, *prev;
831 
832 	for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
833 		if (jp == cj) {
834 			if (prev != NULL)
835 				prev->next = jp->next;
836 			else
837 				jobmru = jp->next;
838 			jp->next = jobmru;
839 			jobmru = cj;
840 			return;
841 		}
842 	}
843 	cj->next = jobmru;
844 	jobmru = cj;
845 }
846 
847 static void
deljob(struct job * j)848 deljob(struct job *j)
849 {
850 	struct job *jp, *prev;
851 
852 	for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
853 		if (jp == j) {
854 			if (prev != NULL)
855 				prev->next = jp->next;
856 			else
857 				jobmru = jp->next;
858 			return;
859 		}
860 	}
861 }
862 
863 /*
864  * Return the most recently used job that isn't `nj', and preferably one
865  * that is stopped.
866  */
867 static struct job *
getcurjob(struct job * nj)868 getcurjob(struct job *nj)
869 {
870 	struct job *jp;
871 
872 	/* Try to find a stopped one.. */
873 	for (jp = jobmru; jp != NULL; jp = jp->next)
874 		if (jp->used && jp != nj && jp->state == JOBSTOPPED)
875 			return (jp);
876 	/* Otherwise the most recently used job that isn't `nj' */
877 	for (jp = jobmru; jp != NULL; jp = jp->next)
878 		if (jp->used && jp != nj)
879 			return (jp);
880 
881 	return (NULL);
882 }
883 
884 #endif
885 
886 /*
887  * Fork of a subshell.  If we are doing job control, give the subshell its
888  * own process group.  Jp is a job structure that the job is to be added to.
889  * N is the command that will be evaluated by the child.  Both jp and n may
890  * be NULL.  The mode parameter can be one of the following:
891  *	FORK_FG - Fork off a foreground process.
892  *	FORK_BG - Fork off a background process.
893  *	FORK_NOJOB - Like FORK_FG, but don't give the process its own
894  *		     process group even if job control is on.
895  *
896  * When job control is turned off, background processes have their standard
897  * input redirected to /dev/null (except for the second and later processes
898  * in a pipeline).
899  */
900 
901 pid_t
forkshell(struct job * jp,union node * n,int mode)902 forkshell(struct job *jp, union node *n, int mode)
903 {
904 	pid_t pid;
905 	pid_t pgrp;
906 
907 	TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
908 	    mode));
909 	INTOFF;
910 	if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
911 		checkzombies();
912 	flushall();
913 	pid = fork();
914 	if (pid == -1) {
915 		TRACE(("Fork failed, errno=%d\n", errno));
916 		INTON;
917 		error("Cannot fork: %s", strerror(errno));
918 	}
919 	if (pid == 0) {
920 		struct job *p;
921 		int wasroot;
922 		int i;
923 
924 		TRACE(("Child shell %d\n", (int)getpid()));
925 		wasroot = rootshell;
926 		rootshell = 0;
927 		handler = &main_handler;
928 		closescript();
929 		INTON;
930 		forcelocal = 0;
931 		clear_traps();
932 #if JOBS
933 		jobctl = 0;		/* do job control only in root shell */
934 		if (wasroot && mode != FORK_NOJOB && mflag) {
935 			if (jp == NULL || jp->nprocs == 0)
936 				pgrp = getpid();
937 			else
938 				pgrp = jp->ps[0].pid;
939 			if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
940 			    ttyfd >= 0) {
941 				/*** this causes superfluous TIOCSPGRPS ***/
942 				if (tcsetpgrp(ttyfd, pgrp) < 0)
943 					error("tcsetpgrp failed, errno=%d", errno);
944 			}
945 			setsignal(SIGTSTP);
946 			setsignal(SIGTTOU);
947 		} else if (mode == FORK_BG) {
948 			ignoresig(SIGINT);
949 			ignoresig(SIGQUIT);
950 			if ((jp == NULL || jp->nprocs == 0) &&
951 			    ! fd0_redirected_p ()) {
952 				close(0);
953 				if (open(_PATH_DEVNULL, O_RDONLY) != 0)
954 					error("cannot open %s: %s",
955 					    _PATH_DEVNULL, strerror(errno));
956 			}
957 		}
958 #else
959 		if (mode == FORK_BG) {
960 			ignoresig(SIGINT);
961 			ignoresig(SIGQUIT);
962 			if ((jp == NULL || jp->nprocs == 0) &&
963 			    ! fd0_redirected_p ()) {
964 				close(0);
965 				if (open(_PATH_DEVNULL, O_RDONLY) != 0)
966 					error("cannot open %s: %s",
967 					    _PATH_DEVNULL, strerror(errno));
968 			}
969 		}
970 #endif
971 		INTOFF;
972 		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
973 			if (p->used)
974 				freejob(p);
975 		INTON;
976 		if (wasroot && iflag) {
977 			setsignal(SIGINT);
978 			setsignal(SIGQUIT);
979 			setsignal(SIGTERM);
980 		}
981 		return pid;
982 	}
983 	if (rootshell && mode != FORK_NOJOB && mflag) {
984 		if (jp == NULL || jp->nprocs == 0)
985 			pgrp = pid;
986 		else
987 			pgrp = jp->ps[0].pid;
988 		setpgid(pid, pgrp);
989 	}
990 	if (mode == FORK_BG) {
991 		if (bgjob != NULL && bgjob->state == JOBDONE &&
992 		    !bgjob->remembered && !iflag)
993 			freejob(bgjob);
994 		backgndpid = pid;		/* set $! */
995 		bgjob = jp;
996 	}
997 	if (jp) {
998 		struct procstat *ps = &jp->ps[jp->nprocs++];
999 		ps->pid = pid;
1000 		ps->status = -1;
1001 		ps->cmd = nullstr;
1002 		if (iflag && rootshell && n)
1003 			ps->cmd = commandtext(n);
1004 		jp->foreground = mode == FORK_FG;
1005 #if JOBS
1006 		setcurjob(jp);
1007 #endif
1008 	}
1009 	INTON;
1010 	TRACE(("In parent shell:  child = %d\n", (int)pid));
1011 	return pid;
1012 }
1013 
1014 
1015 pid_t
vforkexecshell(struct job * jp,char ** argv,char ** envp,const char * path,int idx,int pip[2])1016 vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
1017 {
1018 	pid_t pid;
1019 	struct jmploc jmploc;
1020 	struct jmploc *savehandler;
1021 	int inton;
1022 
1023 	TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
1024 	    (void *)pip));
1025 	inton = is_int_on();
1026 	INTOFF;
1027 	flushall();
1028 	savehandler = handler;
1029 	pid = vfork();
1030 	if (pid == -1) {
1031 		TRACE(("Vfork failed, errno=%d\n", errno));
1032 		INTON;
1033 		error("Cannot fork: %s", strerror(errno));
1034 	}
1035 	if (pid == 0) {
1036 		TRACE(("Child shell %d\n", (int)getpid()));
1037 		if (setjmp(jmploc.loc))
1038 			_exit(exitstatus);
1039 		if (pip != NULL) {
1040 			close(pip[0]);
1041 			if (pip[1] != 1) {
1042 				dup2(pip[1], 1);
1043 				close(pip[1]);
1044 			}
1045 		}
1046 		handler = &jmploc;
1047 		shellexec(argv, envp, path, idx);
1048 	}
1049 	handler = savehandler;
1050 	if (jp) {
1051 		struct procstat *ps = &jp->ps[jp->nprocs++];
1052 		ps->pid = pid;
1053 		ps->status = -1;
1054 		ps->cmd = nullstr;
1055 		jp->foreground = 1;
1056 #if JOBS
1057 		setcurjob(jp);
1058 #endif
1059 	}
1060 	SETINTON(inton);
1061 	TRACE(("In parent shell:  child = %d\n", (int)pid));
1062 	return pid;
1063 }
1064 
1065 
1066 /*
1067  * Wait for job to finish.
1068  *
1069  * Under job control we have the problem that while a child process is
1070  * running interrupts generated by the user are sent to the child but not
1071  * to the shell.  This means that an infinite loop started by an inter-
1072  * active user may be hard to kill.  With job control turned off, an
1073  * interactive user may place an interactive program inside a loop.  If
1074  * the interactive program catches interrupts, the user doesn't want
1075  * these interrupts to also abort the loop.  The approach we take here
1076  * is to have the shell ignore interrupt signals while waiting for a
1077  * foreground process to terminate, and then send itself an interrupt
1078  * signal if the child process was terminated by an interrupt signal.
1079  * Unfortunately, some programs want to do a bit of cleanup and then
1080  * exit on interrupt; unless these processes terminate themselves by
1081  * sending a signal to themselves (instead of calling exit) they will
1082  * confuse this approach.
1083  */
1084 
1085 int
waitforjob(struct job * jp,int * signaled)1086 waitforjob(struct job *jp, int *signaled)
1087 {
1088 #if JOBS
1089 	int propagate_int = jp->jobctl && jp->foreground;
1090 #endif
1091 	int status;
1092 	int st;
1093 
1094 	INTOFF;
1095 	TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
1096 	while (jp->state == 0)
1097 		if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
1098 		    DOWAIT_SIG_TRAP : 0), jp) == -1)
1099 			dotrap();
1100 #if JOBS
1101 	if (jp->jobctl) {
1102 		if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
1103 			error("tcsetpgrp failed, errno=%d\n", errno);
1104 	}
1105 	if (jp->state == JOBSTOPPED)
1106 		setcurjob(jp);
1107 #endif
1108 	status = getjobstatus(jp);
1109 	if (signaled != NULL)
1110 		*signaled = WIFSIGNALED(status);
1111 	/* convert to 8 bits */
1112 	if (WIFEXITED(status))
1113 		st = WEXITSTATUS(status);
1114 #if JOBS
1115 	else if (WIFSTOPPED(status))
1116 		st = WSTOPSIG(status) + 128;
1117 #endif
1118 	else
1119 		st = WTERMSIG(status) + 128;
1120 	if (! JOBS || jp->state == JOBDONE)
1121 		freejob(jp);
1122 	if (int_pending()) {
1123 		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
1124 			CLEAR_PENDING_INT;
1125 	}
1126 #if JOBS
1127 	else if (rootshell && propagate_int &&
1128 			WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1129 		kill(getpid(), SIGINT);
1130 #endif
1131 	INTON;
1132 	return st;
1133 }
1134 
1135 
1136 static void
dummy_handler(int sig __unused)1137 dummy_handler(int sig __unused)
1138 {
1139 }
1140 
1141 /*
1142  * Wait for a process to terminate.
1143  */
1144 
1145 static pid_t
dowait(int mode,struct job * job)1146 dowait(int mode, struct job *job)
1147 {
1148 	struct sigaction sa, osa;
1149 	sigset_t mask, omask;
1150 	pid_t pid;
1151 	int status;
1152 	struct procstat *sp;
1153 	struct job *jp;
1154 	struct job *thisjob;
1155 	const char *sigstr;
1156 	int done;
1157 	int stopped;
1158 	int sig;
1159 	int coredump;
1160 	int wflags;
1161 	int restore_sigchld;
1162 
1163 	TRACE(("dowait(%d, %p) called\n", mode, job));
1164 	restore_sigchld = 0;
1165 	if ((mode & DOWAIT_SIG) != 0) {
1166 		sigfillset(&mask);
1167 		sigprocmask(SIG_BLOCK, &mask, &omask);
1168 		INTOFF;
1169 		if (!issigchldtrapped()) {
1170 			restore_sigchld = 1;
1171 			sa.sa_handler = dummy_handler;
1172 			sa.sa_flags = 0;
1173 			sigemptyset(&sa.sa_mask);
1174 			sigaction(SIGCHLD, &sa, &osa);
1175 		}
1176 	}
1177 	do {
1178 #if JOBS
1179 		if (iflag)
1180 			wflags = WUNTRACED | WCONTINUED;
1181 		else
1182 #endif
1183 			wflags = 0;
1184 		if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
1185 			wflags |= WNOHANG;
1186 		pid = wait3(&status, wflags, (struct rusage *)NULL);
1187 		TRACE(("wait returns %d, status=%d\n", (int)pid, status));
1188 		if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
1189 			pid = -1;
1190 			if (((mode & DOWAIT_SIG_TRAP) != 0 ?
1191 			    pendingsig : pendingsig_waitcmd) != 0) {
1192 				errno = EINTR;
1193 				break;
1194 			}
1195 			sigsuspend(&omask);
1196 			if (int_pending())
1197 				break;
1198 		}
1199 	} while (pid == -1 && errno == EINTR);
1200 	if (pid == -1 && errno == ECHILD && job != NULL)
1201 		job->state = JOBDONE;
1202 	if ((mode & DOWAIT_SIG) != 0) {
1203 		if (restore_sigchld)
1204 			sigaction(SIGCHLD, &osa, NULL);
1205 		sigprocmask(SIG_SETMASK, &omask, NULL);
1206 		INTON;
1207 	}
1208 	if (pid <= 0)
1209 		return pid;
1210 	INTOFF;
1211 	thisjob = NULL;
1212 	for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1213 		if (jp->used && jp->nprocs > 0) {
1214 			done = 1;
1215 			stopped = 1;
1216 			for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1217 				if (sp->pid == -1)
1218 					continue;
1219 				if (sp->pid == pid && (sp->status == -1 ||
1220 				    WIFSTOPPED(sp->status))) {
1221 					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
1222 						   (int)pid, sp->status,
1223 						   status));
1224 					if (WIFCONTINUED(status)) {
1225 						sp->status = -1;
1226 						jp->state = 0;
1227 					} else
1228 						sp->status = status;
1229 					thisjob = jp;
1230 				}
1231 				if (sp->status == -1)
1232 					stopped = 0;
1233 				else if (WIFSTOPPED(sp->status))
1234 					done = 0;
1235 			}
1236 			if (stopped) {		/* stopped or done */
1237 				int state = done? JOBDONE : JOBSTOPPED;
1238 				if (jp->state != state) {
1239 					TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
1240 					jp->state = state;
1241 					if (jp != job) {
1242 						if (done && !jp->remembered &&
1243 						    !iflag && jp != bgjob)
1244 							freejob(jp);
1245 #if JOBS
1246 						else if (done)
1247 							deljob(jp);
1248 #endif
1249 					}
1250 				}
1251 			}
1252 		}
1253 	}
1254 	INTON;
1255 	if (!thisjob || thisjob->state == 0)
1256 		;
1257 	else if ((!rootshell || !iflag || thisjob == job) &&
1258 	    thisjob->foreground && thisjob->state != JOBSTOPPED) {
1259 		sig = 0;
1260 		coredump = 0;
1261 		for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
1262 			if (WIFSIGNALED(sp->status)) {
1263 				sig = WTERMSIG(sp->status);
1264 				coredump = WCOREDUMP(sp->status);
1265 			}
1266 		if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
1267 			sigstr = strsignal(sig);
1268 			if (sigstr != NULL)
1269 				out2str(sigstr);
1270 			else
1271 				out2str("Unknown signal");
1272 			if (coredump)
1273 				out2str(" (core dumped)");
1274 			out2c('\n');
1275 			flushout(out2);
1276 		}
1277 	} else {
1278 		TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1279 		thisjob->changed = 1;
1280 	}
1281 	return pid;
1282 }
1283 
1284 
1285 
1286 /*
1287  * return 1 if there are stopped jobs, otherwise 0
1288  */
1289 int job_warning = 0;
1290 int
stoppedjobs(void)1291 stoppedjobs(void)
1292 {
1293 	int jobno;
1294 	struct job *jp;
1295 
1296 	if (job_warning)
1297 		return (0);
1298 	for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1299 		if (jp->used == 0)
1300 			continue;
1301 		if (jp->state == JOBSTOPPED) {
1302 			out2fmt_flush("You have stopped jobs.\n");
1303 			job_warning = 2;
1304 			return (1);
1305 		}
1306 	}
1307 
1308 	return (0);
1309 }
1310 
1311 
1312 static void
checkzombies(void)1313 checkzombies(void)
1314 {
1315 	while (njobs > 0 && dowait(0, NULL) > 0)
1316 		;
1317 }
1318 
1319 
1320 int
backgndpidset(void)1321 backgndpidset(void)
1322 {
1323 	return backgndpid != -1;
1324 }
1325 
1326 
1327 pid_t
backgndpidval(void)1328 backgndpidval(void)
1329 {
1330 	if (bgjob != NULL && !forcelocal)
1331 		bgjob->remembered = 1;
1332 	return backgndpid;
1333 }
1334 
1335 /*
1336  * Return a string identifying a command (to be printed by the
1337  * jobs command.
1338  */
1339 
1340 static char *cmdnextc;
1341 static int cmdnleft;
1342 #define MAXCMDTEXT	200
1343 
1344 char *
commandtext(union node * n)1345 commandtext(union node *n)
1346 {
1347 	char *name;
1348 
1349 	cmdnextc = name = ckmalloc(MAXCMDTEXT);
1350 	cmdnleft = MAXCMDTEXT - 4;
1351 	cmdtxt(n);
1352 	*cmdnextc = '\0';
1353 	return name;
1354 }
1355 
1356 
1357 static void
cmdtxtdogroup(union node * n)1358 cmdtxtdogroup(union node *n)
1359 {
1360 	cmdputs("; do ");
1361 	cmdtxt(n);
1362 	cmdputs("; done");
1363 }
1364 
1365 
1366 static void
cmdtxtredir(union node * n,const char * op,int deffd)1367 cmdtxtredir(union node *n, const char *op, int deffd)
1368 {
1369 	char s[2];
1370 
1371 	if (n->nfile.fd != deffd) {
1372 		s[0] = n->nfile.fd + '0';
1373 		s[1] = '\0';
1374 		cmdputs(s);
1375 	}
1376 	cmdputs(op);
1377 	if (n->type == NTOFD || n->type == NFROMFD) {
1378 		if (n->ndup.dupfd >= 0)
1379 			s[0] = n->ndup.dupfd + '0';
1380 		else
1381 			s[0] = '-';
1382 		s[1] = '\0';
1383 		cmdputs(s);
1384 	} else {
1385 		cmdtxt(n->nfile.fname);
1386 	}
1387 }
1388 
1389 
1390 static void
cmdtxt(union node * n)1391 cmdtxt(union node *n)
1392 {
1393 	union node *np;
1394 	struct nodelist *lp;
1395 
1396 	if (n == NULL)
1397 		return;
1398 	switch (n->type) {
1399 	case NSEMI:
1400 		cmdtxt(n->nbinary.ch1);
1401 		cmdputs("; ");
1402 		cmdtxt(n->nbinary.ch2);
1403 		break;
1404 	case NAND:
1405 		cmdtxt(n->nbinary.ch1);
1406 		cmdputs(" && ");
1407 		cmdtxt(n->nbinary.ch2);
1408 		break;
1409 	case NOR:
1410 		cmdtxt(n->nbinary.ch1);
1411 		cmdputs(" || ");
1412 		cmdtxt(n->nbinary.ch2);
1413 		break;
1414 	case NPIPE:
1415 		for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1416 			cmdtxt(lp->n);
1417 			if (lp->next)
1418 				cmdputs(" | ");
1419 		}
1420 		break;
1421 	case NSUBSHELL:
1422 		cmdputs("(");
1423 		cmdtxt(n->nredir.n);
1424 		cmdputs(")");
1425 		break;
1426 	case NREDIR:
1427 	case NBACKGND:
1428 		cmdtxt(n->nredir.n);
1429 		break;
1430 	case NIF:
1431 		cmdputs("if ");
1432 		cmdtxt(n->nif.test);
1433 		cmdputs("; then ");
1434 		cmdtxt(n->nif.ifpart);
1435 		cmdputs("...");
1436 		break;
1437 	case NWHILE:
1438 		cmdputs("while ");
1439 		cmdtxt(n->nbinary.ch1);
1440 		cmdtxtdogroup(n->nbinary.ch2);
1441 		break;
1442 	case NUNTIL:
1443 		cmdputs("until ");
1444 		cmdtxt(n->nbinary.ch1);
1445 		cmdtxtdogroup(n->nbinary.ch2);
1446 		break;
1447 	case NFOR:
1448 		cmdputs("for ");
1449 		cmdputs(n->nfor.var);
1450 		cmdputs(" in ...");
1451 		break;
1452 	case NCASE:
1453 		cmdputs("case ");
1454 		cmdputs(n->ncase.expr->narg.text);
1455 		cmdputs(" in ...");
1456 		break;
1457 	case NDEFUN:
1458 		cmdputs(n->narg.text);
1459 		cmdputs("() ...");
1460 		break;
1461 	case NNOT:
1462 		cmdputs("! ");
1463 		cmdtxt(n->nnot.com);
1464 		break;
1465 	case NCMD:
1466 		for (np = n->ncmd.args ; np ; np = np->narg.next) {
1467 			cmdtxt(np);
1468 			if (np->narg.next)
1469 				cmdputs(" ");
1470 		}
1471 		for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1472 			cmdputs(" ");
1473 			cmdtxt(np);
1474 		}
1475 		break;
1476 	case NARG:
1477 		cmdputs(n->narg.text);
1478 		break;
1479 	case NTO:
1480 		cmdtxtredir(n, ">", 1);
1481 		break;
1482 	case NAPPEND:
1483 		cmdtxtredir(n, ">>", 1);
1484 		break;
1485 	case NTOFD:
1486 		cmdtxtredir(n, ">&", 1);
1487 		break;
1488 	case NCLOBBER:
1489 		cmdtxtredir(n, ">|", 1);
1490 		break;
1491 	case NFROM:
1492 		cmdtxtredir(n, "<", 0);
1493 		break;
1494 	case NFROMTO:
1495 		cmdtxtredir(n, "<>", 0);
1496 		break;
1497 	case NFROMFD:
1498 		cmdtxtredir(n, "<&", 0);
1499 		break;
1500 	case NHERE:
1501 	case NXHERE:
1502 		cmdputs("<<...");
1503 		break;
1504 	default:
1505 		cmdputs("???");
1506 		break;
1507 	}
1508 }
1509 
1510 
1511 
1512 static void
cmdputs(const char * s)1513 cmdputs(const char *s)
1514 {
1515 	const char *p;
1516 	char *q;
1517 	char c;
1518 	int subtype = 0;
1519 
1520 	if (cmdnleft <= 0)
1521 		return;
1522 	p = s;
1523 	q = cmdnextc;
1524 	while ((c = *p++) != '\0') {
1525 		if (c == CTLESC)
1526 			*q++ = *p++;
1527 		else if (c == CTLVAR) {
1528 			*q++ = '$';
1529 			if (--cmdnleft > 0)
1530 				*q++ = '{';
1531 			subtype = *p++;
1532 			if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
1533 				*q++ = '#';
1534 		} else if (c == '=' && subtype != 0) {
1535 			*q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
1536 			if (*q)
1537 				q++;
1538 			else
1539 				cmdnleft++;
1540 			if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
1541 			    (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
1542 			    --cmdnleft > 0)
1543 				*q = q[-1], q++;
1544 			subtype = 0;
1545 		} else if (c == CTLENDVAR) {
1546 			*q++ = '}';
1547 		} else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
1548 			cmdnleft -= 5;
1549 			if (cmdnleft > 0) {
1550 				*q++ = '$';
1551 				*q++ = '(';
1552 				*q++ = '.';
1553 				*q++ = '.';
1554 				*q++ = '.';
1555 				*q++ = ')';
1556 			}
1557 		} else if (c == CTLARI) {
1558 			cmdnleft -= 2;
1559 			if (cmdnleft > 0) {
1560 				*q++ = '$';
1561 				*q++ = '(';
1562 				*q++ = '(';
1563 			}
1564 			p++;
1565 		} else if (c == CTLENDARI) {
1566 			if (--cmdnleft > 0) {
1567 				*q++ = ')';
1568 				*q++ = ')';
1569 			}
1570 		} else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
1571 			cmdnleft++; /* ignore */
1572 		else
1573 			*q++ = c;
1574 		if (--cmdnleft <= 0) {
1575 			*q++ = '.';
1576 			*q++ = '.';
1577 			*q++ = '.';
1578 			break;
1579 		}
1580 	}
1581 	cmdnextc = q;
1582 }
1583