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