758ba575fc824274d04a832cbaa66f3caa6aa7b7
[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.27.2.10 2003/04/04 08:16:26 tjr Exp $
38  * $DragonFly: src/bin/sh/jobs.c,v 1.2 2003/06/17 04:22:50 dillon 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 struct job *jobtab;             /* array of jobs */
76 int njobs;                      /* size of array */
77 MKINIT pid_t backgndpid = -1;   /* pid of last background process */
78 #if JOBS
79 struct job *jobmru;             /* most recently used job list */
80 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(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, 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, (int *)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, "[%d] ", 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, sformat, lformat;
269
270         optind = optreset = 1;
271         opterr = 0;
272         sformat = lformat = 0;
273         while ((ch = getopt(argc, argv, "ls")) != -1) {
274                 switch (ch) {
275                 case 'l':
276                         lformat = 1;
277                         break;
278                 case 's':
279                         sformat = 1;
280                         break;
281                 case '?':
282                 default:
283                         error("unknown option: -%c", optopt);
284                 }
285         }
286         argc -= optind;
287         argv += optind;
288
289         if (argc == 0)
290                 showjobs(0, sformat, lformat);
291         else
292                 while ((id = *argv++) != NULL)
293                         showjob(getjob(id), 0, sformat, lformat);
294
295         return (0);
296 }
297
298 STATIC void
299 showjob(struct job *jp, pid_t pid, int sformat, int lformat)
300 {
301         char s[64];
302         struct procstat *ps;
303         struct job *j;
304         int col, curr, i, jobno, prev, procno;
305         char c;
306
307         procno = jp->nprocs;
308         jobno = jp - jobtab + 1;
309         curr = prev = 0;
310 #if JOBS
311         if ((j = getcurjob(NULL)) != NULL) {
312                 curr = j - jobtab + 1;
313                 if ((j = getcurjob(j)) != NULL)
314                         prev = j - jobtab + 1;
315         }
316 #endif
317         for (ps = jp->ps ; ; ps++) {    /* for each process */
318                 if (sformat) {
319                         out1fmt("%d\n", (int)ps->pid);
320                         goto skip;
321                 }
322                 if (!lformat && ps != jp->ps && pid == 0)
323                         goto skip;
324                 if (pid != 0 && pid != ps->pid)
325                         goto skip;
326                 if (jobno == curr && ps == jp->ps)
327                         c = '+';
328                 else if (jobno == prev && ps == jp->ps)
329                         c = '-';
330                 else
331                         c = ' ';
332                 if (ps == jp->ps)
333                         fmtstr(s, 64, "[%d] %c ", jobno, c);
334                 else
335                         fmtstr(s, 64, "    %c ", c);
336                 out1str(s);
337                 col = strlen(s);
338                 if (lformat) {
339                         fmtstr(s, 64, "%d ", (int)ps->pid);
340                         out1str(s);
341                         col += strlen(s);
342                 }
343                 s[0] = '\0';
344                 if (ps != jp->ps) {
345                         *s = '\0';
346                 } else if (ps->status == -1) {
347                         strcpy(s, "Running");
348                 } else if (WIFEXITED(ps->status)) {
349                         if (WEXITSTATUS(ps->status) == 0)
350                                 strcpy(s, "Done");
351                         else
352                                 fmtstr(s, 64, "Done (%d)",
353                                     WEXITSTATUS(ps->status));
354                 } else {
355 #if JOBS
356                         if (WIFSTOPPED(ps->status)) 
357                                 i = WSTOPSIG(ps->status);
358                         else
359 #endif
360                                 i = WTERMSIG(ps->status);
361                         if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
362                                 scopy(sys_siglist[i & 0x7F], s);
363                         else
364                                 fmtstr(s, 64, "Signal %d", i & 0x7F);
365                         if (WCOREDUMP(ps->status))
366                                 strcat(s, " (core dumped)");
367                 }
368                 out1str(s);
369                 col += strlen(s);
370                 do {
371                         out1c(' ');
372                         col++;
373                 } while (col < 30);
374                 out1str(ps->cmd);
375                 out1c('\n');
376 skip:           if (--procno <= 0)
377                         break;
378         }
379 }
380
381 /*
382  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
383  * statuses have changed since the last call to showjobs.
384  *
385  * If the shell is interrupted in the process of creating a job, the
386  * result may be a job structure containing zero processes.  Such structures
387  * will be freed here.
388  */
389
390 void
391 showjobs(int change, int sformat, int lformat)
392 {
393         int jobno;
394         struct job *jp;
395
396         TRACE(("showjobs(%d) called\n", change));
397         while (dowait(0, (struct job *)NULL) > 0);
398         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
399                 if (! jp->used)
400                         continue;
401                 if (jp->nprocs == 0) {
402                         freejob(jp);
403                         continue;
404                 }
405                 if (change && ! jp->changed)
406                         continue;
407                 showjob(jp, 0, sformat, lformat);
408                 jp->changed = 0;
409                 if (jp->state == JOBDONE) {
410                         freejob(jp);
411                 }
412         }
413 }
414
415
416 /*
417  * Mark a job structure as unused.
418  */
419
420 STATIC void
421 freejob(struct job *jp)
422 {
423         struct procstat *ps;
424         int i;
425
426         INTOFF;
427         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
428                 if (ps->cmd != nullstr)
429                         ckfree(ps->cmd);
430         }
431         if (jp->ps != &jp->ps0)
432                 ckfree(jp->ps);
433         jp->used = 0;
434 #if JOBS
435         deljob(jp);
436 #endif
437         INTON;
438 }
439
440
441
442 int
443 waitcmd(int argc, char **argv)
444 {
445         struct job *job;
446         int status, retval;
447         struct job *jp;
448
449         if (argc > 1) {
450                 job = getjob(argv[1]);
451         } else {
452                 job = NULL;
453         }
454
455         /*
456          * Loop until a process is terminated or stopped, or a SIGINT is
457          * received.
458          */
459
460         in_waitcmd++;
461         do {
462                 if (job != NULL) {
463                         if (job->state) {
464                                 status = job->ps[job->nprocs - 1].status;
465                                 if (WIFEXITED(status))
466                                         retval = WEXITSTATUS(status);
467 #if JOBS
468                                 else if (WIFSTOPPED(status))
469                                         retval = WSTOPSIG(status) + 128;
470 #endif
471                                 else
472                                         retval = WTERMSIG(status) + 128;
473                                 if (! iflag)
474                                         freejob(job);
475                                 in_waitcmd--;
476                                 return retval;
477                         }
478                 } else {
479                         for (jp = jobtab ; ; jp++) {
480                                 if (jp >= jobtab + njobs) {     /* no running procs */
481                                         in_waitcmd--;
482                                         return 0;
483                                 }
484                                 if (jp->used && jp->state == 0)
485                                         break;
486                         }
487                 }
488         } while (dowait(1, (struct job *)NULL) != -1);
489         in_waitcmd--;
490
491         return 0;
492 }
493
494
495
496 int
497 jobidcmd(int argc __unused, char **argv)
498 {
499         struct job *jp;
500         int i;
501
502         jp = getjob(argv[1]);
503         for (i = 0 ; i < jp->nprocs ; ) {
504                 out1fmt("%d", (int)jp->ps[i].pid);
505                 out1c(++i < jp->nprocs? ' ' : '\n');
506         }
507         return 0;
508 }
509
510
511
512 /*
513  * Convert a job name to a job structure.
514  */
515
516 STATIC struct job *
517 getjob(char *name)
518 {
519         int jobno;
520         struct job *found, *jp;
521         pid_t pid;
522         int i;
523
524         if (name == NULL) {
525 #if JOBS
526 currentjob:     if ((jp = getcurjob(NULL)) == NULL)
527                         error("No current job");
528                 return (jp);
529 #else
530                 error("No current job");
531 #endif
532         } else if (name[0] == '%') {
533                 if (is_digit(name[1])) {
534                         jobno = number(name + 1);
535                         if (jobno > 0 && jobno <= njobs
536                          && jobtab[jobno - 1].used != 0)
537                                 return &jobtab[jobno - 1];
538 #if JOBS
539                 } else if (name[1] == '%' && name[2] == '\0') {
540                         goto currentjob;
541                 } else if (name[1] == '+' && name[2] == '\0') {
542                         goto currentjob;
543                 } else if (name[1] == '-' && name[2] == '\0') {
544                         if ((jp = getcurjob(NULL)) == NULL ||
545                             (jp = getcurjob(jp)) == NULL)
546                                 error("No previous job");
547                         return (jp);
548 #endif
549                 } else if (name[1] == '?') {
550                         found = NULL;
551                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
552                                 if (jp->used && jp->nprocs > 0
553                                  && strstr(jp->ps[0].cmd, name + 2) != NULL) {
554                                         if (found)
555                                                 error("%s: ambiguous", name);
556                                         found = jp;
557                                 }
558                         }
559                         if (found != NULL)
560                                 return (found);
561                 } else {
562                         found = NULL;
563                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
564                                 if (jp->used && jp->nprocs > 0
565                                  && prefix(name + 1, jp->ps[0].cmd)) {
566                                         if (found)
567                                                 error("%s: ambiguous", name);
568                                         found = jp;
569                                 }
570                         }
571                         if (found)
572                                 return found;
573                 }
574         } else if (is_number(name)) {
575                 pid = (pid_t)number(name);
576                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
577                         if (jp->used && jp->nprocs > 0
578                          && jp->ps[jp->nprocs - 1].pid == pid)
579                                 return jp;
580                 }
581         }
582         error("No such job: %s", name);
583         /*NOTREACHED*/
584         return NULL;
585 }
586
587
588
589 /*
590  * Return a new job structure,
591  */
592
593 struct job *
594 makejob(union node *node __unused, int nprocs)
595 {
596         int i;
597         struct job *jp;
598
599         for (i = njobs, jp = jobtab ; ; jp++) {
600                 if (--i < 0) {
601                         INTOFF;
602                         if (njobs == 0) {
603                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
604 #if JOBS
605                                 jobmru = NULL;
606 #endif
607                         } else {
608                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
609                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
610 #if JOBS
611                                 /* Relocate `next' pointers and list head */
612                                 if (jobmru != NULL)
613                                         jobmru = &jp[jobmru - jobtab];
614                                 for (i = 0; i < njobs; i++)
615                                         if (jp[i].next != NULL)
616                                                 jp[i].next = &jp[jp[i].next -
617                                                     jobtab];
618 #endif
619                                 /* Relocate `ps' pointers */
620                                 for (i = 0; i < njobs; i++)
621                                         if (jp[i].ps == &jobtab[i].ps0)
622                                                 jp[i].ps = &jp[i].ps0;
623                                 ckfree(jobtab);
624                                 jobtab = jp;
625                         }
626                         jp = jobtab + njobs;
627                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
628                         INTON;
629                         break;
630                 }
631                 if (jp->used == 0)
632                         break;
633         }
634         INTOFF;
635         jp->state = 0;
636         jp->used = 1;
637         jp->changed = 0;
638         jp->nprocs = 0;
639         jp->foreground = 0;
640 #if JOBS
641         jp->jobctl = jobctl;
642         jp->next = NULL;
643 #endif
644         if (nprocs > 1) {
645                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
646         } else {
647                 jp->ps = &jp->ps0;
648         }
649         INTON;
650         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
651             jp - jobtab + 1));
652         return jp;
653 }
654
655 #if JOBS
656 STATIC void
657 setcurjob(struct job *cj)
658 {
659         struct job *jp, *prev;
660
661         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
662                 if (jp == cj) {
663                         if (prev != NULL)
664                                 prev->next = jp->next;
665                         else
666                                 jobmru = jp->next;
667                         jp->next = jobmru;
668                         jobmru = cj;
669                         return;
670                 }
671         }
672         cj->next = jobmru;
673         jobmru = cj;
674 }
675
676 STATIC void
677 deljob(struct job *j)
678 {
679         struct job *jp, *prev;
680
681         for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
682                 if (jp == j) {
683                         if (prev != NULL)
684                                 prev->next = jp->next;
685                         else
686                                 jobmru = jp->next;
687                         return;
688                 }
689         }
690 }
691
692 /*
693  * Return the most recently used job that isn't `nj', and preferably one
694  * that is stopped.
695  */
696 STATIC struct job *
697 getcurjob(struct job *nj)
698 {
699         struct job *jp;
700
701         /* Try to find a stopped one.. */
702         for (jp = jobmru; jp != NULL; jp = jp->next)
703                 if (jp->used && jp != nj && jp->state == JOBSTOPPED)
704                         return (jp);
705         /* Otherwise the most recently used job that isn't `nj' */
706         for (jp = jobmru; jp != NULL; jp = jp->next)
707                 if (jp->used && jp != nj)
708                         return (jp);
709
710         return (NULL);
711 }
712
713 #endif
714
715 /*
716  * Fork of a subshell.  If we are doing job control, give the subshell its
717  * own process group.  Jp is a job structure that the job is to be added to.
718  * N is the command that will be evaluated by the child.  Both jp and n may
719  * be NULL.  The mode parameter can be one of the following:
720  *      FORK_FG - Fork off a foreground process.
721  *      FORK_BG - Fork off a background process.
722  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
723  *                   process group even if job control is on.
724  *
725  * When job control is turned off, background processes have their standard
726  * input redirected to /dev/null (except for the second and later processes
727  * in a pipeline).
728  */
729
730 pid_t
731 forkshell(struct job *jp, union node *n, int mode)
732 {
733         pid_t pid;
734         pid_t pgrp;
735
736         TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
737             mode));
738         INTOFF;
739         flushall();
740         pid = fork();
741         if (pid == -1) {
742                 TRACE(("Fork failed, errno=%d\n", errno));
743                 INTON;
744                 error("Cannot fork: %s", strerror(errno));
745         }
746         if (pid == 0) {
747                 struct job *p;
748                 int wasroot;
749                 int i;
750
751                 TRACE(("Child shell %d\n", (int)getpid()));
752                 wasroot = rootshell;
753                 rootshell = 0;
754                 closescript();
755                 INTON;
756                 clear_traps();
757 #if JOBS
758                 jobctl = 0;             /* do job control only in root shell */
759                 if (wasroot && mode != FORK_NOJOB && mflag) {
760                         if (jp == NULL || jp->nprocs == 0)
761                                 pgrp = getpid();
762                         else
763                                 pgrp = jp->ps[0].pid;
764                         if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
765                                 /*** this causes superfluous TIOCSPGRPS ***/
766                                 if (tcsetpgrp(ttyfd, pgrp) < 0)
767                                         error("tcsetpgrp failed, errno=%d", errno);
768                         }
769                         setsignal(SIGTSTP);
770                         setsignal(SIGTTOU);
771                 } else if (mode == FORK_BG) {
772                         ignoresig(SIGINT);
773                         ignoresig(SIGQUIT);
774                         if ((jp == NULL || jp->nprocs == 0) &&
775                             ! fd0_redirected_p ()) {
776                                 close(0);
777                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
778                                         error("Can't open %s: %s",
779                                             _PATH_DEVNULL, strerror(errno));
780                         }
781                 }
782 #else
783                 if (mode == FORK_BG) {
784                         ignoresig(SIGINT);
785                         ignoresig(SIGQUIT);
786                         if ((jp == NULL || jp->nprocs == 0) &&
787                             ! fd0_redirected_p ()) {
788                                 close(0);
789                                 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
790                                         error("Can't open %s: %s", 
791                                             _PATH_DEVNULL, strerror(errno));
792                         }
793                 }
794 #endif
795                 INTOFF;
796                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
797                         if (p->used)
798                                 freejob(p);
799                 INTON;
800                 if (wasroot && iflag) {
801                         setsignal(SIGINT);
802                         setsignal(SIGQUIT);
803                         setsignal(SIGTERM);
804                 }
805                 return pid;
806         }
807         if (rootshell && mode != FORK_NOJOB && mflag) {
808                 if (jp == NULL || jp->nprocs == 0)
809                         pgrp = pid;
810                 else
811                         pgrp = jp->ps[0].pid;
812                 setpgid(pid, pgrp);
813         }
814         if (mode == FORK_BG)
815                 backgndpid = pid;               /* set $! */
816         if (jp) {
817                 struct procstat *ps = &jp->ps[jp->nprocs++];
818                 ps->pid = pid;
819                 ps->status = -1;
820                 ps->cmd = nullstr;
821                 if (iflag && rootshell && n)
822                         ps->cmd = commandtext(n);
823                 jp->foreground = mode == FORK_FG;
824 #if JOBS
825                 setcurjob(jp);
826 #endif
827         }
828         INTON;
829         TRACE(("In parent shell:  child = %d\n", (int)pid));
830         return pid;
831 }
832
833
834
835 /*
836  * Wait for job to finish.
837  *
838  * Under job control we have the problem that while a child process is
839  * running interrupts generated by the user are sent to the child but not
840  * to the shell.  This means that an infinite loop started by an inter-
841  * active user may be hard to kill.  With job control turned off, an
842  * interactive user may place an interactive program inside a loop.  If
843  * the interactive program catches interrupts, the user doesn't want
844  * these interrupts to also abort the loop.  The approach we take here
845  * is to have the shell ignore interrupt signals while waiting for a
846  * foreground process to terminate, and then send itself an interrupt
847  * signal if the child process was terminated by an interrupt signal.
848  * Unfortunately, some programs want to do a bit of cleanup and then
849  * exit on interrupt; unless these processes terminate themselves by
850  * sending a signal to themselves (instead of calling exit) they will
851  * confuse this approach.
852  */
853
854 int
855 waitforjob(struct job *jp, int *origstatus)
856 {
857 #if JOBS
858         pid_t mypgrp = getpgrp();
859 #endif
860         int status;
861         int st;
862
863         INTOFF;
864         TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
865         while (jp->state == 0)
866                 if (dowait(1, jp) == -1)
867                         dotrap();
868 #if JOBS
869         if (jp->jobctl) {
870                 if (tcsetpgrp(ttyfd, mypgrp) < 0)
871                         error("tcsetpgrp failed, errno=%d\n", errno);
872         }
873         if (jp->state == JOBSTOPPED)
874                 setcurjob(jp);
875 #endif
876         status = jp->ps[jp->nprocs - 1].status;
877         if (origstatus != NULL)
878                 *origstatus = status;
879         /* convert to 8 bits */
880         if (WIFEXITED(status))
881                 st = WEXITSTATUS(status);
882 #if JOBS
883         else if (WIFSTOPPED(status))
884                 st = WSTOPSIG(status) + 128;
885 #endif
886         else
887                 st = WTERMSIG(status) + 128;
888         if (! JOBS || jp->state == JOBDONE)
889                 freejob(jp);
890         if (int_pending()) {
891                 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
892                         kill(getpid(), SIGINT);
893                 else
894                         CLEAR_PENDING_INT;
895         }
896         INTON;
897         return st;
898 }
899
900
901
902 /*
903  * Wait for a process to terminate.
904  */
905
906 STATIC pid_t
907 dowait(int block, struct job *job)
908 {
909         pid_t pid;
910         int status;
911         struct procstat *sp;
912         struct job *jp;
913         struct job *thisjob;
914         int done;
915         int stopped;
916         int sig;
917         int i;
918
919         in_dowait++;
920         TRACE(("dowait(%d) called\n", block));
921         do {
922                 pid = waitproc(block, &status);
923                 TRACE(("wait returns %d, status=%d\n", (int)pid, status));
924         } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
925             (WIFSTOPPED(status) && !iflag));
926         in_dowait--;
927         if (breakwaitcmd != 0) {
928                 breakwaitcmd = 0;
929                 return -1;
930         }
931         if (pid <= 0)
932                 return pid;
933         INTOFF;
934         thisjob = NULL;
935         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
936                 if (jp->used) {
937                         done = 1;
938                         stopped = 1;
939                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
940                                 if (sp->pid == -1)
941                                         continue;
942                                 if (sp->pid == pid) {
943                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
944                                                    (int)pid, sp->status,
945                                                    status));
946                                         sp->status = status;
947                                         thisjob = jp;
948                                 }
949                                 if (sp->status == -1)
950                                         stopped = 0;
951                                 else if (WIFSTOPPED(sp->status))
952                                         done = 0;
953                         }
954                         if (stopped) {          /* stopped or done */
955                                 int state = done? JOBDONE : JOBSTOPPED;
956                                 if (jp->state != state) {
957                                         TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
958                                         jp->state = state;
959 #if JOBS
960                                         if (done)
961                                                 deljob(jp);
962 #endif
963                                 }
964                         }
965                 }
966         }
967         INTON;
968         if (! rootshell || ! iflag || (job && thisjob == job)) {
969 #if JOBS
970                 if (WIFSTOPPED(status))
971                         sig = WSTOPSIG(status);
972                 else
973 #endif
974                 {
975                         if (WIFEXITED(status))
976                                 sig = 0;
977                         else
978                                 sig = WTERMSIG(status);
979                 }
980                 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
981                         if (!mflag ||
982                             (thisjob->foreground && !WIFSTOPPED(status))) {
983                                 i = WTERMSIG(status);
984                                 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
985                                         out1str(sys_siglist[i & 0x7F]);
986                                 else
987                                         out1fmt("Signal %d", i & 0x7F);
988                                 if (WCOREDUMP(status))
989                                         out1str(" (core dumped)");
990                                 out1c('\n');
991                         } else
992                                 showjob(thisjob, pid, 0, 0);
993                 }
994         } else {
995                 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
996                 if (thisjob)
997                         thisjob->changed = 1;
998         }
999         return pid;
1000 }
1001
1002
1003
1004 /*
1005  * Do a wait system call.  If job control is compiled in, we accept
1006  * stopped processes.  If block is zero, we return a value of zero
1007  * rather than blocking.
1008  */
1009 STATIC pid_t
1010 waitproc(int block, int *status)
1011 {
1012         int flags;
1013
1014 #if JOBS
1015         flags = WUNTRACED;
1016 #else
1017         flags = 0;
1018 #endif
1019         if (block == 0)
1020                 flags |= WNOHANG;
1021         return wait3(status, flags, (struct rusage *)NULL);
1022 }
1023
1024 /*
1025  * return 1 if there are stopped jobs, otherwise 0
1026  */
1027 int job_warning = 0;
1028 int
1029 stoppedjobs(void)
1030 {
1031         int jobno;
1032         struct job *jp;
1033
1034         if (job_warning)
1035                 return (0);
1036         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
1037                 if (jp->used == 0)
1038                         continue;
1039                 if (jp->state == JOBSTOPPED) {
1040                         out2str("You have stopped jobs.\n");
1041                         job_warning = 2;
1042                         return (1);
1043                 }
1044         }
1045
1046         return (0);
1047 }
1048
1049 /*
1050  * Return a string identifying a command (to be printed by the
1051  * jobs command.
1052  */
1053
1054 STATIC char *cmdnextc;
1055 STATIC int cmdnleft;
1056 #define MAXCMDTEXT      200
1057
1058 char *
1059 commandtext(union node *n)
1060 {
1061         char *name;
1062
1063         cmdnextc = name = ckmalloc(MAXCMDTEXT);
1064         cmdnleft = MAXCMDTEXT - 4;
1065         cmdtxt(n);
1066         *cmdnextc = '\0';
1067         return name;
1068 }
1069
1070
1071 STATIC void
1072 cmdtxt(union node *n)
1073 {
1074         union node *np;
1075         struct nodelist *lp;
1076         char *p;
1077         int i;
1078         char s[2];
1079
1080         if (n == NULL)
1081                 return;
1082         switch (n->type) {
1083         case NSEMI:
1084                 cmdtxt(n->nbinary.ch1);
1085                 cmdputs("; ");
1086                 cmdtxt(n->nbinary.ch2);
1087                 break;
1088         case NAND:
1089                 cmdtxt(n->nbinary.ch1);
1090                 cmdputs(" && ");
1091                 cmdtxt(n->nbinary.ch2);
1092                 break;
1093         case NOR:
1094                 cmdtxt(n->nbinary.ch1);
1095                 cmdputs(" || ");
1096                 cmdtxt(n->nbinary.ch2);
1097                 break;
1098         case NPIPE:
1099                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1100                         cmdtxt(lp->n);
1101                         if (lp->next)
1102                                 cmdputs(" | ");
1103                 }
1104                 break;
1105         case NSUBSHELL:
1106                 cmdputs("(");
1107                 cmdtxt(n->nredir.n);
1108                 cmdputs(")");
1109                 break;
1110         case NREDIR:
1111         case NBACKGND:
1112                 cmdtxt(n->nredir.n);
1113                 break;
1114         case NIF:
1115                 cmdputs("if ");
1116                 cmdtxt(n->nif.test);
1117                 cmdputs("; then ");
1118                 cmdtxt(n->nif.ifpart);
1119                 cmdputs("...");
1120                 break;
1121         case NWHILE:
1122                 cmdputs("while ");
1123                 goto until;
1124         case NUNTIL:
1125                 cmdputs("until ");
1126 until:
1127                 cmdtxt(n->nbinary.ch1);
1128                 cmdputs("; do ");
1129                 cmdtxt(n->nbinary.ch2);
1130                 cmdputs("; done");
1131                 break;
1132         case NFOR:
1133                 cmdputs("for ");
1134                 cmdputs(n->nfor.var);
1135                 cmdputs(" in ...");
1136                 break;
1137         case NCASE:
1138                 cmdputs("case ");
1139                 cmdputs(n->ncase.expr->narg.text);
1140                 cmdputs(" in ...");
1141                 break;
1142         case NDEFUN:
1143                 cmdputs(n->narg.text);
1144                 cmdputs("() ...");
1145                 break;
1146         case NCMD:
1147                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
1148                         cmdtxt(np);
1149                         if (np->narg.next)
1150                                 cmdputs(" ");
1151                 }
1152                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
1153                         cmdputs(" ");
1154                         cmdtxt(np);
1155                 }
1156                 break;
1157         case NARG:
1158                 cmdputs(n->narg.text);
1159                 break;
1160         case NTO:
1161                 p = ">";  i = 1;  goto redir;
1162         case NAPPEND:
1163                 p = ">>";  i = 1;  goto redir;
1164         case NTOFD:
1165                 p = ">&";  i = 1;  goto redir;
1166         case NCLOBBER:
1167                 p = ">|"; i = 1; goto redir;
1168         case NFROM:
1169                 p = "<";  i = 0;  goto redir;
1170         case NFROMTO:
1171                 p = "<>";  i = 0;  goto redir;
1172         case NFROMFD:
1173                 p = "<&";  i = 0;  goto redir;
1174 redir:
1175                 if (n->nfile.fd != i) {
1176                         s[0] = n->nfile.fd + '0';
1177                         s[1] = '\0';
1178                         cmdputs(s);
1179                 }
1180                 cmdputs(p);
1181                 if (n->type == NTOFD || n->type == NFROMFD) {
1182                         if (n->ndup.dupfd >= 0)
1183                                 s[0] = n->ndup.dupfd + '0';
1184                         else
1185                                 s[0] = '-';
1186                         s[1] = '\0';
1187                         cmdputs(s);
1188                 } else {
1189                         cmdtxt(n->nfile.fname);
1190                 }
1191                 break;
1192         case NHERE:
1193         case NXHERE:
1194                 cmdputs("<<...");
1195                 break;
1196         default:
1197                 cmdputs("???");
1198                 break;
1199         }
1200 }
1201
1202
1203
1204 STATIC void
1205 cmdputs(char *s)
1206 {
1207         char *p, *q;
1208         char c;
1209         int subtype = 0;
1210
1211         if (cmdnleft <= 0)
1212                 return;
1213         p = s;
1214         q = cmdnextc;
1215         while ((c = *p++) != '\0') {
1216                 if (c == CTLESC)
1217                         *q++ = *p++;
1218                 else if (c == CTLVAR) {
1219                         *q++ = '$';
1220                         if (--cmdnleft > 0)
1221                                 *q++ = '{';
1222                         subtype = *p++;
1223                 } else if (c == '=' && subtype != 0) {
1224                         *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
1225                         subtype = 0;
1226                 } else if (c == CTLENDVAR) {
1227                         *q++ = '}';
1228                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
1229                         cmdnleft++;             /* ignore it */
1230                 else
1231                         *q++ = c;
1232                 if (--cmdnleft <= 0) {
1233                         *q++ = '.';
1234                         *q++ = '.';
1235                         *q++ = '.';
1236                         break;
1237                 }
1238         }
1239         cmdnextc = q;
1240 }