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