]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - bin/sh/jobs.c
MFC r309400:
[FreeBSD/stable/8.git] / bin / sh / jobs.c
1 /*-
2  * Copyright (c) 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)jobs.c      8.5 (Berkeley) 5/4/95";
36 #endif
37 #endif /* not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/ioctl.h>
42 #include <sys/param.h>
43 #include <sys/resource.h>
44 #include <sys/time.h>
45 #include <sys/wait.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <paths.h>
49 #include <signal.h>
50 #include <stddef.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53
54 #include "shell.h"
55 #if JOBS
56 #include <termios.h>
57 #undef CEOF                     /* syntax.h redefines this */
58 #endif
59 #include "redir.h"
60 #include "show.h"
61 #include "main.h"
62 #include "parser.h"
63 #include "nodes.h"
64 #include "jobs.h"
65 #include "options.h"
66 #include "trap.h"
67 #include "syntax.h"
68 #include "input.h"
69 #include "output.h"
70 #include "memalloc.h"
71 #include "error.h"
72 #include "mystring.h"
73
74
75 static struct job *jobtab;      /* array of jobs */
76 static int njobs;               /* size of array */
77 MKINIT pid_t backgndpid = -1;   /* pid of last background process */
78 #if JOBS
79 static struct job *jobmru;      /* most recently used job list */
80 static pid_t initialpgrp;       /* pgrp of shell on invocation */
81 #endif
82 int in_waitcmd = 0;             /* are we in waitcmd()? */
83 int in_dowait = 0;              /* are we in dowait()? */
84 volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */
85 static int ttyfd = -1;
86
87 #if JOBS
88 static void restartjob(struct job *);
89 #endif
90 static void freejob(struct job *);
91 static struct job *getjob(char *);
92 static pid_t dowait(int, struct job *);
93 static pid_t waitproc(int, int *);
94 static void checkzombies(void);
95 static void cmdtxt(union node *);
96 static void cmdputs(const char *);
97 #if JOBS
98 static void setcurjob(struct job *);
99 static void deljob(struct job *);
100 static struct job *getcurjob(struct job *);
101 #endif
102 static void showjob(struct job *, pid_t, int);
103
104
105 /*
106  * Turn job control on and off.
107  */
108
109 MKINIT int jobctl;
110
111 #if JOBS
112 void
113 setjobctl(int on)
114 {
115         int i;
116
117         if (on == jobctl || rootshell == 0)
118                 return;
119         if (on) {
120                 if (ttyfd != -1)
121                         close(ttyfd);
122                 if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
123                         i = 0;
124                         while (i <= 2 && !isatty(i))
125                                 i++;
126                         if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0)
127                                 goto out;
128                 }
129                 if (ttyfd < 10) {
130                         /*
131                          * Keep our TTY file descriptor out of the way of
132                          * the user's redirections.
133                          */
134                         if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) {
135                                 close(ttyfd);
136                                 ttyfd = -1;
137                                 goto out;
138                         }
139                         close(ttyfd);
140                         ttyfd = i;
141                 }
142                 if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
143                         close(ttyfd);
144                         ttyfd = -1;
145                         goto out;
146                 }
147                 do { /* while we are in the background */
148                         initialpgrp = tcgetpgrp(ttyfd);
149                         if (initialpgrp < 0) {
150 out:                            out2str("sh: can't access tty; job control turned off\n");
151                                 mflag = 0;
152                                 return;
153                         }
154                         if (initialpgrp == -1)
155                                 initialpgrp = getpgrp();
156                         else if (initialpgrp != getpgrp()) {
157                                 killpg(0, SIGTTIN);
158                                 continue;
159                         }
160                 } while (0);
161                 setsignal(SIGTSTP);
162                 setsignal(SIGTTOU);
163                 setsignal(SIGTTIN);
164                 setpgid(0, rootpid);
165                 tcsetpgrp(ttyfd, rootpid);
166         } else { /* turning job control off */
167                 setpgid(0, initialpgrp);
168                 tcsetpgrp(ttyfd, initialpgrp);
169                 close(ttyfd);
170                 ttyfd = -1;
171                 setsignal(SIGTSTP);
172                 setsignal(SIGTTOU);
173                 setsignal(SIGTTIN);
174         }
175         jobctl = on;
176 }
177 #endif
178
179
180 #ifdef mkinit
181 INCLUDE <sys/types.h>
182 INCLUDE <stdlib.h>
183
184 SHELLPROC {
185         backgndpid = -1;
186 #if JOBS
187         jobctl = 0;
188 #endif
189 }
190
191 #endif
192
193
194
195 #if JOBS
196 int
197 fgcmd(int argc __unused, char **argv)
198 {
199         struct job *jp;
200         pid_t pgrp;
201         int status;
202
203         jp = getjob(argv[1]);
204         if (jp->jobctl == 0)
205                 error("job not created under job control");
206         out1str(jp->ps[0].cmd);
207         out1c('\n');
208         flushout(&output);
209         pgrp = jp->ps[0].pid;
210         tcsetpgrp(ttyfd, pgrp);
211         restartjob(jp);
212         jp->foreground = 1;
213         INTOFF;
214         status = waitforjob(jp, (int *)NULL);
215         INTON;
216         return status;
217 }
218
219
220 int
221 bgcmd(int argc, char **argv)
222 {
223         char s[64];
224         struct job *jp;
225
226         do {
227                 jp = getjob(*++argv);
228                 if (jp->jobctl == 0)
229                         error("job not created under job control");
230                 if (jp->state == JOBDONE)
231                         continue;
232                 restartjob(jp);
233                 jp->foreground = 0;
234                 fmtstr(s, 64, "[%td] ", jp - jobtab + 1);
235                 out1str(s);
236                 out1str(jp->ps[0].cmd);
237                 out1c('\n');
238         } while (--argc > 1);
239         return 0;
240 }
241
242
243 static void
244 restartjob(struct job *jp)
245 {
246         struct procstat *ps;
247         int i;
248
249         if (jp->state == JOBDONE)
250                 return;
251         setcurjob(jp);
252         INTOFF;
253         killpg(jp->ps[0].pid, SIGCONT);
254         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
255                 if (WIFSTOPPED(ps->status)) {
256                         ps->status = -1;
257                         jp->state = 0;
258                 }
259         }
260         INTON;
261 }
262 #endif
263
264
265 int
266 jobscmd(int argc, char *argv[])
267 {
268         char *id;
269         int ch, mode;
270
271         optind = optreset = 1;
272         opterr = 0;
273         mode = SHOWJOBS_DEFAULT;
274         while ((ch = getopt(argc, argv, "lps")) != -1) {
275                 switch (ch) {
276                 case 'l':
277                         mode = SHOWJOBS_VERBOSE;
278                         break;
279                 case 'p':
280                         mode = SHOWJOBS_PGIDS;
281                         break;
282                 case 's':
283                         mode = SHOWJOBS_PIDS;
284                         break;
285                 case '?':
286                 default:
287                         error("unknown option: -%c", optopt);
288                 }
289         }
290         argc -= optind;
291         argv += optind;
292
293         if (argc == 0)
294                 showjobs(0, mode);
295         else
296                 while ((id = *argv++) != NULL)
297                         showjob(getjob(id), 0, mode);
298
299         return (0);
300 }
301
302 static void
303 showjob(struct job *jp, pid_t pid, int mode)
304 {
305         char s[64];
306         struct procstat *ps;
307         struct job *j;
308         int col, curr, i, jobno, prev, procno;
309         pid_t ppid;
310         char c;
311
312         procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
313         jobno = jp - jobtab + 1;
314         curr = prev = 0;
315 #if JOBS
316         if ((j = getcurjob(NULL)) != NULL) {
317                 curr = j - jobtab + 1;
318                 if ((j = getcurjob(j)) != NULL)
319                         prev = j - jobtab + 1;
320         }
321 #endif
322         for (ps = jp->ps ; ; ps++) {    /* for each process */
323                 if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
324                         ppid = (mode == SHOWJOBS_PIDS) ? ps->pid :
325                             getpgid(ps->pid);
326                         out1fmt("%d\n", (int)ppid);
327                         goto skip;
328                 }
329                 if (mode != SHOWJOBS_VERBOSE && ps != jp->ps && pid == 0)
330                         goto skip;
331                 if (pid != 0 && pid != ps->pid)
332                         goto skip;
333                 if (jobno == curr && ps == jp->ps)
334                         c = '+';
335                 else if (jobno == prev && ps == jp->ps)
336                         c = '-';
337                 else
338                         c = ' ';
339                 if (ps == jp->ps)
340                         fmtstr(s, 64, "[%d] %c ", jobno, c);
341                 else
342                         fmtstr(s, 64, "    %c ", c);
343                 out1str(s);
344                 col = strlen(s);
345                 if (mode == SHOWJOBS_VERBOSE) {
346                         fmtstr(s, 64, "%d ", (int)ps->pid);
347                         out1str(s);
348                         col += strlen(s);
349                 }
350                 s[0] = '\0';
351                 if (ps != jp->ps) {
352                         *s = '\0';
353                 } else if (ps->status == -1) {
354                         strcpy(s, "Running");
355                 } else if (WIFEXITED(ps->status)) {
356                         if (WEXITSTATUS(ps->status) == 0)
357                                 strcpy(s, "Done");
358                         else
359                                 fmtstr(s, 64, "Done (%d)",
360                                     WEXITSTATUS(ps->status));
361                 } else {
362 #if JOBS
363                         if (WIFSTOPPED(ps->status))
364                                 i = WSTOPSIG(ps->status);
365                         else
366 #endif
367                                 i = WTERMSIG(ps->status);
368                         if ((i & 0x7F) < sys_nsig && sys_siglist[i & 0x7F])
369                                 scopy(sys_siglist[i & 0x7F], s);
370                         else
371                                 fmtstr(s, 64, "Signal %d", i & 0x7F);
372                         if (WCOREDUMP(ps->status))
373                                 strcat(s, " (core dumped)");
374                 }
375                 out1str(s);
376                 col += strlen(s);
377                 do {
378                         out1c(' ');
379                         col++;
380                 } while (col < 30);
381                 out1str(ps->cmd);
382                 out1c('\n');
383 skip:           if (--procno <= 0)
384                         break;
385         }
386 }
387
388 /*
389  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
390  * statuses have changed since the last call to showjobs.
391  *
392  * If the shell is interrupted in the process of creating a job, the
393  * result may be a job structure containing zero processes.  Such structures
394  * will be freed here.
395  */
396
397 void
398 showjobs(int change, int mode)
399 {
400         int jobno;
401         struct job *jp;
402
403         TRACE(("showjobs(%d) called\n", change));
404         checkzombies();
405         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
406                 if (! jp->used)
407                         continue;
408                 if (jp->nprocs == 0) {
409                         freejob(jp);
410                         continue;
411                 }
412                 if (change && ! jp->changed)
413                         continue;
414                 showjob(jp, 0, mode);
415                 jp->changed = 0;
416                 if (jp->state == JOBDONE) {
417                         freejob(jp);
418                 }
419         }
420 }
421
422
423 /*
424  * Mark a job structure as unused.
425  */
426
427 static void
428 freejob(struct job *jp)
429 {
430         struct procstat *ps;
431         int i;
432
433         INTOFF;
434         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
435                 if (ps->cmd != nullstr)
436                         ckfree(ps->cmd);
437         }
438         if (jp->ps != &jp->ps0)
439                 ckfree(jp->ps);
440         jp->used = 0;
441 #if JOBS
442         deljob(jp);
443 #endif
444         INTON;
445 }
446
447
448
449 int
450 waitcmd(int argc, char **argv)
451 {
452         struct job *job;
453         int status, retval;
454         struct job *jp;
455
456         if (argc > 1) {
457                 job = getjob(argv[1]);
458         } else {
459                 job = NULL;
460         }
461
462         /*
463          * Loop until a process is terminated or stopped, or a SIGINT is
464          * received.
465          */
466
467         in_waitcmd++;
468         do {
469                 if (job != NULL) {
470                         if (job->state) {
471                                 status = job->ps[job->nprocs - 1].status;
472                                 if (WIFEXITED(status))
473                                         retval = WEXITSTATUS(status);
474 #if JOBS
475                                 else if (WIFSTOPPED(status))
476                                         retval = WSTOPSIG(status) + 128;
477 #endif
478                                 else
479                                         retval = WTERMSIG(status) + 128;
480                                 if (! iflag)
481                                         freejob(job);
482                                 in_waitcmd--;
483                                 return retval;
484                         }
485                 } else {
486                         for (jp = jobtab ; ; jp++) {
487                                 if (jp >= jobtab + njobs) {     /* no running procs */
488                                         in_waitcmd--;
489                                         return 0;
490                                 }
491                                 if (jp->used && jp->state == 0)
492                                         break;
493                         }
494                 }
495         } while (dowait(1, (struct job *)NULL) != -1);
496         in_waitcmd--;
497
498         return 0;
499 }
500
501
502
503 int
504 jobidcmd(int argc __unused, char **argv)
505 {
506         struct job *jp;
507         int i;
508
509         jp = getjob(argv[1]);
510         for (i = 0 ; i < jp->nprocs ; ) {
511                 out1fmt("%d", (int)jp->ps[i].pid);
512                 out1c(++i < jp->nprocs? ' ' : '\n');
513         }
514         return 0;
515 }
516
517
518
519 /*
520  * Convert a job name to a job structure.
521  */
522
523 static struct job *
524 getjob(char *name)
525 {
526         int jobno;
527         struct job *found, *jp;
528         pid_t pid;
529         int i;
530
531         if (name == NULL) {
532 #if JOBS
533 currentjob:     if ((jp = getcurjob(NULL)) == NULL)
534                         error("No current job");
535                 return (jp);
536 #else
537                 error("No current job");
538 #endif
539         } else if (name[0] == '%') {
540                 if (is_digit(name[1])) {
541                         jobno = number(name + 1);
542                         if (jobno > 0 && jobno <= njobs
543                          && jobtab[jobno - 1].used != 0)
544                                 return &jobtab[jobno - 1];
545 #if JOBS
546                 } else if (name[1] == '%' && name[2] == '\0') {
547                         goto currentjob;
548                 } else if (name[1] == '+' && name[2] == '\0') {
549                         goto currentjob;
550                 } else if (name[1] == '-' && name[2] == '\0') {
551                         if ((jp = getcurjob(NULL)) == NULL ||
552                             (jp = getcurjob(jp)) == NULL)
553                                 error("No previous job");
554                         return (jp);
555 #endif
556                 } else if (name[1] == '?') {
557                         found = NULL;
558                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
559                                 if (jp->used && jp->nprocs > 0
560                                  && strstr(jp->ps[0].cmd, name + 2) != NULL) {
561                                         if (found)
562                                                 error("%s: ambiguous", name);
563                                         found = jp;
564                                 }
565                         }
566                         if (found != NULL)
567                                 return (found);
568                 } else {
569                         found = NULL;
570                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
571                                 if (jp->used && jp->nprocs > 0
572                                  && prefix(name + 1, jp->ps[0].cmd)) {
573                                         if (found)
574                                                 error("%s: ambiguous", name);
575                                         found = jp;
576                                 }
577                         }
578                         if (found)
579                                 return found;
580                 }
581         } else if (is_number(name)) {
582                 pid = (pid_t)number(name);
583                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
584                         if (jp->used && jp->nprocs > 0
585                          && jp->ps[jp->nprocs - 1].pid == pid)
586                                 return jp;
587                 }
588         }
589         error("No such job: %s", name);
590         /*NOTREACHED*/
591         return NULL;
592 }
593
594
595
596 /*
597  * Return a new job structure,
598  */
599
600 struct job *
601 makejob(union node *node __unused, int nprocs)
602 {
603         int i;
604         struct job *jp;
605
606         for (i = njobs, jp = jobtab ; ; jp++) {
607                 if (--i < 0) {
608                         INTOFF;
609                         if (njobs == 0) {
610                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
611 #if JOBS
612                                 jobmru = NULL;
613 #endif
614                         } else {
615                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
616                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
617 #if JOBS
618                                 /* Relocate `next' pointers and list head */
619                                 if (jobmru != NULL)
620                                         jobmru = &jp[jobmru - jobtab];
621                                 for (i = 0; i < njobs; i++)
622                                         if (jp[i].next != NULL)
623                                                 jp[i].next = &jp[jp[i].next -
624                                                     jobtab];
625 #endif
626                                 /* Relocate `ps' pointers */
627                                 for (i = 0; i < njobs; i++)
628                                         if (jp[i].ps == &jobtab[i].ps0)
629                                                 jp[i].ps = &jp[i].ps0;
630                                 ckfree(jobtab);
631                                 jobtab = jp;
632                         }
633                         jp = jobtab + njobs;
634                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
635                         INTON;
636                         break;
637                 }
638                 if (jp->used == 0)
639                         break;
640         }
641         INTOFF;
642         jp->state = 0;
643         jp->used = 1;
644         jp->changed = 0;
645         jp->nprocs = 0;
646         jp->foreground = 0;
647 #if JOBS
648         jp->jobctl = jobctl;
649         jp->next = NULL;
650 #endif
651         if (nprocs > 1) {
652                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
653         } else {
654                 jp->ps = &jp->ps0;
655         }
656         INTON;
657         TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
658             jp - jobtab + 1));
659         return jp;
660 }
661
662 #if JOBS
663 static void
664 setcurjob(struct job *cj)
665 {
666         struct job *jp, *prev;
667
668         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
669                 if (jp == cj) {
670                         if (prev != NULL)
671                                 prev->next = jp->next;
672                         else
673                                 jobmru = jp->next;
674                         jp->next = jobmru;
675                         jobmru = cj;
676                         return;
677                 }
678         }
679         cj->next = jobmru;
680         jobmru = cj;
681 }
682
683 static void
684 deljob(struct job *j)
685 {
686         struct job *jp, *prev;
687
688         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
689                 if (jp == j) {
690                         if (prev != NULL)
691                                 prev->next = jp->next;
692                         else
693                                 jobmru = jp->next;
694                         return;
695                 }
696         }
697 }
698
699 /*
700  * Return the most recently used job that isn't `nj', and preferably one
701  * that is stopped.
702  */
703 static struct job *
704 getcurjob(struct job *nj)
705 {
706         struct job *jp;
707
708         /* Try to find a stopped one.. */
709         for (jp = jobmru; jp != NULL; jp = jp->next)
710                 if (jp->used && jp != nj && jp->state == JOBSTOPPED)
711                         return (jp);
712         /* Otherwise the most recently used job that isn't `nj' */
713         for (jp = jobmru; jp != NULL; jp = jp->next)
714                 if (jp->used && jp != nj)
715                         return (jp);
716
717         return (NULL);
718 }
719
720 #endif
721
722 /*
723  * Fork of a subshell.  If we are doing job control, give the subshell its
724  * own process group.  Jp is a job structure that the job is to be added to.
725  * N is the command that will be evaluated by the child.  Both jp and n may
726  * be NULL.  The mode parameter can be one of the following:
727  *      FORK_FG - Fork off a foreground process.
728  *      FORK_BG - Fork off a background process.
729  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
730  *                   process group even if job control is on.
731  *
732  * When job control is turned off, background processes have their standard
733  * input redirected to /dev/null (except for the second and later processes
734  * in a pipeline).
735  */
736
737 pid_t
738 forkshell(struct job *jp, union node *n, int mode)
739 {
740         pid_t pid;
741         pid_t pgrp;
742
743         TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
744             mode));
745         INTOFF;
746         if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
747                 checkzombies();
748         flushall();
749         pid = fork();
750         if (pid == -1) {
751                 TRACE(("Fork failed, errno=%d\n", errno));
752                 INTON;
753                 error("Cannot fork: %s", strerror(errno));
754         }
755         if (pid == 0) {
756                 struct job *p;
757                 int wasroot;
758                 int i;
759
760                 TRACE(("Child shell %d\n", (int)getpid()));
761                 wasroot = rootshell;
762                 rootshell = 0;
763                 closescript();
764                 INTON;
765                 clear_traps();
766 #if JOBS
767                 jobctl = 0;             /* do job control only in root shell */
768                 if (wasroot && mode != FORK_NOJOB && mflag) {
769                         if (jp == NULL || jp->nprocs == 0)
770                                 pgrp = getpid();
771                         else
772                                 pgrp = jp->ps[0].pid;
773                         if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
774                                 /*** this causes superfluous TIOCSPGRPS ***/
775                                 if (tcsetpgrp(ttyfd, pgrp) < 0)
776                                         error("tcsetpgrp failed, errno=%d", errno);
777                         }
778                         setsignal(SIGTSTP);
779                         setsignal(SIGTTOU);
780                 } else if (mode == FORK_BG) {
781                         ignoresig(SIGINT);
782                         ignoresig(SIGQUIT);
783                         if ((jp == NULL || jp->nprocs == 0) &&
784                             ! fd0_redirected_p ()) {
785                                 close(0);
786                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
787                                         error("Can't open %s: %s",
788                                             _PATH_DEVNULL, strerror(errno));
789                         }
790                 }
791 #else
792                 if (mode == FORK_BG) {
793                         ignoresig(SIGINT);
794                         ignoresig(SIGQUIT);
795                         if ((jp == NULL || jp->nprocs == 0) &&
796                             ! fd0_redirected_p ()) {
797                                 close(0);
798                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
799                                         error("Can't open %s: %s",
800                                             _PATH_DEVNULL, strerror(errno));
801                         }
802                 }
803 #endif
804                 INTOFF;
805                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
806                         if (p->used)
807                                 freejob(p);
808                 INTON;
809                 if (wasroot && iflag) {
810                         setsignal(SIGINT);
811                         setsignal(SIGQUIT);
812                         setsignal(SIGTERM);
813                 }
814                 return pid;
815         }
816         if (rootshell && mode != FORK_NOJOB && mflag) {
817                 if (jp == NULL || jp->nprocs == 0)
818                         pgrp = pid;
819                 else
820                         pgrp = jp->ps[0].pid;
821                 setpgid(pid, pgrp);
822         }
823         if (mode == FORK_BG)
824                 backgndpid = pid;               /* set $! */
825         if (jp) {
826                 struct procstat *ps = &jp->ps[jp->nprocs++];
827                 ps->pid = pid;
828                 ps->status = -1;
829                 ps->cmd = nullstr;
830                 if (iflag && rootshell && n)
831                         ps->cmd = commandtext(n);
832                 jp->foreground = mode == FORK_FG;
833 #if JOBS
834                 setcurjob(jp);
835 #endif
836         }
837         INTON;
838         TRACE(("In parent shell:  child = %d\n", (int)pid));
839         return pid;
840 }
841
842
843
844 /*
845  * Wait for job to finish.
846  *
847  * Under job control we have the problem that while a child process is
848  * running interrupts generated by the user are sent to the child but not
849  * to the shell.  This means that an infinite loop started by an inter-
850  * active user may be hard to kill.  With job control turned off, an
851  * interactive user may place an interactive program inside a loop.  If
852  * the interactive program catches interrupts, the user doesn't want
853  * these interrupts to also abort the loop.  The approach we take here
854  * is to have the shell ignore interrupt signals while waiting for a
855  * foreground process to terminate, and then send itself an interrupt
856  * signal if the child process was terminated by an interrupt signal.
857  * Unfortunately, some programs want to do a bit of cleanup and then
858  * exit on interrupt; unless these processes terminate themselves by
859  * sending a signal to themselves (instead of calling exit) they will
860  * confuse this approach.
861  */
862
863 int
864 waitforjob(struct job *jp, int *origstatus)
865 {
866 #if JOBS
867         pid_t mypgrp = getpgrp();
868         int propagate_int = jp->jobctl && jp->foreground;
869 #endif
870         int status;
871         int st;
872
873         INTOFF;
874         TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
875         while (jp->state == 0)
876                 if (dowait(1, jp) == -1)
877                         dotrap();
878 #if JOBS
879         if (jp->jobctl) {
880                 if (tcsetpgrp(ttyfd, mypgrp) < 0)
881                         error("tcsetpgrp failed, errno=%d\n", errno);
882         }
883         if (jp->state == JOBSTOPPED)
884                 setcurjob(jp);
885 #endif
886         status = jp->ps[jp->nprocs - 1].status;
887         if (origstatus != NULL)
888                 *origstatus = status;
889         /* convert to 8 bits */
890         if (WIFEXITED(status))
891                 st = WEXITSTATUS(status);
892 #if JOBS
893         else if (WIFSTOPPED(status))
894                 st = WSTOPSIG(status) + 128;
895 #endif
896         else
897                 st = WTERMSIG(status) + 128;
898         if (! JOBS || jp->state == JOBDONE)
899                 freejob(jp);
900         if (int_pending()) {
901                 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
902                         kill(getpid(), SIGINT);
903                 else
904                         CLEAR_PENDING_INT;
905         }
906 #if JOBS
907         else if (rootshell && iflag && propagate_int &&
908                         WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
909                 kill(getpid(), SIGINT);
910 #endif
911         INTON;
912         return st;
913 }
914
915
916
917 /*
918  * Wait for a process to terminate.
919  */
920
921 static pid_t
922 dowait(int block, struct job *job)
923 {
924         pid_t pid;
925         int status;
926         struct procstat *sp;
927         struct job *jp;
928         struct job *thisjob;
929         int done;
930         int stopped;
931         int sig;
932         int i;
933
934         in_dowait++;
935         TRACE(("dowait(%d) called\n", block));
936         do {
937                 pid = waitproc(block, &status);
938                 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
939         } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
940                  (pid > 0 && WIFSTOPPED(status) && !iflag));
941         in_dowait--;
942         if (pid == -1 && errno == ECHILD && job != NULL)
943                 job->state = JOBDONE;
944         if (breakwaitcmd != 0) {
945                 breakwaitcmd = 0;
946                 if (pid <= 0)
947                         return -1;
948         }
949         if (pid <= 0)
950                 return pid;
951         INTOFF;
952         thisjob = NULL;
953         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
954                 if (jp->used && jp->nprocs > 0) {
955                         done = 1;
956                         stopped = 1;
957                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
958                                 if (sp->pid == -1)
959                                         continue;
960                                 if (sp->pid == pid) {
961                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
962                                                    (int)pid, sp->status,
963                                                    status));
964                                         sp->status = status;
965                                         thisjob = jp;
966                                 }
967                                 if (sp->status == -1)
968                                         stopped = 0;
969                                 else if (WIFSTOPPED(sp->status))
970                                         done = 0;
971                         }
972                         if (stopped) {          /* stopped or done */
973                                 int state = done? JOBDONE : JOBSTOPPED;
974                                 if (jp->state != state) {
975                                         TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
976                                         jp->state = state;
977 #if JOBS
978                                         if (done)
979                                                 deljob(jp);
980 #endif
981                                 }
982                         }
983                 }
984         }
985         INTON;
986         if (! rootshell || ! iflag || (job && thisjob == job)) {
987 #if JOBS
988                 if (WIFSTOPPED(status))
989                         sig = WSTOPSIG(status);
990                 else
991 #endif
992                 {
993                         if (WIFEXITED(status))
994                                 sig = 0;
995                         else
996                                 sig = WTERMSIG(status);
997                 }
998                 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
999                         if (!mflag ||
1000                             (thisjob->foreground && !WIFSTOPPED(status))) {
1001                                 i = WTERMSIG(status);
1002                                 if ((i & 0x7F) < sys_nsig && sys_siglist[i & 0x7F])
1003                                         out1str(sys_siglist[i & 0x7F]);
1004                                 else
1005                                         out1fmt("Signal %d", i & 0x7F);
1006                                 if (WCOREDUMP(status))
1007                                         out1str(" (core dumped)");
1008                                 out1c('\n');
1009                         } else
1010                                 showjob(thisjob, pid, SHOWJOBS_DEFAULT);
1011                         flushout(out1);
1012                 }
1013         } else {
1014                 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1015                 if (thisjob)
1016                         thisjob->changed = 1;
1017         }
1018         return pid;
1019 }
1020
1021
1022
1023 /*
1024  * Do a wait system call.  If job control is compiled in, we accept
1025  * stopped processes.  If block is zero, we return a value of zero
1026  * rather than blocking.
1027  */
1028 static pid_t
1029 waitproc(int block, int *status)
1030 {
1031         int flags;
1032
1033 #if JOBS
1034         flags = WUNTRACED;
1035 #else
1036         flags = 0;
1037 #endif
1038         if (block == 0)
1039                 flags |= WNOHANG;
1040         return wait3(status, flags, (struct rusage *)NULL);
1041 }
1042
1043 /*
1044  * return 1 if there are stopped jobs, otherwise 0
1045  */
1046 int job_warning = 0;
1047 int
1048 stoppedjobs(void)
1049 {
1050         int jobno;
1051         struct job *jp;
1052
1053         if (job_warning)
1054                 return (0);
1055         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1056                 if (jp->used == 0)
1057                         continue;
1058                 if (jp->state == JOBSTOPPED) {
1059                         out2str("You have stopped jobs.\n");
1060                         job_warning = 2;
1061                         return (1);
1062                 }
1063         }
1064
1065         return (0);
1066 }
1067
1068
1069 static void
1070 checkzombies(void)
1071 {
1072         while (njobs > 0 && dowait(0, NULL) > 0)
1073                 ;
1074 }
1075
1076
1077 /*
1078  * Return a string identifying a command (to be printed by the
1079  * jobs command.
1080  */
1081
1082 static char *cmdnextc;
1083 static int cmdnleft;
1084 #define MAXCMDTEXT      200
1085
1086 char *
1087 commandtext(union node *n)
1088 {
1089         char *name;
1090
1091         cmdnextc = name = ckmalloc(MAXCMDTEXT);
1092         cmdnleft = MAXCMDTEXT - 4;
1093         cmdtxt(n);
1094         *cmdnextc = '\0';
1095         return name;
1096 }
1097
1098
1099 static void
1100 cmdtxt(union node *n)
1101 {
1102         union node *np;
1103         struct nodelist *lp;
1104         const char *p;
1105         int i;
1106         char s[2];
1107
1108         if (n == NULL)
1109                 return;
1110         switch (n->type) {
1111         case NSEMI:
1112                 cmdtxt(n->nbinary.ch1);
1113                 cmdputs("; ");
1114                 cmdtxt(n->nbinary.ch2);
1115                 break;
1116         case NAND:
1117                 cmdtxt(n->nbinary.ch1);
1118                 cmdputs(" && ");
1119                 cmdtxt(n->nbinary.ch2);
1120                 break;
1121         case NOR:
1122                 cmdtxt(n->nbinary.ch1);
1123                 cmdputs(" || ");
1124                 cmdtxt(n->nbinary.ch2);
1125                 break;
1126         case NPIPE:
1127                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1128                         cmdtxt(lp->n);
1129                         if (lp->next)
1130                                 cmdputs(" | ");
1131                 }
1132                 break;
1133         case NSUBSHELL:
1134                 cmdputs("(");
1135                 cmdtxt(n->nredir.n);
1136                 cmdputs(")");
1137                 break;
1138         case NREDIR:
1139         case NBACKGND:
1140                 cmdtxt(n->nredir.n);
1141                 break;
1142         case NIF:
1143                 cmdputs("if ");
1144                 cmdtxt(n->nif.test);
1145                 cmdputs("; then ");
1146                 cmdtxt(n->nif.ifpart);
1147                 cmdputs("...");
1148                 break;
1149         case NWHILE:
1150                 cmdputs("while ");
1151                 goto until;
1152         case NUNTIL:
1153                 cmdputs("until ");
1154 until:
1155                 cmdtxt(n->nbinary.ch1);
1156                 cmdputs("; do ");
1157                 cmdtxt(n->nbinary.ch2);
1158                 cmdputs("; done");
1159                 break;
1160         case NFOR:
1161                 cmdputs("for ");
1162                 cmdputs(n->nfor.var);
1163                 cmdputs(" in ...");
1164                 break;
1165         case NCASE:
1166                 cmdputs("case ");
1167                 cmdputs(n->ncase.expr->narg.text);
1168                 cmdputs(" in ...");
1169                 break;
1170         case NDEFUN:
1171                 cmdputs(n->narg.text);
1172                 cmdputs("() ...");
1173                 break;
1174         case NCMD:
1175                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1176                         cmdtxt(np);
1177                         if (np->narg.next)
1178                                 cmdputs(" ");
1179                 }
1180                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1181                         cmdputs(" ");
1182                         cmdtxt(np);
1183                 }
1184                 break;
1185         case NARG:
1186                 cmdputs(n->narg.text);
1187                 break;
1188         case NTO:
1189                 p = ">";  i = 1;  goto redir;
1190         case NAPPEND:
1191                 p = ">>";  i = 1;  goto redir;
1192         case NTOFD:
1193                 p = ">&";  i = 1;  goto redir;
1194         case NCLOBBER:
1195                 p = ">|"; i = 1; goto redir;
1196         case NFROM:
1197                 p = "<";  i = 0;  goto redir;
1198         case NFROMTO:
1199                 p = "<>";  i = 0;  goto redir;
1200         case NFROMFD:
1201                 p = "<&";  i = 0;  goto redir;
1202 redir:
1203                 if (n->nfile.fd != i) {
1204                         s[0] = n->nfile.fd + '0';
1205                         s[1] = '\0';
1206                         cmdputs(s);
1207                 }
1208                 cmdputs(p);
1209                 if (n->type == NTOFD || n->type == NFROMFD) {
1210                         if (n->ndup.dupfd >= 0)
1211                                 s[0] = n->ndup.dupfd + '0';
1212                         else
1213                                 s[0] = '-';
1214                         s[1] = '\0';
1215                         cmdputs(s);
1216                 } else {
1217                         cmdtxt(n->nfile.fname);
1218                 }
1219                 break;
1220         case NHERE:
1221         case NXHERE:
1222                 cmdputs("<<...");
1223                 break;
1224         default:
1225                 cmdputs("???");
1226                 break;
1227         }
1228 }
1229
1230
1231
1232 static void
1233 cmdputs(const char *s)
1234 {
1235         const char *p;
1236         char *q;
1237         char c;
1238         int subtype = 0;
1239
1240         if (cmdnleft <= 0)
1241                 return;
1242         p = s;
1243         q = cmdnextc;
1244         while ((c = *p++) != '\0') {
1245                 if (c == CTLESC)
1246                         *q++ = *p++;
1247                 else if (c == CTLVAR) {
1248                         *q++ = '$';
1249                         if (--cmdnleft > 0)
1250                                 *q++ = '{';
1251                         subtype = *p++;
1252                 } else if (c == '=' && subtype != 0) {
1253                         *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1254                         subtype = 0;
1255                 } else if (c == CTLENDVAR) {
1256                         *q++ = '}';
1257                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1258                         cmdnleft++;             /* ignore it */
1259                 else
1260                         *q++ = c;
1261                 if (--cmdnleft <= 0) {
1262                         *q++ = '.';
1263                         *q++ = '.';
1264                         *q++ = '.';
1265                         break;
1266                 }
1267         }
1268         cmdnextc = q;
1269 }