$ ); echo $? echoed 0,all other shells echo 2.
[unix-history] / usr / src / bin / sh / jobs.c
CommitLineData
d4d2fb62 1/*-
d1b73048
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
d4d2fb62
KB
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
af49c367 8 * %sccs.include.redist.c%
d4d2fb62
KB
9 */
10
11#ifndef lint
13b3e634 12static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) %G%";
d4d2fb62
KB
13#endif /* not lint */
14
13b3e634
CZ
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
d4d2fb62
KB
28#include "shell.h"
29#if JOBS
30#include "sgtty.h"
31#undef CEOF /* syntax.h redefines this */
32#endif
13b3e634
CZ
33#include "redir.h"
34#include "show.h"
d4d2fb62
KB
35#include "main.h"
36#include "parser.h"
37#include "nodes.h"
38#include "jobs.h"
39#include "options.h"
40#include "trap.h"
d4d2fb62
KB
41#include "syntax.h"
42#include "input.h"
43#include "output.h"
44#include "memalloc.h"
45#include "error.h"
46#include "mystring.h"
d4d2fb62
KB
47
48
49struct job *jobtab; /* array of jobs */
50int njobs; /* size of array */
51MKINIT short backgndpid = -1; /* pid of last background process */
52#if JOBS
53int initialpgrp; /* pgrp of shell on invocation */
54short curjob; /* current job */
55#endif
56
13b3e634
CZ
57STATIC void restartjob __P((struct job *));
58STATIC void freejob __P((struct job *));
59STATIC struct job *getjob __P((char *));
60STATIC int dowait __P((int, struct job *));
61STATIC int onsigchild __P((void));
62STATIC int waitproc __P((int, int *));
63STATIC void cmdtxt __P((union node *));
64STATIC void cmdputs __P((char *));
d4d2fb62 65
79b6cd19 66
d4d2fb62
KB
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
75MKINIT int jobctl;
76
77void
13b3e634
CZ
78setjobctl(on)
79 int on;
80{
8979b8b4 81#ifdef OLD_TTY_DRIVER
d4d2fb62 82 int ldisc;
8979b8b4 83#endif
d4d2fb62
KB
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) {
057eb6b7
MT
90 out2str("sh: can't access tty; job control turned off\n");
91 mflag = 0;
d4d2fb62
KB
92 return;
93 }
94 if (initialpgrp == -1)
af49c367
KB
95 initialpgrp = getpgrp();
96 else if (initialpgrp != getpgrp()) {
d4d2fb62
KB
97 killpg(initialpgrp, SIGTTIN);
98 continue;
99 }
100 } while (0);
057eb6b7 101#ifdef OLD_TTY_DRIVER
d4d2fb62 102 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
057eb6b7
MT
103 out2str("sh: need new tty driver to run job control; job control turned off\n");
104 mflag = 0;
d4d2fb62
KB
105 return;
106 }
057eb6b7 107#endif
d4d2fb62
KB
108 setsignal(SIGTSTP);
109 setsignal(SIGTTOU);
f97844eb 110 setsignal(SIGTTIN);
543f5e91 111 setpgid(0, rootpid);
d4d2fb62
KB
112 ioctl(2, TIOCSPGRP, (char *)&rootpid);
113 } else { /* turning job control off */
543f5e91 114 setpgid(0, initialpgrp);
d4d2fb62
KB
115 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
116 setsignal(SIGTSTP);
117 setsignal(SIGTTOU);
f97844eb 118 setsignal(SIGTTIN);
d4d2fb62
KB
119 }
120 jobctl = on;
121}
d4d2fb62
KB
122
123
124#ifdef mkinit
13b3e634 125INCLUDE <stdlib.h>
d4d2fb62
KB
126
127SHELLPROC {
128 backgndpid = -1;
129#if JOBS
130 jobctl = 0;
131#endif
132}
133
134#endif
135
136
137
138#if JOBS
13b3e634
CZ
139int
140fgcmd(argc, argv)
141 int argc;
142 char **argv;
143{
d4d2fb62
KB
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
13b3e634
CZ
161int
162bgcmd(argc, argv)
163 int argc;
164 char **argv;
165{
d4d2fb62
KB
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
178STATIC void
179restartjob(jp)
180 struct job *jp;
13b3e634 181{
d4d2fb62
KB
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
200int
13b3e634
CZ
201jobscmd(argc, argv)
202 int argc;
203 char **argv;
204{
d4d2fb62
KB
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
219void
13b3e634
CZ
220showjobs(change)
221 int change;
222{
d4d2fb62
KB
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
f2240806
KB
261 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
262 scopy(sys_siglist[i & 0x7F], s);
d4d2fb62
KB
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
291STATIC void
292freejob(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
315int
13b3e634
CZ
316waitcmd(argc, argv)
317 int argc;
318 char **argv;
319{
d4d2fb62
KB
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
13b3e634
CZ
360int
361jobidcmd(argc, argv)
362 int argc;
363 char **argv;
364{
d4d2fb62
KB
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
382STATIC struct job *
383getjob(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
393currentjob:
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);
13b3e634
CZ
432 /*NOTREACHED*/
433 return NULL;
d4d2fb62
KB
434}
435
436
437
438/*
439 * Return a new job structure,
440 */
441
442struct job *
443makejob(node, nprocs)
444 union node *node;
13b3e634
CZ
445 int nprocs;
446{
d4d2fb62
KB
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]);
13b3e634 457 memcpy(jp, jobtab, njobs * sizeof jp[0]);
d4d2fb62
KB
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;
13b3e634
CZ
483 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
484 jp - jobtab + 1));
d4d2fb62
KB
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
504int
505forkshell(jp, n, mode)
506 union node *n;
507 struct job *jp;
13b3e634
CZ
508 int mode;
509{
d4d2fb62
KB
510 int pid;
511 int pgrp;
512
13b3e634
CZ
513 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
514 mode));
d4d2fb62
KB
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 */
057eb6b7 538 if (wasroot && mode != FORK_NOJOB && mflag) {
d4d2fb62
KB
539 if (jp == NULL || jp->nprocs == 0)
540 pgrp = getpid();
541 else
542 pgrp = jp->ps[0].pid;
543f5e91 543 setpgid(0, pgrp);
d4d2fb62
KB
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);
ddc16cae
MT
554 if ((jp == NULL || jp->nprocs == 0) &&
555 ! fd0_redirected_p ()) {
d4d2fb62
KB
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);
ddc16cae
MT
565 if ((jp == NULL || jp->nprocs == 0) &&
566 ! fd0_redirected_p ()) {
d4d2fb62
KB
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 }
057eb6b7 580 if (rootshell && mode != FORK_NOJOB && mflag) {
d4d2fb62
KB
581 if (jp == NULL || jp->nprocs == 0)
582 pgrp = pid;
583 else
584 pgrp = jp->ps[0].pid;
543f5e91 585 setpgid(pid, pgrp);
d4d2fb62
KB
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
623int
624waitforjob(jp)
625 register struct job *jp;
626 {
627#if JOBS
af49c367 628 int mypgrp = getpgrp();
d4d2fb62
KB
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
671STATIC int
672dowait(block, job)
13b3e634 673 int block;
d4d2fb62 674 struct job *job;
13b3e634 675{
d4d2fb62
KB
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
f2240806
KB
739 if (status < NSIG && sys_siglist[status])
740 out2str(sys_siglist[status]);
d4d2fb62
KB
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
790STATIC int gotsigchild;
791
792STATIC int onsigchild() {
793 gotsigchild = 1;
794}
795#endif
796
797
798STATIC int
799waitproc(block, status)
13b3e634 800 int block;
d4d2fb62 801 int *status;
13b3e634 802{
d4d2fb62
KB
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;
057eb6b7 813 return wait3(status, flags, (struct rusage *)NULL);
d4d2fb62
KB
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
0dc9f70e
MT
834/*
835 * return 1 if there are stopped jobs, otherwise 0
836 */
837int job_warning = 0;
838int
79b6cd19 839stoppedjobs()
0dc9f70e 840{
8979b8b4
MT
841 register int jobno;
842 register struct job *jp;
d4d2fb62 843
0dc9f70e
MT
844 if (job_warning)
845 return (0);
8979b8b4
MT
846 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
847 if (jp->used == 0)
0dc9f70e 848 continue;
8979b8b4 849 if (jp->state == JOBSTOPPED) {
0dc9f70e
MT
850 out2str("You have stopped jobs.\n");
851 job_warning = 2;
852 return (1);
853 }
854 }
855
856 return (0);
857}
d4d2fb62
KB
858
859/*
860 * Return a string identifying a command (to be printed by the
861 * jobs command.
862 */
863
864STATIC char *cmdnextc;
865STATIC int cmdnleft;
866STATIC void cmdtxt(), cmdputs();
85774404 867#define MAXCMDTEXT 200
d4d2fb62 868
85774404 869char *
d4d2fb62
KB
870commandtext(n)
871 union node *n;
872 {
873 char *name;
874
85774404
MT
875 cmdnextc = name = ckmalloc(MAXCMDTEXT);
876 cmdnleft = MAXCMDTEXT - 4;
d4d2fb62
KB
877 cmdtxt(n);
878 *cmdnextc = '\0';
879 return name;
880}
881
882
883STATIC void
884cmdtxt(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
057eb6b7
MT
893 if (n == NULL)
894 return;
d4d2fb62
KB
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 ");
939until:
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;
983redir:
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
1010STATIC void
1011cmdputs(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}