xref: /freebsd/contrib/tcsh/sh.proc.c (revision 6560ac57ce879857203bc456cdc3849808dc0700)
1  /*
2   * sh.proc.c: Job manipulations
3   */
4  /*-
5   * Copyright (c) 1980, 1991 The Regents of the University of California.
6   * All rights reserved.
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  #include "sh.h"
33  #include "ed.h"
34  #include "tc.h"
35  #include "tc.wait.h"
36  
37  #ifdef WINNT_NATIVE
38  #undef POSIX
39  #define POSIX
40  #endif /* WINNT_NATIVE */
41  #ifdef aiws
42  # undef HZ
43  # define HZ 16
44  #endif /* aiws */
45  
46  #if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid)
47  # define BSDWAIT
48  #endif /* _BSD || (IRIS4D && __STDC__) || __lucid */
49  #ifndef WTERMSIG
50  # define WTERMSIG(w)	(((union wait *) &(w))->w_termsig)
51  # ifndef BSDWAIT
52  #  define BSDWAIT
53  # endif /* !BSDWAIT */
54  #endif /* !WTERMSIG */
55  #ifndef WEXITSTATUS
56  # define WEXITSTATUS(w)	(((union wait *) &(w))->w_retcode)
57  #endif /* !WEXITSTATUS */
58  #ifndef WSTOPSIG
59  # define WSTOPSIG(w)	(((union wait *) &(w))->w_stopsig)
60  #endif /* !WSTOPSIG */
61  
62  #ifdef __osf__
63  # ifndef WCOREDUMP
64  #  define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG)
65  # endif
66  #endif
67  
68  #ifndef WCOREDUMP
69  # ifdef BSDWAIT
70  #  define WCOREDUMP(w)	(((union wait *) &(w))->w_coredump)
71  # else /* !BSDWAIT */
72  #  define WCOREDUMP(w)	((w) & 0200)
73  # endif /* !BSDWAIT */
74  #endif /* !WCOREDUMP */
75  
76  #ifndef JOBDEBUG
77  # define jobdebug_xprintf(x)	(void)0
78  # define jobdebug_flush()	(void)0
79  #else
80  # define jobdebug_xprintf(s)	xprintf s
81  # define jobdebug_flush()	flush()
82  #endif
83  
84  /*
85   * C Shell - functions that manage processes, handling hanging, termination
86   */
87  
88  #define BIGINDEX	9	/* largest desirable job index */
89  
90  #ifdef BSDTIMES
91  # ifdef convex
92  /* use 'cvxrusage' to get parallel statistics */
93  static struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L,
94  				0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
95  				{0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L,
96  				0LL, 0LL, {0L, 0L, 0L, 0L, 0L}};
97  # else
98  static struct rusage zru;
99  # endif /* convex */
100  #else /* !BSDTIMES */
101  # ifdef _SEQUENT_
102  static struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0,
103  				   0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
104  # else /* !_SEQUENT_ */
105  #  ifdef _SX
106  static struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0};
107  #  else	/* !_SX */
108  static struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L};
109  #  endif	/* !_SX */
110  # endif	/* !_SEQUENT_ */
111  #endif /* !BSDTIMES */
112  
113  #ifndef BSDTIMES
114  static int timesdone;	/* shtimes buffer full ? */
115  #endif /* BSDTIMES */
116  
117  #ifndef RUSAGE_CHILDREN
118  # define	RUSAGE_CHILDREN	-1
119  #endif /* RUSAGE_CHILDREN */
120  
121  static	void		 pflushall	(void);
122  static	void		 pflush		(struct process *);
123  static	void		 pfree		(struct process *);
124  static	void		 pclrcurr	(struct process *);
125  static	void		 morecommand	(size_t);
126  static	void		 padd		(struct command *);
127  static	int		 pprint		(struct process *, int);
128  static	void		 ptprint	(struct process *);
129  static	void		 pads		(Char *);
130  static	void		 pkill		(Char **, int);
131  static	struct process	*pgetcurr	(struct process *);
132  static	void		 okpcntl	(void);
133  static	void		 setttypgrp	(int);
134  
135  /*
136   * pchild - call queued by the SIGCHLD signal
137   *	indicating that at least one child has terminated or stopped
138   *	thus at least one wait system call will definitely return a
139   *	childs status.  Top level routines (like pwait) must be sure
140   *	to mask interrupts when playing with the proclist data structures!
141   */
142  void
pchild(void)143  pchild(void)
144  {
145      struct process *pp;
146      struct process *fp;
147      pid_t pid;
148  #ifdef BSDWAIT
149      union wait w;
150  #else /* !BSDWAIT */
151      int     w;
152  #endif /* !BSDWAIT */
153      int     jobflags;
154  #ifdef BSDTIMES
155      struct sysrusage ru;
156  #else /* !BSDTIMES */
157  # ifdef _SEQUENT_
158      struct process_stats ru;
159      struct process_stats cpst1, cpst2;
160      timeval_t tv;
161  # else /* !_SEQUENT_ */
162      struct tms proctimes;
163  
164      if (!timesdone) {
165  	timesdone++;
166  	(void) times(&shtimes);
167      }
168  # endif	/* !_SEQUENT_ */
169  #endif /* !BSDTIMES */
170  
171      jobdebug_xprintf(("pchild()\n"));
172  
173  loop:
174      jobdebug_xprintf(("Waiting...\n"));
175      jobdebug_flush();
176      errno = 0;			/* reset, just in case */
177  
178  #ifndef WINNT_NATIVE
179  # ifdef BSDJOBS
180  #  ifdef BSDTIMES
181  #   ifdef convex
182      /* use 'cvxwait' to get parallel statistics */
183      pid = cvxwait(&w,
184          (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
185  #   else
186      /* both a wait3 and rusage */
187  #    if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__)
188  #ifdef __ANDROID__ /* no wait3, only wait4 */
189      pid = wait4(-1, &w,
190         (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
191  #else
192      pid = wait3(&w,
193         (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
194  #endif /* __ANDROID__ */
195  #    else /* BSDWAIT */
196      pid = wait3(&w.w_status,
197         (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru);
198  #    endif /* BSDWAIT */
199  #   endif /* convex */
200  #  else /* !BSDTIMES */
201  #   ifdef _SEQUENT_
202      (void) get_process_stats(&tv, PS_SELF, 0, &cpst1);
203      pid = waitpid(-1, &w,
204  	    (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
205      (void) get_process_stats(&tv, PS_SELF, 0, &cpst2);
206      pr_stat_sub(&cpst2, &cpst1, &ru);
207  #   else	/* !_SEQUENT_ */
208  #    ifndef POSIX
209      /* we have a wait3, but no rusage stuff */
210      pid = wait3(&w.w_status,
211  	 (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
212  #    else /* POSIX */
213      pid = waitpid(-1, &w,
214  	    (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
215  #    endif /* POSIX */
216  #   endif /* !_SEQUENT_ */
217  #  endif	/* !BSDTIMES */
218  # else /* !BSDJOBS */
219  #  ifdef BSDTIMES
220  #   define HAVEwait3
221      /* both a wait3 and rusage */
222  #   ifdef hpux
223      pid = wait3(&w.w_status, WNOHANG, 0);
224  #   else	/* !hpux */
225  #     ifndef BSDWAIT
226      pid = wait3(&w, WNOHANG, &ru);
227  #     else
228      pid = wait3(&w.w_status, WNOHANG, &ru);
229  #     endif /* BSDWAIT */
230  #   endif /* !hpux */
231  #  else /* !BSDTIMES */
232  #   ifdef ODT  /* For Sco Unix 3.2.0 or ODT 1.0 */
233  #    define HAVEwait3
234      pid = waitpid(-1, &w,
235   	    (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
236  #   endif /* ODT */
237  #   if defined(aiws) || defined(uts)
238  #    define HAVEwait3
239      pid = wait3(&w.w_status,
240  	(setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0);
241  #   endif /* aiws || uts */
242  #   ifndef HAVEwait3
243  #    ifndef BSDWAIT
244       /* no wait3, therefore no rusage */
245       /* on Sys V, this may hang.  I hope it's not going to be a problem */
246      pid = wait(&w);
247  #    else /* BSDWAIT */
248       /*
249        * XXX: for greater than 3 we should use waitpid().
250        * but then again, SVR4 falls into the POSIX/BSDJOBS category.
251        */
252      pid = wait(&w.w_status);
253  #    endif /* BSDWAIT */
254  #   endif /* !HAVEwait3 */
255  #  endif	/* !BSDTIMES */
256  # endif /* !BSDJOBS */
257  #else /* WINNT_NATIVE */
258      pid = waitpid(-1, &w,
259  	    (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG));
260  #endif /* WINNT_NATIVE */
261  
262      jobdebug_xprintf(("parent %d pid %d, retval %x termsig %x retcode %x\n",
263  		      (int)getpid(), (int)pid, w, WTERMSIG(w),
264  		      WEXITSTATUS(w)));
265      jobdebug_flush();
266  
267      if ((pid == 0) || (pid == -1)) {
268  	(void)handle_pending_signals();
269  	jobdebug_xprintf(("errno == %d\n", errno));
270  	if (errno == EINTR)
271  	    goto loop;
272  	goto end;
273      }
274      for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
275  	if (pid == pp->p_procid)
276  	    goto found;
277  #if !defined(BSDJOBS) && !defined(WINNT_NATIVE)
278      /* this should never have happened */
279      stderror(ERR_SYNC, pid);
280      xexit(0);
281  #else /* BSDJOBS || WINNT_NATIVE */
282      goto loop;
283  #endif /* !BSDJOBS && !WINNT_NATIVE */
284  found:
285      pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED);
286      if (WIFSTOPPED(w)) {
287  	pp->p_flags |= PSTOPPED;
288  	pp->p_reason = WSTOPSIG(w);
289      }
290      else {
291  	if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime))
292  #ifndef BSDTIMES
293  # ifdef _SEQUENT_
294  	    (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL);
295  # else	/* !_SEQUENT_ */
296  	    pp->p_etime = times(&proctimes);
297  # endif	/* !_SEQUENT_ */
298  #else /* BSDTIMES */
299  	    (void) gettimeofday(&pp->p_etime, NULL);
300  #endif /* BSDTIMES */
301  
302  
303  #if defined(BSDTIMES) || defined(_SEQUENT_)
304  	pp->p_rusage = ru;
305  #else /* !BSDTIMES && !_SEQUENT_ */
306  	(void) times(&proctimes);
307  	pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime;
308  	pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime;
309  	shtimes = proctimes;
310  #endif /* !BSDTIMES && !_SEQUENT_ */
311  	if (WIFSIGNALED(w)) {
312  	    if (WTERMSIG(w) == SIGINT)
313  		pp->p_flags |= PINTERRUPTED;
314  	    else
315  		pp->p_flags |= PSIGNALED;
316  	    if (WCOREDUMP(w))
317  		pp->p_flags |= PDUMPED;
318  	    pp->p_reason = WTERMSIG(w);
319  	}
320  	else {
321  	    pp->p_reason = WEXITSTATUS(w);
322  	    if (pp->p_reason != 0)
323  		pp->p_flags |= PAEXITED;
324  	    else
325  		pp->p_flags |= PNEXITED;
326  	}
327      }
328      jobflags = 0;
329      fp = pp;
330      do {
331  	if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 &&
332  	    !child && adrof(STRtime) &&
333  #ifdef BSDTIMES
334  	    fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec
335  #else /* !BSDTIMES */
336  # ifdef _SEQUENT_
337  	    fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec
338  # else /* !_SEQUENT_ */
339  #  ifndef POSIX
340  	    (fp->p_utime + fp->p_stime) / HZ
341  #  else /* POSIX */
342  	    (fp->p_utime + fp->p_stime) / clk_tck
343  #  endif /* POSIX */
344  # endif /* !_SEQUENT_ */
345  #endif /* !BSDTIMES */
346  	    >= atoi(short2str(varval(STRtime))))
347  	    fp->p_flags |= PTIME;
348  	jobflags |= fp->p_flags;
349      } while ((fp = fp->p_friends) != pp);
350      pp->p_flags &= ~PFOREGND;
351      if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
352  	pp->p_flags &= ~PPTIME;
353  	pp->p_flags |= PTIME;
354      }
355      if ((jobflags & (PRUNNING | PREPORTED)) == 0) {
356  	fp = pp;
357  	do {
358  	    if (fp->p_flags & PSTOPPED)
359  		fp->p_flags |= PREPORTED;
360  	} while ((fp = fp->p_friends) != pp);
361  	while (fp->p_procid != fp->p_jobid)
362  	    fp = fp->p_friends;
363  	if (jobflags & PSTOPPED) {
364  	    if (pcurrent && pcurrent != fp)
365  		pprevious = pcurrent;
366  	    pcurrent = fp;
367  	}
368  	else
369  	    pclrcurr(fp);
370  	if (jobflags & PFOREGND) {
371  	    if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||
372  #ifdef notdef
373  		jobflags & PAEXITED ||
374  #endif /* notdef */
375  		fp->p_cwd == NULL ||
376  		!eq(dcwd->di_name, fp->p_cwd->di_name))) {
377  	    /* PWP: print a newline after ^C */
378  		if (jobflags & PINTERRUPTED) {
379  		    xputchar('\r' | QUOTE);
380  		    xputchar('\n');
381  		}
382  #ifdef notdef
383  		else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)
384  		    ptprint(fp);
385  #endif /* notdef */
386  	    }
387  	}
388  	else {
389  	    if (jobflags & PNOTIFY || adrof(STRnotify)) {
390  	        xputchar('\r' | QUOTE);
391  		xputchar('\n');
392  		(void) pprint(pp, NUMBER | NAME | REASON);
393  		if ((jobflags & PSTOPPED) == 0)
394  		    pflush(pp);
395  		if (GettingInput) {
396  		    errno = 0;
397  		    (void) Rawmode();
398  #ifdef notdef
399  		    /*
400  		     * don't really want to do that, because it
401  		     * will erase our message in case of multi-line
402  		     * input
403  		     */
404  		    ClearLines();
405  #endif /* notdef */
406  		    ClearDisp();
407  		    Refresh();
408  		}
409  	    }
410  	    else {
411  		fp->p_flags |= PNEEDNOTE;
412  		neednote = 1;
413  	    }
414  	}
415      }
416  #if defined(BSDJOBS) || defined(HAVEwait3) ||defined(WINNT_NATIVE)
417      goto loop;
418  #endif /* BSDJOBS || HAVEwait3 */
419   end:
420      ;
421  }
422  
423  void
pnote(void)424  pnote(void)
425  {
426      struct process *pp;
427      int     flags;
428  
429      neednote = 0;
430      for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) {
431  	if (pp->p_flags & PNEEDNOTE) {
432  	    pchild_disabled++;
433  	    cleanup_push(&pchild_disabled, disabled_cleanup);
434  	    pp->p_flags &= ~PNEEDNOTE;
435  	    flags = pprint(pp, NUMBER | NAME | REASON);
436  	    if ((flags & (PRUNNING | PSTOPPED)) == 0)
437  		pflush(pp);
438  	    cleanup_until(&pchild_disabled);
439  	}
440      }
441  }
442  
443  
444  static void
pfree(struct process * pp)445  pfree(struct process *pp)
446  {
447      xfree(pp->p_command);
448      if (pp->p_cwd && --pp->p_cwd->di_count == 0)
449  	if (pp->p_cwd->di_next == 0)
450  	    dfree(pp->p_cwd);
451      xfree(pp);
452  }
453  
454  
455  /*
456   * pwait - wait for current job to terminate, maintaining integrity
457   *	of current and previous job indicators.
458   */
459  void
pwait(void)460  pwait(void)
461  {
462      struct process *fp, *pp;
463  
464      /*
465       * Here's where dead procs get flushed.
466       */
467      for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next)
468  	if (pp->p_procid == 0) {
469  	    fp->p_next = pp->p_next;
470  	    pfree(pp);
471  	    pp = fp;
472  	}
473      pjwait(pcurrjob);
474  }
475  
476  
477  /*
478   * pjwait - wait for a job to finish or become stopped
479   *	It is assumed to be in the foreground state (PFOREGND)
480   */
481  void
pjwait(struct process * pp)482  pjwait(struct process *pp)
483  {
484      struct process *fp;
485      int     jobflags, reason;
486      sigset_t oset, set, pause_mask;
487      Char *reason_str;
488  
489      while (pp->p_procid != pp->p_jobid)
490  	pp = pp->p_friends;
491      fp = pp;
492  
493      do {
494  	if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING)
495  	  xprintf("%s", CGETS(17, 1, "BUG: waiting for background job!\n"));
496      } while ((fp = fp->p_friends) != pp);
497      /*
498       * Now keep pausing as long as we are not interrupted (SIGINT), and the
499       * target process, or any of its friends, are running
500       */
501      fp = pp;
502      sigemptyset(&set);
503      sigaddset(&set, SIGINT);
504      sigaddset(&set, SIGCHLD);
505      (void)sigprocmask(SIG_BLOCK, &set, &oset);
506      cleanup_push(&oset, sigprocmask_cleanup);
507      pause_mask = oset;
508      sigdelset(&pause_mask, SIGCHLD);
509      sigaddset(&pause_mask, SIGINT);
510      for (;;) {
511  	(void)handle_pending_signals();
512  	jobflags = 0;
513  	do
514  	    jobflags |= fp->p_flags;
515  	while ((fp = (fp->p_friends)) != pp);
516  	if ((jobflags & PRUNNING) == 0)
517  	    break;
518  	jobdebug_xprintf(("%d starting to sigsuspend for SIGCHLD on %d\n",
519  			  getpid(), fp->p_procid));
520  	sigsuspend(&pause_mask);
521      }
522      cleanup_until(&oset);
523      jobdebug_xprintf(("%d returned from sigsuspend loop\n", getpid()));
524  #ifdef BSDJOBS
525      if (tpgrp > 0)		/* get tty back */
526  	(void) tcsetpgrp(FSHTTY, tpgrp);
527  #endif /* BSDJOBS */
528      if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) ||
529  	fp->p_cwd == NULL || !eq(dcwd->di_name, fp->p_cwd->di_name)) {
530  	if (jobflags & PSTOPPED) {
531  	    xputchar('\n');
532  	    if (adrof(STRlistjobs)) {
533  		Char   *jobcommand[3];
534  
535  		jobcommand[0] = STRjobs;
536  		if (eq(varval(STRlistjobs), STRlong))
537  		    jobcommand[1] = STRml;
538  		else
539  		    jobcommand[1] = NULL;
540  		jobcommand[2] = NULL;
541  
542  		dojobs(jobcommand, NULL);
543  		(void) pprint(pp, SHELLDIR);
544  	    }
545  	    else
546  		(void) pprint(pp, AREASON | SHELLDIR);
547  	}
548  	else
549  	    (void) pprint(pp, AREASON | SHELLDIR);
550      }
551      if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr &&
552  	(!gointr || !eq(gointr, STRminus))) {
553  	if ((jobflags & PSTOPPED) == 0)
554  	    pflush(pp);
555  	pintr1(0);
556  	/* NOTREACHED */
557      }
558      reason = 0;
559      fp = pp;
560      do {
561  	/* In case of pipelines only the result of the last
562  	 * command should be taken in account */
563  	if (!anyerror && !(fp->p_flags & PBRACE)
564  		&& ((fp->p_flags & PPOU) || (fp->p_flags & PBACKQ)))
565  	    continue;
566  	if (fp->p_reason)
567  	    reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ?
568  		fp->p_reason | META : fp->p_reason;
569      } while ((fp = fp->p_friends) != pp);
570      /*
571       * Don't report on backquoted jobs, cause it will mess up
572       * their output.
573       */
574      if ((reason != 0) && (adrof(STRprintexitvalue)) &&
575  	(pp->p_flags & PBACKQ) == 0)
576  	xprintf(CGETS(17, 2, "Exit %d\n"), reason);
577      reason_str = putn((tcsh_number_t)reason);
578      cleanup_push(reason_str, xfree);
579      setv(STRstatus, reason_str, VAR_READWRITE);
580      cleanup_ignore(reason_str);
581      cleanup_until(reason_str);
582      if (reason && exiterr)
583  	exitstat();
584      pflush(pp);
585  }
586  
587  /*
588   * dowait - wait for all processes to finish
589   */
590  
591  /*ARGSUSED*/
592  void
dowait(Char ** v,struct command * c)593  dowait(Char **v, struct command *c)
594  {
595      struct process *pp;
596  
597      /* the current block mask to be able to restore */
598      sigset_t old_mask;
599  
600      /* block mask for critical section: OLD_MASK U {SIGCHLD} */
601      sigset_t block_mask;
602  
603      /* ignore those during blocking sigsuspend:
604         OLD_MASK / {SIGCHLD, possibly(SIGINT)} */
605      sigset_t pause_mask;
606  
607      int opintr_disabled, gotsig;
608  
609      USE(c);
610      USE(v);
611      pjobs++;
612  
613      sigprocmask(SIG_BLOCK, NULL, &pause_mask);
614      sigdelset(&pause_mask, SIGCHLD);
615      if (setintr)
616  	sigdelset(&pause_mask, SIGINT);
617  
618      /* critical section, block also SIGCHLD */
619      sigprocmask(SIG_BLOCK, NULL, &block_mask);
620      sigaddset(&block_mask, SIGCHLD);
621      sigprocmask(SIG_BLOCK, &block_mask, &old_mask);
622  
623      /* detect older SIGCHLDs and remove PRUNNING flag from proclist */
624      (void)handle_pending_signals();
625  
626  loop:
627      for (pp = proclist.p_next; pp; pp = pp->p_next)
628  	if (pp->p_procid &&	/* pp->p_procid == pp->p_jobid && */
629  	    pp->p_flags & PRUNNING) {
630  	    /* wait for (or pick up alredy blocked) SIGCHLD */
631  	    sigsuspend(&pause_mask);
632  
633  	    /* make the 'wait' interuptable by CTRL-C */
634  	    opintr_disabled = pintr_disabled;
635  	    pintr_disabled = 0;
636  	    gotsig = handle_pending_signals();
637  	    pintr_disabled = opintr_disabled;
638  	    if (gotsig)
639  		break;
640  	    goto loop;
641  	}
642      pjobs = 0;
643  
644      sigprocmask(SIG_SETMASK, &old_mask, NULL);
645  }
646  
647  /*
648   * pflushall - flush all jobs from list (e.g. at fork())
649   */
650  static void
pflushall(void)651  pflushall(void)
652  {
653      struct process *pp;
654  
655      for (pp = proclist.p_next; pp != NULL; pp = pp->p_next)
656  	if (pp->p_procid)
657  	    pflush(pp);
658  }
659  
660  /*
661   * pflush - flag all process structures in the same job as the
662   *	the argument process for deletion.  The actual free of the
663   *	space is not done here since pflush is called at interrupt level.
664   */
665  static void
pflush(struct process * pp)666  pflush(struct process *pp)
667  {
668      struct process *np;
669      int idx;
670  
671      if (pp->p_procid == 0) {
672  	xprintf("%s", CGETS(17, 3, "BUG: process flushed twice"));
673  	return;
674      }
675      while (pp->p_procid != pp->p_jobid)
676  	pp = pp->p_friends;
677      pclrcurr(pp);
678      if (pp == pcurrjob)
679  	pcurrjob = 0;
680      idx = pp->p_index;
681      np = pp;
682      do {
683  	np->p_index = np->p_procid = 0;
684  	np->p_flags &= ~PNEEDNOTE;
685      } while ((np = np->p_friends) != pp);
686      if (idx == pmaxindex) {
687  	for (np = proclist.p_next, idx = 0; np; np = np->p_next)
688  	    if (np->p_index > idx)
689  		idx = np->p_index;
690  	pmaxindex = idx;
691      }
692  }
693  
694  /*
695   * pclrcurr - make sure the given job is not the current or previous job;
696   *	pp MUST be the job leader
697   */
698  static void
pclrcurr(struct process * pp)699  pclrcurr(struct process *pp)
700  {
701      if (pp == pcurrent) {
702  	if (pprevious != NULL) {
703  	    pcurrent = pprevious;
704  	    pprevious = pgetcurr(pp);
705  	}
706  	else {
707  	    pcurrent = pgetcurr(pp);
708  	    pprevious = pgetcurr(pp);
709  	}
710      }
711      else if (pp == pprevious)
712  	pprevious = pgetcurr(pp);
713  }
714  
715  /* +4 here is 1 for '\0', 1 ea for << >& >> */
716  static Char *cmdstr;
717  static size_t cmdmax;
718  static size_t cmdlen;
719  static Char *cmdp;
720  #define CMD_INIT 1024
721  #define CMD_INCR 64
722  
723  static void
morecommand(size_t s)724  morecommand(size_t s)
725  {
726      Char *ncmdstr;
727      ptrdiff_t d;
728  
729      cmdmax += s;
730      ncmdstr = xrealloc(cmdstr, cmdmax * sizeof(*cmdstr));
731      d = ncmdstr - cmdstr;
732      cmdstr = ncmdstr;
733      cmdp += d;
734  }
735  
736  /* GrP
737   * unparse - Export padd() functionality
738   */
739  Char *
unparse(struct command * t)740  unparse(struct command *t)
741  {
742      if (cmdmax == 0)
743  	morecommand(CMD_INIT);
744      cmdp = cmdstr;
745      cmdlen = 0;
746      padd(t);
747      *cmdp++ = '\0';
748      return Strsave(cmdstr);
749  }
750  
751  
752  /*
753   * palloc - allocate a process structure and fill it up.
754   *	an important assumption is made that the process is running.
755   */
756  void
palloc(pid_t pid,struct command * t)757  palloc(pid_t pid, struct command *t)
758  {
759      struct process *pp;
760      int     i;
761  
762      pp = xcalloc(1, sizeof(struct process));
763      pp->p_procid = pid;
764      pp->p_parentid = shpgrp;
765      pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING;
766      if (t->t_dflg & F_TIME)
767  	pp->p_flags |= PPTIME;
768      if (t->t_dflg & F_BACKQ)
769  	pp->p_flags |= PBACKQ;
770      if (t->t_dflg & F_HUP)
771  	pp->p_flags |= PHUP;
772      if (t->t_dcom && t->t_dcom[0] && (*t->t_dcom[0] == '{'))
773  	pp->p_flags |= PBRACE;
774      if (cmdmax == 0)
775  	morecommand(CMD_INIT);
776      cmdp = cmdstr;
777      cmdlen = 0;
778      padd(t);
779      *cmdp++ = 0;
780      if (t->t_dflg & F_PIPEOUT) {
781  	pp->p_flags |= PPOU;
782  	if (t->t_dflg & F_STDERR)
783  	    pp->p_flags |= PDIAG;
784      }
785      pp->p_command = Strsave(cmdstr);
786      if (pcurrjob) {
787  	struct process *fp;
788  
789  	/* careful here with interrupt level */
790  	pp->p_cwd = 0;
791  	pp->p_index = pcurrjob->p_index;
792  	pp->p_friends = pcurrjob;
793  	pp->p_jobid = pcurrjob->p_procid;
794  	for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)
795  	    continue;
796  	fp->p_friends = pp;
797      }
798      else {
799  	pcurrjob = pp;
800  	pp->p_jobid = pid;
801  	pp->p_friends = pp;
802  	pp->p_cwd = dcwd;
803  	dcwd->di_count++;
804  	if (pmaxindex < BIGINDEX)
805  	    pp->p_index = ++pmaxindex;
806  	else {
807  	    struct process *np;
808  
809  	    for (i = 1;; i++) {
810  		for (np = proclist.p_next; np; np = np->p_next)
811  		    if (np->p_index == i)
812  			goto tryagain;
813  		pp->p_index = i;
814  		if (i > pmaxindex)
815  		    pmaxindex = i;
816  		break;
817  	tryagain:;
818  	    }
819  	}
820  	if (pcurrent == NULL)
821  	    pcurrent = pp;
822  	else if (pprevious == NULL)
823  	    pprevious = pp;
824      }
825      pp->p_next = proclist.p_next;
826      proclist.p_next = pp;
827  #ifdef BSDTIMES
828      (void) gettimeofday(&pp->p_btime, NULL);
829  #else /* !BSDTIMES */
830  # ifdef _SEQUENT_
831      (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL);
832  # else /* !_SEQUENT_ */
833      {
834  	struct tms tmptimes;
835  
836  	pp->p_btime = times(&tmptimes);
837      }
838  # endif /* !_SEQUENT_ */
839  #endif /* !BSDTIMES */
840  }
841  
842  static void
padd(struct command * t)843  padd(struct command *t)
844  {
845      Char  **argp;
846  
847      if (t == 0)
848  	return;
849      switch (t->t_dtyp) {
850  
851      case NODE_PAREN:
852  	pads(STRLparensp);
853  	padd(t->t_dspr);
854  	pads(STRspRparen);
855  	break;
856  
857      case NODE_COMMAND:
858  	for (argp = t->t_dcom; *argp; argp++) {
859  	    pads(*argp);
860  	    if (argp[1])
861  		pads(STRspace);
862  	}
863  	break;
864  
865      case NODE_OR:
866      case NODE_AND:
867      case NODE_PIPE:
868      case NODE_LIST:
869  	padd(t->t_dcar);
870  	switch (t->t_dtyp) {
871  	case NODE_OR:
872  	    pads(STRspor2sp);
873  	    break;
874  	case NODE_AND:
875  	    pads(STRspand2sp);
876  	    break;
877  	case NODE_PIPE:
878  	    pads(STRsporsp);
879  	    break;
880  	case NODE_LIST:
881  	    pads(STRsemisp);
882  	    break;
883  	default:
884  	    break;
885  	}
886  	padd(t->t_dcdr);
887  	return;
888  
889      default:
890  	break;
891      }
892      if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) {
893  	pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp);
894  	pads(t->t_dlef);
895      }
896      if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) {
897  	pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow);
898  	if (t->t_dflg & F_STDERR)
899  	    pads(STRand);
900  	pads(STRspace);
901  	pads(t->t_drit);
902      }
903  }
904  
905  static void
pads(Char * cp)906  pads(Char *cp)
907  {
908      size_t i, len;
909  
910      /*
911       * Avoid the Quoted Space alias hack! Reported by:
912       * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks)
913       */
914      if (cp[0] == STRQNULL[0])
915  	cp++;
916  
917      i = Strlen(cp);
918  
919      len = cmdlen + i + CMD_INCR;
920      if (len >= cmdmax)
921  	morecommand(len);
922      (void) Strcpy(cmdp, cp);
923      cmdp += i;
924      cmdlen += i;
925  }
926  
927  /*
928   * psavejob - temporarily save the current job on a one level stack
929   *	so another job can be created.  Used for { } in exp6
930   *	and `` in globbing.
931   */
932  void
psavejob(void)933  psavejob(void)
934  {
935      pholdjob = pcurrjob;
936      pcurrjob = NULL;
937  }
938  
939  void
psavejob_cleanup(void * dummy)940  psavejob_cleanup(void *dummy)
941  {
942      USE(dummy);
943      pcurrjob = pholdjob;
944      pholdjob = NULL;
945  }
946  
947  /*
948   * pendjob - indicate that a job (set of commands) has been completed
949   *	or is about to begin.
950   */
951  void
pendjob(void)952  pendjob(void)
953  {
954      struct process *pp, *tp;
955  
956      if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) {
957  	pp = pcurrjob;
958  	pcurrjob = NULL;
959  	while (pp->p_procid != pp->p_jobid)
960  	    pp = pp->p_friends;
961  	xprintf("[%d]", pp->p_index);
962  	tp = pp;
963  	do {
964  	    xprintf(" %d", pp->p_procid);
965  	    pp = pp->p_friends;
966  	} while (pp != tp);
967  	xputchar('\n');
968      }
969      pholdjob = pcurrjob = 0;
970  }
971  
972  /*
973   * pprint - print a job
974   */
975  
976  /*
977   * Hacks have been added for SVR4 to deal with pipe's being spawned in
978   * reverse order
979   *
980   * David Dawes (dawes@physics.su.oz.au) Oct 1991
981   */
982  
983  static int
pprint(struct process * pp,int flag)984  pprint(struct process *pp, int flag)
985  {
986      int status, reason;
987      struct process *tp;
988      int     jobflags, pstatus, pcond;
989      const char *format;
990      int ohaderr;
991  
992  #ifdef BACKPIPE
993      struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL;
994      int inpipe = 0;
995  #endif /* BACKPIPE */
996  
997      while (pp->p_procid != pp->p_jobid)
998  	pp = pp->p_friends;
999      if (pp == pp->p_friends && (pp->p_flags & PPTIME)) {
1000  	pp->p_flags &= ~PPTIME;
1001  	pp->p_flags |= PTIME;
1002      }
1003      tp = pp;
1004      status = reason = -1;
1005      jobflags = 0;
1006      ohaderr = haderr;
1007      /* Print status to stderr, except for jobs built-in */
1008      haderr = !(flag & JOBLIST);
1009      do {
1010  #ifdef BACKPIPE
1011  	/*
1012  	 * The pipeline is reversed, so locate the real head of the pipeline
1013  	 * if pp is at the tail of a pipe (and not already in a pipeline)
1014  	 */
1015  	if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) {
1016  	    inpipe = 1;
1017  	    pipetail = pp;
1018  	    do
1019  		pp = pp->p_friends;
1020  	    while (pp->p_friends->p_flags & PPOU);
1021  	    pipehead = pp;
1022  	    pmarker = pp;
1023  	/*
1024  	 * pmarker is used to hold the place of the proc being processed, so
1025  	 * we can search for the next one downstream later.
1026  	 */
1027  	}
1028  	pcond = (tp != pp || (inpipe && tp == pp));
1029  #else /* !BACKPIPE */
1030  	pcond = (tp != pp);
1031  #endif /* BACKPIPE */
1032  
1033  	jobflags |= pp->p_flags;
1034  	pstatus = (int) (pp->p_flags & PALLSTATES);
1035  	if (pcond && linp != linbuf && !(flag & FANCY) &&
1036  	    ((pstatus == status && pp->p_reason == reason) ||
1037  	     !(flag & REASON)))
1038  	    xputchar(' ');
1039  	else {
1040  	    if (pcond && linp != linbuf)
1041  		xputchar('\n');
1042  	    if (flag & NUMBER) {
1043  #ifdef BACKPIPE
1044  		pcond = ((pp == tp && !inpipe) ||
1045  			 (inpipe && pipetail == tp && pp == pipehead));
1046  #else /* BACKPIPE */
1047  		pcond = (pp == tp);
1048  #endif /* BACKPIPE */
1049  		if (pcond)
1050  		    xprintf("[%d]%s %c ", pp->p_index,
1051  			    pp->p_index < 10 ? " " : "",
1052  			    pp == pcurrent ? '+' :
1053  			    (pp == pprevious ? '-' : ' '));
1054  		else
1055  		    xprintf("       ");
1056  	    }
1057  	    if (flag & FANCY) {
1058  		xprintf("%5d ", pp->p_procid);
1059  #ifdef TCF
1060  		xprintf("%11s ", sitename(pp->p_procid));
1061  #endif /* TCF */
1062  	    }
1063  	    if (flag & (REASON | AREASON)) {
1064  		if (flag & NAME)
1065  		    format = "%-30s";
1066  		else
1067  		    format = "%s";
1068  		if (pstatus == status) {
1069  		    if (pp->p_reason == reason) {
1070  			xprintf(format, "");
1071  			goto prcomd;
1072  		    }
1073  		    else
1074  			reason = (int) pp->p_reason;
1075  		}
1076  		else {
1077  		    status = pstatus;
1078  		    reason = (int) pp->p_reason;
1079  		}
1080  		switch (status) {
1081  
1082  		case PRUNNING:
1083  		    xprintf(format, CGETS(17, 4, "Running "));
1084  		    break;
1085  
1086  		case PINTERRUPTED:
1087  		case PSTOPPED:
1088  		case PSIGNALED:
1089  		    /*
1090  		     * tell what happened to the background job
1091  		     * From: Michael Schroeder
1092  		     * <mlschroe@immd4.informatik.uni-erlangen.de>
1093  		     */
1094  		    if ((flag & REASON)
1095  			|| ((flag & AREASON)
1096  			    && reason != SIGINT
1097  			    && (reason != SIGPIPE
1098  				|| (pp->p_flags & PPOU) == 0))) {
1099  			char *ptr;
1100  			int free_ptr;
1101  
1102  			free_ptr = 0;
1103  			ptr = (char *)(intptr_t)mesg[pp->p_reason & 0177].pname;
1104  			if (ptr == NULL) {
1105  			    ptr = xasprintf("%s %d", CGETS(17, 5, "Signal"),
1106  					    pp->p_reason & 0177);
1107  			    cleanup_push(ptr, xfree);
1108  			    free_ptr = 1;
1109  			}
1110  			xprintf(format, ptr);
1111  			if (free_ptr != 0)
1112  			    cleanup_until(ptr);
1113  		    }
1114  		    else
1115  			reason = -1;
1116  		    break;
1117  
1118  		case PNEXITED:
1119  		case PAEXITED:
1120  		    if (flag & REASON) {
1121  			if (pp->p_reason)
1122  			    xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason);
1123  			else
1124  			    xprintf(format, CGETS(17, 7, "Done"));
1125  		    }
1126  		    break;
1127  
1128  		default:
1129  		    xprintf(CGETS(17, 8, "BUG: status=%-9o"),
1130  			    status);
1131  		}
1132  	    }
1133  	}
1134  prcomd:
1135  	if (flag & NAME) {
1136  	    xprintf("%S", pp->p_command);
1137  	    if (pp->p_flags & PPOU)
1138  		xprintf(" |");
1139  	    if (pp->p_flags & PDIAG)
1140  		xprintf("&");
1141  	}
1142  	if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED)
1143  	    xprintf("%s", CGETS(17, 9, " (core dumped)"));
1144  	if (tp == pp->p_friends) {
1145  	    if (flag & AMPERSAND)
1146  		xprintf(" &");
1147  	    if (flag & JOBDIR &&
1148  		!eq(tp->p_cwd->di_name, dcwd->di_name)) {
1149  		xprintf("%s", CGETS(17, 10, " (wd: "));
1150  		dtildepr(tp->p_cwd->di_name);
1151  		xprintf(")");
1152  	    }
1153  	}
1154  	if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) {
1155  	    if (linp != linbuf)
1156  		xprintf("\n\t");
1157  #if defined(BSDTIMES) || defined(_SEQUENT_)
1158  	    prusage(&zru, &pp->p_rusage, &pp->p_etime,
1159  		    &pp->p_btime);
1160  #else /* !BSDTIMES && !SEQUENT */
1161  	    lru.tms_utime = pp->p_utime;
1162  	    lru.tms_stime = pp->p_stime;
1163  	    lru.tms_cutime = 0;
1164  	    lru.tms_cstime = 0;
1165  	    prusage(&zru, &lru, pp->p_etime,
1166  		    pp->p_btime);
1167  #endif /* !BSDTIMES && !SEQUENT */
1168  
1169  	}
1170  #ifdef BACKPIPE
1171  	pcond = ((tp == pp->p_friends && !inpipe) ||
1172  		 (inpipe && pipehead->p_friends == tp && pp == pipetail));
1173  #else  /* !BACKPIPE */
1174  	pcond = (tp == pp->p_friends);
1175  #endif /* BACKPIPE */
1176  	if (pcond) {
1177  	    if (linp != linbuf)
1178  		xputchar('\n');
1179  	    if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) {
1180  		xprintf("%s", CGETS(17, 11, "(wd now: "));
1181  		dtildepr(dcwd->di_name);
1182  		xprintf(")\n");
1183  	    }
1184  	}
1185  #ifdef BACKPIPE
1186  	if (inpipe) {
1187  	    /*
1188  	     * if pmaker == pipetail, we are finished that pipeline, and
1189  	     * can now skip to past the head
1190  	     */
1191  	    if (pmarker == pipetail) {
1192  		inpipe = 0;
1193  		pp = pipehead;
1194  	    }
1195  	    else {
1196  	    /*
1197  	     * set pp to one before the one we want next, so the while below
1198  	     * increments to the correct spot.
1199  	     */
1200  		do
1201  		    pp = pp->p_friends;
1202  	    	while (pp->p_friends->p_friends != pmarker);
1203  	    	pmarker = pp->p_friends;
1204  	    }
1205  	}
1206  	pcond = ((pp = pp->p_friends) != tp || inpipe);
1207  #else /* !BACKPIPE */
1208  	pcond = ((pp = pp->p_friends) != tp);
1209  #endif /* BACKPIPE */
1210      } while (pcond);
1211  
1212      if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) {
1213  	if (jobflags & NUMBER)
1214  	    xprintf("       ");
1215  	ptprint(tp);
1216      }
1217      haderr = ohaderr;
1218      return (jobflags);
1219  }
1220  
1221  /*
1222   * All 4.3 BSD derived implementations are buggy and I've had enough.
1223   * The following implementation produces similar code and works in all
1224   * cases. The 4.3BSD one works only for <, >, !=
1225   */
1226  # undef timercmp
1227  #  define timercmp(tvp, uvp, cmp) \
1228        (((tvp)->tv_sec == (uvp)->tv_sec) ? \
1229  	   ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
1230  	   ((tvp)->tv_sec  cmp (uvp)->tv_sec))
1231  
1232  static void
ptprint(struct process * tp)1233  ptprint(struct process *tp)
1234  {
1235  #ifdef BSDTIMES
1236      struct timeval tetime, diff;
1237      static struct timeval ztime;
1238      struct sysrusage ru;
1239      struct process *pp = tp;
1240  
1241      ru = zru;
1242      tetime = ztime;
1243      do {
1244  	ruadd(&ru, &pp->p_rusage);
1245  	tvsub(&diff, &pp->p_etime, &pp->p_btime);
1246  	if (timercmp(&diff, &tetime, >))
1247  	    tetime = diff;
1248      } while ((pp = pp->p_friends) != tp);
1249      prusage(&zru, &ru, &tetime, &ztime);
1250  #else /* !BSDTIMES */
1251  # ifdef _SEQUENT_
1252      timeval_t tetime, diff;
1253      static timeval_t ztime;
1254      struct process_stats ru;
1255      struct process *pp = tp;
1256  
1257      ru = zru;
1258      tetime = ztime;
1259      do {
1260  	ruadd(&ru, &pp->p_rusage);
1261  	tvsub(&diff, &pp->p_etime, &pp->p_btime);
1262  	if (timercmp(&diff, &tetime, >))
1263  	    tetime = diff;
1264      } while ((pp = pp->p_friends) != tp);
1265      prusage(&zru, &ru, &tetime, &ztime);
1266  # else /* !_SEQUENT_ */
1267  #  ifndef POSIX
1268      static time_t ztime = 0;
1269      static time_t zu_time = 0;
1270      static time_t zs_time = 0;
1271      time_t  tetime, diff;
1272      time_t  u_time, s_time;
1273  
1274  #  else	/* POSIX */
1275      static clock_t ztime = 0;
1276      static clock_t zu_time = 0;
1277      static clock_t zs_time = 0;
1278      clock_t tetime, diff;
1279      clock_t u_time, s_time;
1280  
1281  #  endif /* POSIX */
1282      struct tms zts, rts;
1283      struct process *pp = tp;
1284  
1285      u_time = zu_time;
1286      s_time = zs_time;
1287      tetime = ztime;
1288      do {
1289  	u_time += pp->p_utime;
1290  	s_time += pp->p_stime;
1291  	diff = pp->p_etime - pp->p_btime;
1292  	if (diff > tetime)
1293  	    tetime = diff;
1294      } while ((pp = pp->p_friends) != tp);
1295      zts.tms_utime = zu_time;
1296      zts.tms_stime = zs_time;
1297      zts.tms_cutime = 0;
1298      zts.tms_cstime = 0;
1299      rts.tms_utime = u_time;
1300      rts.tms_stime = s_time;
1301      rts.tms_cutime = 0;
1302      rts.tms_cstime = 0;
1303      prusage(&zts, &rts, tetime, ztime);
1304  # endif /* !_SEQUENT_ */
1305  #endif	/* !BSDTIMES */
1306  }
1307  
1308  /*
1309   * dojobs - print all jobs
1310   */
1311  /*ARGSUSED*/
1312  void
dojobs(Char ** v,struct command * c)1313  dojobs(Char **v, struct command *c)
1314  {
1315      struct process *pp;
1316      int flag = NUMBER | NAME | REASON | JOBLIST;
1317      int     i;
1318  
1319      USE(c);
1320      if (chkstop)
1321  	chkstop = 2;
1322      if (*++v) {
1323  	if (v[1] || !eq(*v, STRml))
1324  	    stderror(ERR_JOBS);
1325  	flag |= FANCY | JOBDIR;
1326      }
1327      for (i = 1; i <= pmaxindex; i++)
1328  	for (pp = proclist.p_next; pp; pp = pp->p_next)
1329  	    if (pp->p_index == i && pp->p_procid == pp->p_jobid) {
1330  		pp->p_flags &= ~PNEEDNOTE;
1331  		if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED)))
1332  		    pflush(pp);
1333  		break;
1334  	    }
1335  }
1336  
1337  /*
1338   * dofg - builtin - put the job into the foreground
1339   */
1340  /*ARGSUSED*/
1341  void
dofg(Char ** v,struct command * c)1342  dofg(Char **v, struct command *c)
1343  {
1344      struct process *pp;
1345  
1346      USE(c);
1347      okpcntl();
1348      ++v;
1349      do {
1350  	pp = pfind(*v);
1351  	if (!pstart(pp, 1)) {
1352  	    pp->p_procid = 0;
1353  	    stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1354  	    continue;
1355  	}
1356  	pjwait(pp);
1357      } while (*v && *++v);
1358  }
1359  
1360  /*
1361   * %... - builtin - put the job into the foreground
1362   */
1363  /*ARGSUSED*/
1364  void
dofg1(Char ** v,struct command * c)1365  dofg1(Char **v, struct command *c)
1366  {
1367      struct process *pp;
1368  
1369      USE(c);
1370      okpcntl();
1371      pp = pfind(v[0]);
1372      if (!pstart(pp, 1)) {
1373  	pp->p_procid = 0;
1374  	stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1375  	return;
1376      }
1377      pjwait(pp);
1378  }
1379  
1380  /*
1381   * dobg - builtin - put the job into the background
1382   */
1383  /*ARGSUSED*/
1384  void
dobg(Char ** v,struct command * c)1385  dobg(Char **v, struct command *c)
1386  {
1387      struct process *pp;
1388  
1389      USE(c);
1390      okpcntl();
1391      ++v;
1392      do {
1393  	pp = pfind(*v);
1394  	if (!pstart(pp, 0)) {
1395  	    pp->p_procid = 0;
1396  	    stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1397  	}
1398      } while (*v && *++v);
1399  }
1400  
1401  /*
1402   * %... & - builtin - put the job into the background
1403   */
1404  /*ARGSUSED*/
1405  void
dobg1(Char ** v,struct command * c)1406  dobg1(Char **v, struct command *c)
1407  {
1408      struct process *pp;
1409  
1410      USE(c);
1411      pp = pfind(v[0]);
1412      if (!pstart(pp, 0)) {
1413  	pp->p_procid = 0;
1414  	stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno));
1415      }
1416  }
1417  
1418  /*
1419   * dostop - builtin - stop the job
1420   */
1421  /*ARGSUSED*/
1422  void
dostop(Char ** v,struct command * c)1423  dostop(Char **v, struct command *c)
1424  {
1425      USE(c);
1426  #ifdef BSDJOBS
1427      pkill(++v, SIGSTOP);
1428  #endif /* BSDJOBS */
1429  }
1430  
1431  /*
1432   * dokill - builtin - superset of kill (1)
1433   */
1434  /*ARGSUSED*/
1435  void
dokill(Char ** v,struct command * c)1436  dokill(Char **v, struct command *c)
1437  {
1438      int signum, len = 0;
1439      const char *name;
1440      Char *sigptr;
1441  
1442      USE(c);
1443      v++;
1444      if (v[0] && v[0][0] == '-') {
1445  	if (v[0][1] == 'l') {
1446  	    for (signum = 0; signum <= nsig; signum++) {
1447  		if ((name = mesg[signum].iname) != NULL) {
1448  		    len += strlen(name) + 1;
1449  		    if (len >= TermH - 1) {
1450  			xputchar('\n');
1451  			len = strlen(name) + 1;
1452  		    }
1453  		    xprintf("%s ", name);
1454  		}
1455  	    }
1456  	    xputchar('\n');
1457  	    return;
1458  	}
1459   	sigptr = &v[0][1];
1460   	if (v[0][1] == 's') {
1461   	    if (v[1]) {
1462   		v++;
1463   		sigptr = &v[0][0];
1464   	    } else {
1465   		stderror(ERR_NAME | ERR_TOOFEW);
1466   	    }
1467   	}
1468   	if (Isdigit(*sigptr)) {
1469  	    char *ep;
1470   	    signum = strtoul(short2str(sigptr), &ep, 0);
1471  	    if (*ep || signum < 0 || signum > (MAXSIG-1))
1472  		stderror(ERR_NAME | ERR_BADSIG);
1473  	}
1474  	else {
1475  	    for (signum = 0; signum <= nsig; signum++)
1476  		if (mesg[signum].iname &&
1477   		    eq(sigptr, str2short(mesg[signum].iname)))
1478  		    goto gotsig;
1479   	    setname(short2str(sigptr));
1480  	    stderror(ERR_NAME | ERR_UNKSIG);
1481  	}
1482  gotsig:
1483  	v++;
1484      }
1485      else
1486  	signum = SIGTERM;
1487      pkill(v, signum);
1488  }
1489  
1490  static void
pkill(Char ** v,int signum)1491  pkill(Char **v, int signum)
1492  {
1493      struct process *pp, *np;
1494      int jobflags = 0, err1 = 0;
1495      pid_t     pid;
1496      Char *cp, **vp, **globbed;
1497  
1498      /* Avoid globbing %?x patterns */
1499      for (vp = v; vp && *vp; vp++)
1500  	if (**vp == '%')
1501  	    (void) quote(*vp);
1502  
1503      v = glob_all_or_error(v);
1504      globbed = v;
1505      cleanup_push(globbed, blk_cleanup);
1506  
1507      pchild_disabled++;
1508      cleanup_push(&pchild_disabled, disabled_cleanup);
1509      if (setintr) {
1510  	pintr_disabled++;
1511  	cleanup_push(&pintr_disabled, disabled_cleanup);
1512      }
1513  
1514      while (v && (cp = *v)) {
1515  	if (*cp == '%') {
1516  	    np = pp = pfind(cp);
1517  	    do
1518  		jobflags |= np->p_flags;
1519  	    while ((np = np->p_friends) != pp);
1520  #ifdef BSDJOBS
1521  	    switch (signum) {
1522  
1523  	    case SIGSTOP:
1524  	    case SIGTSTP:
1525  	    case SIGTTIN:
1526  	    case SIGTTOU:
1527  		if ((jobflags & PRUNNING) == 0) {
1528  # ifdef SUSPENDED
1529  		    xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp);
1530  # else /* !SUSPENDED */
1531  		    xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp);
1532  # endif /* !SUSPENDED */
1533  		    err1++;
1534  		    goto cont;
1535  		}
1536  		break;
1537  		/*
1538  		 * suspend a process, kill -CONT %, then type jobs; the shell
1539  		 * says it is suspended, but it is running; thanks jaap..
1540  		 */
1541  	    case SIGCONT:
1542  		if (!pstart(pp, 0)) {
1543  		    pp->p_procid = 0;
1544  		    stderror(ERR_NAME|ERR_BADJOB, pp->p_command,
1545  			     strerror(errno));
1546  		}
1547  		goto cont;
1548  	    default:
1549  		break;
1550  	    }
1551  #endif /* BSDJOBS */
1552  	    if (killpg(pp->p_jobid, signum) < 0) {
1553  		xprintf("%S: %s\n", cp, strerror(errno));
1554  		err1++;
1555  	    }
1556  #ifdef BSDJOBS
1557  	    if (signum == SIGTERM || signum == SIGHUP)
1558  		(void) killpg(pp->p_jobid, SIGCONT);
1559  #endif /* BSDJOBS */
1560  	}
1561  	else if (!(Isdigit(*cp) || *cp == '-'))
1562  	    stderror(ERR_NAME | ERR_JOBARGS);
1563  	else {
1564  	    char *ep;
1565  #ifndef WINNT_NATIVE
1566  	    pid = strtol(short2str(cp), &ep, 10);
1567  #else
1568  	    pid = strtoul(short2str(cp), &ep, 0);
1569  #endif /* WINNT_NATIVE */
1570  	    if (*ep)
1571  		stderror(ERR_NAME | ERR_JOBARGS);
1572  	    else if (kill(pid, signum) < 0) {
1573  		xprintf("%d: %s\n", pid, strerror(errno));
1574  		err1++;
1575  		goto cont;
1576  	    }
1577  #ifdef BSDJOBS
1578  	    if (signum == SIGTERM || signum == SIGHUP)
1579  		(void) kill(pid, SIGCONT);
1580  #endif /* BSDJOBS */
1581  	}
1582  cont:
1583  	v++;
1584      }
1585      cleanup_until(&pchild_disabled);
1586      if (err1)
1587  	stderror(ERR_SILENT);
1588  }
1589  
1590  /*
1591   * pstart - start the job in foreground/background
1592   */
1593  int
pstart(struct process * pp,int foregnd)1594  pstart(struct process *pp, int foregnd)
1595  {
1596      int rv = 0;
1597      struct process *np;
1598      /* We don't use jobflags in this function right now (see below) */
1599      /* long    jobflags = 0; */
1600  
1601      pchild_disabled++;
1602      cleanup_push(&pchild_disabled, disabled_cleanup);
1603      np = pp;
1604      do {
1605  	/* We don't use jobflags in this function right now (see below) */
1606  	/* jobflags |= np->p_flags; */
1607  	if (np->p_flags & (PRUNNING | PSTOPPED)) {
1608  	    np->p_flags |= PRUNNING;
1609  	    np->p_flags &= ~PSTOPPED;
1610  	    if (foregnd)
1611  		np->p_flags |= PFOREGND;
1612  	    else
1613  		np->p_flags &= ~PFOREGND;
1614  	}
1615      } while ((np = np->p_friends) != pp);
1616      if (!foregnd)
1617  	pclrcurr(pp);
1618      (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND);
1619  
1620      /* GrP run jobcmd hook if foregrounding */
1621      if (foregnd) {
1622  	job_cmd(pp->p_command);
1623      }
1624  
1625  #ifdef BSDJOBS
1626      if (foregnd) {
1627  	rv = tcsetpgrp(FSHTTY, pp->p_jobid);
1628      }
1629      /*
1630       * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU
1631       * 2. parent process (csh) receives SIGCHLD
1632       * 3. The "csh" signal handling function pchild() is invoked
1633       *    with a SIGCHLD signal.
1634       * 4. pchild() calls wait3(WNOHANG) which returns 0.
1635       *    The child process is NOT ready to be waited for at this time.
1636       *    pchild() returns without picking-up the correct status
1637       *    for the child process which generated the SIGCHLD.
1638       * 5. CONSEQUENCE : csh is UNaware that the process is stopped
1639       * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED)
1640       * 	  (beto@aixwiz.austin.ibm.com - aug/03/91)
1641       * 7. I removed the line completely and added extra checks for
1642       *    pstart, so that if a job gets attached to and dies inside
1643       *    a debugger it does not confuse the shell. [christos]
1644       * 8. on the nec sx-4 there seems to be a problem, which requires
1645       *    a syscall(151, getpid(), getpid()) in osinit. Don't ask me
1646       *    what this is doing. [schott@rzg.mpg.de]
1647       */
1648  
1649      if (rv != -1)
1650  	rv = killpg(pp->p_jobid, SIGCONT);
1651  #endif /* BSDJOBS */
1652      cleanup_until(&pchild_disabled);
1653      return rv != -1;
1654  }
1655  
1656  void
panystop(int neednl)1657  panystop(int neednl)
1658  {
1659      struct process *pp;
1660  
1661      chkstop = 2;
1662      for (pp = proclist.p_next; pp; pp = pp->p_next)
1663  	if (pp->p_flags & PSTOPPED)
1664  	    stderror(ERR_STOPPED, neednl ? "\n" : "");
1665  }
1666  
1667  struct process *
pfind(Char * cp)1668  pfind(Char *cp)
1669  {
1670      struct process *pp, *np;
1671  
1672      if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) {
1673  	if (pcurrent == NULL)
1674  	    stderror(ERR_NAME | ERR_JOBCUR);
1675  	return (pcurrent);
1676      }
1677      if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) {
1678  	if (pprevious == NULL)
1679  	    stderror(ERR_NAME | ERR_JOBPREV);
1680  	return (pprevious);
1681      }
1682      if (Isdigit(cp[1])) {
1683  	int     idx = atoi(short2str(cp + 1));
1684  
1685  	for (pp = proclist.p_next; pp; pp = pp->p_next)
1686  	    if (pp->p_index == idx && pp->p_procid == pp->p_jobid)
1687  		return (pp);
1688  	stderror(ERR_NAME | ERR_NOSUCHJOB);
1689      }
1690      np = NULL;
1691      for (pp = proclist.p_next; pp; pp = pp->p_next)
1692  	if (pp->p_procid == pp->p_jobid) {
1693  	    if (cp[1] == '?') {
1694  		Char *dp;
1695  
1696  		for (dp = pp->p_command; *dp; dp++) {
1697  		    if (*dp != cp[2])
1698  			continue;
1699  		    if (prefix(cp + 2, dp))
1700  			goto match;
1701  		}
1702  	    }
1703  	    else if (prefix(cp + 1, pp->p_command)) {
1704  	match:
1705  		if (np)
1706  		    stderror(ERR_NAME | ERR_AMBIG);
1707  		np = pp;
1708  	    }
1709  	}
1710      if (np)
1711  	return (np);
1712      stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB));
1713      /* NOTREACHED */
1714      return (0);
1715  }
1716  
1717  
1718  /*
1719   * pgetcurr - find most recent job that is not pp, preferably stopped
1720   */
1721  static struct process *
pgetcurr(struct process * pp)1722  pgetcurr(struct process *pp)
1723  {
1724      struct process *np;
1725      struct process *xp = NULL;
1726  
1727      for (np = proclist.p_next; np; np = np->p_next)
1728  	if (np != pcurrent && np != pp && np->p_procid &&
1729  	    np->p_procid == np->p_jobid) {
1730  	    if (np->p_flags & PSTOPPED)
1731  		return (np);
1732  	    if (xp == NULL)
1733  		xp = np;
1734  	}
1735      return (xp);
1736  }
1737  
1738  /*
1739   * donotify - flag the job so as to report termination asynchronously
1740   */
1741  /*ARGSUSED*/
1742  void
donotify(Char ** v,struct command * c)1743  donotify(Char **v, struct command *c)
1744  {
1745      struct process *pp;
1746  
1747      USE(c);
1748      pp = pfind(*++v);
1749      pp->p_flags |= PNOTIFY;
1750  }
1751  
1752  #ifdef SIGSYNCH
1753  static void
synch_handler(int sno)1754  synch_handler(int sno)
1755  {
1756      USE(sno);
1757  }
1758  #endif /* SIGSYNCH */
1759  
1760  /*
1761   * Do the fork and whatever should be done in the child side that
1762   * should not be done if we are not forking at all (like for simple builtin's)
1763   * Also do everything that needs any signals fiddled with in the parent side
1764   *
1765   * Wanttty tells whether process and/or tty pgrps are to be manipulated:
1766   *	-1:	leave tty alone; inherit pgrp from parent
1767   *	 0:	already have tty; manipulate process pgrps only
1768   *	 1:	want to claim tty; manipulate process and tty pgrps
1769   * It is usually just the value of tpgrp.
1770   */
1771  
1772  pid_t
pfork(struct command * t,int wanttty)1773  pfork(struct command *t, int wanttty)
1774  {
1775      pid_t pid;
1776      int    ignint = 0;
1777      pid_t pgrp;
1778  #ifdef SIGSYNCH
1779      struct sigaction osa, nsa;
1780  #endif /* SIGSYNCH */
1781  
1782      /*
1783       * A child will be uninterruptible only under very special conditions.
1784       * Remember that the semantics of '&' is implemented by disconnecting the
1785       * process from the tty so signals do not need to ignored just for '&'.
1786       * Thus signals are set to default action for children unless: we have had
1787       * an "onintr -" (then specifically ignored) we are not playing with
1788       * signals (inherit action)
1789       */
1790      if (setintr)
1791  	ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT))
1792  	    || (gointr && eq(gointr, STRminus));
1793  
1794      /*
1795       * Check for maximum nesting of 16 processes to avoid Forking loops
1796       */
1797      if (child == 16)
1798  	stderror(ERR_NESTING, 16);
1799  #ifdef SIGSYNCH
1800      nsa.sa_handler = synch_handler;
1801      sigfillset(&nsa.sa_mask);
1802      nsa.sa_flags = SA_RESTART;
1803      if (sigaction(SIGSYNCH, &nsa, &osa))
1804  	stderror(ERR_SYSTEM, "pfork: sigaction set", strerror(errno));
1805  #endif /* SIGSYNCH */
1806      /*
1807       * Hold pchild() until we have the process installed in our table.
1808       */
1809      if (wanttty < 0) {
1810  	pchild_disabled++;
1811  	cleanup_push(&pchild_disabled, disabled_cleanup);
1812      }
1813      while ((pid = fork()) == -1)
1814  	if (setintr == 0)
1815  	    (void) sleep(FORKSLEEP);
1816  	else
1817  	    stderror(ERR_NOPROC);
1818      if (pid == 0) {
1819  	(void)cleanup_push_mark(); /* Never to be popped */
1820  	pchild_disabled = 0;
1821  	settimes();
1822  	pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
1823  	pflushall();
1824  	pcurrjob = NULL;
1825  #if !defined(BSDTIMES) && !defined(_SEQUENT_)
1826  	timesdone = 0;
1827  #endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */
1828  	child++;
1829  	if (setintr) {
1830  	    setintr = 0;	/* until I think otherwise */
1831  	    /*
1832  	     * Children just get blown away on SIGINT, SIGQUIT unless "onintr
1833  	     * -" seen.
1834  	     */
1835  	    (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL);
1836  	    (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL);
1837  #ifdef BSDJOBS
1838  	    if (wanttty >= 0) {
1839  		/* make stoppable */
1840  		(void) signal(SIGTSTP, SIG_DFL);
1841  		(void) signal(SIGTTIN, SIG_DFL);
1842  		(void) signal(SIGTTOU, SIG_DFL);
1843  	    }
1844  #endif /* BSDJOBS */
1845  	    sigaction(SIGTERM, &parterm, NULL);
1846  	}
1847  	else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) {
1848  	    (void) signal(SIGINT, SIG_IGN);
1849  	    (void) signal(SIGQUIT, SIG_IGN);
1850  	}
1851  #ifdef OREO
1852  	signal(SIGIO, SIG_IGN);	/* ignore SIGIO in child too */
1853  #endif /* OREO */
1854  
1855  	pgetty(wanttty, pgrp);
1856  	/*
1857  	 * Nohup and nice apply only to NODE_COMMAND's but it would be nice
1858  	 * (?!?) if you could say "nohup (foo;bar)" Then the parser would have
1859  	 * to know about nice/nohup/time
1860  	 */
1861  	if (t->t_dflg & F_NOHUP)
1862  	    (void) signal(SIGHUP, SIG_IGN);
1863  	if (t->t_dflg & F_NICE) {
1864  	    int nval = SIGN_EXTEND_CHAR(t->t_nice);
1865  #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
1866  	    if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno)
1867  		stderror(ERR_SYSTEM, "setpriority", strerror(errno));
1868  #else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */
1869  	    (void) nice(nval);
1870  #endif /* HAVE_SETPRIORITY  && PRIO_PROCESS */
1871  	}
1872  #ifdef F_VER
1873          if (t->t_dflg & F_VER) {
1874  	    tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53);
1875  	    dohash(NULL, NULL);
1876  	}
1877  #endif /* F_VER */
1878  #ifdef SIGSYNCH
1879  	/* rfw 8/89 now parent can continue */
1880  	if (kill(getppid(), SIGSYNCH))
1881  	    stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno));
1882  #endif /* SIGSYNCH */
1883  
1884      }
1885      else {
1886  #ifdef POSIXJOBS
1887          if (wanttty >= 0) {
1888  	    /*
1889  	     * `Walking' process group fix from Beto Appleton.
1890  	     * (beto@aixwiz.austin.ibm.com)
1891  	     * If setpgid fails at this point that means that
1892  	     * our process leader has died. We flush the current
1893  	     * job and become the process leader ourselves.
1894  	     * The parent will figure that out later.
1895  	     */
1896  	    pgrp = pcurrjob ? pcurrjob->p_jobid : pid;
1897  	    if (setpgid(pid, pgrp) == -1 && errno == EPERM) {
1898  		pcurrjob = NULL;
1899  		/*
1900  		 * We don't care if this causes an error here;
1901  		 * then we are already in the right process group
1902  		 */
1903  		(void) setpgid(pid, pgrp = pid);
1904  	    }
1905  	}
1906  #endif /* POSIXJOBS */
1907  	palloc(pid, t);
1908  #ifdef SIGSYNCH
1909  	{
1910  	    sigset_t pause_mask;
1911  
1912  	/*
1913  	 * rfw 8/89 Wait for child to own terminal.  Solves half of ugly
1914  	 * synchronization problem.  With this change, we know that the only
1915  	 * reason setpgrp to a previous process in a pipeline can fail is that
1916  	 * the previous process has already exited. Without this hack, he may
1917  	 * either have exited or not yet started to run.  Two uglies become
1918  	 * one.
1919  	 */
1920  	    sigprocmask(SIG_BLOCK, NULL, &pause);
1921  	    sigdelset(&pause_mask, SIGCHLD);
1922  	    sigdelset(&pause_mask, SIGSYNCH);
1923  	    sigsuspend(&pause_mask);
1924  	    (void)handle_pending_signals();
1925  	    if (sigaction(SIGSYNCH, &osa, NULL))
1926  		stderror(ERR_SYSTEM, "pfork parent: sigaction restore",
1927  			 strerror(errno));
1928  	}
1929  #endif /* SIGSYNCH */
1930  
1931  	if (wanttty < 0)
1932  	    cleanup_until(&pchild_disabled);
1933      }
1934      return (pid);
1935  }
1936  
1937  static void
okpcntl(void)1938  okpcntl(void)
1939  {
1940      if (tpgrp == -1)
1941  	stderror(ERR_JOBCONTROL);
1942      if (tpgrp == 0)
1943  	stderror(ERR_JOBCTRLSUB);
1944  }
1945  
1946  
1947  static void
setttypgrp(int pgrp)1948  setttypgrp(int pgrp)
1949  {
1950      /*
1951       * If we are piping out a builtin, eg. 'echo | more' things can go
1952       * out of sequence, i.e. the more can run before the echo. This
1953       * can happen even if we have vfork, since the echo will be forked
1954       * with the regular fork. In this case, we need to set the tty
1955       * pgrp ourselves. If that happens, then the process will be still
1956       * alive. And the tty process group will already be set.
1957       * This should fix the famous sequent problem as a side effect:
1958       *    The controlling terminal is lost if all processes in the
1959       *    terminal process group are zombies. In this case tcgetpgrp()
1960       *    returns 0. If this happens we must set the terminal process
1961       *    group again.
1962       */
1963      if (tcgetpgrp(FSHTTY) != pgrp) {
1964  #ifdef POSIXJOBS
1965  	struct sigaction old;
1966  
1967          /*
1968  	 * tcsetpgrp will set SIGTTOU to all the the processes in
1969  	 * the background according to POSIX... We ignore this here.
1970  	 */
1971  	sigaction(SIGTTOU, NULL, &old);
1972  	signal(SIGTTOU, SIG_IGN);
1973  #endif
1974  	(void) tcsetpgrp(FSHTTY, pgrp);
1975  # ifdef POSIXJOBS
1976  	sigaction(SIGTTOU, &old, NULL);
1977  # endif
1978  
1979      }
1980  }
1981  
1982  
1983  /*
1984   * if we don't have vfork(), things can still go in the wrong order
1985   * resulting in the famous 'Stopped (tty output)'. But some systems
1986   * don't permit the setpgid() call, (these are more recent secure
1987   * systems such as ibm's aix), when they do. Then we'd rather print
1988   * an error message than hang the shell!
1989   * I am open to suggestions how to fix that.
1990   */
1991  void
pgetty(int wanttty,pid_t pgrp)1992  pgetty(int wanttty, pid_t pgrp)
1993  {
1994  #ifdef BSDJOBS
1995  # ifdef POSIXJOBS
1996      sigset_t oset, set;
1997  # endif /* POSIXJOBS */
1998  
1999      jobdebug_xprintf(("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n",
2000  		      wanttty, (int)getpid(), (int)pgrp, (int)mygetpgrp(),
2001  		      (int)tcgetpgrp(FSHTTY)));
2002  # ifdef POSIXJOBS
2003      /*
2004       * christos: I am blocking the tty signals till I've set things
2005       * correctly....
2006       */
2007      if (wanttty > 0) {
2008  	sigemptyset(&set);
2009  	sigaddset(&set, SIGTSTP);
2010  	sigaddset(&set, SIGTTIN);
2011  	(void)sigprocmask(SIG_BLOCK, &set, &oset);
2012  	cleanup_push(&oset, sigprocmask_cleanup);
2013      }
2014  # endif /* POSIXJOBS */
2015  
2016  # ifndef POSIXJOBS
2017      if (wanttty > 0)
2018  	setttypgrp(pgrp);
2019  # endif /* !POSIXJOBS */
2020  
2021      /*
2022       * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
2023       * Don't check for tpgrp >= 0 so even non-interactive shells give
2024       * background jobs process groups Same for the comparison in the other part
2025       * of the #ifdef
2026       */
2027      if (wanttty >= 0) {
2028  	if (setpgid(0, pgrp) == -1) {
2029  # ifdef POSIXJOBS
2030  	    /* Walking process group fix; see above */
2031  	    if (setpgid(0, pgrp = getpid()) == -1) {
2032  # endif /* POSIXJOBS */
2033  		stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno));
2034  		xexit(0);
2035  # ifdef POSIXJOBS
2036  	    }
2037  	    wanttty = pgrp;  /* Now we really want the tty, since we became the
2038  			      * the process group leader
2039  			      */
2040  # endif /* POSIXJOBS */
2041  	}
2042      }
2043  
2044  # ifdef POSIXJOBS
2045      if (wanttty > 0) {
2046  	setttypgrp(pgrp);
2047  	cleanup_until(&oset);
2048      }
2049  # endif /* POSIXJOBS */
2050  
2051      jobdebug_xprintf(("wanttty %d pid %d pgrp %d tpgrp %d\n",
2052  		      wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY)));
2053  
2054      if (tpgrp > 0)
2055  	tpgrp = 0;		/* gave tty away */
2056  #endif /* BSDJOBS */
2057  }
2058