jobs.c revision 1.98.2.2 1 /* $NetBSD: jobs.c,v 1.98.2.2 2018/09/30 01:44:21 pgoyette Exp $ */
2
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/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: jobs.c,v 1.98.2.2 2018/09/30 01:44:21 pgoyette Exp $");
41 #endif
42 #endif /* not lint */
43
44 #include <stdio.h>
45 #include <fcntl.h>
46 #include <signal.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <paths.h>
51 #include <sys/types.h>
52 #include <sys/param.h>
53 #ifdef BSD
54 #include <sys/wait.h>
55 #include <sys/time.h>
56 #include <sys/resource.h>
57 #endif
58 #include <sys/ioctl.h>
59
60 #include "shell.h"
61 #if JOBS
62 #if OLD_TTY_DRIVER
63 #include "sgtty.h"
64 #else
65 #include <termios.h>
66 #endif
67 #undef CEOF /* syntax.h redefines this */
68 #endif
69 #include "redir.h"
70 #include "show.h"
71 #include "main.h"
72 #include "parser.h"
73 #include "nodes.h"
74 #include "jobs.h"
75 #include "var.h"
76 #include "options.h"
77 #include "builtins.h"
78 #include "trap.h"
79 #include "syntax.h"
80 #include "input.h"
81 #include "output.h"
82 #include "memalloc.h"
83 #include "error.h"
84 #include "mystring.h"
85
86
87 #ifndef WCONTINUED
88 #define WCONTINUED 0 /* So we can compile on old systems */
89 #endif
90 #ifndef WIFCONTINUED
91 #define WIFCONTINUED(x) (0) /* ditto */
92 #endif
93
94
95 static struct job *jobtab; /* array of jobs */
96 static int njobs; /* size of array */
97 static int jobs_invalid; /* set in child */
98 MKINIT pid_t backgndpid = -1; /* pid of last background process */
99 #if JOBS
100 int initialpgrp; /* pgrp of shell on invocation */
101 static int curjob = -1; /* current job */
102 #endif
103 static int ttyfd = -1;
104
105 STATIC void restartjob(struct job *);
106 STATIC void freejob(struct job *);
107 STATIC struct job *getjob(const char *, int);
108 STATIC int dowait(int, struct job *, struct job **);
109 #define WBLOCK 1
110 #define WNOFREE 2
111 #define WSILENT 4
112 STATIC int jobstatus(const struct job *, int);
113 STATIC int waitproc(int, struct job *, int *);
114 STATIC void cmdtxt(union node *);
115 STATIC void cmdlist(union node *, int);
116 STATIC void cmdputs(const char *);
117 inline static void cmdputi(int);
118
119 #ifdef SYSV
120 STATIC int onsigchild(void);
121 #endif
122
123 #ifdef OLD_TTY_DRIVER
124 static pid_t tcgetpgrp(int fd);
125 static int tcsetpgrp(int fd, pid_t pgrp);
126
127 static pid_t
128 tcgetpgrp(int fd)
129 {
130 pid_t pgrp;
131 if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
132 return -1;
133 else
134 return pgrp;
135 }
136
137 static int
138 tcsetpgrp(int fd, pid_tpgrp)
139 {
140 return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
141 }
142 #endif
143
144 static void
145 ttyfd_change(int from, int to)
146 {
147 if (ttyfd == from)
148 ttyfd = to;
149 }
150
151 /*
152 * Turn job control on and off.
153 *
154 * Note: This code assumes that the third arg to ioctl is a character
155 * pointer, which is true on Berkeley systems but not System V. Since
156 * System V doesn't have job control yet, this isn't a problem now.
157 */
158
159 MKINIT int jobctl;
160
161 void
162 setjobctl(int on)
163 {
164 #ifdef OLD_TTY_DRIVER
165 int ldisc;
166 #endif
167
168 if (on == jobctl || rootshell == 0)
169 return;
170 if (on) {
171 #if defined(FIOCLEX) || defined(FD_CLOEXEC)
172 int i;
173
174 if (ttyfd != -1)
175 sh_close(ttyfd);
176 if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
177 for (i = 0; i < 3; i++) {
178 if (isatty(i) && (ttyfd = dup(i)) != -1)
179 break;
180 }
181 if (i == 3)
182 goto out;
183 }
184 ttyfd = to_upper_fd(ttyfd); /* Move to a high fd */
185 register_sh_fd(ttyfd, ttyfd_change);
186 #else
187 out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
188 goto out;
189 #endif
190 do { /* while we are in the background */
191 if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
192 out:
193 out2str("sh: can't access tty; job control turned off\n");
194 mflag = 0;
195 return;
196 }
197 if (initialpgrp == -1)
198 initialpgrp = getpgrp();
199 else if (initialpgrp != getpgrp()) {
200 killpg(0, SIGTTIN);
201 continue;
202 }
203 } while (0);
204
205 #ifdef OLD_TTY_DRIVER
206 if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
207 || ldisc != NTTYDISC) {
208 out2str("sh: need new tty driver to run job control; job control turned off\n");
209 mflag = 0;
210 return;
211 }
212 #endif
213 setsignal(SIGTSTP, 0);
214 setsignal(SIGTTOU, 0);
215 setsignal(SIGTTIN, 0);
216 if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
217 error("Cannot set process group (%s) at %d",
218 strerror(errno), __LINE__);
219 if (tcsetpgrp(ttyfd, rootpid) == -1)
220 error("Cannot set tty process group (%s) at %d",
221 strerror(errno), __LINE__);
222 } else { /* turning job control off */
223 if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
224 error("Cannot set process group (%s) at %d",
225 strerror(errno), __LINE__);
226 if (tcsetpgrp(ttyfd, initialpgrp) == -1)
227 error("Cannot set tty process group (%s) at %d",
228 strerror(errno), __LINE__);
229 sh_close(ttyfd);
230 ttyfd = -1;
231 setsignal(SIGTSTP, 0);
232 setsignal(SIGTTOU, 0);
233 setsignal(SIGTTIN, 0);
234 }
235 jobctl = on;
236 }
237
238
239 #ifdef mkinit
240 INCLUDE <stdlib.h>
241
242 SHELLPROC {
243 backgndpid = -1;
244 #if JOBS
245 jobctl = 0;
246 #endif
247 }
248
249 #endif
250
251
252
253 #if JOBS
254 static int
255 do_fgcmd(const char *arg_ptr)
256 {
257 struct job *jp;
258 int i;
259 int status;
260
261 if (jobs_invalid)
262 error("No current jobs");
263 jp = getjob(arg_ptr, 0);
264 if (jp->jobctl == 0)
265 error("job not created under job control");
266 out1fmt("%s", jp->ps[0].cmd);
267 for (i = 1; i < jp->nprocs; i++)
268 out1fmt(" | %s", jp->ps[i].cmd );
269 out1c('\n');
270 flushall();
271
272 for (i = 0; i < jp->nprocs; i++)
273 if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1)
274 break;
275
276 if (i >= jp->nprocs) {
277 error("Cannot set tty process group (%s) at %d",
278 strerror(errno), __LINE__);
279 }
280 restartjob(jp);
281 INTOFF;
282 status = waitforjob(jp);
283 INTON;
284 return status;
285 }
286
287 int
288 fgcmd(int argc, char **argv)
289 {
290 nextopt("");
291 return do_fgcmd(*argptr);
292 }
293
294 int
295 fgcmd_percent(int argc, char **argv)
296 {
297 nextopt("");
298 return do_fgcmd(*argv);
299 }
300
301 static void
302 set_curjob(struct job *jp, int mode)
303 {
304 struct job *jp1, *jp2;
305 int i, ji;
306
307 ji = jp - jobtab;
308
309 /* first remove from list */
310 if (ji == curjob)
311 curjob = jp->prev_job;
312 else {
313 for (i = 0; i < njobs; i++) {
314 if (jobtab[i].prev_job != ji)
315 continue;
316 jobtab[i].prev_job = jp->prev_job;
317 break;
318 }
319 }
320
321 /* Then re-insert in correct position */
322 switch (mode) {
323 case 0: /* job being deleted */
324 jp->prev_job = -1;
325 break;
326 case 1: /* newly created job or backgrounded job,
327 put after all stopped jobs. */
328 if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
329 for (jp1 = jobtab + curjob; ; jp1 = jp2) {
330 if (jp1->prev_job == -1)
331 break;
332 jp2 = jobtab + jp1->prev_job;
333 if (jp2->state != JOBSTOPPED)
334 break;
335 }
336 jp->prev_job = jp1->prev_job;
337 jp1->prev_job = ji;
338 break;
339 }
340 /* FALLTHROUGH */
341 case 2: /* newly stopped job - becomes curjob */
342 jp->prev_job = curjob;
343 curjob = ji;
344 break;
345 }
346 }
347
348 int
349 bgcmd(int argc, char **argv)
350 {
351 struct job *jp;
352 int i;
353
354 nextopt("");
355 if (jobs_invalid)
356 error("No current jobs");
357 do {
358 jp = getjob(*argptr, 0);
359 if (jp->jobctl == 0)
360 error("job not created under job control");
361 set_curjob(jp, 1);
362 out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd);
363 for (i = 1; i < jp->nprocs; i++)
364 out1fmt(" | %s", jp->ps[i].cmd );
365 out1c('\n');
366 flushall();
367 restartjob(jp);
368 } while (*argptr && *++argptr);
369 return 0;
370 }
371
372
373 STATIC void
374 restartjob(struct job *jp)
375 {
376 struct procstat *ps;
377 int i;
378
379 if (jp->state == JOBDONE)
380 return;
381 INTOFF;
382 for (i = 0; i < jp->nprocs; i++)
383 if (killpg(jp->ps[i].pid, SIGCONT) != -1)
384 break;
385 if (i >= jp->nprocs)
386 error("Cannot continue job (%s)", strerror(errno));
387 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
388 if (WIFSTOPPED(ps->status)) {
389 VTRACE(DBG_JOBS, (
390 "restartjob: [%zu] pid %d status change"
391 " from %#x (stopped) to -1 (running)\n",
392 (size_t)(jp-jobtab+1), ps->pid, ps->status));
393 ps->status = -1;
394 jp->state = JOBRUNNING;
395 }
396 }
397 INTON;
398 }
399 #endif
400
401 inline static void
402 cmdputi(int n)
403 {
404 char str[20];
405
406 fmtstr(str, sizeof str, "%d", n);
407 cmdputs(str);
408 }
409
410 static void
411 showjob(struct output *out, struct job *jp, int mode)
412 {
413 int procno;
414 int st;
415 struct procstat *ps;
416 int col;
417 char s[64];
418
419 #if JOBS
420 if (mode & SHOW_PGID) {
421 /* just output process (group) id of pipeline */
422 outfmt(out, "%ld\n", (long)jp->ps->pid);
423 return;
424 }
425 #endif
426
427 procno = jp->nprocs;
428 if (!procno)
429 return;
430
431 if (mode & SHOW_PID)
432 mode |= SHOW_MULTILINE;
433
434 if ((procno > 1 && !(mode & SHOW_MULTILINE))
435 || (mode & SHOW_SIGNALLED)) {
436 /* See if we have more than one status to report */
437 ps = jp->ps;
438 st = ps->status;
439 do {
440 int st1 = ps->status;
441 if (st1 != st)
442 /* yes - need multi-line output */
443 mode |= SHOW_MULTILINE;
444 if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
445 continue;
446 if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
447 && st1 != SIGINT && st1 != SIGPIPE))
448 mode |= SHOW_ISSIG;
449
450 } while (ps++, --procno);
451 procno = jp->nprocs;
452 }
453
454 if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
455 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
456 VTRACE(DBG_JOBS, ("showjob: freeing job %d\n",
457 jp - jobtab + 1));
458 freejob(jp);
459 }
460 return;
461 }
462
463 for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */
464 if (ps == jp->ps)
465 fmtstr(s, 16, "[%ld] %c ",
466 (long)(jp - jobtab + 1),
467 #if JOBS
468 jp - jobtab == curjob ?
469 '+' :
470 curjob != -1 &&
471 jp - jobtab == jobtab[curjob].prev_job ?
472 '-' :
473 #endif
474 ' ');
475 else
476 fmtstr(s, 16, " " );
477 col = strlen(s);
478 if (mode & SHOW_PID) {
479 fmtstr(s + col, 16, "%ld ", (long)ps->pid);
480 col += strlen(s + col);
481 }
482 if (ps->status == -1) {
483 scopy("Running", s + col);
484 } else if (WIFEXITED(ps->status)) {
485 st = WEXITSTATUS(ps->status);
486 if (st)
487 fmtstr(s + col, 16, "Done(%d)", st);
488 else
489 fmtstr(s + col, 16, "Done");
490 } else {
491 #if JOBS
492 if (WIFSTOPPED(ps->status))
493 st = WSTOPSIG(ps->status);
494 else /* WIFSIGNALED(ps->status) */
495 #endif
496 st = WTERMSIG(ps->status);
497 st &= 0x7f;
498 if (st < NSIG && sys_siglist[st])
499 scopyn(sys_siglist[st], s + col, 32);
500 else
501 fmtstr(s + col, 16, "Signal %d", st);
502 if (WCOREDUMP(ps->status)) {
503 col += strlen(s + col);
504 scopyn(" (core dumped)", s + col, 64 - col);
505 }
506 }
507 col += strlen(s + col);
508 outstr(s, out);
509 do {
510 outc(' ', out);
511 col++;
512 } while (col < 30);
513 outstr(ps->cmd, out);
514 if (mode & SHOW_MULTILINE) {
515 if (procno > 0) {
516 outc(' ', out);
517 outc('|', out);
518 }
519 } else {
520 while (--procno >= 0)
521 outfmt(out, " | %s", (++ps)->cmd );
522 }
523 outc('\n', out);
524 }
525 flushout(out);
526 jp->flags &= ~JOBCHANGED;
527 if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
528 freejob(jp);
529 }
530
531 int
532 jobscmd(int argc, char **argv)
533 {
534 int mode, m;
535
536 mode = 0;
537 while ((m = nextopt("lp")))
538 if (m == 'l')
539 mode = SHOW_PID;
540 else
541 mode = SHOW_PGID;
542 if (!iflag)
543 mode |= SHOW_NO_FREE;
544 if (*argptr)
545 do
546 showjob(out1, getjob(*argptr,0), mode);
547 while (*++argptr);
548 else
549 showjobs(out1, mode);
550 return 0;
551 }
552
553
554 /*
555 * Print a list of jobs. If "change" is nonzero, only print jobs whose
556 * statuses have changed since the last call to showjobs.
557 *
558 * If the shell is interrupted in the process of creating a job, the
559 * result may be a job structure containing zero processes. Such structures
560 * will be freed here.
561 */
562
563 void
564 showjobs(struct output *out, int mode)
565 {
566 int jobno;
567 struct job *jp;
568 int silent = 0, gotpid;
569
570 CTRACE(DBG_JOBS, ("showjobs(%x) called\n", mode));
571
572 /* If not even one one job changed, there is nothing to do */
573 gotpid = dowait(WSILENT, NULL, NULL);
574 while (dowait(WSILENT, NULL, NULL) > 0)
575 continue;
576 #ifdef JOBS
577 /*
578 * Check if we are not in our foreground group, and if not
579 * put us in it.
580 */
581 if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
582 if (tcsetpgrp(ttyfd, getpid()) == -1)
583 error("Cannot set tty process group (%s) at %d",
584 strerror(errno), __LINE__);
585 VTRACE(DBG_JOBS|DBG_INPUT, ("repaired tty process group\n"));
586 silent = 1;
587 }
588 #endif
589
590 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
591 if (!jp->used)
592 continue;
593 if (jp->nprocs == 0) {
594 if (!jobs_invalid)
595 freejob(jp);
596 continue;
597 }
598 if ((mode & SHOW_CHANGED) && !(jp->flags & JOBCHANGED))
599 continue;
600 if (silent && (jp->flags & JOBCHANGED)) {
601 jp->flags &= ~JOBCHANGED;
602 continue;
603 }
604 showjob(out, jp, mode);
605 }
606 }
607
608 /*
609 * Mark a job structure as unused.
610 */
611
612 STATIC void
613 freejob(struct job *jp)
614 {
615 INTOFF;
616 if (jp->ps != &jp->ps0) {
617 ckfree(jp->ps);
618 jp->ps = &jp->ps0;
619 }
620 jp->nprocs = 0;
621 jp->used = 0;
622 #if JOBS
623 set_curjob(jp, 0);
624 #endif
625 INTON;
626 }
627
628 /*
629 * Extract the status of a completed job (for $?)
630 */
631 STATIC int
632 jobstatus(const struct job *jp, int raw)
633 {
634 int status = 0;
635 int retval;
636
637 if ((jp->flags & JPIPEFAIL) && jp->nprocs) {
638 int i;
639
640 for (i = 0; i < jp->nprocs; i++)
641 if (jp->ps[i].status != 0)
642 status = jp->ps[i].status;
643 } else
644 status = jp->ps[jp->nprocs ? jp->nprocs - 1 : 0].status;
645
646 if (raw)
647 return status;
648
649 if (WIFEXITED(status))
650 retval = WEXITSTATUS(status);
651 #if JOBS
652 else if (WIFSTOPPED(status))
653 retval = WSTOPSIG(status) + 128;
654 #endif
655 else {
656 /* XXX: limits number of signals */
657 retval = WTERMSIG(status) + 128;
658 }
659
660 return retval;
661 }
662
663
664
665 int
666 waitcmd(int argc, char **argv)
667 {
668 struct job *job, *last;
669 int retval;
670 struct job *jp;
671 int i;
672 int any = 0;
673 int found;
674 char *pid = NULL, *fpid;
675 char **arg;
676 char idstring[20];
677
678 while ((i = nextopt("np:")) != '\0') {
679 switch (i) {
680 case 'n':
681 any = 1;
682 break;
683 case 'p':
684 if (pid)
685 error("more than one -p unsupported");
686 pid = optionarg;
687 break;
688 }
689 }
690
691 if (pid != NULL) {
692 if (!validname(pid, '\0', NULL))
693 error("invalid name: -p '%s'", pid);
694 if (unsetvar(pid, 0))
695 error("%s readonly", pid);
696 }
697
698 /*
699 * If we have forked, and not yet created any new jobs, then
700 * we have no children, whatever jobtab claims,
701 * so simply return in that case.
702 *
703 * The return code is 127 if we had any pid args (none are found)
704 * or if we had -n (nothing exited), but 0 for plain old "wait".
705 */
706 if (jobs_invalid) {
707 CTRACE(DBG_WAIT, ("builtin wait%s%s in child, invalid jobtab\n",
708 any ? " -n" : "", *argptr ? " pid..." : ""));
709 return (any || *argptr) ? 127 : 0;
710 }
711
712 /* clear stray flags left from previous waitcmd */
713 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
714 jp->flags &= ~JOBWANTED;
715 jp->ref = NULL;
716 }
717
718 CTRACE(DBG_WAIT,
719 ("builtin wait%s%s\n", any ? " -n" : "", *argptr ? " pid..." : ""));
720
721 /*
722 * First, validate the jobnum args, count how many refer to
723 * (different) running jobs, and if we had -n, and found that one has
724 * already finished, we return that one. Otherwise remember
725 * which ones we are looking for (JOBWANTED).
726 */
727 found = 0;
728 last = NULL;
729 for (arg = argptr; *arg; arg++) {
730 last = jp = getjob(*arg, 1);
731 if (!jp)
732 continue;
733 if (jp->ref == NULL)
734 jp->ref = *arg;
735 if (any && jp->state == JOBDONE) {
736 /*
737 * We just want any of them, and this one is
738 * ready for consumption, bon apetit ...
739 */
740 retval = jobstatus(jp, 0);
741 if (pid)
742 setvar(pid, *arg, 0);
743 if (!iflag)
744 freejob(jp);
745 CTRACE(DBG_WAIT, ("wait -n found %s already done: %d\n", *arg, retval));
746 return retval;
747 }
748 if (!(jp->flags & JOBWANTED)) {
749 /*
750 * It is possible to list the same job several
751 * times - the obvious "wait 1 1 1" or
752 * "wait %% %2 102" where job 2 is current and pid 102
753 * However many times it is requested, it is found once.
754 */
755 found++;
756 jp->flags |= JOBWANTED;
757 }
758 job = jp;
759 }
760
761 VTRACE(DBG_WAIT, ("wait %s%s%sfound %d candidates (last %s)\n",
762 any ? "-n " : "", *argptr ? *argptr : "",
763 argptr[0] && argptr[1] ? "... " : " ", found,
764 job ? (job->ref ? job->ref : "<no-arg>") : "none"));
765
766 /*
767 * If we were given a list of jobnums:
768 * and none of those exist, then we're done.
769 */
770 if (*argptr && found == 0)
771 return 127;
772
773 /*
774 * Otherwise we need to wait for something to complete
775 * When it does, we check and see if it is one of the
776 * jobs we're waiting on, and if so, we clean it up.
777 * If we had -n, then we're done, otherwise we do it all again
778 * until all we had listed are done, of if there were no
779 * jobnum args, all are done.
780 */
781
782 retval = any || *argptr ? 127 : 0;
783 fpid = NULL;
784 for (;;) {
785 VTRACE(DBG_WAIT, ("wait waiting (%d remain): ", found));
786 for (jp = jobtab, i = njobs; --i >= 0; jp++) {
787 if (jp->used && jp->flags & JOBWANTED &&
788 jp->state == JOBDONE)
789 break;
790 if (jp->used && jp->state == JOBRUNNING)
791 break;
792 }
793 if (i < 0) {
794 CTRACE(DBG_WAIT, ("nothing running (ret: %d) fpid %s\n",
795 retval, fpid ? fpid : "unset"));
796 if (pid && fpid)
797 setvar(pid, fpid, 0);
798 return retval;
799 }
800 VTRACE(DBG_WAIT, ("found @%d/%d state: %d\n", njobs-i, njobs,
801 jp->state));
802
803 /*
804 * There is at least 1 job running, so we can
805 * safely wait() for something to exit.
806 */
807 if (jp->state == JOBRUNNING) {
808 job = NULL;
809 if ((i = dowait(WBLOCK|WNOFREE, NULL, &job)) == -1)
810 return 128 + lastsig();
811
812 /*
813 * one of the job's processes exited,
814 * but there are more
815 */
816 if (job->state == JOBRUNNING)
817 continue;
818 } else
819 job = jp; /* we want this, and it is done */
820
821 if (job->flags & JOBWANTED || (*argptr == 0 && any)) {
822 int rv;
823
824 job->flags &= ~JOBWANTED; /* got it */
825 rv = jobstatus(job, 0);
826 VTRACE(DBG_WAIT, (
827 "wanted %d (%s) done: st=%d", i,
828 job->ref ? job->ref : "", rv));
829 if (any || job == last) {
830 retval = rv;
831 fpid = job->ref;
832
833 VTRACE(DBG_WAIT, (" save"));
834 if (pid) {
835 /*
836 * don't need fpid unless we are going
837 * to return it.
838 */
839 if (fpid == NULL) {
840 /*
841 * this only happens with "wait -n"
842 * (that is, no pid args)
843 */
844 snprintf(idstring, sizeof idstring,
845 "%d", job->ps[ job->nprocs ?
846 job->nprocs-1 :
847 0 ].pid);
848 fpid = idstring;
849 }
850 VTRACE(DBG_WAIT, (" (for %s)", fpid));
851 }
852 }
853
854 if (job->state == JOBDONE) {
855 VTRACE(DBG_WAIT, (" free"));
856 freejob(job);
857 }
858
859 if (any || (found > 0 && --found == 0)) {
860 if (pid && fpid)
861 setvar(pid, fpid, 0);
862 VTRACE(DBG_WAIT, (" return %d\n", retval));
863 return retval;
864 }
865 VTRACE(DBG_WAIT, ("\n"));
866 continue;
867 }
868
869 /* this is to handle "wait" (no args) */
870 if (found == 0 && job->state == JOBDONE) {
871 VTRACE(DBG_JOBS|DBG_WAIT, ("Cleanup: %d\n", i));
872 freejob(job);
873 }
874 }
875 }
876
877
878 int
879 jobidcmd(int argc, char **argv)
880 {
881 struct job *jp;
882 int i;
883 int pg = 0, onep = 0, job = 0;
884
885 while ((i = nextopt("gjp"))) {
886 switch (i) {
887 case 'g': pg = 1; break;
888 case 'j': job = 1; break;
889 case 'p': onep = 1; break;
890 }
891 }
892 CTRACE(DBG_JOBS, ("jobidcmd%s%s%s%s %s\n", pg ? " -g" : "",
893 onep ? " -p" : "", job ? " -j" : "", jobs_invalid ? " [inv]" : "",
894 *argptr ? *argptr : "<implicit %%>"));
895 if (pg + onep + job > 1)
896 error("-g -j and -p options cannot be combined");
897
898 if (argptr[0] && argptr[1])
899 error("usage: jobid [-g|-p|-r] jobid");
900
901 jp = getjob(*argptr, 0);
902 if (job) {
903 out1fmt("%%%zu\n", (size_t)(jp - jobtab + 1));
904 return 0;
905 }
906 if (pg) {
907 if (jp->pgrp != 0) {
908 out1fmt("%ld\n", (long)jp->pgrp);
909 return 0;
910 }
911 return 1;
912 }
913 if (onep) {
914 i = jp->nprocs - 1;
915 if (i < 0)
916 return 1;
917 out1fmt("%ld\n", (long)jp->ps[i].pid);
918 return 0;
919 }
920 for (i = 0 ; i < jp->nprocs ; ) {
921 out1fmt("%ld", (long)jp->ps[i].pid);
922 out1c(++i < jp->nprocs ? ' ' : '\n');
923 }
924 return 0;
925 }
926
927 int
928 getjobpgrp(const char *name)
929 {
930 struct job *jp;
931
932 if (jobs_invalid)
933 error("No such job: %s", name);
934 jp = getjob(name, 1);
935 if (jp == 0)
936 return 0;
937 return -jp->ps[0].pid;
938 }
939
940 /*
941 * Convert a job name to a job structure.
942 */
943
944 STATIC struct job *
945 getjob(const char *name, int noerror)
946 {
947 int jobno = -1;
948 struct job *jp;
949 int pid;
950 int i;
951 const char *err_msg = "No such job: %s";
952
953 if (name == NULL) {
954 #if JOBS
955 jobno = curjob;
956 #endif
957 err_msg = "No current job";
958 } else if (name[0] == '%') {
959 if (is_number(name + 1)) {
960 jobno = number(name + 1) - 1;
961 } else if (!name[1] || !name[2]) {
962 switch (name[1]) {
963 #if JOBS
964 case 0:
965 case '+':
966 case '%':
967 jobno = curjob;
968 err_msg = "No current job";
969 break;
970 case '-':
971 jobno = curjob;
972 if (jobno != -1)
973 jobno = jobtab[jobno].prev_job;
974 err_msg = "No previous job";
975 break;
976 #endif
977 default:
978 goto check_pattern;
979 }
980 } else {
981 struct job *found;
982 check_pattern:
983 found = NULL;
984 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
985 if (!jp->used || jp->nprocs <= 0)
986 continue;
987 if ((name[1] == '?'
988 && strstr(jp->ps[0].cmd, name + 2))
989 || prefix(name + 1, jp->ps[0].cmd)) {
990 if (found) {
991 err_msg = "%s: ambiguous";
992 found = 0;
993 break;
994 }
995 found = jp;
996 }
997 }
998 if (found)
999 return found;
1000 }
1001
1002 } else if (is_number(name)) {
1003 pid = number(name);
1004 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
1005 if (jp->used && jp->nprocs > 0
1006 && jp->ps[jp->nprocs - 1].pid == pid)
1007 return jp;
1008 }
1009 }
1010
1011 if (jobno >= 0 && jobno < njobs) {
1012 jp = jobtab + jobno;
1013 if (jp->used)
1014 return jp;
1015 }
1016 if (!noerror)
1017 error(err_msg, name);
1018 return 0;
1019 }
1020
1021
1022
1023 /*
1024 * Return a new job structure,
1025 */
1026
1027 struct job *
1028 makejob(union node *node, int nprocs)
1029 {
1030 int i;
1031 struct job *jp;
1032
1033 if (jobs_invalid) {
1034 for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
1035 if (jp->used)
1036 freejob(jp);
1037 }
1038 jobs_invalid = 0;
1039 }
1040
1041 for (i = njobs, jp = jobtab ; ; jp++) {
1042 if (--i < 0) {
1043 INTOFF;
1044 if (njobs == 0) {
1045 jobtab = ckmalloc(4 * sizeof jobtab[0]);
1046 } else {
1047 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
1048 memcpy(jp, jobtab, njobs * sizeof jp[0]);
1049 /* Relocate `ps' pointers */
1050 for (i = 0; i < njobs; i++)
1051 if (jp[i].ps == &jobtab[i].ps0)
1052 jp[i].ps = &jp[i].ps0;
1053 ckfree(jobtab);
1054 jobtab = jp;
1055 }
1056 jp = jobtab + njobs;
1057 for (i = 4 ; --i >= 0 ; njobs++) {
1058 jobtab[njobs].used = 0;
1059 jobtab[njobs].prev_job = -1;
1060 }
1061 INTON;
1062 break;
1063 }
1064 if (jp->used == 0)
1065 break;
1066 }
1067 INTOFF;
1068 jp->state = JOBRUNNING;
1069 jp->used = 1;
1070 jp->flags = pipefail ? JPIPEFAIL : 0;
1071 jp->nprocs = 0;
1072 jp->pgrp = 0;
1073 #if JOBS
1074 jp->jobctl = jobctl;
1075 set_curjob(jp, 1);
1076 #endif
1077 if (nprocs > 1) {
1078 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
1079 } else {
1080 jp->ps = &jp->ps0;
1081 }
1082 INTON;
1083 VTRACE(DBG_JOBS, ("makejob(%p, %d)%s returns %%%d\n", (void *)node,
1084 nprocs, (jp->flags&JPIPEFAIL)?" PF":"", jp - jobtab + 1));
1085 return jp;
1086 }
1087
1088
1089 /*
1090 * Fork off a subshell. If we are doing job control, give the subshell its
1091 * own process group. Jp is a job structure that the job is to be added to.
1092 * N is the command that will be evaluated by the child. Both jp and n may
1093 * be NULL. The mode parameter can be one of the following:
1094 * FORK_FG - Fork off a foreground process.
1095 * FORK_BG - Fork off a background process.
1096 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
1097 * process group even if job control is on.
1098 *
1099 * When job control is turned off, background processes have their standard
1100 * input redirected to /dev/null (except for the second and later processes
1101 * in a pipeline).
1102 */
1103
1104 int
1105 forkshell(struct job *jp, union node *n, int mode)
1106 {
1107 pid_t pid;
1108 int serrno;
1109
1110 CTRACE(DBG_JOBS, ("forkshell(%%%d, %p, %d) called\n",
1111 jp - jobtab, n, mode));
1112
1113 switch ((pid = fork())) {
1114 case -1:
1115 serrno = errno;
1116 VTRACE(DBG_JOBS, ("Fork failed, errno=%d\n", serrno));
1117 INTON;
1118 error("Cannot fork (%s)", strerror(serrno));
1119 break;
1120 case 0:
1121 SHELL_FORKED();
1122 forkchild(jp, n, mode, 0);
1123 return 0;
1124 default:
1125 return forkparent(jp, n, mode, pid);
1126 }
1127 }
1128
1129 int
1130 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
1131 {
1132 int pgrp;
1133
1134 if (rootshell && mode != FORK_NOJOB && mflag) {
1135 if (jp == NULL || jp->nprocs == 0)
1136 pgrp = pid;
1137 else
1138 pgrp = jp->ps[0].pid;
1139 jp->pgrp = pgrp;
1140 /* This can fail because we are doing it in the child also */
1141 (void)setpgid(pid, pgrp);
1142 }
1143 if (mode == FORK_BG)
1144 backgndpid = pid; /* set $! */
1145 if (jp) {
1146 struct procstat *ps = &jp->ps[jp->nprocs++];
1147 ps->pid = pid;
1148 ps->status = -1;
1149 ps->cmd[0] = 0;
1150 if (/* iflag && rootshell && */ n)
1151 commandtext(ps, n);
1152 }
1153 CTRACE(DBG_JOBS, ("In parent shell: child = %d (mode %d)\n",pid,mode));
1154 return pid;
1155 }
1156
1157 void
1158 forkchild(struct job *jp, union node *n, int mode, int vforked)
1159 {
1160 int wasroot;
1161 int pgrp;
1162 const char *devnull = _PATH_DEVNULL;
1163 const char *nullerr = "Can't open %s";
1164
1165 wasroot = rootshell;
1166 CTRACE(DBG_JOBS, ("Child shell %d %sforked from %d (mode %d)\n",
1167 getpid(), vforked?"v":"", getppid(), mode));
1168 if (!vforked)
1169 rootshell = 0;
1170
1171 closescript(vforked);
1172 clear_traps(vforked);
1173 #if JOBS
1174 if (!vforked)
1175 jobctl = 0; /* do job control only in root shell */
1176 if (wasroot && mode != FORK_NOJOB && mflag) {
1177 if (jp == NULL || jp->nprocs == 0)
1178 pgrp = getpid();
1179 else
1180 pgrp = jp->ps[0].pid;
1181 /* This can fail because we are doing it in the parent also */
1182 (void)setpgid(0, pgrp);
1183 if (mode == FORK_FG) {
1184 if (tcsetpgrp(ttyfd, pgrp) == -1)
1185 error("Cannot set tty process group (%s) at %d",
1186 strerror(errno), __LINE__);
1187 }
1188 setsignal(SIGTSTP, vforked);
1189 setsignal(SIGTTOU, vforked);
1190 } else if (mode == FORK_BG) {
1191 ignoresig(SIGINT, vforked);
1192 ignoresig(SIGQUIT, vforked);
1193 if ((jp == NULL || jp->nprocs == 0) &&
1194 ! fd0_redirected_p ()) {
1195 close(0);
1196 if (open(devnull, O_RDONLY) != 0)
1197 error(nullerr, devnull);
1198 }
1199 }
1200 #else
1201 if (mode == FORK_BG) {
1202 ignoresig(SIGINT, vforked);
1203 ignoresig(SIGQUIT, vforked);
1204 if ((jp == NULL || jp->nprocs == 0) &&
1205 ! fd0_redirected_p ()) {
1206 close(0);
1207 if (open(devnull, O_RDONLY) != 0)
1208 error(nullerr, devnull);
1209 }
1210 }
1211 #endif
1212 if (wasroot && iflag) {
1213 setsignal(SIGINT, vforked);
1214 setsignal(SIGQUIT, vforked);
1215 setsignal(SIGTERM, vforked);
1216 }
1217
1218 if (!vforked)
1219 jobs_invalid = 1;
1220 }
1221
1222 /*
1223 * Wait for job to finish.
1224 *
1225 * Under job control we have the problem that while a child process is
1226 * running interrupts generated by the user are sent to the child but not
1227 * to the shell. This means that an infinite loop started by an inter-
1228 * active user may be hard to kill. With job control turned off, an
1229 * interactive user may place an interactive program inside a loop. If
1230 * the interactive program catches interrupts, the user doesn't want
1231 * these interrupts to also abort the loop. The approach we take here
1232 * is to have the shell ignore interrupt signals while waiting for a
1233 * forground process to terminate, and then send itself an interrupt
1234 * signal if the child process was terminated by an interrupt signal.
1235 * Unfortunately, some programs want to do a bit of cleanup and then
1236 * exit on interrupt; unless these processes terminate themselves by
1237 * sending a signal to themselves (instead of calling exit) they will
1238 * confuse this approach.
1239 */
1240
1241 int
1242 waitforjob(struct job *jp)
1243 {
1244 #if JOBS
1245 int mypgrp = getpgrp();
1246 #endif
1247 int status;
1248 int st;
1249
1250 INTOFF;
1251 VTRACE(DBG_JOBS, ("waitforjob(%%%d) called\n", jp - jobtab + 1));
1252 while (jp->state == JOBRUNNING) {
1253 dowait(WBLOCK, jp, NULL);
1254 }
1255 #if JOBS
1256 if (jp->jobctl) {
1257 if (tcsetpgrp(ttyfd, mypgrp) == -1)
1258 error("Cannot set tty process group (%s) at %d",
1259 strerror(errno), __LINE__);
1260 }
1261 if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
1262 set_curjob(jp, 2);
1263 #endif
1264 status = jobstatus(jp, 1);
1265
1266 /* convert to 8 bits */
1267 if (WIFEXITED(status))
1268 st = WEXITSTATUS(status);
1269 #if JOBS
1270 else if (WIFSTOPPED(status))
1271 st = WSTOPSIG(status) + 128;
1272 #endif
1273 else
1274 st = WTERMSIG(status) + 128;
1275
1276 VTRACE(DBG_JOBS, ("waitforjob: job %d, nproc %d, status %d, st %x\n",
1277 jp - jobtab + 1, jp->nprocs, status, st));
1278 #if JOBS
1279 if (jp->jobctl) {
1280 /*
1281 * This is truly gross.
1282 * If we're doing job control, then we did a TIOCSPGRP which
1283 * caused us (the shell) to no longer be in the controlling
1284 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
1285 * intuit from the subprocess exit status whether a SIGINT
1286 * occurred, and if so interrupt ourselves. Yuck. - mycroft
1287 */
1288 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1289 raise(SIGINT);
1290 }
1291 #endif
1292 if (! JOBS || jp->state == JOBDONE)
1293 freejob(jp);
1294 INTON;
1295 return st;
1296 }
1297
1298
1299
1300 /*
1301 * Wait for a process to terminate.
1302 */
1303
1304 STATIC int
1305 dowait(int flags, struct job *job, struct job **changed)
1306 {
1307 int pid;
1308 int status;
1309 struct procstat *sp;
1310 struct job *jp;
1311 struct job *thisjob;
1312 int done;
1313 int stopped;
1314
1315 VTRACE(DBG_JOBS|DBG_PROCS, ("dowait(%x) called\n", flags));
1316
1317 if (changed != NULL)
1318 *changed = NULL;
1319
1320 do {
1321 pid = waitproc(flags & WBLOCK, job, &status);
1322 VTRACE(DBG_JOBS|DBG_PROCS, ("wait returns pid %d, status %#x\n",
1323 pid, status));
1324 } while (pid == -1 && errno == EINTR && pendingsigs == 0);
1325 if (pid <= 0)
1326 return pid;
1327 INTOFF;
1328 thisjob = NULL;
1329 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1330 if (jp->used) {
1331 done = 1;
1332 stopped = 1;
1333 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1334 if (sp->pid == -1)
1335 continue;
1336 if (sp->pid == pid &&
1337 (sp->status==-1 || WIFSTOPPED(sp->status))) {
1338 VTRACE(DBG_JOBS | DBG_PROCS,
1339 ("Job %d: changing status of proc %d from %#x to %#x\n",
1340 jp - jobtab + 1, pid,
1341 sp->status, status));
1342 if (WIFCONTINUED(status)) {
1343 if (sp->status != -1)
1344 jp->flags |= JOBCHANGED;
1345 sp->status = -1;
1346 jp->state = 0;
1347 } else
1348 sp->status = status;
1349 thisjob = jp;
1350 if (changed != NULL)
1351 *changed = jp;
1352 }
1353 if (sp->status == -1)
1354 stopped = 0;
1355 else if (WIFSTOPPED(sp->status))
1356 done = 0;
1357 }
1358 if (stopped) { /* stopped or done */
1359 int state = done ? JOBDONE : JOBSTOPPED;
1360
1361 if (jp->state != state) {
1362 VTRACE(DBG_JOBS,
1363 ("Job %d: changing state from %d to %d\n",
1364 jp - jobtab + 1, jp->state, state));
1365 jp->state = state;
1366 #if JOBS
1367 if (done)
1368 set_curjob(jp, 0);
1369 #endif
1370 }
1371 }
1372 }
1373 }
1374
1375 if (thisjob &&
1376 (thisjob->state != JOBRUNNING || thisjob->flags & JOBCHANGED)) {
1377 int mode = 0;
1378
1379 if (!rootshell || !iflag)
1380 mode = SHOW_SIGNALLED;
1381 if ((job == thisjob && (flags & WNOFREE) == 0) ||
1382 job != thisjob)
1383 mode = SHOW_SIGNALLED | SHOW_NO_FREE;
1384 if (mode && (flags & WSILENT) == 0)
1385 showjob(out2, thisjob, mode);
1386 else {
1387 VTRACE(DBG_JOBS,
1388 ("Not printing status, rootshell=%d, job=%p\n",
1389 rootshell, job));
1390 thisjob->flags |= JOBCHANGED;
1391 }
1392 }
1393
1394 INTON;
1395 return pid;
1396 }
1397
1398
1399
1400 /*
1401 * Do a wait system call. If job control is compiled in, we accept
1402 * stopped processes. If block is zero, we return a value of zero
1403 * rather than blocking.
1404 *
1405 * System V doesn't have a non-blocking wait system call. It does
1406 * have a SIGCLD signal that is sent to a process when one of its
1407 * children dies. The obvious way to use SIGCLD would be to install
1408 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
1409 * was received, and have waitproc bump another counter when it got
1410 * the status of a process. Waitproc would then know that a wait
1411 * system call would not block if the two counters were different.
1412 * This approach doesn't work because if a process has children that
1413 * have not been waited for, System V will send it a SIGCLD when it
1414 * installs a signal handler for SIGCLD. What this means is that when
1415 * a child exits, the shell will be sent SIGCLD signals continuously
1416 * until is runs out of stack space, unless it does a wait call before
1417 * restoring the signal handler. The code below takes advantage of
1418 * this (mis)feature by installing a signal handler for SIGCLD and
1419 * then checking to see whether it was called. If there are any
1420 * children to be waited for, it will be.
1421 *
1422 * If neither SYSV nor BSD is defined, we don't implement nonblocking
1423 * waits at all. In this case, the user will not be informed when
1424 * a background process until the next time she runs a real program
1425 * (as opposed to running a builtin command or just typing return),
1426 * and the jobs command may give out of date information.
1427 */
1428
1429 #ifdef SYSV
1430 STATIC int gotsigchild;
1431
1432 STATIC int onsigchild() {
1433 gotsigchild = 1;
1434 }
1435 #endif
1436
1437
1438 STATIC int
1439 waitproc(int block, struct job *jp, int *status)
1440 {
1441 #ifdef BSD
1442 int flags = 0;
1443
1444 #if JOBS
1445 if (mflag || (jp != NULL && jp->jobctl))
1446 flags |= WUNTRACED | WCONTINUED;
1447 #endif
1448 if (block == 0)
1449 flags |= WNOHANG;
1450 VTRACE(DBG_WAIT, ("waitproc: doing waitpid(flags=%#x)\n", flags));
1451 return waitpid(-1, status, flags);
1452 #else
1453 #ifdef SYSV
1454 int (*save)();
1455
1456 if (block == 0) {
1457 gotsigchild = 0;
1458 save = signal(SIGCLD, onsigchild);
1459 signal(SIGCLD, save);
1460 if (gotsigchild == 0)
1461 return 0;
1462 }
1463 return wait(status);
1464 #else
1465 if (block == 0)
1466 return 0;
1467 return wait(status);
1468 #endif
1469 #endif
1470 }
1471
1472 /*
1473 * return 1 if there are stopped jobs, otherwise 0
1474 */
1475 int job_warning = 0;
1476 int
1477 stoppedjobs(void)
1478 {
1479 int jobno;
1480 struct job *jp;
1481
1482 if (job_warning || jobs_invalid)
1483 return (0);
1484 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1485 if (jp->used == 0)
1486 continue;
1487 if (jp->state == JOBSTOPPED) {
1488 out2str("You have stopped jobs.\n");
1489 job_warning = 2;
1490 return (1);
1491 }
1492 }
1493
1494 return (0);
1495 }
1496
1497 /*
1498 * Return a string identifying a command (to be printed by the
1499 * jobs command).
1500 */
1501
1502 STATIC char *cmdnextc;
1503 STATIC int cmdnleft;
1504
1505 void
1506 commandtext(struct procstat *ps, union node *n)
1507 {
1508 int len;
1509
1510 cmdnextc = ps->cmd;
1511 if (iflag || mflag || sizeof(ps->cmd) <= 60)
1512 len = sizeof(ps->cmd);
1513 else if (sizeof ps->cmd <= 400)
1514 len = 50;
1515 else if (sizeof ps->cmd <= 800)
1516 len = 80;
1517 else
1518 len = sizeof(ps->cmd) / 10;
1519 cmdnleft = len;
1520 cmdtxt(n);
1521 if (cmdnleft <= 0) {
1522 char *p = ps->cmd + len - 4;
1523 p[0] = '.';
1524 p[1] = '.';
1525 p[2] = '.';
1526 p[3] = 0;
1527 } else
1528 *cmdnextc = '\0';
1529
1530 VTRACE(DBG_JOBS,
1531 ("commandtext: ps->cmd %p, end %p, left %d\n\t\"%s\"\n",
1532 ps->cmd, cmdnextc, cmdnleft, ps->cmd));
1533 }
1534
1535
1536 STATIC void
1537 cmdtxt(union node *n)
1538 {
1539 union node *np;
1540 struct nodelist *lp;
1541 const char *p;
1542 int i;
1543
1544 if (n == NULL || cmdnleft <= 0)
1545 return;
1546 switch (n->type) {
1547 case NSEMI:
1548 cmdtxt(n->nbinary.ch1);
1549 cmdputs("; ");
1550 cmdtxt(n->nbinary.ch2);
1551 break;
1552 case NAND:
1553 cmdtxt(n->nbinary.ch1);
1554 cmdputs(" && ");
1555 cmdtxt(n->nbinary.ch2);
1556 break;
1557 case NOR:
1558 cmdtxt(n->nbinary.ch1);
1559 cmdputs(" || ");
1560 cmdtxt(n->nbinary.ch2);
1561 break;
1562 case NDNOT:
1563 cmdputs("! ");
1564 /* FALLTHROUGH */
1565 case NNOT:
1566 cmdputs("! ");
1567 cmdtxt(n->nnot.com);
1568 break;
1569 case NPIPE:
1570 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1571 cmdtxt(lp->n);
1572 if (lp->next)
1573 cmdputs(" | ");
1574 }
1575 if (n->npipe.backgnd)
1576 cmdputs(" &");
1577 break;
1578 case NSUBSHELL:
1579 cmdputs("(");
1580 cmdtxt(n->nredir.n);
1581 cmdputs(")");
1582 break;
1583 case NREDIR:
1584 case NBACKGND:
1585 cmdtxt(n->nredir.n);
1586 break;
1587 case NIF:
1588 cmdputs("if ");
1589 cmdtxt(n->nif.test);
1590 cmdputs("; then ");
1591 cmdtxt(n->nif.ifpart);
1592 if (n->nif.elsepart) {
1593 cmdputs("; else ");
1594 cmdtxt(n->nif.elsepart);
1595 }
1596 cmdputs("; fi");
1597 break;
1598 case NWHILE:
1599 cmdputs("while ");
1600 goto until;
1601 case NUNTIL:
1602 cmdputs("until ");
1603 until:
1604 cmdtxt(n->nbinary.ch1);
1605 cmdputs("; do ");
1606 cmdtxt(n->nbinary.ch2);
1607 cmdputs("; done");
1608 break;
1609 case NFOR:
1610 cmdputs("for ");
1611 cmdputs(n->nfor.var);
1612 cmdputs(" in ");
1613 cmdlist(n->nfor.args, 1);
1614 cmdputs("; do ");
1615 cmdtxt(n->nfor.body);
1616 cmdputs("; done");
1617 break;
1618 case NCASE:
1619 cmdputs("case ");
1620 cmdputs(n->ncase.expr->narg.text);
1621 cmdputs(" in ");
1622 for (np = n->ncase.cases; np; np = np->nclist.next) {
1623 cmdtxt(np->nclist.pattern);
1624 cmdputs(") ");
1625 cmdtxt(np->nclist.body);
1626 switch (n->type) { /* switch (not if) for later */
1627 case NCLISTCONT:
1628 cmdputs(";& ");
1629 break;
1630 default:
1631 cmdputs(";; ");
1632 break;
1633 }
1634 }
1635 cmdputs("esac");
1636 break;
1637 case NDEFUN:
1638 cmdputs(n->narg.text);
1639 cmdputs("() { ... }");
1640 break;
1641 case NCMD:
1642 cmdlist(n->ncmd.args, 1);
1643 cmdlist(n->ncmd.redirect, 0);
1644 if (n->ncmd.backgnd)
1645 cmdputs(" &");
1646 break;
1647 case NARG:
1648 cmdputs(n->narg.text);
1649 break;
1650 case NTO:
1651 p = ">"; i = 1; goto redir;
1652 case NCLOBBER:
1653 p = ">|"; i = 1; goto redir;
1654 case NAPPEND:
1655 p = ">>"; i = 1; goto redir;
1656 case NTOFD:
1657 p = ">&"; i = 1; goto redir;
1658 case NFROM:
1659 p = "<"; i = 0; goto redir;
1660 case NFROMFD:
1661 p = "<&"; i = 0; goto redir;
1662 case NFROMTO:
1663 p = "<>"; i = 0; goto redir;
1664 redir:
1665 if (n->nfile.fd != i)
1666 cmdputi(n->nfile.fd);
1667 cmdputs(p);
1668 if (n->type == NTOFD || n->type == NFROMFD) {
1669 if (n->ndup.dupfd < 0)
1670 cmdputs("-");
1671 else
1672 cmdputi(n->ndup.dupfd);
1673 } else {
1674 cmdtxt(n->nfile.fname);
1675 }
1676 break;
1677 case NHERE:
1678 case NXHERE:
1679 cmdputs("<<...");
1680 break;
1681 default:
1682 cmdputs("???");
1683 break;
1684 }
1685 }
1686
1687 STATIC void
1688 cmdlist(union node *np, int sep)
1689 {
1690 for (; np; np = np->narg.next) {
1691 if (!sep)
1692 cmdputs(" ");
1693 cmdtxt(np);
1694 if (sep && np->narg.next)
1695 cmdputs(" ");
1696 }
1697 }
1698
1699
1700 STATIC void
1701 cmdputs(const char *s)
1702 {
1703 const char *p, *str = 0;
1704 char c, cc[2] = " ";
1705 char *nextc;
1706 int nleft;
1707 int subtype = 0;
1708 int quoted = 0;
1709 static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
1710 "#", "##", "%", "%%", "}" };
1711
1712 p = s;
1713 nextc = cmdnextc;
1714 nleft = cmdnleft;
1715 while (nleft > 0 && (c = *p++) != 0) {
1716 switch (c) {
1717 case CTLNONL:
1718 c = '\0';
1719 break;
1720 case CTLESC:
1721 c = *p++;
1722 break;
1723 case CTLVAR:
1724 subtype = *p++;
1725 if (subtype & VSLINENO) { /* undo LINENO hack */
1726 if ((subtype & VSTYPE) == VSLENGTH)
1727 str = "${#LINENO"; /*}*/
1728 else
1729 str = "${LINENO"; /*}*/
1730 while (is_digit(*p))
1731 p++;
1732 } else if ((subtype & VSTYPE) == VSLENGTH)
1733 str = "${#"; /*}*/
1734 else
1735 str = "${"; /*}*/
1736 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
1737 quoted ^= 1;
1738 c = '"';
1739 } else {
1740 c = *str++;
1741 }
1742 break;
1743 case CTLENDVAR: /*{*/
1744 c = '}';
1745 if (quoted & 1)
1746 str = "\"";
1747 quoted >>= 1;
1748 subtype = 0;
1749 break;
1750 case CTLBACKQ:
1751 c = '$';
1752 str = "(...)";
1753 break;
1754 case CTLBACKQ+CTLQUOTE:
1755 c = '"';
1756 str = "$(...)\"";
1757 break;
1758 case CTLARI:
1759 c = '$';
1760 if (*p == ' ')
1761 p++;
1762 str = "(("; /*))*/
1763 break;
1764 case CTLENDARI: /*((*/
1765 c = ')';
1766 str = ")";
1767 break;
1768 case CTLQUOTEMARK:
1769 quoted ^= 1;
1770 c = '"';
1771 break;
1772 case CTLQUOTEEND:
1773 quoted >>= 1;
1774 c = '"';
1775 break;
1776 case '=':
1777 if (subtype == 0)
1778 break;
1779 str = vstype[subtype & VSTYPE];
1780 if (subtype & VSNUL)
1781 c = ':';
1782 else
1783 c = *str++; /*{*/
1784 if (c != '}')
1785 quoted <<= 1;
1786 else if (*p == CTLENDVAR)
1787 c = *str++;
1788 subtype = 0;
1789 break;
1790 case '\'':
1791 case '\\':
1792 case '"':
1793 case '$':
1794 /* These can only happen inside quotes */
1795 cc[0] = c;
1796 str = cc;
1797 c = '\\';
1798 break;
1799 default:
1800 break;
1801 }
1802 if (c != '\0') do { /* c == 0 implies nothing in str */
1803 *nextc++ = c;
1804 } while (--nleft > 0 && str && (c = *str++));
1805 str = 0;
1806 }
1807 if ((quoted & 1) && nleft) {
1808 *nextc++ = '"';
1809 nleft--;
1810 }
1811 cmdnleft = nleft;
1812 cmdnextc = nextc;
1813 }
1814