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