1 /* $Header: /src/pub/tcsh/sh.proc.c,v 3.90 2005/03/03 19:57:07 kim Exp $ */
3 * sh.proc.c: Job manipulations
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$Id: sh.proc.c,v 3.90 2005/03/03 19:57:07 kim Exp $")
44 #endif /* WINNT_NATIVE */
50 #if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) || defined(linux) || defined(__GNU__) || defined(__GLIBC__)
52 #endif /* _BSD || (IRIS4D && __STDC__) || __lucid || glibc */
54 # define WTERMSIG(w) (((union wait *) &(w))->w_termsig)
57 # endif /* !BSDWAIT */
58 #endif /* !WTERMSIG */
60 # define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode)
61 #endif /* !WEXITSTATUS */
63 # define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig)
64 #endif /* !WSTOPSIG */
68 # define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
74 # define WCOREDUMP(w) (((union wait *) &(w))->w_coredump)
76 # define WCOREDUMP(w) ((w) & 0200)
77 # endif /* !BSDWAIT */
78 #endif /* !WCOREDUMP */
81 * C Shell - functions that manage processes, handling hanging, termination
84 #define BIGINDEX 9 /* largest desirable job index */
88 /* use 'cvxrusage' to get parallel statistics */
89 static struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L,
90 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
91 {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L,
92 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}};
94 static struct rusage zru;
98 static struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
100 # else /* !_SEQUENT_ */
102 static struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0};
104 static struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L};
106 # endif /* !_SEQUENT_ */
107 #endif /* !BSDTIMES */
109 #ifndef RUSAGE_CHILDREN
110 # define RUSAGE_CHILDREN -1
111 #endif /* RUSAGE_CHILDREN */
113 static void pflushall __P((void));
114 static void pflush __P((struct process *));
115 static void pfree __P((struct process *));
116 static void pclrcurr __P((struct process *));
117 static void padd __P((struct command *));
118 static int pprint __P((struct process *, int));
119 static void ptprint __P((struct process *));
120 static void pads __P((Char *));
121 static void pkill __P((Char **, int));
122 static struct process *pgetcurr __P((struct process *));
123 static void okpcntl __P((void));
124 static void setttypgrp __P((int));
127 * pchild - called at interrupt level by the SIGCHLD signal
128 * indicating that at least one child has terminated or stopped
129 * thus at least one wait system call will definitely return a
130 * childs status. Top level routines (like pwait) must be sure
131 * to mask interrupts when playing with the proclist data structures!
145 #endif /* !BSDWAIT */
149 #else /* !BSDTIMES */
151 struct process_stats ru;
152 struct process_stats cpst1, cpst2;
154 # else /* !_SEQUENT_ */
155 struct tms proctimes;
159 (void) times(&shtimes);
161 # endif /* !_SEQUENT_ */
162 #endif /* !BSDTIMES */
166 xprintf("pchild()\n");
167 #endif /* JOBDEBUG */
169 /* Christos on where the signal(SIGCHLD, pchild) shoud be:
171 * I think that it should go *after* the wait, unlike most signal handlers.
173 * In release two (for which I have manuals), it says that wait will remove
174 * the first child from the queue of dead children.
175 * All the rest of the children that die while in the signal handler of the
176 * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish
177 * the signal handler, and there are items in the queue, the process will
178 * receive another SIGC(H)LD before signal returns. BTW this is from the
179 * manual page on comp-sim... Maybe it is not applicable to the hp's, but
180 * I read on the news in comp.unix.wizards or comp.unix.questions yesterday
181 * that another person was claiming the the signal() call should be after
186 errno = 0; /* reset, just in case */
188 xprintf("Waiting...\n");
190 #endif /* JOBDEBUG */
195 /* use 'cvxwait' to get parallel statistics */
197 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
199 /* both a wait3 and rusage */
200 # if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(linux) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && (__STDC__ || defined(PROTOTYPES)) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__)
202 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
204 pid = wait3(&w.w_status,
205 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
206 # endif /* BSDWAIT */
208 # else /* !BSDTIMES */
210 (void) get_process_stats(&tv, PS_SELF, 0, &cpst1);
211 pid = waitpid(-1, &w,
212 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
213 (void) get_process_stats(&tv, PS_SELF, 0, &cpst2);
214 pr_stat_sub(&cpst2, &cpst1, &ru);
215 # else /* !_SEQUENT_ */
217 /* we have a wait3, but no rusage stuff */
218 pid = wait3(&w.w_status,
219 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
221 pid = waitpid(-1, &w,
222 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
224 # endif /* !_SEQUENT_ */
225 # endif /* !BSDTIMES */
226 # else /* !BSDJOBS */
229 /* both a wait3 and rusage */
231 pid = wait3(&w.w_status, WNOHANG, 0);
233 pid = wait3(&w.w_status, WNOHANG, &ru);
235 # else /* !BSDTIMES */
236 # ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */
238 pid = waitpid(-1, &w,
239 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
241 # if defined(aiws) || defined(uts)
243 pid = wait3(&w.w_status,
244 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
245 # endif /* aiws || uts */
248 /* no wait3, therefore no rusage */
249 /* on Sys V, this may hang. I hope it's not going to be a problem */
253 pid = ourwait(&w.w_status);
255 # else /* !UNRELSIGS */
257 * XXX: for greater than 3 we should use waitpid().
258 * but then again, SVR4 falls into the POSIX/BSDJOBS category.
260 pid = wait(&w.w_status);
261 # endif /* !UNRELSIGS */
262 # endif /* !HAVEwait3 */
263 # endif /* !BSDTIMES */
265 (void) sigset(SIGCHLD, pchild);
266 # endif /* !BSDSIGS */
267 # endif /* !BSDJOBS */
268 #else /* WINNT_NATIVE */
271 pid = waitpid(-1, &w,
272 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
274 #endif /* WINNT_NATIVE */
277 xprintf("parent %d pid %d, retval %x termsig %x retcode %x\n",
278 getpid(), pid, w, WTERMSIG(w), WEXITSTATUS(w));
280 #endif /* JOBDEBUG */
282 if ((pid == 0) || (pid == -1)) {
284 xprintf("errno == %d\n", errno);
285 #endif /* JOBDEBUG */
286 if (errno == EINTR) {
290 pnoprocesses = pid == -1;
293 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
294 if (pid == pp->p_procid)
296 #if !defined(BSDJOBS) && !defined(WINNT_NATIVE)
297 /* this should never have happened */
298 stderror(ERR_SYNC, pid);
300 #else /* BSDJOBS || WINNT_NATIVE */
302 #endif /* !BSDJOBS && !WINNT_NATIVE */
304 pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
306 pp->p_flags |= PSTOPPED;
307 pp->p_reason = WSTOPSIG(w);
310 if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
313 (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL);
314 # else /* !_SEQUENT_ */
316 pp->p_etime = times(&proctimes);
317 # else /* COHERENT */
318 pp->p_etime = HZ * time(NULL);
320 # endif /* COHERENT */
321 # endif /* !_SEQUENT_ */
323 (void) gettimeofday(&pp->p_etime, NULL);
324 #endif /* BSDTIMES */
327 #if defined(BSDTIMES) || defined(_SEQUENT_)
329 #else /* !BSDTIMES && !_SEQUENT_ */
330 (void) times(&proctimes);
331 pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime;
332 pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime;
334 #endif /* !BSDTIMES && !_SEQUENT_ */
335 if (WIFSIGNALED(w)) {
336 if (WTERMSIG(w) == SIGINT)
337 pp->p_flags |= PINTERRUPTED;
339 pp->p_flags |= PSIGNALED;
341 pp->p_flags |= PDUMPED;
342 pp->p_reason = WTERMSIG(w);
345 pp->p_reason = WEXITSTATUS(w);
346 if (pp->p_reason != 0)
347 pp->p_flags |= PAEXITED;
349 pp->p_flags |= PNEXITED;
355 if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
356 !child && adrof(STRtime) &&
358 fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
359 #else /* !BSDTIMES */
361 fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec
362 # else /* !_SEQUENT_ */
364 (fp->p_utime + fp->p_stime) / HZ
366 (fp->p_utime + fp->p_stime) / clk_tck
368 # endif /* !_SEQUENT_ */
369 #endif /* !BSDTIMES */
370 >= atoi(short2str(varval(STRtime))))
371 fp->p_flags |= PTIME;
372 jobflags |= fp->p_flags;
373 } while ((fp = fp->p_friends) != pp);
374 pp->p_flags &= ~PFOREGND;
375 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
376 pp->p_flags &= ~PPTIME;
377 pp->p_flags |= PTIME;
379 if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
382 if (fp->p_flags & PSTOPPED)
383 fp->p_flags |= PREPORTED;
384 } while ((fp = fp->p_friends) != pp);
385 while (fp->p_procid != fp->p_jobid)
387 if (jobflags & PSTOPPED) {
388 if (pcurrent && pcurrent != fp)
389 pprevious = pcurrent;
394 if (jobflags & PFOREGND) {
395 if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
397 jobflags & PAEXITED ||
399 !eq(dcwd->di_name, fp->p_cwd->di_name))) {
400 /* PWP: print a newline after ^C */
401 if (jobflags & PINTERRUPTED) {
403 xputchar('\r' | QUOTE), xputchar('\n');
404 #else /* !SHORT_STRINGS */
405 xprintf("\215\n"); /* \215 is a quoted ^M */
406 #endif /* !SHORT_STRINGS */
409 else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
415 if (jobflags & PNOTIFY || adrof(STRnotify)) {
417 xputchar('\r' | QUOTE), xputchar('\n');
418 #else /* !SHORT_STRINGS */
419 xprintf("\215\n"); /* \215 is a quoted ^M */
420 #endif /* !SHORT_STRINGS */
421 (void) pprint(pp, NUMBER | NAME | REASON);
422 if ((jobflags & PSTOPPED) == 0)
430 * don't really want to do that, because it
431 * will erase our message in case of multi-line
442 fp->p_flags |= PNEEDNOTE;
447 #if defined(BSDJOBS) || defined(HAVEwait3)
449 #endif /* BSDJOBS || HAVEwait3 */
464 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
465 if (pp->p_flags & PNEEDNOTE) {
467 omask = sigblock(sigmask(SIGCHLD));
469 (void) sighold(SIGCHLD);
470 #endif /* !BSDSIGS */
471 pp->p_flags &= ~PNEEDNOTE;
472 flags = pprint(pp, NUMBER | NAME | REASON);
473 if ((flags & (PRUNNING | PSTOPPED)) == 0)
476 (void) sigsetmask(omask);
478 (void) sigrelse(SIGCHLD);
479 #endif /* !BSDSIGS */
489 xfree((ptr_t) pp->p_command);
490 if (pp->p_cwd && --pp->p_cwd->di_count == 0)
491 if (pp->p_cwd->di_next == 0)
498 * pwait - wait for current job to terminate, maintaining integrity
499 * of current and previous job indicators.
504 struct process *fp, *pp;
510 * Here's where dead procs get flushed.
513 omask = sigblock(sigmask(SIGCHLD));
515 (void) sighold(SIGCHLD);
516 #endif /* !BSDSIGS */
517 for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
518 if (pp->p_procid == 0) {
519 fp->p_next = pp->p_next;
524 (void) sigsetmask(omask);
526 (void) sigrelse(SIGCHLD);
531 #endif /* !BSDSIGS */
537 * pjwait - wait for a job to finish or become stopped
538 * It is assumed to be in the foreground state (PFOREGND)
545 int jobflags, reason;
550 signalfun_t inthandler;
551 #endif /* UNRELSIGS */
552 while (pp->p_procid != pp->p_jobid)
557 if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
558 xprintf(CGETS(17, 1, "BUG: waiting for background job!\n"));
559 } while ((fp = fp->p_friends) != pp);
561 * Now keep pausing as long as we are not interrupted (SIGINT), and the
562 * target process, or any of its friends, are running
566 omask = sigblock(sigmask(SIGCHLD));
570 inthandler = signal(SIGINT, SIG_IGN);
571 #endif /* UNRELSIGS */
574 (void) sighold(SIGCHLD);
575 #endif /* !BSDSIGS */
578 jobflags |= fp->p_flags;
579 while ((fp = (fp->p_friends)) != pp);
580 if ((jobflags & PRUNNING) == 0)
583 xprintf("%d starting to sigpause for SIGCHLD on %d\n",
584 getpid(), fp->p_procid);
585 #endif /* JOBDEBUG */
587 /* (void) sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */
588 (void) sigpause(omask & ~sigmask(SIGCHLD));
590 (void) sigpause(SIGCHLD);
591 #endif /* !BSDSIGS */
594 xprintf("%d returned from sigpause loop\n", getpid());
595 #endif /* JOBDEBUG */
597 (void) sigsetmask(omask);
599 (void) sigrelse(SIGCHLD);
600 #endif /* !BSDSIGS */
603 (void) signal(SIGINT, inthandler);
604 #endif /* UNRELSIGS */
606 if (tpgrp > 0) /* get tty back */
607 (void) tcsetpgrp(FSHTTY, tpgrp);
609 if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
610 !eq(dcwd->di_name, fp->p_cwd->di_name)) {
611 if (jobflags & PSTOPPED) {
613 if (adrof(STRlistjobs)) {
616 jobcommand[0] = STRjobs;
617 if (eq(varval(STRlistjobs), STRlong))
618 jobcommand[1] = STRml;
620 jobcommand[1] = NULL;
621 jobcommand[2] = NULL;
623 dojobs(jobcommand, NULL);
624 (void) pprint(pp, SHELLDIR);
627 (void) pprint(pp, AREASON | SHELLDIR);
630 (void) pprint(pp, AREASON | SHELLDIR);
632 if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
633 (!gointr || !eq(gointr, STRminus))) {
634 if ((jobflags & PSTOPPED) == 0)
643 reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
644 fp->p_reason | META : fp->p_reason;
645 } while ((fp = fp->p_friends) != pp);
647 * Don't report on backquoted jobs, cause it will mess up
650 if ((reason != 0) && (adrof(STRprintexitvalue)) &&
651 (pp->p_flags & PBACKQ) == 0)
652 xprintf(CGETS(17, 2, "Exit %d\n"), reason);
653 set(STRstatus, putn(reason), VAR_READWRITE);
654 if (reason && exiterr)
660 * dowait - wait for all processes to finish
678 omask = sigblock(sigmask(SIGCHLD));
682 (void) sigrelse(SIGINT);
684 (void) sighold(SIGCHLD);
685 #endif /* !BSDSIGS */
686 for (pp = proclist.p_next; pp; pp = pp->p_next)
687 if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */
688 pp->p_flags & PRUNNING) {
690 (void) sigpause((sigmask_t) 0);
692 (void) sigpause(SIGCHLD);
693 #endif /* !BSDSIGS */
697 (void) sigsetmask(omask);
699 (void) sigrelse(SIGCHLD);
700 #endif /* !BSDSIGS */
705 * pflushall - flush all jobs from list (e.g. at fork())
712 for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
718 * pflush - flag all process structures in the same job as the
719 * the argument process for deletion. The actual free of the
720 * space is not done here since pflush is called at interrupt level.
729 if (pp->p_procid == 0) {
730 xprintf(CGETS(17, 3, "BUG: process flushed twice"));
733 while (pp->p_procid != pp->p_jobid)
741 np->p_index = np->p_procid = 0;
742 np->p_flags &= ~PNEEDNOTE;
743 } while ((np = np->p_friends) != pp);
744 if (idx == pmaxindex) {
745 for (np = proclist.p_next, idx = 0; np; np = np->p_next)
746 if (np->p_index > idx)
753 * pclrcurr - make sure the given job is not the current or previous job;
754 * pp MUST be the job leader
760 if (pp == pcurrent) {
761 if (pprevious != NULL) {
762 pcurrent = pprevious;
763 pprevious = pgetcurr(pp);
766 pcurrent = pgetcurr(pp);
767 pprevious = pgetcurr(pp);
770 else if (pp == pprevious)
771 pprevious = pgetcurr(pp);
774 /* +4 here is 1 for '\0', 1 ea for << >& >> */
775 static Char command[PMAXLEN + 4];
780 * unparse - Export padd() functionality
790 return Strsave(command);
795 * palloc - allocate a process structure and fill it up.
796 * an important assumption is made that the process is running.
806 pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process));
808 pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING;
809 if (t->t_dflg & F_TIME)
810 pp->p_flags |= PPTIME;
811 if (t->t_dflg & F_BACKQ)
812 pp->p_flags |= PBACKQ;
813 if (t->t_dflg & F_HUP)
819 if (t->t_dflg & F_PIPEOUT) {
821 if (t->t_dflg & F_STDERR)
822 pp->p_flags |= PDIAG;
824 pp->p_command = Strsave(command);
828 /* careful here with interrupt level */
830 pp->p_index = pcurrjob->p_index;
831 pp->p_friends = pcurrjob;
832 pp->p_jobid = pcurrjob->p_procid;
833 for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
843 if (pmaxindex < BIGINDEX)
844 pp->p_index = ++pmaxindex;
849 for (np = proclist.p_next; np; np = np->p_next)
850 if (np->p_index == i)
859 if (pcurrent == NULL)
861 else if (pprevious == NULL)
864 pp->p_next = proclist.p_next;
865 proclist.p_next = pp;
867 (void) gettimeofday(&pp->p_btime, NULL);
868 #else /* !BSDTIMES */
870 (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL);
871 # else /* !_SEQUENT_ */
876 pp->p_btime = times(&tmptimes);
877 # else /* !COHERENT */
878 pp->p_btime = HZ * time(NULL);
880 # endif /* !COHERENT */
882 # endif /* !_SEQUENT_ */
883 #endif /* !BSDTIMES */
903 for (argp = t->t_dcom; *argp; argp++) {
937 if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
938 pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
941 if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
942 pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
943 if (t->t_dflg & F_STDERR)
957 * Avoid the Quoted Space alias hack! Reported by:
958 * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
960 if (cp[0] == STRQNULL[0])
963 i = (int) Strlen(cp);
965 if (cmdlen >= PMAXLEN)
967 if (cmdlen + i >= PMAXLEN) {
968 (void) Strcpy(cmdp, STRsp3dots);
973 (void) Strcpy(cmdp, cp);
979 * psavejob - temporarily save the current job on a one level stack
980 * so another job can be created. Used for { } in exp6
981 * and `` in globbing.
991 * prestjob - opposite of psavejob. This may be missed if we are interrupted
992 * somewhere, but pendjob cleans up anyway.
1002 * pendjob - indicate that a job (set of commands) has been completed
1003 * or is about to begin.
1008 struct process *pp, *tp;
1010 if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
1012 while (pp->p_procid != pp->p_jobid)
1014 xprintf("[%d]", pp->p_index);
1017 xprintf(" %d", pp->p_procid);
1022 pholdjob = pcurrjob = 0;
1026 * pprint - print a job
1030 * Hacks have been added for SVR4 to deal with pipe's being spawned in
1033 * David Dawes (dawes@physics.su.oz.au) Oct 1991
1043 int jobflags, pstatus, pcond;
1047 struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL;
1049 #endif /* BACKPIPE */
1051 while (pp->p_procid != pp->p_jobid)
1053 if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
1054 pp->p_flags &= ~PPTIME;
1055 pp->p_flags |= PTIME;
1058 status = reason = -1;
1063 * The pipeline is reversed, so locate the real head of the pipeline
1064 * if pp is at the tail of a pipe (and not already in a pipeline)
1066 if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) {
1071 while (pp->p_friends->p_flags & PPOU);
1075 * pmarker is used to hold the place of the proc being processed, so
1076 * we can search for the next one downstream later.
1079 pcond = (int) (tp != pp || (inpipe && tp == pp));
1080 #else /* !BACKPIPE */
1081 pcond = (int) (tp != pp);
1082 #endif /* BACKPIPE */
1084 jobflags |= pp->p_flags;
1085 pstatus = (int) (pp->p_flags & PALLSTATES);
1086 if (pcond && linp != linbuf && !(flag & FANCY) &&
1087 ((pstatus == status && pp->p_reason == reason) ||
1091 if (pcond && linp != linbuf)
1093 if (flag & NUMBER) {
1095 pcond = ((pp == tp && !inpipe) ||
1096 (inpipe && pipetail == tp && pp == pipehead));
1097 #else /* BACKPIPE */
1099 #endif /* BACKPIPE */
1101 xprintf("[%d]%s %c ", pp->p_index,
1102 pp->p_index < 10 ? " " : "",
1103 pp == pcurrent ? '+' :
1104 (pp == pprevious ? '-' : ' '));
1110 extern char *sitename();
1113 xprintf("%5d ", pp->p_procid);
1115 xprintf("%11s ", sitename(pp->p_procid));
1118 if (flag & (REASON | AREASON)) {
1123 if (pstatus == status) {
1124 if (pp->p_reason == reason) {
1125 xprintf(format, "");
1129 reason = (int) pp->p_reason;
1133 reason = (int) pp->p_reason;
1138 xprintf(format, CGETS(17, 4, "Running "));
1145 * tell what happened to the background job
1146 * From: Michael Schroeder
1147 * <mlschroe@immd4.informatik.uni-erlangen.de>
1150 || ((flag & AREASON)
1152 && (reason != SIGPIPE
1153 || (pp->p_flags & PPOU) == 0))) {
1157 if ((ptr = mesg[pp->p_reason & ASCII].pname) == NULL) {
1158 xsnprintf(buf, sizeof(buf), "%s %d",
1159 CGETS(17, 5, "Signal"), pp->p_reason & ASCII);
1162 xprintf(format, ptr);
1170 if (flag & REASON) {
1172 xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason);
1174 xprintf(format, CGETS(17, 7, "Done"));
1179 xprintf(CGETS(17, 8, "BUG: status=%-9o"),
1186 xprintf("%S", pp->p_command);
1187 if (pp->p_flags & PPOU)
1189 if (pp->p_flags & PDIAG)
1192 if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED)
1193 xprintf(CGETS(17, 9, " (core dumped)"));
1194 if (tp == pp->p_friends) {
1195 if (flag & AMPERSAND)
1197 if (flag & JOBDIR &&
1198 !eq(tp->p_cwd->di_name, dcwd->di_name)) {
1199 xprintf(CGETS(17, 10, " (wd: "));
1200 dtildepr(tp->p_cwd->di_name);
1204 if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
1207 #if defined(BSDTIMES) || defined(_SEQUENT_)
1208 prusage(&zru, &pp->p_rusage, &pp->p_etime,
1210 #else /* !BSDTIMES && !SEQUENT */
1211 lru.tms_utime = pp->p_utime;
1212 lru.tms_stime = pp->p_stime;
1215 prusage(&zru, &lru, pp->p_etime,
1217 #endif /* !BSDTIMES && !SEQUENT */
1221 pcond = ((tp == pp->p_friends && !inpipe) ||
1222 (inpipe && pipehead->p_friends == tp && pp == pipetail));
1223 #else /* !BACKPIPE */
1224 pcond = (tp == pp->p_friends);
1225 #endif /* BACKPIPE */
1229 if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
1230 xprintf(CGETS(17, 11, "(wd now: "));
1231 dtildepr(dcwd->di_name);
1238 * if pmaker == pipetail, we are finished that pipeline, and
1239 * can now skip to past the head
1241 if (pmarker == pipetail) {
1247 * set pp to one before the one we want next, so the while below
1248 * increments to the correct spot.
1252 while (pp->p_friends->p_friends != pmarker);
1253 pmarker = pp->p_friends;
1256 pcond = ((pp = pp->p_friends) != tp || inpipe);
1257 #else /* !BACKPIPE */
1258 pcond = ((pp = pp->p_friends) != tp);
1259 #endif /* BACKPIPE */
1262 if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
1263 if (jobflags & NUMBER)
1271 * All 4.3 BSD derived implementations are buggy and I've had enough.
1272 * The following implementation produces similar code and works in all
1273 * cases. The 4.3BSD one works only for <, >, !=
1276 # define timercmp(tvp, uvp, cmp) \
1277 (((tvp)->tv_sec == (uvp)->tv_sec) ? \
1278 ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
1279 ((tvp)->tv_sec cmp (uvp)->tv_sec))
1286 struct timeval tetime, diff;
1287 static struct timeval ztime;
1288 struct sysrusage ru;
1289 struct process *pp = tp;
1294 ruadd(&ru, &pp->p_rusage);
1295 tvsub(&diff, &pp->p_etime, &pp->p_btime);
1296 if (timercmp(&diff, &tetime, >))
1298 } while ((pp = pp->p_friends) != tp);
1299 prusage(&zru, &ru, &tetime, &ztime);
1300 #else /* !BSDTIMES */
1302 timeval_t tetime, diff;
1303 static timeval_t ztime;
1304 struct process_stats ru;
1305 struct process *pp = tp;
1310 ruadd(&ru, &pp->p_rusage);
1311 tvsub(&diff, &pp->p_etime, &pp->p_btime);
1312 if (timercmp(&diff, &tetime, >))
1314 } while ((pp = pp->p_friends) != tp);
1315 prusage(&zru, &ru, &tetime, &ztime);
1316 # else /* !_SEQUENT_ */
1318 static time_t ztime = 0;
1319 static time_t zu_time = 0;
1320 static time_t zs_time = 0;
1321 time_t tetime, diff;
1322 time_t u_time, s_time;
1325 static clock_t ztime = 0;
1326 static clock_t zu_time = 0;
1327 static clock_t zs_time = 0;
1328 clock_t tetime, diff;
1329 clock_t u_time, s_time;
1332 struct tms zts, rts;
1333 struct process *pp = tp;
1339 u_time += pp->p_utime;
1340 s_time += pp->p_stime;
1341 diff = pp->p_etime - pp->p_btime;
1344 } while ((pp = pp->p_friends) != tp);
1345 zts.tms_utime = zu_time;
1346 zts.tms_stime = zs_time;
1349 rts.tms_utime = u_time;
1350 rts.tms_stime = s_time;
1353 prusage(&zts, &rts, tetime, ztime);
1354 # endif /* !_SEQUENT_ */
1355 #endif /* !BSDTIMES */
1359 * dojobs - print all jobs
1368 int flag = NUMBER | NAME | REASON;
1375 if (v[1] || !eq(*v, STRml))
1377 flag |= FANCY | JOBDIR;
1379 for (i = 1; i <= pmaxindex; i++)
1380 for (pp = proclist.p_next; pp; pp = pp->p_next)
1381 if (pp->p_index == i && pp->p_procid == pp->p_jobid) {
1382 pp->p_flags &= ~PNEEDNOTE;
1383 if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
1390 * dofg - builtin - put the job into the foreground
1405 if (!pstart(pp, 1)) {
1407 stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1415 #endif /* !BSDSIGS */
1417 } while (*v && *++v);
1421 * %... - builtin - put the job into the foreground
1434 if (!pstart(pp, 1)) {
1436 stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1444 #endif /* !BSDSIGS */
1449 * dobg - builtin - put the job into the background
1464 if (!pstart(pp, 0)) {
1466 stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1468 } while (*v && *++v);
1472 * %... & - builtin - put the job into the background
1484 if (!pstart(pp, 0)) {
1486 stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1491 * dostop - builtin - stop the job
1501 pkill(++v, SIGSTOP);
1502 #endif /* BSDJOBS */
1506 * dokill - builtin - superset of kill (1)
1514 int signum, len = 0;
1520 if (v[0] && v[0][0] == '-') {
1521 if (v[0][1] == 'l') {
1522 for (signum = 0; signum <= nsig; signum++) {
1523 if ((name = mesg[signum].iname) != NULL) {
1524 len += strlen(name) + 1;
1525 if (len >= T_Cols - 1) {
1527 len = strlen(name) + 1;
1529 xprintf("%s ", name);
1536 if (v[0][1] == 's') {
1541 stderror(ERR_NAME | ERR_TOOFEW);
1544 if (Isdigit(*sigptr)) {
1546 signum = strtoul(short2str(sigptr), &ep, 0);
1547 if (*ep || signum < 0 || signum > (MAXSIG-1))
1548 stderror(ERR_NAME | ERR_BADSIG);
1551 for (signum = 0; signum <= nsig; signum++)
1552 if (mesg[signum].iname &&
1553 eq(sigptr, str2short(mesg[signum].iname)))
1555 setname(short2str(sigptr));
1556 stderror(ERR_NAME | ERR_UNKSIG);
1571 struct process *pp, *np;
1572 int jobflags = 0, err1 = 0;
1576 #endif /* BSDSIGS */
1580 omask = sigmask(SIGCHLD);
1582 omask |= sigmask(SIGINT);
1583 omask = sigblock(omask) & ~omask;
1584 #else /* !BSDSIGS */
1586 (void) sighold(SIGINT);
1587 (void) sighold(SIGCHLD);
1588 #endif /* !BSDSIGS */
1590 /* Avoid globbing %?x patterns */
1591 for (vp = v; vp && *vp; vp++)
1595 gflag = 0, tglob(v);
1599 stderror(ERR_NAME | ERR_NOMATCH);
1602 v = gargv = saveblk(v);
1607 while (v && (cp = *v)) {
1609 np = pp = pfind(cp);
1611 jobflags |= np->p_flags;
1612 while ((np = np->p_friends) != pp);
1620 if ((jobflags & PRUNNING) == 0) {
1622 xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp);
1623 # else /* !SUSPENDED */
1624 xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp);
1625 # endif /* !SUSPENDED */
1631 * suspend a process, kill -CONT %, then type jobs; the shell
1632 * says it is suspended, but it is running; thanks jaap..
1635 if (!pstart(pp, 0)) {
1637 stderror(ERR_NAME|ERR_BADJOB, pp->p_command,
1644 #endif /* BSDJOBS */
1645 if (killpg(pp->p_jobid, signum) < 0) {
1646 xprintf("%S: %s\n", cp, strerror(errno));
1650 if (signum == SIGTERM || signum == SIGHUP)
1651 (void) killpg(pp->p_jobid, SIGCONT);
1652 #endif /* BSDJOBS */
1654 else if (!(Isdigit(*cp) || *cp == '-'))
1655 stderror(ERR_NAME | ERR_JOBARGS);
1658 #ifndef WINNT_NATIVE
1659 pid = strtol(short2str(cp), &ep, 10);
1661 pid = strtoul(short2str(cp), &ep, 0);
1662 #endif /* WINNT_NATIVE */
1664 stderror(ERR_NAME | ERR_JOBARGS);
1665 else if (kill(pid, signum) < 0) {
1666 xprintf("%d: %s\n", pid, strerror(errno));
1671 if (signum == SIGTERM || signum == SIGHUP)
1672 (void) kill(pid, SIGCONT);
1673 #endif /* BSDJOBS */
1679 blkfree(gargv), gargv = 0;
1681 (void) sigsetmask(omask);
1682 #else /* !BSDSIGS */
1683 (void) sigrelse(SIGCHLD);
1685 (void) sigrelse(SIGINT);
1686 #endif /* !BSDSIGS */
1688 stderror(ERR_SILENT);
1692 * pstart - start the job in foreground/background
1703 #endif /* BSDSIGS */
1704 /* We don't use jobflags in this function right now (see below) */
1705 /* long jobflags = 0; */
1708 omask = sigblock(sigmask(SIGCHLD));
1709 #else /* !BSDSIGS */
1710 (void) sighold(SIGCHLD);
1714 /* We don't use jobflags in this function right now (see below) */
1715 /* jobflags |= np->p_flags; */
1716 if (np->p_flags & (PRUNNING | PSTOPPED)) {
1717 np->p_flags |= PRUNNING;
1718 np->p_flags &= ~PSTOPPED;
1720 np->p_flags |= PFOREGND;
1722 np->p_flags &= ~PFOREGND;
1724 } while ((np = np->p_friends) != pp);
1727 (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1729 /* GrP run jobcmd hook if foregrounding */
1731 job_cmd(pp->p_command);
1736 rv = tcsetpgrp(FSHTTY, pp->p_jobid);
1739 * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU
1740 * 2. parent process (csh) receives SIGCHLD
1741 * 3. The "csh" signal handling function pchild() is invoked
1742 * with a SIGCHLD signal.
1743 * 4. pchild() calls wait3(WNOHANG) which returns 0.
1744 * The child process is NOT ready to be waited for at this time.
1745 * pchild() returns without picking-up the correct status
1746 * for the child process which generated the SIGCHILD.
1747 * 5. CONSEQUENCE : csh is UNaware that the process is stopped
1748 * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED)
1749 * (beto@aixwiz.austin.ibm.com - aug/03/91)
1750 * 7. I removed the line completely and added extra checks for
1751 * pstart, so that if a job gets attached to and dies inside
1752 * a debugger it does not confuse the shell. [christos]
1753 * 8. on the nec sx-4 there seems to be a problem, which requires
1754 * a syscall(151, getpid(), getpid()) in osinit. Don't ask me
1755 * what this is doing. [schott@rzg.mpg.de]
1759 rv = killpg(pp->p_jobid, SIGCONT);
1760 #endif /* BSDJOBS */
1762 (void) sigsetmask(omask);
1763 #else /* !BSDSIGS */
1764 (void) sigrelse(SIGCHLD);
1765 #endif /* !BSDSIGS */
1776 for (pp = proclist.p_next; pp; pp = pp->p_next)
1777 if (pp->p_flags & PSTOPPED)
1778 stderror(ERR_STOPPED, neednl ? "\n" : "");
1785 struct process *pp, *np;
1787 if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1788 if (pcurrent == NULL)
1789 stderror(ERR_NAME | ERR_JOBCUR);
1792 if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1793 if (pprevious == NULL)
1794 stderror(ERR_NAME | ERR_JOBPREV);
1797 if (Isdigit(cp[1])) {
1798 int idx = atoi(short2str(cp + 1));
1800 for (pp = proclist.p_next; pp; pp = pp->p_next)
1801 if (pp->p_index == idx && pp->p_procid == pp->p_jobid)
1803 stderror(ERR_NAME | ERR_NOSUCHJOB);
1806 for (pp = proclist.p_next; pp; pp = pp->p_next)
1807 if (pp->p_procid == pp->p_jobid) {
1811 for (dp = pp->p_command; *dp; dp++) {
1814 if (prefix(cp + 2, dp))
1818 else if (prefix(cp + 1, pp->p_command)) {
1821 stderror(ERR_NAME | ERR_AMBIG);
1827 stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1834 * pgetcurr - find most recent job that is not pp, preferably stopped
1836 static struct process *
1841 struct process *xp = NULL;
1843 for (np = proclist.p_next; np; np = np->p_next)
1844 if (np != pcurrent && np != pp && np->p_procid &&
1845 np->p_procid == np->p_jobid) {
1846 if (np->p_flags & PSTOPPED)
1855 * donotify - flag the job so as to report termination asynchronously
1867 pp->p_flags |= PNOTIFY;
1871 * Do the fork and whatever should be done in the child side that
1872 * should not be done if we are not forking at all (like for simple builtin's)
1873 * Also do everything that needs any signals fiddled with in the parent side
1875 * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1876 * -1: leave tty alone; inherit pgrp from parent
1877 * 0: already have tty; manipulate process pgrps only
1878 * 1: want to claim tty; manipulate process and tty pgrps
1879 * It is usually just the value of tpgrp.
1884 struct command *t; /* command we are forking for */
1891 sigmask_t omask = 0;
1892 #endif /* BSDSIGS */
1895 static sigvec_t nsv = {synch_handler, (sigset_t) ~0, 0};
1896 #endif /* SIGSYNCH */
1899 * A child will be uninterruptible only under very special conditions.
1900 * Remember that the semantics of '&' is implemented by disconnecting the
1901 * process from the tty so signals do not need to ignored just for '&'.
1902 * Thus signals are set to default action for children unless: we have had
1903 * an "onintr -" (then specifically ignored) we are not playing with
1904 * signals (inherit action)
1907 ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1908 || (gointr && eq(gointr, STRminus));
1911 ignint |= gointr && eq(gointr, STRminus);
1912 #endif /* COHERENT */
1915 * Check for maximum nesting of 16 processes to avoid Forking loops
1918 stderror(ERR_NESTING, 16);
1920 if (mysigvec(SIGSYNCH, &nsv, &osv))
1921 stderror(ERR_SYSTEM, "pfork: sigvec set", strerror(errno));
1922 #endif /* SIGSYNCH */
1924 * Hold SIGCHLD until we have the process installed in our table.
1928 omask = sigblock(sigmask(SIGCHLD));
1929 #else /* !BSDSIGS */
1930 (void) sighold(SIGCHLD);
1931 #endif /* !BSDSIGS */
1933 while ((pid = fork()) == -1)
1935 (void) sleep(FORKSLEEP);
1939 (void) sigsetmask(omask);
1940 #else /* !BSDSIGS */
1941 (void) sigrelse(SIGCHLD);
1942 (void) sigrelse(SIGINT);
1943 #endif /* !BSDSIGS */
1944 stderror(ERR_NOPROC);
1948 pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1951 #if !defined(BSDTIMES) && !defined(_SEQUENT_)
1953 #endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */
1956 setintr = 0; /* until I think otherwise */
1959 (void) sigrelse(SIGCHLD);
1960 #endif /* !BSDSIGS */
1962 * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1965 (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1966 (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1969 /* make stoppable */
1970 (void) signal(SIGTSTP, SIG_DFL);
1971 (void) signal(SIGTTIN, SIG_DFL);
1972 (void) signal(SIGTTOU, SIG_DFL);
1974 #endif /* BSDJOBS */
1975 (void) signal(SIGTERM, parterm);
1977 else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1978 (void) signal(SIGINT, SIG_IGN);
1979 (void) signal(SIGQUIT, SIG_IGN);
1982 sigignore(SIGIO); /* ignore SIGIO in child too */
1985 pgetty(wanttty, pgrp);
1987 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1988 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1989 * to know about nice/nohup/time
1991 if (t->t_dflg & F_NOHUP)
1992 (void) signal(SIGHUP, SIG_IGN);
1993 if (t->t_dflg & F_NICE) {
1994 int nval = SIGN_EXTEND_CHAR(t->t_nice);
1995 #ifdef HAVE_SETPRIORITY
1996 if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno)
1997 stderror(ERR_SYSTEM, "setpriority", strerror(errno));
1998 #else /* !HAVE_SETPRIORITY */
2000 #endif /* !HAVE_SETPRIORITY */
2003 if (t->t_dflg & F_VER) {
2004 tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
2009 /* rfw 8/89 now parent can continue */
2010 if (kill(getppid(), SIGSYNCH))
2011 stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno));
2012 #endif /* SIGSYNCH */
2019 * `Walking' process group fix from Beto Appleton.
2020 * (beto@aixwiz.austin.ibm.com)
2021 * If setpgid fails at this point that means that
2022 * our process leader has died. We flush the current
2023 * job and become the process leader ourselves.
2024 * The parent will figure that out later.
2026 pgrp = pcurrjob ? pcurrjob->p_jobid : pid;
2027 if (setpgid(pid, pgrp) == -1 && errno == EPERM) {
2030 * We don't care if this causes an error here;
2031 * then we are already in the right process group
2033 (void) setpgid(pid, pgrp = pid);
2036 #endif /* POSIXJOBS */
2040 * rfw 8/89 Wait for child to own terminal. Solves half of ugly
2041 * synchronization problem. With this change, we know that the only
2042 * reason setpgrp to a previous process in a pipeline can fail is that
2043 * the previous process has already exited. Without this hack, he may
2044 * either have exited or not yet started to run. Two uglies become
2047 (void) sigpause(omask & ~SYNCHMASK);
2048 if (mysigvec(SIGSYNCH, &osv, NULL))
2049 stderror(ERR_SYSTEM, "pfork parent: sigvec restore",
2051 #endif /* SIGSYNCH */
2055 (void) sigsetmask(omask);
2056 #else /* !BSDSIGS */
2057 (void) sigrelse(SIGCHLD);
2058 #endif /* !BSDSIGS */
2068 stderror(ERR_JOBCONTROL);
2070 stderror(ERR_JOBCTRLSUB);
2079 * If we are piping out a builtin, eg. 'echo | more' things can go
2080 * out of sequence, i.e. the more can run before the echo. This
2081 * can happen even if we have vfork, since the echo will be forked
2082 * with the regular fork. In this case, we need to set the tty
2083 * pgrp ourselves. If that happens, then the process will be still
2084 * alive. And the tty process group will already be set.
2085 * This should fix the famous sequent problem as a side effect:
2086 * The controlling terminal is lost if all processes in the
2087 * terminal process group are zombies. In this case tcgetpgrp()
2088 * returns 0. If this happens we must set the terminal process
2091 if (tcgetpgrp(FSHTTY) != pgrp) {
2094 * tcsetpgrp will set SIGTTOU to all the the processes in
2095 * the background according to POSIX... We ignore this here.
2097 signalfun_t old = sigset(SIGTTOU, SIG_IGN);
2099 (void) tcsetpgrp(FSHTTY, pgrp);
2101 (void) sigset(SIGTTOU, old);
2109 * if we don't have vfork(), things can still go in the wrong order
2110 * resulting in the famous 'Stopped (tty output)'. But some systems
2111 * don't permit the setpgid() call, (these are more recent secure
2112 * systems such as ibm's aix), when they do. Then we'd rather print
2113 * an error message than hang the shell!
2114 * I am open to suggestions how to fix that.
2117 pgetty(wanttty, pgrp)
2121 # if defined(BSDSIGS) && defined(POSIXJOBS)
2122 sigmask_t omask = 0;
2123 # endif /* BSDSIGS && POSIXJOBS */
2126 xprintf("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n",
2127 wanttty, getpid(), pgrp, mygetpgrp(), tcgetpgrp(FSHTTY));
2128 # endif /* JOBDEBUG */
2131 * christos: I am blocking the tty signals till I've set things
2136 omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN));
2137 # else /* !BSDSIGS */
2139 (void) sighold(SIGTSTP);
2140 (void) sighold(SIGTTIN);
2142 # endif /* !BSDSIGS */
2143 # endif /* POSIXJOBS */
2148 # endif /* !POSIXJOBS */
2151 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
2152 * Don't check for tpgrp >= 0 so even non-interactive shells give
2153 * background jobs process groups Same for the comparison in the other part
2157 if (setpgid(0, pgrp) == -1) {
2159 /* Walking process group fix; see above */
2160 if (setpgid(0, pgrp = getpid()) == -1) {
2161 # endif /* POSIXJOBS */
2162 stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno));
2166 wanttty = pgrp; /* Now we really want the tty, since we became the
2167 * the process group leader
2169 # endif /* POSIXJOBS */
2177 (void) sigsetmask(omask);
2178 # else /* BSDSIGS */
2179 (void) sigrelse(SIGTSTP);
2180 (void) sigrelse(SIGTTIN);
2181 # endif /* !BSDSIGS */
2182 # endif /* POSIXJOBS */
2185 xprintf("wanttty %d pid %d pgrp %d tpgrp %d\n",
2186 wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY));
2187 # endif /* JOBDEBUG */
2190 tpgrp = 0; /* gave tty away */
2191 #endif /* BSDJOBS */