]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - bin/sh/jobs.c
MFC r230998,r233792: sh: Use vfork in a few common cases.
[FreeBSD/stable/9.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, char **argv)
463 {
464         struct job *job;
465         int status, retval;
466         struct job *jp;
467
468         if (argc > 1) {
469                 job = getjob(argv[1]);
470         } else {
471                 job = NULL;
472         }
473
474         /*
475          * Loop until a process is terminated or stopped, or a SIGINT is
476          * received.
477          */
478
479         in_waitcmd++;
480         do {
481                 if (job != NULL) {
482                         if (job->state) {
483                                 status = job->ps[job->nprocs - 1].status;
484                                 if (WIFEXITED(status))
485                                         retval = WEXITSTATUS(status);
486 #if JOBS
487                                 else if (WIFSTOPPED(status))
488                                         retval = WSTOPSIG(status) + 128;
489 #endif
490                                 else
491                                         retval = WTERMSIG(status) + 128;
492                                 if (! iflag || ! job->changed)
493                                         freejob(job);
494                                 else {
495                                         job->remembered = 0;
496                                         if (job == bgjob)
497                                                 bgjob = NULL;
498                                 }
499                                 in_waitcmd--;
500                                 return retval;
501                         }
502                 } else {
503                         for (jp = jobtab ; jp < jobtab + njobs; jp++)
504                                 if (jp->used && jp->state == JOBDONE) {
505                                         if (! iflag || ! jp->changed)
506                                                 freejob(jp);
507                                         else {
508                                                 jp->remembered = 0;
509                                                 if (jp == bgjob)
510                                                         bgjob = NULL;
511                                         }
512                                 }
513                         for (jp = jobtab ; ; jp++) {
514                                 if (jp >= jobtab + njobs) {     /* no running procs */
515                                         in_waitcmd--;
516                                         return 0;
517                                 }
518                                 if (jp->used && jp->state == 0)
519                                         break;
520                         }
521                 }
522         } while (dowait(1, (struct job *)NULL) != -1);
523         in_waitcmd--;
524
525         return 0;
526 }
527
528
529
530 int
531 jobidcmd(int argc __unused, char **argv)
532 {
533         struct job *jp;
534         int i;
535
536         jp = getjob(argv[1]);
537         for (i = 0 ; i < jp->nprocs ; ) {
538                 out1fmt("%d", (int)jp->ps[i].pid);
539                 out1c(++i < jp->nprocs? ' ' : '\n');
540         }
541         return 0;
542 }
543
544
545
546 /*
547  * Convert a job name to a job structure.
548  */
549
550 static struct job *
551 getjob(char *name)
552 {
553         int jobno;
554         struct job *found, *jp;
555         pid_t pid;
556         int i;
557
558         if (name == NULL) {
559 #if JOBS
560 currentjob:     if ((jp = getcurjob(NULL)) == NULL)
561                         error("No current job");
562                 return (jp);
563 #else
564                 error("No current job");
565 #endif
566         } else if (name[0] == '%') {
567                 if (is_digit(name[1])) {
568                         jobno = number(name + 1);
569                         if (jobno > 0 && jobno <= njobs
570                          && jobtab[jobno - 1].used != 0)
571                                 return &jobtab[jobno - 1];
572 #if JOBS
573                 } else if (name[1] == '%' && name[2] == '\0') {
574                         goto currentjob;
575                 } else if (name[1] == '+' && name[2] == '\0') {
576                         goto currentjob;
577                 } else if (name[1] == '-' && name[2] == '\0') {
578                         if ((jp = getcurjob(NULL)) == NULL ||
579                             (jp = getcurjob(jp)) == NULL)
580                                 error("No previous job");
581                         return (jp);
582 #endif
583                 } else if (name[1] == '?') {
584                         found = NULL;
585                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
586                                 if (jp->used && jp->nprocs > 0
587                                  && strstr(jp->ps[0].cmd, name + 2) != NULL) {
588                                         if (found)
589                                                 error("%s: ambiguous", name);
590                                         found = jp;
591                                 }
592                         }
593                         if (found != NULL)
594                                 return (found);
595                 } else {
596                         found = NULL;
597                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
598                                 if (jp->used && jp->nprocs > 0
599                                  && prefix(name + 1, jp->ps[0].cmd)) {
600                                         if (found)
601                                                 error("%s: ambiguous", name);
602                                         found = jp;
603                                 }
604                         }
605                         if (found)
606                                 return found;
607                 }
608         } else if (is_number(name)) {
609                 pid = (pid_t)number(name);
610                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
611                         if (jp->used && jp->nprocs > 0
612                          && jp->ps[jp->nprocs - 1].pid == pid)
613                                 return jp;
614                 }
615         }
616         error("No such job: %s", name);
617         /*NOTREACHED*/
618         return NULL;
619 }
620
621
622 pid_t
623 getjobpgrp(char *name)
624 {
625         struct job *jp;
626
627         jp = getjob(name);
628         return -jp->ps[0].pid;
629 }
630
631 /*
632  * Return a new job structure,
633  */
634
635 struct job *
636 makejob(union node *node __unused, int nprocs)
637 {
638         int i;
639         struct job *jp;
640
641         for (i = njobs, jp = jobtab ; ; jp++) {
642                 if (--i < 0) {
643                         INTOFF;
644                         if (njobs == 0) {
645                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
646 #if JOBS
647                                 jobmru = NULL;
648 #endif
649                         } else {
650                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
651                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
652 #if JOBS
653                                 /* Relocate `next' pointers and list head */
654                                 if (jobmru != NULL)
655                                         jobmru = &jp[jobmru - jobtab];
656                                 for (i = 0; i < njobs; i++)
657                                         if (jp[i].next != NULL)
658                                                 jp[i].next = &jp[jp[i].next -
659                                                     jobtab];
660 #endif
661                                 if (bgjob != NULL)
662                                         bgjob = &jp[bgjob - jobtab];
663                                 /* Relocate `ps' pointers */
664                                 for (i = 0; i < njobs; i++)
665                                         if (jp[i].ps == &jobtab[i].ps0)
666                                                 jp[i].ps = &jp[i].ps0;
667                                 ckfree(jobtab);
668                                 jobtab = jp;
669                         }
670                         jp = jobtab + njobs;
671                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
672                         INTON;
673                         break;
674                 }
675                 if (jp->used == 0)
676                         break;
677         }
678         INTOFF;
679         jp->state = 0;
680         jp->used = 1;
681         jp->changed = 0;
682         jp->nprocs = 0;
683         jp->foreground = 0;
684         jp->remembered = 0;
685 #if JOBS
686         jp->jobctl = jobctl;
687         jp->next = NULL;
688 #endif
689         if (nprocs > 1) {
690                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
691         } else {
692                 jp->ps = &jp->ps0;
693         }
694         INTON;
695         TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
696             jp - jobtab + 1));
697         return jp;
698 }
699
700 #if JOBS
701 static void
702 setcurjob(struct job *cj)
703 {
704         struct job *jp, *prev;
705
706         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
707                 if (jp == cj) {
708                         if (prev != NULL)
709                                 prev->next = jp->next;
710                         else
711                                 jobmru = jp->next;
712                         jp->next = jobmru;
713                         jobmru = cj;
714                         return;
715                 }
716         }
717         cj->next = jobmru;
718         jobmru = cj;
719 }
720
721 static void
722 deljob(struct job *j)
723 {
724         struct job *jp, *prev;
725
726         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
727                 if (jp == j) {
728                         if (prev != NULL)
729                                 prev->next = jp->next;
730                         else
731                                 jobmru = jp->next;
732                         return;
733                 }
734         }
735 }
736
737 /*
738  * Return the most recently used job that isn't `nj', and preferably one
739  * that is stopped.
740  */
741 static struct job *
742 getcurjob(struct job *nj)
743 {
744         struct job *jp;
745
746         /* Try to find a stopped one.. */
747         for (jp = jobmru; jp != NULL; jp = jp->next)
748                 if (jp->used && jp != nj && jp->state == JOBSTOPPED)
749                         return (jp);
750         /* Otherwise the most recently used job that isn't `nj' */
751         for (jp = jobmru; jp != NULL; jp = jp->next)
752                 if (jp->used && jp != nj)
753                         return (jp);
754
755         return (NULL);
756 }
757
758 #endif
759
760 /*
761  * Fork of a subshell.  If we are doing job control, give the subshell its
762  * own process group.  Jp is a job structure that the job is to be added to.
763  * N is the command that will be evaluated by the child.  Both jp and n may
764  * be NULL.  The mode parameter can be one of the following:
765  *      FORK_FG - Fork off a foreground process.
766  *      FORK_BG - Fork off a background process.
767  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
768  *                   process group even if job control is on.
769  *
770  * When job control is turned off, background processes have their standard
771  * input redirected to /dev/null (except for the second and later processes
772  * in a pipeline).
773  */
774
775 pid_t
776 forkshell(struct job *jp, union node *n, int mode)
777 {
778         pid_t pid;
779         pid_t pgrp;
780
781         TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
782             mode));
783         INTOFF;
784         if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
785                 checkzombies();
786         flushall();
787         pid = fork();
788         if (pid == -1) {
789                 TRACE(("Fork failed, errno=%d\n", errno));
790                 INTON;
791                 error("Cannot fork: %s", strerror(errno));
792         }
793         if (pid == 0) {
794                 struct job *p;
795                 int wasroot;
796                 int i;
797
798                 TRACE(("Child shell %d\n", (int)getpid()));
799                 wasroot = rootshell;
800                 rootshell = 0;
801                 handler = &main_handler;
802                 closescript();
803                 INTON;
804                 forcelocal = 0;
805                 clear_traps();
806 #if JOBS
807                 jobctl = 0;             /* do job control only in root shell */
808                 if (wasroot && mode != FORK_NOJOB && mflag) {
809                         if (jp == NULL || jp->nprocs == 0)
810                                 pgrp = getpid();
811                         else
812                                 pgrp = jp->ps[0].pid;
813                         if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
814                                 /*** this causes superfluous TIOCSPGRPS ***/
815                                 if (tcsetpgrp(ttyfd, pgrp) < 0)
816                                         error("tcsetpgrp failed, errno=%d", errno);
817                         }
818                         setsignal(SIGTSTP);
819                         setsignal(SIGTTOU);
820                 } else if (mode == FORK_BG) {
821                         ignoresig(SIGINT);
822                         ignoresig(SIGQUIT);
823                         if ((jp == NULL || jp->nprocs == 0) &&
824                             ! fd0_redirected_p ()) {
825                                 close(0);
826                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
827                                         error("cannot open %s: %s",
828                                             _PATH_DEVNULL, strerror(errno));
829                         }
830                 }
831 #else
832                 if (mode == FORK_BG) {
833                         ignoresig(SIGINT);
834                         ignoresig(SIGQUIT);
835                         if ((jp == NULL || jp->nprocs == 0) &&
836                             ! fd0_redirected_p ()) {
837                                 close(0);
838                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
839                                         error("cannot open %s: %s",
840                                             _PATH_DEVNULL, strerror(errno));
841                         }
842                 }
843 #endif
844                 INTOFF;
845                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
846                         if (p->used)
847                                 freejob(p);
848                 INTON;
849                 if (wasroot && iflag) {
850                         setsignal(SIGINT);
851                         setsignal(SIGQUIT);
852                         setsignal(SIGTERM);
853                 }
854                 return pid;
855         }
856         if (rootshell && mode != FORK_NOJOB && mflag) {
857                 if (jp == NULL || jp->nprocs == 0)
858                         pgrp = pid;
859                 else
860                         pgrp = jp->ps[0].pid;
861                 setpgid(pid, pgrp);
862         }
863         if (mode == FORK_BG) {
864                 if (bgjob != NULL && bgjob->state == JOBDONE &&
865                     !bgjob->remembered && !iflag)
866                         freejob(bgjob);
867                 backgndpid = pid;               /* set $! */
868                 bgjob = jp;
869         }
870         if (jp) {
871                 struct procstat *ps = &jp->ps[jp->nprocs++];
872                 ps->pid = pid;
873                 ps->status = -1;
874                 ps->cmd = nullstr;
875                 if (iflag && rootshell && n)
876                         ps->cmd = commandtext(n);
877                 jp->foreground = mode == FORK_FG;
878 #if JOBS
879                 setcurjob(jp);
880 #endif
881         }
882         INTON;
883         TRACE(("In parent shell:  child = %d\n", (int)pid));
884         return pid;
885 }
886
887
888 pid_t
889 vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
890 {
891         pid_t pid;
892         struct jmploc jmploc;
893         struct jmploc *savehandler;
894
895         TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
896             (void *)pip));
897         INTOFF;
898         flushall();
899         savehandler = handler;
900         pid = vfork();
901         if (pid == -1) {
902                 TRACE(("Vfork failed, errno=%d\n", errno));
903                 INTON;
904                 error("Cannot fork: %s", strerror(errno));
905         }
906         if (pid == 0) {
907                 TRACE(("Child shell %d\n", (int)getpid()));
908                 if (setjmp(jmploc.loc))
909                         _exit(exception == EXEXEC ? exerrno : 2);
910                 if (pip != NULL) {
911                         close(pip[0]);
912                         if (pip[1] != 1) {
913                                 dup2(pip[1], 1);
914                                 close(pip[1]);
915                         }
916                 }
917                 handler = &jmploc;
918                 shellexec(argv, envp, path, idx);
919         }
920         handler = savehandler;
921         if (jp) {
922                 struct procstat *ps = &jp->ps[jp->nprocs++];
923                 ps->pid = pid;
924                 ps->status = -1;
925                 ps->cmd = nullstr;
926                 jp->foreground = 1;
927 #if JOBS
928                 setcurjob(jp);
929 #endif
930         }
931         INTON;
932         TRACE(("In parent shell:  child = %d\n", (int)pid));
933         return pid;
934 }
935
936
937 /*
938  * Wait for job to finish.
939  *
940  * Under job control we have the problem that while a child process is
941  * running interrupts generated by the user are sent to the child but not
942  * to the shell.  This means that an infinite loop started by an inter-
943  * active user may be hard to kill.  With job control turned off, an
944  * interactive user may place an interactive program inside a loop.  If
945  * the interactive program catches interrupts, the user doesn't want
946  * these interrupts to also abort the loop.  The approach we take here
947  * is to have the shell ignore interrupt signals while waiting for a
948  * foreground process to terminate, and then send itself an interrupt
949  * signal if the child process was terminated by an interrupt signal.
950  * Unfortunately, some programs want to do a bit of cleanup and then
951  * exit on interrupt; unless these processes terminate themselves by
952  * sending a signal to themselves (instead of calling exit) they will
953  * confuse this approach.
954  */
955
956 int
957 waitforjob(struct job *jp, int *origstatus)
958 {
959 #if JOBS
960         pid_t mypgrp = getpgrp();
961         int propagate_int = jp->jobctl && jp->foreground;
962 #endif
963         int status;
964         int st;
965
966         INTOFF;
967         TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
968         while (jp->state == 0)
969                 if (dowait(1, jp) == -1)
970                         dotrap();
971 #if JOBS
972         if (jp->jobctl) {
973                 if (tcsetpgrp(ttyfd, mypgrp) < 0)
974                         error("tcsetpgrp failed, errno=%d\n", errno);
975         }
976         if (jp->state == JOBSTOPPED)
977                 setcurjob(jp);
978 #endif
979         status = jp->ps[jp->nprocs - 1].status;
980         if (origstatus != NULL)
981                 *origstatus = status;
982         /* convert to 8 bits */
983         if (WIFEXITED(status))
984                 st = WEXITSTATUS(status);
985 #if JOBS
986         else if (WIFSTOPPED(status))
987                 st = WSTOPSIG(status) + 128;
988 #endif
989         else
990                 st = WTERMSIG(status) + 128;
991         if (! JOBS || jp->state == JOBDONE)
992                 freejob(jp);
993         if (int_pending()) {
994                 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
995                         CLEAR_PENDING_INT;
996         }
997 #if JOBS
998         else if (rootshell && iflag && propagate_int &&
999                         WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
1000                 kill(getpid(), SIGINT);
1001 #endif
1002         INTON;
1003         return st;
1004 }
1005
1006
1007
1008 /*
1009  * Wait for a process to terminate.
1010  */
1011
1012 static pid_t
1013 dowait(int block, struct job *job)
1014 {
1015         pid_t pid;
1016         int status;
1017         struct procstat *sp;
1018         struct job *jp;
1019         struct job *thisjob;
1020         int done;
1021         int stopped;
1022         int sig;
1023         int coredump;
1024
1025         in_dowait++;
1026         TRACE(("dowait(%d) called\n", block));
1027         do {
1028                 pid = waitproc(block, &status);
1029                 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
1030         } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
1031                  (pid > 0 && WIFSTOPPED(status) && !iflag));
1032         in_dowait--;
1033         if (pid == -1 && errno == ECHILD && job != NULL)
1034                 job->state = JOBDONE;
1035         if (breakwaitcmd != 0) {
1036                 breakwaitcmd = 0;
1037                 if (pid <= 0)
1038                         return -1;
1039         }
1040         if (pid <= 0)
1041                 return pid;
1042         INTOFF;
1043         thisjob = NULL;
1044         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
1045                 if (jp->used && jp->nprocs > 0) {
1046                         done = 1;
1047                         stopped = 1;
1048                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
1049                                 if (sp->pid == -1)
1050                                         continue;
1051                                 if (sp->pid == pid) {
1052                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
1053                                                    (int)pid, sp->status,
1054                                                    status));
1055                                         sp->status = status;
1056                                         thisjob = jp;
1057                                 }
1058                                 if (sp->status == -1)
1059                                         stopped = 0;
1060                                 else if (WIFSTOPPED(sp->status))
1061                                         done = 0;
1062                         }
1063                         if (stopped) {          /* stopped or done */
1064                                 int state = done? JOBDONE : JOBSTOPPED;
1065                                 if (jp->state != state) {
1066                                         TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
1067                                         jp->state = state;
1068                                         if (jp != job) {
1069                                                 if (done && !jp->remembered &&
1070                                                     !iflag && jp != bgjob)
1071                                                         freejob(jp);
1072 #if JOBS
1073                                                 else if (done)
1074                                                         deljob(jp);
1075 #endif
1076                                         }
1077                                 }
1078                         }
1079                 }
1080         }
1081         INTON;
1082         if (!thisjob || thisjob->state == 0)
1083                 ;
1084         else if ((!rootshell || !iflag || thisjob == job) &&
1085             thisjob->foreground && thisjob->state != JOBSTOPPED) {
1086                 sig = 0;
1087                 coredump = 0;
1088                 for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
1089                         if (WIFSIGNALED(sp->status)) {
1090                                 sig = WTERMSIG(sp->status);
1091                                 coredump = WCOREDUMP(sp->status);
1092                         }
1093                 if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
1094                         if (sig < sys_nsig && sys_siglist[sig])
1095                                 out2str(sys_siglist[sig]);
1096                         else
1097                                 outfmt(out2, "Signal %d", sig);
1098                         if (coredump)
1099                                 out2str(" (core dumped)");
1100                         out2c('\n');
1101                         flushout(out2);
1102                 }
1103         } else {
1104                 TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
1105                 thisjob->changed = 1;
1106         }
1107         return pid;
1108 }
1109
1110
1111
1112 /*
1113  * Do a wait system call.  If job control is compiled in, we accept
1114  * stopped processes.  If block is zero, we return a value of zero
1115  * rather than blocking.
1116  */
1117 static pid_t
1118 waitproc(int block, int *status)
1119 {
1120         int flags;
1121
1122 #if JOBS
1123         flags = WUNTRACED;
1124 #else
1125         flags = 0;
1126 #endif
1127         if (block == 0)
1128                 flags |= WNOHANG;
1129         return wait3(status, flags, (struct rusage *)NULL);
1130 }
1131
1132 /*
1133  * return 1 if there are stopped jobs, otherwise 0
1134  */
1135 int job_warning = 0;
1136 int
1137 stoppedjobs(void)
1138 {
1139         int jobno;
1140         struct job *jp;
1141
1142         if (job_warning)
1143                 return (0);
1144         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1145                 if (jp->used == 0)
1146                         continue;
1147                 if (jp->state == JOBSTOPPED) {
1148                         out2fmt_flush("You have stopped jobs.\n");
1149                         job_warning = 2;
1150                         return (1);
1151                 }
1152         }
1153
1154         return (0);
1155 }
1156
1157
1158 static void
1159 checkzombies(void)
1160 {
1161         while (njobs > 0 && dowait(0, NULL) > 0)
1162                 ;
1163 }
1164
1165
1166 int
1167 backgndpidset(void)
1168 {
1169         return backgndpid != -1;
1170 }
1171
1172
1173 pid_t
1174 backgndpidval(void)
1175 {
1176         if (bgjob != NULL && !forcelocal)
1177                 bgjob->remembered = 1;
1178         return backgndpid;
1179 }
1180
1181 /*
1182  * Return a string identifying a command (to be printed by the
1183  * jobs command.
1184  */
1185
1186 static char *cmdnextc;
1187 static int cmdnleft;
1188 #define MAXCMDTEXT      200
1189
1190 char *
1191 commandtext(union node *n)
1192 {
1193         char *name;
1194
1195         cmdnextc = name = ckmalloc(MAXCMDTEXT);
1196         cmdnleft = MAXCMDTEXT - 4;
1197         cmdtxt(n);
1198         *cmdnextc = '\0';
1199         return name;
1200 }
1201
1202
1203 static void
1204 cmdtxt(union node *n)
1205 {
1206         union node *np;
1207         struct nodelist *lp;
1208         const char *p;
1209         int i;
1210         char s[2];
1211
1212         if (n == NULL)
1213                 return;
1214         switch (n->type) {
1215         case NSEMI:
1216                 cmdtxt(n->nbinary.ch1);
1217                 cmdputs("; ");
1218                 cmdtxt(n->nbinary.ch2);
1219                 break;
1220         case NAND:
1221                 cmdtxt(n->nbinary.ch1);
1222                 cmdputs(" && ");
1223                 cmdtxt(n->nbinary.ch2);
1224                 break;
1225         case NOR:
1226                 cmdtxt(n->nbinary.ch1);
1227                 cmdputs(" || ");
1228                 cmdtxt(n->nbinary.ch2);
1229                 break;
1230         case NPIPE:
1231                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1232                         cmdtxt(lp->n);
1233                         if (lp->next)
1234                                 cmdputs(" | ");
1235                 }
1236                 break;
1237         case NSUBSHELL:
1238                 cmdputs("(");
1239                 cmdtxt(n->nredir.n);
1240                 cmdputs(")");
1241                 break;
1242         case NREDIR:
1243         case NBACKGND:
1244                 cmdtxt(n->nredir.n);
1245                 break;
1246         case NIF:
1247                 cmdputs("if ");
1248                 cmdtxt(n->nif.test);
1249                 cmdputs("; then ");
1250                 cmdtxt(n->nif.ifpart);
1251                 cmdputs("...");
1252                 break;
1253         case NWHILE:
1254                 cmdputs("while ");
1255                 goto until;
1256         case NUNTIL:
1257                 cmdputs("until ");
1258 until:
1259                 cmdtxt(n->nbinary.ch1);
1260                 cmdputs("; do ");
1261                 cmdtxt(n->nbinary.ch2);
1262                 cmdputs("; done");
1263                 break;
1264         case NFOR:
1265                 cmdputs("for ");
1266                 cmdputs(n->nfor.var);
1267                 cmdputs(" in ...");
1268                 break;
1269         case NCASE:
1270                 cmdputs("case ");
1271                 cmdputs(n->ncase.expr->narg.text);
1272                 cmdputs(" in ...");
1273                 break;
1274         case NDEFUN:
1275                 cmdputs(n->narg.text);
1276                 cmdputs("() ...");
1277                 break;
1278         case NCMD:
1279                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1280                         cmdtxt(np);
1281                         if (np->narg.next)
1282                                 cmdputs(" ");
1283                 }
1284                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1285                         cmdputs(" ");
1286                         cmdtxt(np);
1287                 }
1288                 break;
1289         case NARG:
1290                 cmdputs(n->narg.text);
1291                 break;
1292         case NTO:
1293                 p = ">";  i = 1;  goto redir;
1294         case NAPPEND:
1295                 p = ">>";  i = 1;  goto redir;
1296         case NTOFD:
1297                 p = ">&";  i = 1;  goto redir;
1298         case NCLOBBER:
1299                 p = ">|"; i = 1; goto redir;
1300         case NFROM:
1301                 p = "<";  i = 0;  goto redir;
1302         case NFROMTO:
1303                 p = "<>";  i = 0;  goto redir;
1304         case NFROMFD:
1305                 p = "<&";  i = 0;  goto redir;
1306 redir:
1307                 if (n->nfile.fd != i) {
1308                         s[0] = n->nfile.fd + '0';
1309                         s[1] = '\0';
1310                         cmdputs(s);
1311                 }
1312                 cmdputs(p);
1313                 if (n->type == NTOFD || n->type == NFROMFD) {
1314                         if (n->ndup.dupfd >= 0)
1315                                 s[0] = n->ndup.dupfd + '0';
1316                         else
1317                                 s[0] = '-';
1318                         s[1] = '\0';
1319                         cmdputs(s);
1320                 } else {
1321                         cmdtxt(n->nfile.fname);
1322                 }
1323                 break;
1324         case NHERE:
1325         case NXHERE:
1326                 cmdputs("<<...");
1327                 break;
1328         default:
1329                 cmdputs("???");
1330                 break;
1331         }
1332 }
1333
1334
1335
1336 static void
1337 cmdputs(const char *s)
1338 {
1339         const char *p;
1340         char *q;
1341         char c;
1342         int subtype = 0;
1343
1344         if (cmdnleft <= 0)
1345                 return;
1346         p = s;
1347         q = cmdnextc;
1348         while ((c = *p++) != '\0') {
1349                 if (c == CTLESC)
1350                         *q++ = *p++;
1351                 else if (c == CTLVAR) {
1352                         *q++ = '$';
1353                         if (--cmdnleft > 0)
1354                                 *q++ = '{';
1355                         subtype = *p++;
1356                         if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
1357                                 *q++ = '#';
1358                 } else if (c == '=' && subtype != 0) {
1359                         *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
1360                         if (*q)
1361                                 q++;
1362                         else
1363                                 cmdnleft++;
1364                         if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
1365                             (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
1366                             --cmdnleft > 0)
1367                                 *q = q[-1], q++;
1368                         subtype = 0;
1369                 } else if (c == CTLENDVAR) {
1370                         *q++ = '}';
1371                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
1372                         cmdnleft -= 5;
1373                         if (cmdnleft > 0) {
1374                                 *q++ = '$';
1375                                 *q++ = '(';
1376                                 *q++ = '.';
1377                                 *q++ = '.';
1378                                 *q++ = '.';
1379                                 *q++ = ')';
1380                         }
1381                 } else if (c == CTLARI) {
1382                         cmdnleft -= 2;
1383                         if (cmdnleft > 0) {
1384                                 *q++ = '$';
1385                                 *q++ = '(';
1386                                 *q++ = '(';
1387                         }
1388                         p++;
1389                 } else if (c == CTLENDARI) {
1390                         if (--cmdnleft > 0) {
1391                                 *q++ = ')';
1392                                 *q++ = ')';
1393                         }
1394                 } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
1395                         cmdnleft++; /* ignore */
1396                 else
1397                         *q++ = c;
1398                 if (--cmdnleft <= 0) {
1399                         *q++ = '.';
1400                         *q++ = '.';
1401                         *q++ = '.';
1402                         break;
1403                 }
1404         }
1405         cmdnextc = q;
1406 }