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