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