sh.proc.c revision 83098
183098Smp/* $Header: /src/pub/tcsh/sh.proc.c,v 3.75 2001/08/06 23:52:03 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.proc.c: Job manipulations 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 1759243Sobrien * 3. All advertising materials mentioning features or use of this software 1859243Sobrien * must display the following acknowledgement: 1959243Sobrien * This product includes software developed by the University of 2059243Sobrien * California, Berkeley and its contributors. 2159243Sobrien * 4. Neither the name of the University nor the names of its contributors 2259243Sobrien * may be used to endorse or promote products derived from this software 2359243Sobrien * without specific prior written permission. 2459243Sobrien * 2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2859243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3559243Sobrien * SUCH DAMAGE. 3659243Sobrien */ 3759243Sobrien#include "sh.h" 3859243Sobrien 3983098SmpRCSID("$Id: sh.proc.c,v 3.75 2001/08/06 23:52:03 christos Exp $") 4059243Sobrien 4159243Sobrien#include "ed.h" 4259243Sobrien#include "tc.h" 4359243Sobrien#include "tc.wait.h" 4459243Sobrien 4569408Sache#ifdef WINNT_NATIVE 4659243Sobrien#undef POSIX 4759243Sobrien#define POSIX 4869408Sache#endif /* WINNT_NATIVE */ 4959243Sobrien#ifdef aiws 5059243Sobrien# undef HZ 5159243Sobrien# define HZ 16 5259243Sobrien#endif /* aiws */ 5359243Sobrien 5459243Sobrien#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) || defined(linux) 5559243Sobrien# define BSDWAIT 5659243Sobrien#endif /* _BSD || (IRIS4D && __STDC__) || __lucid || linux */ 5759243Sobrien#ifndef WTERMSIG 5859243Sobrien# define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 5959243Sobrien# ifndef BSDWAIT 6059243Sobrien# define BSDWAIT 6159243Sobrien# endif /* !BSDWAIT */ 6259243Sobrien#endif /* !WTERMSIG */ 6359243Sobrien#ifndef WEXITSTATUS 6459243Sobrien# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 6559243Sobrien#endif /* !WEXITSTATUS */ 6659243Sobrien#ifndef WSTOPSIG 6759243Sobrien# define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 6859243Sobrien#endif /* !WSTOPSIG */ 6959243Sobrien 7059243Sobrien#ifdef __osf__ 7159243Sobrien# ifndef WCOREDUMP 7259243Sobrien# define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) 7359243Sobrien# endif 7459243Sobrien#endif 7559243Sobrien 7659243Sobrien#ifndef WCOREDUMP 7759243Sobrien# ifdef BSDWAIT 7859243Sobrien# define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 7959243Sobrien# else /* !BSDWAIT */ 8059243Sobrien# define WCOREDUMP(w) ((w) & 0200) 8159243Sobrien# endif /* !BSDWAIT */ 8259243Sobrien#endif /* !WCOREDUMP */ 8359243Sobrien 8459243Sobrien/* 8559243Sobrien * C Shell - functions that manage processes, handling hanging, termination 8659243Sobrien */ 8759243Sobrien 8859243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 8959243Sobrien 9059243Sobrien#ifdef BSDTIMES 9159243Sobrien# ifdef convex 9259243Sobrien/* use 'cvxrusage' to get parallel statistics */ 9359243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9459243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9559243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 9659243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 9759243Sobrien# else 9859243Sobrien# if defined(SUNOS4) || defined(hp9000) || (defined(__alpha) && defined(__osf__)) 9959243Sobrienstatic struct rusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 10059243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}; 10159243Sobrien 10259243Sobrien# else /* !SUNOS4 && !hp9000 && !(__alpha && __osf__) */ 10359243Sobrien# ifdef masscomp 10459243Sobrien/* 10559243Sobrien * Initialization of this structure under RTU 4.1A & RTU 5.0 is problematic 10659243Sobrien * because the first two elements are unions of a time_t and a struct timeval. 10759243Sobrien * So we'll just have to trust the loader to do the "right thing", DAS DEC-90. 10859243Sobrien */ 10959243Sobrienstatic struct rusage zru; 11059243Sobrien# else /* masscomp */ 11159243Sobrienstatic struct rusage zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 11259243Sobrien 0, 0, 0, 0, 0, 0}; 11359243Sobrien# endif /* masscomp */ 11459243Sobrien# endif /* SUNOS4 || hp9000 || (__alpha && __osf__) */ 11559243Sobrien# endif /* convex */ 11659243Sobrien#else /* !BSDTIMES */ 11759243Sobrien# ifdef _SEQUENT_ 11859243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 11959243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 12059243Sobrien# else /* !_SEQUENT_ */ 12159243Sobrien# ifdef _SX 12259243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 12359243Sobrien# else /* !_SX */ 12459243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 12559243Sobrien# endif /* !_SX */ 12659243Sobrien# endif /* !_SEQUENT_ */ 12759243Sobrien#endif /* !BSDTIMES */ 12859243Sobrien 12959243Sobrien#ifndef RUSAGE_CHILDREN 13059243Sobrien# define RUSAGE_CHILDREN -1 13159243Sobrien#endif /* RUSAGE_CHILDREN */ 13259243Sobrien 13359243Sobrienstatic void pflushall __P((void)); 13459243Sobrienstatic void pflush __P((struct process *)); 13559243Sobrienstatic void pfree __P((struct process *)); 13659243Sobrienstatic void pclrcurr __P((struct process *)); 13759243Sobrienstatic void padd __P((struct command *)); 13859243Sobrienstatic int pprint __P((struct process *, int)); 13959243Sobrienstatic void ptprint __P((struct process *)); 14059243Sobrienstatic void pads __P((Char *)); 14159243Sobrienstatic void pkill __P((Char **, int)); 14259243Sobrienstatic struct process *pgetcurr __P((struct process *)); 14359243Sobrienstatic void okpcntl __P((void)); 14459243Sobrienstatic void setttypgrp __P((int)); 14559243Sobrien 14659243Sobrien/* 14759243Sobrien * pchild - called at interrupt level by the SIGCHLD signal 14859243Sobrien * indicating that at least one child has terminated or stopped 14959243Sobrien * thus at least one wait system call will definitely return a 15059243Sobrien * childs status. Top level routines (like pwait) must be sure 15159243Sobrien * to mask interrupts when playing with the proclist data structures! 15259243Sobrien */ 15359243Sobriensigret_t 15459243Sobrien/*ARGSUSED*/ 15559243Sobrienpchild(snum) 15659243Sobrienint snum; 15759243Sobrien{ 15859243Sobrien register struct process *pp; 15959243Sobrien register struct process *fp; 16059243Sobrien register int pid; 16159243Sobrien#if defined(BSDJOBS) || (!defined(BSDTIMES) && (defined(ODT) || defined(aiws) || defined(uts))) 16259243Sobrien extern int insource; 16359243Sobrien#endif /* BSDJOBS || (!BSDTIMES && (ODT || aiws || uts)) */ 16459243Sobrien#ifdef BSDWAIT 16559243Sobrien union wait w; 16659243Sobrien#else /* !BSDWAIT */ 16759243Sobrien int w; 16859243Sobrien#endif /* !BSDWAIT */ 16959243Sobrien int jobflags; 17059243Sobrien#ifdef BSDTIMES 17159243Sobrien struct sysrusage ru; 17259243Sobrien#else /* !BSDTIMES */ 17359243Sobrien# ifdef _SEQUENT_ 17459243Sobrien struct process_stats ru; 17559243Sobrien struct process_stats cpst1, cpst2; 17659243Sobrien timeval_t tv; 17759243Sobrien# else /* !_SEQUENT_ */ 17859243Sobrien struct tms proctimes; 17959243Sobrien 18059243Sobrien USE(snum); 18159243Sobrien if (!timesdone) { 18259243Sobrien timesdone++; 18359243Sobrien (void) times(&shtimes); 18459243Sobrien } 18559243Sobrien# endif /* !_SEQUENT_ */ 18659243Sobrien#endif /* !BSDTIMES */ 18759243Sobrien 18859243Sobrien#ifdef JOBDEBUG 18959243Sobrien xprintf("pchild()\n"); 19059243Sobrien#endif /* JOBDEBUG */ 19159243Sobrien 19259243Sobrien/* Christos on where the signal(SIGCHLD, pchild) shoud be: 19359243Sobrien * 19459243Sobrien * I think that it should go *after* the wait, unlike most signal handlers. 19559243Sobrien * 19659243Sobrien * In release two (for which I have manuals), it says that wait will remove 19759243Sobrien * the first child from the queue of dead children. 19859243Sobrien * All the rest of the children that die while in the signal handler of the 19959243Sobrien * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish 20059243Sobrien * the signal handler, and there are items in the queue, the process will 20159243Sobrien * receive another SIGC(H)LD before signal returns. BTW this is from the 20259243Sobrien * manual page on comp-sim... Maybe it is not applicable to the hp's, but 20359243Sobrien * I read on the news in comp.unix.wizards or comp.unix.questions yesterday 20459243Sobrien * that another person was claiming the the signal() call should be after 20559243Sobrien * the wait(). 20659243Sobrien */ 20759243Sobrien 20859243Sobrienloop: 20959243Sobrien errno = 0; /* reset, just in case */ 21059243Sobrien#ifdef JOBDEBUG 21159243Sobrien xprintf("Waiting...\n"); 21259243Sobrien flush(); 21359243Sobrien#endif /* JOBDEBUG */ 21469408Sache#ifndef WINNT_NATIVE 21559243Sobrien# ifdef BSDJOBS 21659243Sobrien# ifdef BSDTIMES 21759243Sobrien# ifdef convex 21859243Sobrien /* use 'cvxwait' to get parallel statistics */ 21959243Sobrien pid = cvxwait(&w, 22059243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 22159243Sobrien# else 22259243Sobrien /* both a wait3 and rusage */ 22359243Sobrien# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(linux) || (defined(IRIS4D) && (__STDC__ || defined(FUNCPROTO)) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 22459243Sobrien pid = wait3(&w, 22559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 22659243Sobrien# else /* BSDWAIT */ 22759243Sobrien pid = wait3(&w.w_status, 22859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 22959243Sobrien# endif /* BSDWAIT */ 23059243Sobrien# endif /* convex */ 23159243Sobrien# else /* !BSDTIMES */ 23259243Sobrien# ifdef _SEQUENT_ 23359243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 23459243Sobrien pid = waitpid(-1, &w, 23559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 23659243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 23759243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 23859243Sobrien# else /* !_SEQUENT_ */ 23959243Sobrien# ifndef POSIX 24059243Sobrien /* we have a wait3, but no rusage stuff */ 24159243Sobrien pid = wait3(&w.w_status, 24259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 24359243Sobrien# else /* POSIX */ 24459243Sobrien pid = waitpid(-1, &w, 24559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 24659243Sobrien# endif /* POSIX */ 24759243Sobrien# endif /* !_SEQUENT_ */ 24859243Sobrien# endif /* !BSDTIMES */ 24959243Sobrien# else /* !BSDJOBS */ 25059243Sobrien# ifdef BSDTIMES 25159243Sobrien# define HAVEwait3 25259243Sobrien /* both a wait3 and rusage */ 25359243Sobrien# ifdef hpux 25459243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 25559243Sobrien# else /* !hpux */ 25659243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 25759243Sobrien# endif /* !hpux */ 25859243Sobrien# else /* !BSDTIMES */ 25959243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 26059243Sobrien# define HAVEwait3 26159243Sobrien pid = waitpid(-1, &w, 26259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 26359243Sobrien# endif /* ODT */ 26459243Sobrien# if defined(aiws) || defined(uts) 26559243Sobrien# define HAVEwait3 26659243Sobrien pid = wait3(&w.w_status, 26759243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 26859243Sobrien# endif /* aiws || uts */ 26959243Sobrien# ifndef HAVEwait3 27059243Sobrien# ifdef UNRELSIGS 27159243Sobrien /* no wait3, therefore no rusage */ 27259243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 27359243Sobrien# ifdef _MINIX 27459243Sobrien pid = wait(&w); 27559243Sobrien# else /* !_MINIX */ 27659243Sobrien pid = ourwait(&w.w_status); 27759243Sobrien# endif /* _MINIX */ 27859243Sobrien# else /* !UNRELSIGS */ 27959243Sobrien /* 28059243Sobrien * XXX: for greater than 3 we should use waitpid(). 28159243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 28259243Sobrien */ 28359243Sobrien pid = wait(&w.w_status); 28459243Sobrien# endif /* !UNRELSIGS */ 28559243Sobrien# endif /* !HAVEwait3 */ 28659243Sobrien# endif /* !BSDTIMES */ 28759243Sobrien# ifndef BSDSIGS 28859243Sobrien (void) sigset(SIGCHLD, pchild); 28959243Sobrien# endif /* !BSDSIGS */ 29059243Sobrien# endif /* !BSDJOBS */ 29169408Sache#else /* WINNT_NATIVE */ 29259243Sobrien { 29359243Sobrien extern int insource; 29459243Sobrien pid = waitpid(-1, &w, 29559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 29659243Sobrien } 29769408Sache#endif /* WINNT_NATIVE */ 29859243Sobrien 29959243Sobrien#ifdef JOBDEBUG 30059243Sobrien xprintf("parent %d pid %d, retval %x termsig %x retcode %x\n", 30159243Sobrien getpid(), pid, w, WTERMSIG(w), WEXITSTATUS(w)); 30259243Sobrien flush(); 30359243Sobrien#endif /* JOBDEBUG */ 30459243Sobrien 30559243Sobrien if ((pid == 0) || (pid == -1)) { 30659243Sobrien#ifdef JOBDEBUG 30759243Sobrien xprintf("errno == %d\n", errno); 30859243Sobrien#endif /* JOBDEBUG */ 30959243Sobrien if (errno == EINTR) { 31059243Sobrien errno = 0; 31159243Sobrien goto loop; 31259243Sobrien } 31359243Sobrien pnoprocesses = pid == -1; 31459243Sobrien#ifndef SIGVOID 31559243Sobrien return (0); 31659243Sobrien#else /* !SIGVOID */ 31759243Sobrien return; 31859243Sobrien#endif /* !SIGVOID */ 31959243Sobrien } 32059243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 32159243Sobrien if (pid == pp->p_procid) 32259243Sobrien goto found; 32369408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 32459243Sobrien /* this should never have happened */ 32559243Sobrien stderror(ERR_SYNC, pid); 32659243Sobrien xexit(0); 32769408Sache#else /* BSDJOBS || WINNT_NATIVE */ 32859243Sobrien goto loop; 32969408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 33059243Sobrienfound: 33159243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 33259243Sobrien if (WIFSTOPPED(w)) { 33359243Sobrien pp->p_flags |= PSTOPPED; 33459243Sobrien pp->p_reason = WSTOPSIG(w); 33559243Sobrien } 33659243Sobrien else { 33759243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 33859243Sobrien#ifndef BSDTIMES 33959243Sobrien# ifdef _SEQUENT_ 34059243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 34159243Sobrien# else /* !_SEQUENT_ */ 34259243Sobrien# ifndef COHERENT 34359243Sobrien pp->p_etime = times(&proctimes); 34459243Sobrien# else /* COHERENT */ 34559243Sobrien pp->p_etime = HZ * time(NULL); 34659243Sobrien times(&proctimes); 34759243Sobrien# endif /* COHERENT */ 34859243Sobrien# endif /* !_SEQUENT_ */ 34959243Sobrien#else /* BSDTIMES */ 35059243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 35159243Sobrien#endif /* BSDTIMES */ 35259243Sobrien 35359243Sobrien 35459243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 35559243Sobrien pp->p_rusage = ru; 35659243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 35759243Sobrien (void) times(&proctimes); 35859243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 35959243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 36059243Sobrien shtimes = proctimes; 36159243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 36259243Sobrien if (WIFSIGNALED(w)) { 36359243Sobrien if (WTERMSIG(w) == SIGINT) 36459243Sobrien pp->p_flags |= PINTERRUPTED; 36559243Sobrien else 36659243Sobrien pp->p_flags |= PSIGNALED; 36759243Sobrien if (WCOREDUMP(w)) 36859243Sobrien pp->p_flags |= PDUMPED; 36959243Sobrien pp->p_reason = WTERMSIG(w); 37059243Sobrien } 37159243Sobrien else { 37259243Sobrien pp->p_reason = WEXITSTATUS(w); 37359243Sobrien if (pp->p_reason != 0) 37459243Sobrien pp->p_flags |= PAEXITED; 37559243Sobrien else 37659243Sobrien pp->p_flags |= PNEXITED; 37759243Sobrien } 37859243Sobrien } 37959243Sobrien jobflags = 0; 38059243Sobrien fp = pp; 38159243Sobrien do { 38259243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 38359243Sobrien !child && adrof(STRtime) && 38459243Sobrien#ifdef BSDTIMES 38559243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 38659243Sobrien#else /* !BSDTIMES */ 38759243Sobrien# ifdef _SEQUENT_ 38859243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 38959243Sobrien# else /* !_SEQUENT_ */ 39059243Sobrien# ifndef POSIX 39159243Sobrien (fp->p_utime + fp->p_stime) / HZ 39259243Sobrien# else /* POSIX */ 39359243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 39459243Sobrien# endif /* POSIX */ 39559243Sobrien# endif /* !_SEQUENT_ */ 39659243Sobrien#endif /* !BSDTIMES */ 39759243Sobrien >= atoi(short2str(varval(STRtime)))) 39859243Sobrien fp->p_flags |= PTIME; 39959243Sobrien jobflags |= fp->p_flags; 40059243Sobrien } while ((fp = fp->p_friends) != pp); 40159243Sobrien pp->p_flags &= ~PFOREGND; 40259243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 40359243Sobrien pp->p_flags &= ~PPTIME; 40459243Sobrien pp->p_flags |= PTIME; 40559243Sobrien } 40659243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 40759243Sobrien fp = pp; 40859243Sobrien do { 40959243Sobrien if (fp->p_flags & PSTOPPED) 41059243Sobrien fp->p_flags |= PREPORTED; 41159243Sobrien } while ((fp = fp->p_friends) != pp); 41259243Sobrien while (fp->p_procid != fp->p_jobid) 41359243Sobrien fp = fp->p_friends; 41459243Sobrien if (jobflags & PSTOPPED) { 41559243Sobrien if (pcurrent && pcurrent != fp) 41659243Sobrien pprevious = pcurrent; 41759243Sobrien pcurrent = fp; 41859243Sobrien } 41959243Sobrien else 42059243Sobrien pclrcurr(fp); 42159243Sobrien if (jobflags & PFOREGND) { 42259243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 42359243Sobrien#ifdef notdef 42459243Sobrien jobflags & PAEXITED || 42559243Sobrien#endif /* notdef */ 42659243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 42759243Sobrien /* PWP: print a newline after ^C */ 42859243Sobrien if (jobflags & PINTERRUPTED) { 42959243Sobrien#ifdef SHORT_STRINGS 43059243Sobrien xputchar('\r' | QUOTE), xputchar('\n'); 43159243Sobrien#else /* !SHORT_STRINGS */ 43259243Sobrien xprintf("\215\n"); /* \215 is a quoted ^M */ 43359243Sobrien#endif /* !SHORT_STRINGS */ 43459243Sobrien } 43559243Sobrien#ifdef notdef 43659243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 43759243Sobrien ptprint(fp); 43859243Sobrien#endif /* notdef */ 43959243Sobrien } 44059243Sobrien } 44159243Sobrien else { 44259243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 44359243Sobrien#ifdef SHORT_STRINGS 44459243Sobrien xputchar('\r' | QUOTE), xputchar('\n'); 44559243Sobrien#else /* !SHORT_STRINGS */ 44659243Sobrien xprintf("\215\n"); /* \215 is a quoted ^M */ 44759243Sobrien#endif /* !SHORT_STRINGS */ 44859243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 44959243Sobrien if ((jobflags & PSTOPPED) == 0) 45059243Sobrien pflush(pp); 45159243Sobrien { 45259243Sobrien extern Char GettingInput; 45359243Sobrien 45459243Sobrien if (GettingInput) { 45559243Sobrien errno = 0; 45659243Sobrien (void) Rawmode(); 45759243Sobrien#ifdef notdef 45859243Sobrien /* 45959243Sobrien * don't really want to do that, because it 46059243Sobrien * will erase our message in case of multi-line 46159243Sobrien * input 46259243Sobrien */ 46359243Sobrien ClearLines(); 46459243Sobrien#endif /* notdef */ 46559243Sobrien ClearDisp(); 46659243Sobrien Refresh(); 46759243Sobrien } 46859243Sobrien } 46959243Sobrien } 47059243Sobrien else { 47159243Sobrien fp->p_flags |= PNEEDNOTE; 47259243Sobrien neednote++; 47359243Sobrien } 47459243Sobrien } 47559243Sobrien } 47659243Sobrien#if defined(BSDJOBS) || defined(HAVEwait3) 47759243Sobrien goto loop; 47859243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 47959243Sobrien} 48059243Sobrien 48159243Sobrienvoid 48259243Sobrienpnote() 48359243Sobrien{ 48459243Sobrien register struct process *pp; 48559243Sobrien int flags; 48659243Sobrien#ifdef BSDSIGS 48759243Sobrien sigmask_t omask; 48859243Sobrien#endif /* BSDSIGS */ 48959243Sobrien 49059243Sobrien neednote = 0; 49159243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 49259243Sobrien if (pp->p_flags & PNEEDNOTE) { 49359243Sobrien#ifdef BSDSIGS 49459243Sobrien omask = sigblock(sigmask(SIGCHLD)); 49559243Sobrien#else /* !BSDSIGS */ 49659243Sobrien (void) sighold(SIGCHLD); 49759243Sobrien#endif /* !BSDSIGS */ 49859243Sobrien pp->p_flags &= ~PNEEDNOTE; 49959243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 50059243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 50159243Sobrien pflush(pp); 50259243Sobrien#ifdef BSDSIGS 50359243Sobrien (void) sigsetmask(omask); 50459243Sobrien#else /* !BSDSIGS */ 50559243Sobrien (void) sigrelse(SIGCHLD); 50659243Sobrien#endif /* !BSDSIGS */ 50759243Sobrien } 50859243Sobrien } 50959243Sobrien} 51059243Sobrien 51159243Sobrien 51259243Sobrienstatic void 51359243Sobrienpfree(pp) 51459243Sobrien struct process *pp; 51559243Sobrien{ 51659243Sobrien xfree((ptr_t) pp->p_command); 51759243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 51859243Sobrien if (pp->p_cwd->di_next == 0) 51959243Sobrien dfree(pp->p_cwd); 52059243Sobrien xfree((ptr_t) pp); 52159243Sobrien} 52259243Sobrien 52359243Sobrien 52459243Sobrien/* 52559243Sobrien * pwait - wait for current job to terminate, maintaining integrity 52659243Sobrien * of current and previous job indicators. 52759243Sobrien */ 52859243Sobrienvoid 52959243Sobrienpwait() 53059243Sobrien{ 53159243Sobrien register struct process *fp, *pp; 53259243Sobrien#ifdef BSDSIGS 53359243Sobrien sigmask_t omask; 53459243Sobrien#endif /* BSDSIGS */ 53559243Sobrien 53659243Sobrien /* 53759243Sobrien * Here's where dead procs get flushed. 53859243Sobrien */ 53959243Sobrien#ifdef BSDSIGS 54059243Sobrien omask = sigblock(sigmask(SIGCHLD)); 54159243Sobrien#else /* !BSDSIGS */ 54259243Sobrien (void) sighold(SIGCHLD); 54359243Sobrien#endif /* !BSDSIGS */ 54459243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 54559243Sobrien if (pp->p_procid == 0) { 54659243Sobrien fp->p_next = pp->p_next; 54759243Sobrien pfree(pp); 54859243Sobrien pp = fp; 54959243Sobrien } 55059243Sobrien#ifdef BSDSIGS 55159243Sobrien (void) sigsetmask(omask); 55259243Sobrien#else /* !BSDSIGS */ 55359243Sobrien (void) sigrelse(SIGCHLD); 55459243Sobrien# ifdef notdef 55559243Sobrien if (setintr) 55659243Sobrien sigignore(SIGINT); 55759243Sobrien# endif /* notdef */ 55859243Sobrien#endif /* !BSDSIGS */ 55959243Sobrien pjwait(pcurrjob); 56059243Sobrien} 56159243Sobrien 56259243Sobrien 56359243Sobrien/* 56459243Sobrien * pjwait - wait for a job to finish or become stopped 56559243Sobrien * It is assumed to be in the foreground state (PFOREGND) 56659243Sobrien */ 56759243Sobrienvoid 56859243Sobrienpjwait(pp) 56959243Sobrien register struct process *pp; 57059243Sobrien{ 57159243Sobrien register struct process *fp; 57259243Sobrien int jobflags, reason; 57359243Sobrien#ifdef BSDSIGS 57459243Sobrien sigmask_t omask; 57559243Sobrien#endif /* BSDSIGS */ 57659243Sobrien#ifdef UNRELSIGS 57759243Sobrien signalfun_t inthandler; 57859243Sobrien#endif /* UNRELSIGS */ 57959243Sobrien while (pp->p_procid != pp->p_jobid) 58059243Sobrien pp = pp->p_friends; 58159243Sobrien fp = pp; 58259243Sobrien 58359243Sobrien do { 58459243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 58559243Sobrien xprintf(CGETS(17, 1, "BUG: waiting for background job!\n")); 58659243Sobrien } while ((fp = fp->p_friends) != pp); 58759243Sobrien /* 58859243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 58959243Sobrien * target process, or any of its friends, are running 59059243Sobrien */ 59159243Sobrien fp = pp; 59259243Sobrien#ifdef BSDSIGS 59359243Sobrien omask = sigblock(sigmask(SIGCHLD)); 59459243Sobrien#endif /* BSDSIGS */ 59559243Sobrien#ifdef UNRELSIGS 59659243Sobrien if (setintr) 59759243Sobrien inthandler = signal(SIGINT, SIG_IGN); 59859243Sobrien#endif /* UNRELSIGS */ 59959243Sobrien for (;;) { 60059243Sobrien#ifndef BSDSIGS 60159243Sobrien (void) sighold(SIGCHLD); 60259243Sobrien#endif /* !BSDSIGS */ 60359243Sobrien jobflags = 0; 60459243Sobrien do 60559243Sobrien jobflags |= fp->p_flags; 60659243Sobrien while ((fp = (fp->p_friends)) != pp); 60759243Sobrien if ((jobflags & PRUNNING) == 0) 60859243Sobrien break; 60959243Sobrien#ifdef JOBDEBUG 61059243Sobrien xprintf("%d starting to sigpause for SIGCHLD on %d\n", 61159243Sobrien getpid(), fp->p_procid); 61259243Sobrien#endif /* JOBDEBUG */ 61359243Sobrien#ifdef BSDSIGS 61459243Sobrien /* (void) sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */ 61559243Sobrien (void) sigpause(omask & ~sigmask(SIGCHLD)); 61659243Sobrien#else /* !BSDSIGS */ 61759243Sobrien (void) sigpause(SIGCHLD); 61859243Sobrien#endif /* !BSDSIGS */ 61959243Sobrien } 62059243Sobrien#ifdef JOBDEBUG 62159243Sobrien xprintf("%d returned from sigpause loop\n", getpid()); 62259243Sobrien#endif /* JOBDEBUG */ 62359243Sobrien#ifdef BSDSIGS 62459243Sobrien (void) sigsetmask(omask); 62559243Sobrien#else /* !BSDSIGS */ 62659243Sobrien (void) sigrelse(SIGCHLD); 62759243Sobrien#endif /* !BSDSIGS */ 62859243Sobrien#ifdef UNRELSIGS 62959243Sobrien if (setintr) 63059243Sobrien (void) signal(SIGINT, inthandler); 63159243Sobrien#endif /* UNRELSIGS */ 63259243Sobrien#ifdef BSDJOBS 63359243Sobrien if (tpgrp > 0) /* get tty back */ 63459243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 63559243Sobrien#endif /* BSDJOBS */ 63659243Sobrien if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 63759243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name)) { 63859243Sobrien if (jobflags & PSTOPPED) { 63959243Sobrien xputchar('\n'); 64059243Sobrien if (adrof(STRlistjobs)) { 64159243Sobrien Char *jobcommand[3]; 64259243Sobrien 64359243Sobrien jobcommand[0] = STRjobs; 64459243Sobrien if (eq(varval(STRlistjobs), STRlong)) 64559243Sobrien jobcommand[1] = STRml; 64659243Sobrien else 64759243Sobrien jobcommand[1] = NULL; 64859243Sobrien jobcommand[2] = NULL; 64959243Sobrien 65059243Sobrien dojobs(jobcommand, NULL); 65159243Sobrien (void) pprint(pp, SHELLDIR); 65259243Sobrien } 65359243Sobrien else 65459243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 65559243Sobrien } 65659243Sobrien else 65759243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 65859243Sobrien } 65959243Sobrien if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 66059243Sobrien (!gointr || !eq(gointr, STRminus))) { 66159243Sobrien if ((jobflags & PSTOPPED) == 0) 66259243Sobrien pflush(pp); 66359243Sobrien pintr1(0); 66459243Sobrien /* NOTREACHED */ 66559243Sobrien } 66659243Sobrien reason = 0; 66759243Sobrien fp = pp; 66859243Sobrien do { 66959243Sobrien if (fp->p_reason) 67059243Sobrien reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 67159243Sobrien fp->p_reason | META : fp->p_reason; 67259243Sobrien } while ((fp = fp->p_friends) != pp); 67359243Sobrien /* 67459243Sobrien * Don't report on backquoted jobs, cause it will mess up 67559243Sobrien * their output. 67659243Sobrien */ 67759243Sobrien if ((reason != 0) && (adrof(STRprintexitvalue)) && 67859243Sobrien (pp->p_flags & PBACKQ) == 0) 67959243Sobrien xprintf(CGETS(17, 2, "Exit %d\n"), reason); 68059243Sobrien set(STRstatus, putn(reason), VAR_READWRITE); 68159243Sobrien if (reason && exiterr) 68259243Sobrien exitstat(); 68359243Sobrien pflush(pp); 68459243Sobrien} 68559243Sobrien 68659243Sobrien/* 68759243Sobrien * dowait - wait for all processes to finish 68859243Sobrien */ 68959243Sobrien 69059243Sobrien/*ARGSUSED*/ 69159243Sobrienvoid 69259243Sobriendowait(v, c) 69359243Sobrien Char **v; 69459243Sobrien struct command *c; 69559243Sobrien{ 69659243Sobrien register struct process *pp; 69759243Sobrien#ifdef BSDSIGS 69859243Sobrien sigmask_t omask; 69959243Sobrien#endif /* BSDSIGS */ 70059243Sobrien 70159243Sobrien USE(c); 70259243Sobrien USE(v); 70359243Sobrien pjobs++; 70459243Sobrien#ifdef BSDSIGS 70559243Sobrien omask = sigblock(sigmask(SIGCHLD)); 70659243Sobrienloop: 70759243Sobrien#else /* !BSDSIGS */ 70859243Sobrien if (setintr) 70959243Sobrien (void) sigrelse(SIGINT); 71059243Sobrienloop: 71159243Sobrien (void) sighold(SIGCHLD); 71259243Sobrien#endif /* !BSDSIGS */ 71359243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 71459243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 71559243Sobrien pp->p_flags & PRUNNING) { 71659243Sobrien#ifdef BSDSIGS 71759243Sobrien (void) sigpause((sigmask_t) 0); 71859243Sobrien#else /* !BSDSIGS */ 71959243Sobrien (void) sigpause(SIGCHLD); 72059243Sobrien#endif /* !BSDSIGS */ 72159243Sobrien goto loop; 72259243Sobrien } 72359243Sobrien#ifdef BSDSIGS 72459243Sobrien (void) sigsetmask(omask); 72559243Sobrien#else /* !BSDSIGS */ 72659243Sobrien (void) sigrelse(SIGCHLD); 72759243Sobrien#endif /* !BSDSIGS */ 72859243Sobrien pjobs = 0; 72959243Sobrien} 73059243Sobrien 73159243Sobrien/* 73259243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 73359243Sobrien */ 73459243Sobrienstatic void 73559243Sobrienpflushall() 73659243Sobrien{ 73759243Sobrien register struct process *pp; 73859243Sobrien 73959243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 74059243Sobrien if (pp->p_procid) 74159243Sobrien pflush(pp); 74259243Sobrien} 74359243Sobrien 74459243Sobrien/* 74559243Sobrien * pflush - flag all process structures in the same job as the 74659243Sobrien * the argument process for deletion. The actual free of the 74759243Sobrien * space is not done here since pflush is called at interrupt level. 74859243Sobrien */ 74959243Sobrienstatic void 75059243Sobrienpflush(pp) 75159243Sobrien register struct process *pp; 75259243Sobrien{ 75359243Sobrien register struct process *np; 75459243Sobrien register int idx; 75559243Sobrien 75659243Sobrien if (pp->p_procid == 0) { 75759243Sobrien xprintf(CGETS(17, 3, "BUG: process flushed twice")); 75859243Sobrien return; 75959243Sobrien } 76059243Sobrien while (pp->p_procid != pp->p_jobid) 76159243Sobrien pp = pp->p_friends; 76259243Sobrien pclrcurr(pp); 76359243Sobrien if (pp == pcurrjob) 76459243Sobrien pcurrjob = 0; 76559243Sobrien idx = pp->p_index; 76659243Sobrien np = pp; 76759243Sobrien do { 76859243Sobrien np->p_index = np->p_procid = 0; 76959243Sobrien np->p_flags &= ~PNEEDNOTE; 77059243Sobrien } while ((np = np->p_friends) != pp); 77159243Sobrien if (idx == pmaxindex) { 77259243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 77359243Sobrien if (np->p_index > idx) 77459243Sobrien idx = np->p_index; 77559243Sobrien pmaxindex = idx; 77659243Sobrien } 77759243Sobrien} 77859243Sobrien 77959243Sobrien/* 78059243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 78159243Sobrien * pp MUST be the job leader 78259243Sobrien */ 78359243Sobrienstatic void 78459243Sobrienpclrcurr(pp) 78559243Sobrien register struct process *pp; 78659243Sobrien{ 78759243Sobrien if (pp == pcurrent) { 78859243Sobrien if (pprevious != NULL) { 78959243Sobrien pcurrent = pprevious; 79059243Sobrien pprevious = pgetcurr(pp); 79159243Sobrien } 79259243Sobrien else { 79359243Sobrien pcurrent = pgetcurr(pp); 79459243Sobrien pprevious = pgetcurr(pp); 79559243Sobrien } 79659243Sobrien } 79759243Sobrien else if (pp == pprevious) 79859243Sobrien pprevious = pgetcurr(pp); 79959243Sobrien} 80059243Sobrien 80159243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 80259243Sobrienstatic Char command[PMAXLEN + 4]; 80359243Sobrienstatic int cmdlen; 80459243Sobrienstatic Char *cmdp; 80559243Sobrien 80683098Smp/* GrP 80783098Smp * unparse - Export padd() functionality 80883098Smp */ 80983098SmpChar * 81083098Smpunparse(t) 81183098Smp register struct command *t; 81283098Smp{ 81383098Smp cmdp = command; 81483098Smp cmdlen = 0; 81583098Smp padd(t); 81683098Smp *cmdp++ = '\0'; 81783098Smp return Strsave(command); 81883098Smp} 81983098Smp 82083098Smp 82159243Sobrien/* 82259243Sobrien * palloc - allocate a process structure and fill it up. 82359243Sobrien * an important assumption is made that the process is running. 82459243Sobrien */ 82559243Sobrienvoid 82659243Sobrienpalloc(pid, t) 82759243Sobrien int pid; 82859243Sobrien register struct command *t; 82959243Sobrien{ 83059243Sobrien register struct process *pp; 83159243Sobrien int i; 83259243Sobrien 83359243Sobrien pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 83459243Sobrien pp->p_procid = pid; 83559243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 83659243Sobrien if (t->t_dflg & F_TIME) 83759243Sobrien pp->p_flags |= PPTIME; 83859243Sobrien if (t->t_dflg & F_BACKQ) 83959243Sobrien pp->p_flags |= PBACKQ; 84059243Sobrien if (t->t_dflg & F_HUP) 84159243Sobrien pp->p_flags |= PHUP; 84259243Sobrien cmdp = command; 84359243Sobrien cmdlen = 0; 84459243Sobrien padd(t); 84559243Sobrien *cmdp++ = 0; 84659243Sobrien if (t->t_dflg & F_PIPEOUT) { 84759243Sobrien pp->p_flags |= PPOU; 84859243Sobrien if (t->t_dflg & F_STDERR) 84959243Sobrien pp->p_flags |= PDIAG; 85059243Sobrien } 85159243Sobrien pp->p_command = Strsave(command); 85259243Sobrien if (pcurrjob) { 85359243Sobrien struct process *fp; 85459243Sobrien 85559243Sobrien /* careful here with interrupt level */ 85659243Sobrien pp->p_cwd = 0; 85759243Sobrien pp->p_index = pcurrjob->p_index; 85859243Sobrien pp->p_friends = pcurrjob; 85959243Sobrien pp->p_jobid = pcurrjob->p_procid; 86059243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 86159243Sobrien continue; 86259243Sobrien fp->p_friends = pp; 86359243Sobrien } 86459243Sobrien else { 86559243Sobrien pcurrjob = pp; 86659243Sobrien pp->p_jobid = pid; 86759243Sobrien pp->p_friends = pp; 86859243Sobrien pp->p_cwd = dcwd; 86959243Sobrien dcwd->di_count++; 87059243Sobrien if (pmaxindex < BIGINDEX) 87159243Sobrien pp->p_index = ++pmaxindex; 87259243Sobrien else { 87359243Sobrien struct process *np; 87459243Sobrien 87559243Sobrien for (i = 1;; i++) { 87659243Sobrien for (np = proclist.p_next; np; np = np->p_next) 87759243Sobrien if (np->p_index == i) 87859243Sobrien goto tryagain; 87959243Sobrien pp->p_index = i; 88059243Sobrien if (i > pmaxindex) 88159243Sobrien pmaxindex = i; 88259243Sobrien break; 88359243Sobrien tryagain:; 88459243Sobrien } 88559243Sobrien } 88659243Sobrien if (pcurrent == NULL) 88759243Sobrien pcurrent = pp; 88859243Sobrien else if (pprevious == NULL) 88959243Sobrien pprevious = pp; 89059243Sobrien } 89159243Sobrien pp->p_next = proclist.p_next; 89259243Sobrien proclist.p_next = pp; 89359243Sobrien#ifdef BSDTIMES 89459243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 89559243Sobrien#else /* !BSDTIMES */ 89659243Sobrien# ifdef _SEQUENT_ 89759243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 89859243Sobrien# else /* !_SEQUENT_ */ 89959243Sobrien { 90059243Sobrien struct tms tmptimes; 90159243Sobrien 90259243Sobrien# ifndef COHERENT 90359243Sobrien pp->p_btime = times(&tmptimes); 90459243Sobrien# else /* !COHERENT */ 90559243Sobrien pp->p_btime = HZ * time(NULL); 90659243Sobrien times(&tmptimes); 90759243Sobrien# endif /* !COHERENT */ 90859243Sobrien } 90959243Sobrien# endif /* !_SEQUENT_ */ 91059243Sobrien#endif /* !BSDTIMES */ 91159243Sobrien} 91259243Sobrien 91359243Sobrienstatic void 91459243Sobrienpadd(t) 91559243Sobrien register struct command *t; 91659243Sobrien{ 91759243Sobrien Char **argp; 91859243Sobrien 91959243Sobrien if (t == 0) 92059243Sobrien return; 92159243Sobrien switch (t->t_dtyp) { 92259243Sobrien 92359243Sobrien case NODE_PAREN: 92459243Sobrien pads(STRLparensp); 92559243Sobrien padd(t->t_dspr); 92659243Sobrien pads(STRspRparen); 92759243Sobrien break; 92859243Sobrien 92959243Sobrien case NODE_COMMAND: 93059243Sobrien for (argp = t->t_dcom; *argp; argp++) { 93159243Sobrien pads(*argp); 93259243Sobrien if (argp[1]) 93359243Sobrien pads(STRspace); 93459243Sobrien } 93559243Sobrien break; 93659243Sobrien 93759243Sobrien case NODE_OR: 93859243Sobrien case NODE_AND: 93959243Sobrien case NODE_PIPE: 94059243Sobrien case NODE_LIST: 94159243Sobrien padd(t->t_dcar); 94259243Sobrien switch (t->t_dtyp) { 94359243Sobrien case NODE_OR: 94459243Sobrien pads(STRspor2sp); 94559243Sobrien break; 94659243Sobrien case NODE_AND: 94759243Sobrien pads(STRspand2sp); 94859243Sobrien break; 94959243Sobrien case NODE_PIPE: 95059243Sobrien pads(STRsporsp); 95159243Sobrien break; 95259243Sobrien case NODE_LIST: 95359243Sobrien pads(STRsemisp); 95459243Sobrien break; 95559243Sobrien default: 95659243Sobrien break; 95759243Sobrien } 95859243Sobrien padd(t->t_dcdr); 95959243Sobrien return; 96059243Sobrien 96159243Sobrien default: 96259243Sobrien break; 96359243Sobrien } 96459243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 96559243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 96659243Sobrien pads(t->t_dlef); 96759243Sobrien } 96859243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 96959243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 97059243Sobrien if (t->t_dflg & F_STDERR) 97159243Sobrien pads(STRand); 97259243Sobrien pads(STRspace); 97359243Sobrien pads(t->t_drit); 97459243Sobrien } 97559243Sobrien} 97659243Sobrien 97759243Sobrienstatic void 97859243Sobrienpads(cp) 97959243Sobrien Char *cp; 98059243Sobrien{ 98159243Sobrien register int i; 98259243Sobrien 98359243Sobrien /* 98459243Sobrien * Avoid the Quoted Space alias hack! Reported by: 98559243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 98659243Sobrien */ 98759243Sobrien if (cp[0] == STRQNULL[0]) 98859243Sobrien cp++; 98959243Sobrien 99059243Sobrien i = (int) Strlen(cp); 99159243Sobrien 99259243Sobrien if (cmdlen >= PMAXLEN) 99359243Sobrien return; 99459243Sobrien if (cmdlen + i >= PMAXLEN) { 99559243Sobrien (void) Strcpy(cmdp, STRsp3dots); 99659243Sobrien cmdlen = PMAXLEN; 99759243Sobrien cmdp += 4; 99859243Sobrien return; 99959243Sobrien } 100059243Sobrien (void) Strcpy(cmdp, cp); 100159243Sobrien cmdp += i; 100259243Sobrien cmdlen += i; 100359243Sobrien} 100459243Sobrien 100559243Sobrien/* 100659243Sobrien * psavejob - temporarily save the current job on a one level stack 100759243Sobrien * so another job can be created. Used for { } in exp6 100859243Sobrien * and `` in globbing. 100959243Sobrien */ 101059243Sobrienvoid 101159243Sobrienpsavejob() 101259243Sobrien{ 101359243Sobrien pholdjob = pcurrjob; 101459243Sobrien pcurrjob = NULL; 101559243Sobrien} 101659243Sobrien 101759243Sobrien/* 101859243Sobrien * prestjob - opposite of psavejob. This may be missed if we are interrupted 101959243Sobrien * somewhere, but pendjob cleans up anyway. 102059243Sobrien */ 102159243Sobrienvoid 102259243Sobrienprestjob() 102359243Sobrien{ 102459243Sobrien pcurrjob = pholdjob; 102559243Sobrien pholdjob = NULL; 102659243Sobrien} 102759243Sobrien 102859243Sobrien/* 102959243Sobrien * pendjob - indicate that a job (set of commands) has been completed 103059243Sobrien * or is about to begin. 103159243Sobrien */ 103259243Sobrienvoid 103359243Sobrienpendjob() 103459243Sobrien{ 103559243Sobrien register struct process *pp, *tp; 103659243Sobrien 103759243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 103859243Sobrien pp = pcurrjob; 103959243Sobrien while (pp->p_procid != pp->p_jobid) 104059243Sobrien pp = pp->p_friends; 104159243Sobrien xprintf("[%d]", pp->p_index); 104259243Sobrien tp = pp; 104359243Sobrien do { 104459243Sobrien xprintf(" %d", pp->p_procid); 104559243Sobrien pp = pp->p_friends; 104659243Sobrien } while (pp != tp); 104759243Sobrien xputchar('\n'); 104859243Sobrien } 104959243Sobrien pholdjob = pcurrjob = 0; 105059243Sobrien} 105159243Sobrien 105259243Sobrien/* 105359243Sobrien * pprint - print a job 105459243Sobrien */ 105559243Sobrien 105659243Sobrien/* 105759243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 105859243Sobrien * reverse order 105959243Sobrien * 106059243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 106159243Sobrien */ 106259243Sobrien 106359243Sobrienstatic int 106459243Sobrienpprint(pp, flag) 106559243Sobrien register struct process *pp; 106659243Sobrien bool flag; 106759243Sobrien{ 106859243Sobrien int status, reason; 106959243Sobrien struct process *tp; 107059243Sobrien extern char *linp, linbuf[]; 107159243Sobrien int jobflags, pstatus, pcond; 107259243Sobrien char *format; 107359243Sobrien 107459243Sobrien#ifdef BACKPIPE 107559243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 107659243Sobrien int inpipe = 0; 107759243Sobrien#endif /* BACKPIPE */ 107859243Sobrien 107959243Sobrien while (pp->p_procid != pp->p_jobid) 108059243Sobrien pp = pp->p_friends; 108159243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 108259243Sobrien pp->p_flags &= ~PPTIME; 108359243Sobrien pp->p_flags |= PTIME; 108459243Sobrien } 108559243Sobrien tp = pp; 108659243Sobrien status = reason = -1; 108759243Sobrien jobflags = 0; 108859243Sobrien do { 108959243Sobrien#ifdef BACKPIPE 109059243Sobrien /* 109159243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 109259243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 109359243Sobrien */ 109459243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 109559243Sobrien inpipe = 1; 109659243Sobrien pipetail = pp; 109759243Sobrien do 109859243Sobrien pp = pp->p_friends; 109959243Sobrien while (pp->p_friends->p_flags & PPOU); 110059243Sobrien pipehead = pp; 110159243Sobrien pmarker = pp; 110259243Sobrien /* 110359243Sobrien * pmarker is used to hold the place of the proc being processed, so 110459243Sobrien * we can search for the next one downstream later. 110559243Sobrien */ 110659243Sobrien } 110759243Sobrien pcond = (int) (tp != pp || (inpipe && tp == pp)); 110859243Sobrien#else /* !BACKPIPE */ 110959243Sobrien pcond = (int) (tp != pp); 111059243Sobrien#endif /* BACKPIPE */ 111159243Sobrien 111259243Sobrien jobflags |= pp->p_flags; 111359243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 111459243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 111559243Sobrien ((pstatus == status && pp->p_reason == reason) || 111659243Sobrien !(flag & REASON))) 111759243Sobrien xputchar(' '); 111859243Sobrien else { 111959243Sobrien if (pcond && linp != linbuf) 112059243Sobrien xputchar('\n'); 112159243Sobrien if (flag & NUMBER) { 112259243Sobrien#ifdef BACKPIPE 112359243Sobrien pcond = ((pp == tp && !inpipe) || 112459243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 112559243Sobrien#else /* BACKPIPE */ 112659243Sobrien pcond = (pp == tp); 112759243Sobrien#endif /* BACKPIPE */ 112859243Sobrien if (pcond) 112959243Sobrien xprintf("[%d]%s %c ", pp->p_index, 113059243Sobrien pp->p_index < 10 ? " " : "", 113159243Sobrien pp == pcurrent ? '+' : 113259243Sobrien (pp == pprevious ? '-' : ' ')); 113359243Sobrien else 113459243Sobrien xprintf(" "); 113559243Sobrien } 113659243Sobrien if (flag & FANCY) { 113759243Sobrien#ifdef TCF 113859243Sobrien extern char *sitename(); 113959243Sobrien 114059243Sobrien#endif /* TCF */ 114159243Sobrien xprintf("%5d ", pp->p_procid); 114259243Sobrien#ifdef TCF 114359243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 114459243Sobrien#endif /* TCF */ 114559243Sobrien } 114659243Sobrien if (flag & (REASON | AREASON)) { 114759243Sobrien if (flag & NAME) 114859243Sobrien format = "%-30s"; 114959243Sobrien else 115059243Sobrien format = "%s"; 115159243Sobrien if (pstatus == status) { 115259243Sobrien if (pp->p_reason == reason) { 115359243Sobrien xprintf(format, ""); 115459243Sobrien goto prcomd; 115559243Sobrien } 115659243Sobrien else 115759243Sobrien reason = (int) pp->p_reason; 115859243Sobrien } 115959243Sobrien else { 116059243Sobrien status = pstatus; 116159243Sobrien reason = (int) pp->p_reason; 116259243Sobrien } 116359243Sobrien switch (status) { 116459243Sobrien 116559243Sobrien case PRUNNING: 116659243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 116759243Sobrien break; 116859243Sobrien 116959243Sobrien case PINTERRUPTED: 117059243Sobrien case PSTOPPED: 117159243Sobrien case PSIGNALED: 117259243Sobrien /* 117359243Sobrien * tell what happened to the background job 117459243Sobrien * From: Michael Schroeder 117559243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 117659243Sobrien */ 117759243Sobrien if ((flag & REASON) 117859243Sobrien || ((flag & AREASON) 117959243Sobrien && reason != SIGINT 118059243Sobrien && (reason != SIGPIPE 118159243Sobrien || (pp->p_flags & PPOU) == 0))) { 118259243Sobrien char *ptr; 118359243Sobrien char buf[1024]; 118459243Sobrien 118559243Sobrien if ((ptr = mesg[pp->p_reason & ASCII].pname) == NULL) 118659243Sobrien xsnprintf(ptr = buf, sizeof(buf), "%s %d", 118759243Sobrien CGETS(17, 5, "Signal"), pp->p_reason & ASCII); 118859243Sobrien xprintf(format, ptr); 118959243Sobrien } 119059243Sobrien else 119159243Sobrien reason = -1; 119259243Sobrien break; 119359243Sobrien 119459243Sobrien case PNEXITED: 119559243Sobrien case PAEXITED: 119659243Sobrien if (flag & REASON) { 119759243Sobrien if (pp->p_reason) 119859243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 119959243Sobrien else 120059243Sobrien xprintf(format, CGETS(17, 7, "Done")); 120159243Sobrien } 120259243Sobrien break; 120359243Sobrien 120459243Sobrien default: 120559243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 120659243Sobrien status); 120759243Sobrien } 120859243Sobrien } 120959243Sobrien } 121059243Sobrienprcomd: 121159243Sobrien if (flag & NAME) { 121259243Sobrien xprintf("%S", pp->p_command); 121359243Sobrien if (pp->p_flags & PPOU) 121459243Sobrien xprintf(" |"); 121559243Sobrien if (pp->p_flags & PDIAG) 121659243Sobrien xprintf("&"); 121759243Sobrien } 121859243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 121959243Sobrien xprintf(CGETS(17, 9, " (core dumped)")); 122059243Sobrien if (tp == pp->p_friends) { 122159243Sobrien if (flag & AMPERSAND) 122259243Sobrien xprintf(" &"); 122359243Sobrien if (flag & JOBDIR && 122459243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 122559243Sobrien xprintf(CGETS(17, 10, " (wd: ")); 122659243Sobrien dtildepr(tp->p_cwd->di_name); 122759243Sobrien xprintf(")"); 122859243Sobrien } 122959243Sobrien } 123059243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 123159243Sobrien if (linp != linbuf) 123259243Sobrien xprintf("\n\t"); 123359243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 123459243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 123559243Sobrien &pp->p_btime); 123659243Sobrien#else /* !BSDTIMES && !SEQUENT */ 123759243Sobrien lru.tms_utime = pp->p_utime; 123859243Sobrien lru.tms_stime = pp->p_stime; 123959243Sobrien lru.tms_cutime = 0; 124059243Sobrien lru.tms_cstime = 0; 124159243Sobrien prusage(&zru, &lru, pp->p_etime, 124259243Sobrien pp->p_btime); 124359243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 124459243Sobrien 124559243Sobrien } 124659243Sobrien#ifdef BACKPIPE 124759243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 124859243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 124959243Sobrien#else /* !BACKPIPE */ 125059243Sobrien pcond = (tp == pp->p_friends); 125159243Sobrien#endif /* BACKPIPE */ 125259243Sobrien if (pcond) { 125359243Sobrien if (linp != linbuf) 125459243Sobrien xputchar('\n'); 125559243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 125659243Sobrien xprintf(CGETS(17, 11, "(wd now: ")); 125759243Sobrien dtildepr(dcwd->di_name); 125859243Sobrien xprintf(")\n"); 125959243Sobrien } 126059243Sobrien } 126159243Sobrien#ifdef BACKPIPE 126259243Sobrien if (inpipe) { 126359243Sobrien /* 126459243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 126559243Sobrien * can now skip to past the head 126659243Sobrien */ 126759243Sobrien if (pmarker == pipetail) { 126859243Sobrien inpipe = 0; 126959243Sobrien pp = pipehead; 127059243Sobrien } 127159243Sobrien else { 127259243Sobrien /* 127359243Sobrien * set pp to one before the one we want next, so the while below 127459243Sobrien * increments to the correct spot. 127559243Sobrien */ 127659243Sobrien do 127759243Sobrien pp = pp->p_friends; 127859243Sobrien while (pp->p_friends->p_friends != pmarker); 127959243Sobrien pmarker = pp->p_friends; 128059243Sobrien } 128159243Sobrien } 128259243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 128359243Sobrien#else /* !BACKPIPE */ 128459243Sobrien pcond = ((pp = pp->p_friends) != tp); 128559243Sobrien#endif /* BACKPIPE */ 128659243Sobrien } while (pcond); 128759243Sobrien 128859243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 128959243Sobrien if (jobflags & NUMBER) 129059243Sobrien xprintf(" "); 129159243Sobrien ptprint(tp); 129259243Sobrien } 129359243Sobrien return (jobflags); 129459243Sobrien} 129559243Sobrien 129659243Sobrien/* 129759243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 129859243Sobrien * The following implementation produces similar code and works in all 129959243Sobrien * cases. The 4.3BSD one works only for <, >, != 130059243Sobrien */ 130159243Sobrien# undef timercmp 130259243Sobrien# define timercmp(tvp, uvp, cmp) \ 130359243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 130459243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 130559243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 130659243Sobrien 130759243Sobrienstatic void 130859243Sobrienptprint(tp) 130959243Sobrien register struct process *tp; 131059243Sobrien{ 131159243Sobrien#ifdef BSDTIMES 131259243Sobrien struct timeval tetime, diff; 131359243Sobrien static struct timeval ztime; 131459243Sobrien struct sysrusage ru; 131559243Sobrien register struct process *pp = tp; 131659243Sobrien 131759243Sobrien ru = zru; 131859243Sobrien tetime = ztime; 131959243Sobrien do { 132059243Sobrien ruadd(&ru, &pp->p_rusage); 132159243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 132259243Sobrien if (timercmp(&diff, &tetime, >)) 132359243Sobrien tetime = diff; 132459243Sobrien } while ((pp = pp->p_friends) != tp); 132559243Sobrien prusage(&zru, &ru, &tetime, &ztime); 132659243Sobrien#else /* !BSDTIMES */ 132759243Sobrien# ifdef _SEQUENT_ 132859243Sobrien timeval_t tetime, diff; 132959243Sobrien static timeval_t ztime; 133059243Sobrien struct process_stats ru; 133159243Sobrien register struct process *pp = tp; 133259243Sobrien 133359243Sobrien ru = zru; 133459243Sobrien tetime = ztime; 133559243Sobrien do { 133659243Sobrien ruadd(&ru, &pp->p_rusage); 133759243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 133859243Sobrien if (timercmp(&diff, &tetime, >)) 133959243Sobrien tetime = diff; 134059243Sobrien } while ((pp = pp->p_friends) != tp); 134159243Sobrien prusage(&zru, &ru, &tetime, &ztime); 134259243Sobrien# else /* !_SEQUENT_ */ 134359243Sobrien# ifndef POSIX 134459243Sobrien static time_t ztime = 0; 134559243Sobrien static time_t zu_time = 0; 134659243Sobrien static time_t zs_time = 0; 134759243Sobrien time_t tetime, diff; 134859243Sobrien time_t u_time, s_time; 134959243Sobrien 135059243Sobrien# else /* POSIX */ 135159243Sobrien static clock_t ztime = 0; 135259243Sobrien static clock_t zu_time = 0; 135359243Sobrien static clock_t zs_time = 0; 135459243Sobrien clock_t tetime, diff; 135559243Sobrien clock_t u_time, s_time; 135659243Sobrien 135759243Sobrien# endif /* POSIX */ 135859243Sobrien struct tms zts, rts; 135959243Sobrien register struct process *pp = tp; 136059243Sobrien 136159243Sobrien u_time = zu_time; 136259243Sobrien s_time = zs_time; 136359243Sobrien tetime = ztime; 136459243Sobrien do { 136559243Sobrien u_time += pp->p_utime; 136659243Sobrien s_time += pp->p_stime; 136759243Sobrien diff = pp->p_etime - pp->p_btime; 136859243Sobrien if (diff > tetime) 136959243Sobrien tetime = diff; 137059243Sobrien } while ((pp = pp->p_friends) != tp); 137159243Sobrien zts.tms_utime = zu_time; 137259243Sobrien zts.tms_stime = zs_time; 137359243Sobrien zts.tms_cutime = 0; 137459243Sobrien zts.tms_cstime = 0; 137559243Sobrien rts.tms_utime = u_time; 137659243Sobrien rts.tms_stime = s_time; 137759243Sobrien rts.tms_cutime = 0; 137859243Sobrien rts.tms_cstime = 0; 137959243Sobrien prusage(&zts, &rts, tetime, ztime); 138059243Sobrien# endif /* !_SEQUENT_ */ 138159243Sobrien#endif /* !BSDTIMES */ 138259243Sobrien} 138359243Sobrien 138459243Sobrien/* 138559243Sobrien * dojobs - print all jobs 138659243Sobrien */ 138759243Sobrien/*ARGSUSED*/ 138859243Sobrienvoid 138959243Sobriendojobs(v, c) 139059243Sobrien Char **v; 139159243Sobrien struct command *c; 139259243Sobrien{ 139359243Sobrien register struct process *pp; 139459243Sobrien register int flag = NUMBER | NAME | REASON; 139559243Sobrien int i; 139659243Sobrien 139759243Sobrien USE(c); 139859243Sobrien if (chkstop) 139959243Sobrien chkstop = 2; 140059243Sobrien if (*++v) { 140159243Sobrien if (v[1] || !eq(*v, STRml)) 140259243Sobrien stderror(ERR_JOBS); 140359243Sobrien flag |= FANCY | JOBDIR; 140459243Sobrien } 140559243Sobrien for (i = 1; i <= pmaxindex; i++) 140659243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 140759243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 140859243Sobrien pp->p_flags &= ~PNEEDNOTE; 140959243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 141059243Sobrien pflush(pp); 141159243Sobrien break; 141259243Sobrien } 141359243Sobrien} 141459243Sobrien 141559243Sobrien/* 141659243Sobrien * dofg - builtin - put the job into the foreground 141759243Sobrien */ 141859243Sobrien/*ARGSUSED*/ 141959243Sobrienvoid 142059243Sobriendofg(v, c) 142159243Sobrien Char **v; 142259243Sobrien struct command *c; 142359243Sobrien{ 142459243Sobrien register struct process *pp; 142559243Sobrien 142659243Sobrien USE(c); 142759243Sobrien okpcntl(); 142859243Sobrien ++v; 142959243Sobrien do { 143059243Sobrien pp = pfind(*v); 143159243Sobrien if (!pstart(pp, 1)) { 143259243Sobrien pp->p_procid = 0; 143359243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 143459243Sobrien continue; 143559243Sobrien } 143659243Sobrien#ifndef BSDSIGS 143759243Sobrien# ifdef notdef 143859243Sobrien if (setintr) 143959243Sobrien sigignore(SIGINT); 144059243Sobrien# endif 144159243Sobrien#endif /* !BSDSIGS */ 144259243Sobrien pjwait(pp); 144359243Sobrien } while (*v && *++v); 144459243Sobrien} 144559243Sobrien 144659243Sobrien/* 144759243Sobrien * %... - builtin - put the job into the foreground 144859243Sobrien */ 144959243Sobrien/*ARGSUSED*/ 145059243Sobrienvoid 145159243Sobriendofg1(v, c) 145259243Sobrien Char **v; 145359243Sobrien struct command *c; 145459243Sobrien{ 145559243Sobrien register struct process *pp; 145659243Sobrien 145759243Sobrien USE(c); 145859243Sobrien okpcntl(); 145959243Sobrien pp = pfind(v[0]); 146059243Sobrien if (!pstart(pp, 1)) { 146159243Sobrien pp->p_procid = 0; 146259243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 146359243Sobrien return; 146459243Sobrien } 146559243Sobrien#ifndef BSDSIGS 146659243Sobrien# ifdef notdef 146759243Sobrien if (setintr) 146859243Sobrien sigignore(SIGINT); 146959243Sobrien# endif 147059243Sobrien#endif /* !BSDSIGS */ 147159243Sobrien pjwait(pp); 147259243Sobrien} 147359243Sobrien 147459243Sobrien/* 147559243Sobrien * dobg - builtin - put the job into the background 147659243Sobrien */ 147759243Sobrien/*ARGSUSED*/ 147859243Sobrienvoid 147959243Sobriendobg(v, c) 148059243Sobrien Char **v; 148159243Sobrien struct command *c; 148259243Sobrien{ 148359243Sobrien register struct process *pp; 148459243Sobrien 148559243Sobrien USE(c); 148659243Sobrien okpcntl(); 148759243Sobrien ++v; 148859243Sobrien do { 148959243Sobrien pp = pfind(*v); 149059243Sobrien if (!pstart(pp, 0)) { 149159243Sobrien pp->p_procid = 0; 149259243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 149359243Sobrien } 149459243Sobrien } while (*v && *++v); 149559243Sobrien} 149659243Sobrien 149759243Sobrien/* 149859243Sobrien * %... & - builtin - put the job into the background 149959243Sobrien */ 150059243Sobrien/*ARGSUSED*/ 150159243Sobrienvoid 150259243Sobriendobg1(v, c) 150359243Sobrien Char **v; 150459243Sobrien struct command *c; 150559243Sobrien{ 150659243Sobrien register struct process *pp; 150759243Sobrien 150859243Sobrien USE(c); 150959243Sobrien pp = pfind(v[0]); 151059243Sobrien if (!pstart(pp, 0)) { 151159243Sobrien pp->p_procid = 0; 151259243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 151359243Sobrien } 151459243Sobrien} 151559243Sobrien 151659243Sobrien/* 151759243Sobrien * dostop - builtin - stop the job 151859243Sobrien */ 151959243Sobrien/*ARGSUSED*/ 152059243Sobrienvoid 152159243Sobriendostop(v, c) 152259243Sobrien Char **v; 152359243Sobrien struct command *c; 152459243Sobrien{ 152559243Sobrien USE(c); 152659243Sobrien#ifdef BSDJOBS 152759243Sobrien pkill(++v, SIGSTOP); 152859243Sobrien#endif /* BSDJOBS */ 152959243Sobrien} 153059243Sobrien 153159243Sobrien/* 153259243Sobrien * dokill - builtin - superset of kill (1) 153359243Sobrien */ 153459243Sobrien/*ARGSUSED*/ 153559243Sobrienvoid 153659243Sobriendokill(v, c) 153759243Sobrien Char **v; 153859243Sobrien struct command *c; 153959243Sobrien{ 154059243Sobrien register int signum, len = 0; 154159243Sobrien register char *name; 154283098Smp Char *sigptr; 154359243Sobrien extern int T_Cols; 154459243Sobrien extern int nsig; 154559243Sobrien 154659243Sobrien USE(c); 154759243Sobrien v++; 154859243Sobrien if (v[0] && v[0][0] == '-') { 154959243Sobrien if (v[0][1] == 'l') { 155059243Sobrien for (signum = 0; signum <= nsig; signum++) { 155159243Sobrien if ((name = mesg[signum].iname) != NULL) { 155259243Sobrien len += strlen(name) + 1; 155359243Sobrien if (len >= T_Cols - 1) { 155459243Sobrien xputchar('\n'); 155559243Sobrien len = strlen(name) + 1; 155659243Sobrien } 155759243Sobrien xprintf("%s ", name); 155859243Sobrien } 155959243Sobrien } 156059243Sobrien xputchar('\n'); 156159243Sobrien return; 156259243Sobrien } 156383098Smp sigptr = &v[0][1]; 156483098Smp if (v[0][1] == 's') { 156583098Smp if (v[1]) { 156683098Smp v++; 156783098Smp sigptr = &v[0][0]; 156883098Smp } else { 156983098Smp stderror(ERR_NAME | ERR_TOOFEW); 157083098Smp } 157183098Smp } 157283098Smp if (Isdigit(*sigptr)) { 157383098Smp signum = atoi(short2str(sigptr)); 157459243Sobrien if (signum < 0 || signum > (MAXSIG-1)) 157559243Sobrien stderror(ERR_NAME | ERR_BADSIG); 157659243Sobrien } 157759243Sobrien else { 157859243Sobrien for (signum = 0; signum <= nsig; signum++) 157959243Sobrien if (mesg[signum].iname && 158083098Smp eq(sigptr, str2short(mesg[signum].iname))) 158159243Sobrien goto gotsig; 158283098Smp setname(short2str(sigptr)); 158359243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 158459243Sobrien } 158559243Sobriengotsig: 158659243Sobrien v++; 158759243Sobrien } 158859243Sobrien else 158959243Sobrien signum = SIGTERM; 159059243Sobrien pkill(v, signum); 159159243Sobrien} 159259243Sobrien 159359243Sobrienstatic void 159459243Sobrienpkill(v, signum) 159559243Sobrien Char **v; 159659243Sobrien int signum; 159759243Sobrien{ 159859243Sobrien register struct process *pp, *np; 159959243Sobrien int jobflags = 0, err1 = 0; 160059243Sobrien pid_t pid; 160159243Sobrien#ifdef BSDSIGS 160259243Sobrien sigmask_t omask; 160359243Sobrien#endif /* BSDSIGS */ 160459243Sobrien Char *cp, **vp; 160559243Sobrien 160659243Sobrien#ifdef BSDSIGS 160759243Sobrien omask = sigmask(SIGCHLD); 160859243Sobrien if (setintr) 160959243Sobrien omask |= sigmask(SIGINT); 161059243Sobrien omask = sigblock(omask) & ~omask; 161159243Sobrien#else /* !BSDSIGS */ 161259243Sobrien if (setintr) 161359243Sobrien (void) sighold(SIGINT); 161459243Sobrien (void) sighold(SIGCHLD); 161559243Sobrien#endif /* !BSDSIGS */ 161659243Sobrien 161759243Sobrien /* Avoid globbing %?x patterns */ 161859243Sobrien for (vp = v; vp && *vp; vp++) 161959243Sobrien if (**vp == '%') 162059243Sobrien (void) quote(*vp); 162159243Sobrien 162259243Sobrien gflag = 0, tglob(v); 162359243Sobrien if (gflag) { 162459243Sobrien v = globall(v); 162559243Sobrien if (v == 0) 162659243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 162759243Sobrien } 162859243Sobrien else { 162959243Sobrien v = gargv = saveblk(v); 163059243Sobrien trim(v); 163159243Sobrien } 163259243Sobrien 163359243Sobrien 163459243Sobrien while (v && (cp = *v)) { 163559243Sobrien if (*cp == '%') { 163659243Sobrien np = pp = pfind(cp); 163759243Sobrien do 163859243Sobrien jobflags |= np->p_flags; 163959243Sobrien while ((np = np->p_friends) != pp); 164059243Sobrien#ifdef BSDJOBS 164159243Sobrien switch (signum) { 164259243Sobrien 164359243Sobrien case SIGSTOP: 164459243Sobrien case SIGTSTP: 164559243Sobrien case SIGTTIN: 164659243Sobrien case SIGTTOU: 164759243Sobrien if ((jobflags & PRUNNING) == 0) { 164859243Sobrien# ifdef SUSPENDED 164959243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 165059243Sobrien# else /* !SUSPENDED */ 165159243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 165259243Sobrien# endif /* !SUSPENDED */ 165359243Sobrien err1++; 165459243Sobrien goto cont; 165559243Sobrien } 165659243Sobrien break; 165759243Sobrien /* 165859243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 165959243Sobrien * says it is suspended, but it is running; thanks jaap.. 166059243Sobrien */ 166159243Sobrien case SIGCONT: 166259243Sobrien if (!pstart(pp, 0)) { 166359243Sobrien pp->p_procid = 0; 166459243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 166559243Sobrien strerror(errno)); 166659243Sobrien } 166759243Sobrien goto cont; 166859243Sobrien default: 166959243Sobrien break; 167059243Sobrien } 167159243Sobrien#endif /* BSDJOBS */ 167259243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 167359243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 167459243Sobrien err1++; 167559243Sobrien } 167659243Sobrien#ifdef BSDJOBS 167759243Sobrien if (signum == SIGTERM || signum == SIGHUP) 167859243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 167959243Sobrien#endif /* BSDJOBS */ 168059243Sobrien } 168159243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 168259243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 168359243Sobrien else { 168469408Sache#ifndef WINNT_NATIVE 168559243Sobrien pid = atoi(short2str(cp)); 168659243Sobrien#else 168759243Sobrien pid = strtoul(short2str(cp),NULL,0); 168869408Sache#endif /* WINNT_NATIVE */ 168959243Sobrien if (kill(pid, signum) < 0) { 169059243Sobrien xprintf("%d: %s\n", pid, strerror(errno)); 169159243Sobrien err1++; 169259243Sobrien goto cont; 169359243Sobrien } 169459243Sobrien#ifdef BSDJOBS 169559243Sobrien if (signum == SIGTERM || signum == SIGHUP) 169659243Sobrien (void) kill(pid, SIGCONT); 169759243Sobrien#endif /* BSDJOBS */ 169859243Sobrien } 169959243Sobriencont: 170059243Sobrien v++; 170159243Sobrien } 170259243Sobrien if (gargv) 170359243Sobrien blkfree(gargv), gargv = 0; 170459243Sobrien#ifdef BSDSIGS 170559243Sobrien (void) sigsetmask(omask); 170659243Sobrien#else /* !BSDSIGS */ 170759243Sobrien (void) sigrelse(SIGCHLD); 170859243Sobrien if (setintr) 170959243Sobrien (void) sigrelse(SIGINT); 171059243Sobrien#endif /* !BSDSIGS */ 171159243Sobrien if (err1) 171259243Sobrien stderror(ERR_SILENT); 171359243Sobrien} 171459243Sobrien 171559243Sobrien/* 171659243Sobrien * pstart - start the job in foreground/background 171759243Sobrien */ 171859243Sobrienint 171959243Sobrienpstart(pp, foregnd) 172059243Sobrien register struct process *pp; 172159243Sobrien int foregnd; 172259243Sobrien{ 172359243Sobrien int rv = 0; 172459243Sobrien register struct process *np; 172559243Sobrien#ifdef BSDSIGS 172659243Sobrien sigmask_t omask; 172759243Sobrien#endif /* BSDSIGS */ 172859243Sobrien /* We don't use jobflags in this function right now (see below) */ 172959243Sobrien /* long jobflags = 0; */ 173059243Sobrien 173159243Sobrien#ifdef BSDSIGS 173259243Sobrien omask = sigblock(sigmask(SIGCHLD)); 173359243Sobrien#else /* !BSDSIGS */ 173459243Sobrien (void) sighold(SIGCHLD); 173559243Sobrien#endif 173659243Sobrien np = pp; 173759243Sobrien do { 173859243Sobrien /* We don't use jobflags in this function right now (see below) */ 173959243Sobrien /* jobflags |= np->p_flags; */ 174059243Sobrien if (np->p_flags & (PRUNNING | PSTOPPED)) { 174159243Sobrien np->p_flags |= PRUNNING; 174259243Sobrien np->p_flags &= ~PSTOPPED; 174359243Sobrien if (foregnd) 174459243Sobrien np->p_flags |= PFOREGND; 174559243Sobrien else 174659243Sobrien np->p_flags &= ~PFOREGND; 174759243Sobrien } 174859243Sobrien } while ((np = np->p_friends) != pp); 174959243Sobrien if (!foregnd) 175059243Sobrien pclrcurr(pp); 175159243Sobrien (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 175283098Smp 175383098Smp /* GrP run jobcmd hook if foregrounding */ 175483098Smp if (foregnd) { 175583098Smp job_cmd(pp->p_command); 175683098Smp } 175783098Smp 175859243Sobrien#ifdef BSDJOBS 175959243Sobrien if (foregnd) { 176059243Sobrien rv = tcsetpgrp(FSHTTY, pp->p_jobid); 176159243Sobrien } 176259243Sobrien /* 176359243Sobrien * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU 176459243Sobrien * 2. parent process (csh) receives SIGCHLD 176559243Sobrien * 3. The "csh" signal handling function pchild() is invoked 176659243Sobrien * with a SIGCHLD signal. 176759243Sobrien * 4. pchild() calls wait3(WNOHANG) which returns 0. 176859243Sobrien * The child process is NOT ready to be waited for at this time. 176959243Sobrien * pchild() returns without picking-up the correct status 177059243Sobrien * for the child process which generated the SIGCHILD. 177159243Sobrien * 5. CONSEQUENCE : csh is UNaware that the process is stopped 177259243Sobrien * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) 177359243Sobrien * (beto@aixwiz.austin.ibm.com - aug/03/91) 177459243Sobrien * 7. I removed the line completely and added extra checks for 177559243Sobrien * pstart, so that if a job gets attached to and dies inside 177659243Sobrien * a debugger it does not confuse the shell. [christos] 177759243Sobrien * 8. on the nec sx-4 there seems to be a problem, which requires 177859243Sobrien * a syscall(151, getpid(), getpid()) in osinit. Don't ask me 177959243Sobrien * what this is doing. [schott@rzg.mpg.de] 178059243Sobrien */ 178159243Sobrien 178259243Sobrien if (rv != -1) 178359243Sobrien rv = killpg(pp->p_jobid, SIGCONT); 178459243Sobrien#endif /* BSDJOBS */ 178559243Sobrien#ifdef BSDSIGS 178659243Sobrien (void) sigsetmask(omask); 178759243Sobrien#else /* !BSDSIGS */ 178859243Sobrien (void) sigrelse(SIGCHLD); 178959243Sobrien#endif /* !BSDSIGS */ 179059243Sobrien return rv != -1; 179159243Sobrien} 179259243Sobrien 179359243Sobrienvoid 179459243Sobrienpanystop(neednl) 179559243Sobrien bool neednl; 179659243Sobrien{ 179759243Sobrien register struct process *pp; 179859243Sobrien 179959243Sobrien chkstop = 2; 180059243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 180159243Sobrien if (pp->p_flags & PSTOPPED) 180259243Sobrien stderror(ERR_STOPPED, neednl ? "\n" : ""); 180359243Sobrien} 180459243Sobrien 180559243Sobrienstruct process * 180659243Sobrienpfind(cp) 180759243Sobrien Char *cp; 180859243Sobrien{ 180959243Sobrien register struct process *pp, *np; 181059243Sobrien 181159243Sobrien if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 181259243Sobrien if (pcurrent == NULL) 181359243Sobrien stderror(ERR_NAME | ERR_JOBCUR); 181459243Sobrien return (pcurrent); 181559243Sobrien } 181659243Sobrien if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 181759243Sobrien if (pprevious == NULL) 181859243Sobrien stderror(ERR_NAME | ERR_JOBPREV); 181959243Sobrien return (pprevious); 182059243Sobrien } 182159243Sobrien if (Isdigit(cp[1])) { 182259243Sobrien int idx = atoi(short2str(cp + 1)); 182359243Sobrien 182459243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 182559243Sobrien if (pp->p_index == idx && pp->p_procid == pp->p_jobid) 182659243Sobrien return (pp); 182759243Sobrien stderror(ERR_NAME | ERR_NOSUCHJOB); 182859243Sobrien } 182959243Sobrien np = NULL; 183059243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 183159243Sobrien if (pp->p_procid == pp->p_jobid) { 183259243Sobrien if (cp[1] == '?') { 183359243Sobrien register Char *dp; 183459243Sobrien 183559243Sobrien for (dp = pp->p_command; *dp; dp++) { 183659243Sobrien if (*dp != cp[2]) 183759243Sobrien continue; 183859243Sobrien if (prefix(cp + 2, dp)) 183959243Sobrien goto match; 184059243Sobrien } 184159243Sobrien } 184259243Sobrien else if (prefix(cp + 1, pp->p_command)) { 184359243Sobrien match: 184459243Sobrien if (np) 184559243Sobrien stderror(ERR_NAME | ERR_AMBIG); 184659243Sobrien np = pp; 184759243Sobrien } 184859243Sobrien } 184959243Sobrien if (np) 185059243Sobrien return (np); 185159243Sobrien stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 185259243Sobrien /* NOTREACHED */ 185359243Sobrien return (0); 185459243Sobrien} 185559243Sobrien 185659243Sobrien 185759243Sobrien/* 185859243Sobrien * pgetcurr - find most recent job that is not pp, preferably stopped 185959243Sobrien */ 186059243Sobrienstatic struct process * 186159243Sobrienpgetcurr(pp) 186259243Sobrien register struct process *pp; 186359243Sobrien{ 186459243Sobrien register struct process *np; 186559243Sobrien register struct process *xp = NULL; 186659243Sobrien 186759243Sobrien for (np = proclist.p_next; np; np = np->p_next) 186859243Sobrien if (np != pcurrent && np != pp && np->p_procid && 186959243Sobrien np->p_procid == np->p_jobid) { 187059243Sobrien if (np->p_flags & PSTOPPED) 187159243Sobrien return (np); 187259243Sobrien if (xp == NULL) 187359243Sobrien xp = np; 187459243Sobrien } 187559243Sobrien return (xp); 187659243Sobrien} 187759243Sobrien 187859243Sobrien/* 187959243Sobrien * donotify - flag the job so as to report termination asynchronously 188059243Sobrien */ 188159243Sobrien/*ARGSUSED*/ 188259243Sobrienvoid 188359243Sobriendonotify(v, c) 188459243Sobrien Char **v; 188559243Sobrien struct command *c; 188659243Sobrien{ 188759243Sobrien register struct process *pp; 188859243Sobrien 188959243Sobrien USE(c); 189059243Sobrien pp = pfind(*++v); 189159243Sobrien pp->p_flags |= PNOTIFY; 189259243Sobrien} 189359243Sobrien 189459243Sobrien/* 189559243Sobrien * Do the fork and whatever should be done in the child side that 189659243Sobrien * should not be done if we are not forking at all (like for simple builtin's) 189759243Sobrien * Also do everything that needs any signals fiddled with in the parent side 189859243Sobrien * 189959243Sobrien * Wanttty tells whether process and/or tty pgrps are to be manipulated: 190059243Sobrien * -1: leave tty alone; inherit pgrp from parent 190159243Sobrien * 0: already have tty; manipulate process pgrps only 190259243Sobrien * 1: want to claim tty; manipulate process and tty pgrps 190359243Sobrien * It is usually just the value of tpgrp. 190459243Sobrien */ 190559243Sobrien 190659243Sobrienint 190759243Sobrienpfork(t, wanttty) 190859243Sobrien struct command *t; /* command we are forking for */ 190959243Sobrien int wanttty; 191059243Sobrien{ 191159243Sobrien register int pid; 191259243Sobrien bool ignint = 0; 191359243Sobrien int pgrp; 191459243Sobrien#ifdef BSDSIGS 191559243Sobrien sigmask_t omask = 0; 191659243Sobrien#endif /* BSDSIGS */ 191759243Sobrien#ifdef SIGSYNCH 191859243Sobrien sigvec_t osv; 191959243Sobrien static sigvec_t nsv = {synch_handler, (sigset_t) ~0, 0}; 192059243Sobrien#endif /* SIGSYNCH */ 192159243Sobrien 192259243Sobrien /* 192359243Sobrien * A child will be uninterruptible only under very special conditions. 192459243Sobrien * Remember that the semantics of '&' is implemented by disconnecting the 192559243Sobrien * process from the tty so signals do not need to ignored just for '&'. 192659243Sobrien * Thus signals are set to default action for children unless: we have had 192759243Sobrien * an "onintr -" (then specifically ignored) we are not playing with 192859243Sobrien * signals (inherit action) 192959243Sobrien */ 193059243Sobrien if (setintr) 193159243Sobrien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 193259243Sobrien || (gointr && eq(gointr, STRminus)); 193359243Sobrien 193459243Sobrien#ifdef COHERENT 193559243Sobrien ignint |= gointr && eq(gointr, STRminus); 193659243Sobrien#endif /* COHERENT */ 193759243Sobrien 193859243Sobrien /* 193959243Sobrien * Check for maximum nesting of 16 processes to avoid Forking loops 194059243Sobrien */ 194159243Sobrien if (child == 16) 194259243Sobrien stderror(ERR_NESTING, 16); 194359243Sobrien#ifdef SIGSYNCH 194459243Sobrien if (mysigvec(SIGSYNCH, &nsv, &osv)) 194559243Sobrien stderror(ERR_SYSTEM, "pfork: sigvec set", strerror(errno)); 194659243Sobrien#endif /* SIGSYNCH */ 194759243Sobrien /* 194859243Sobrien * Hold SIGCHLD until we have the process installed in our table. 194959243Sobrien */ 195059243Sobrien if (wanttty < 0) { 195159243Sobrien#ifdef BSDSIGS 195259243Sobrien omask = sigblock(sigmask(SIGCHLD)); 195359243Sobrien#else /* !BSDSIGS */ 195459243Sobrien (void) sighold(SIGCHLD); 195559243Sobrien#endif /* !BSDSIGS */ 195659243Sobrien } 195759243Sobrien while ((pid = fork()) == -1) 195859243Sobrien if (setintr == 0) 195959243Sobrien (void) sleep(FORKSLEEP); 196059243Sobrien else { 196159243Sobrien if (wanttty < 0) 196259243Sobrien#ifdef BSDSIGS 196359243Sobrien (void) sigsetmask(omask); 196459243Sobrien#else /* !BSDSIGS */ 196559243Sobrien (void) sigrelse(SIGCHLD); 196659243Sobrien (void) sigrelse(SIGINT); 196759243Sobrien#endif /* !BSDSIGS */ 196859243Sobrien stderror(ERR_NOPROC); 196959243Sobrien } 197059243Sobrien if (pid == 0) { 197159243Sobrien settimes(); 197259243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 197359243Sobrien pflushall(); 197459243Sobrien pcurrjob = NULL; 197559243Sobrien#if !defined(BSDTIMES) && !defined(_SEQUENT_) 197659243Sobrien timesdone = 0; 197759243Sobrien#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 197859243Sobrien child++; 197959243Sobrien if (setintr) { 198059243Sobrien setintr = 0; /* until I think otherwise */ 198159243Sobrien#ifndef BSDSIGS 198259243Sobrien if (wanttty < 0) 198359243Sobrien (void) sigrelse(SIGCHLD); 198459243Sobrien#endif /* !BSDSIGS */ 198559243Sobrien /* 198659243Sobrien * Children just get blown away on SIGINT, SIGQUIT unless "onintr 198759243Sobrien * -" seen. 198859243Sobrien */ 198959243Sobrien (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 199059243Sobrien (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 199159243Sobrien#ifdef BSDJOBS 199259243Sobrien if (wanttty >= 0) { 199359243Sobrien /* make stoppable */ 199459243Sobrien (void) signal(SIGTSTP, SIG_DFL); 199559243Sobrien (void) signal(SIGTTIN, SIG_DFL); 199659243Sobrien (void) signal(SIGTTOU, SIG_DFL); 199759243Sobrien } 199859243Sobrien#endif /* BSDJOBS */ 199959243Sobrien (void) signal(SIGTERM, parterm); 200059243Sobrien } 200159243Sobrien else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 200259243Sobrien (void) signal(SIGINT, SIG_IGN); 200359243Sobrien (void) signal(SIGQUIT, SIG_IGN); 200459243Sobrien } 200559243Sobrien#ifdef OREO 200659243Sobrien sigignore(SIGIO); /* ignore SIGIO in child too */ 200759243Sobrien#endif /* OREO */ 200859243Sobrien 200959243Sobrien pgetty(wanttty, pgrp); 201059243Sobrien /* 201159243Sobrien * Nohup and nice apply only to NODE_COMMAND's but it would be nice 201259243Sobrien * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 201359243Sobrien * to know about nice/nohup/time 201459243Sobrien */ 201559243Sobrien if (t->t_dflg & F_NOHUP) 201659243Sobrien (void) signal(SIGHUP, SIG_IGN); 201759243Sobrien if (t->t_dflg & F_NICE) { 201859243Sobrien int nval = SIGN_EXTEND_CHAR(t->t_nice); 201959243Sobrien#ifdef BSDNICE 202083098Smp if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 202183098Smp stderror(ERR_SYSTEM, "setpriority", strerror(errno)); 202259243Sobrien#else /* !BSDNICE */ 202359243Sobrien (void) nice(nval); 202459243Sobrien#endif /* !BSDNICE */ 202559243Sobrien } 202659243Sobrien#ifdef F_VER 202759243Sobrien if (t->t_dflg & F_VER) { 202859243Sobrien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 202959243Sobrien dohash(NULL, NULL); 203059243Sobrien } 203159243Sobrien#endif /* F_VER */ 203259243Sobrien#ifdef SIGSYNCH 203359243Sobrien /* rfw 8/89 now parent can continue */ 203459243Sobrien if (kill(getppid(), SIGSYNCH)) 203559243Sobrien stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 203659243Sobrien#endif /* SIGSYNCH */ 203759243Sobrien 203859243Sobrien } 203959243Sobrien else { 204059243Sobrien#ifdef POSIXJOBS 204159243Sobrien if (wanttty >= 0) { 204259243Sobrien /* 204359243Sobrien * `Walking' process group fix from Beto Appleton. 204459243Sobrien * (beto@aixwiz.austin.ibm.com) 204559243Sobrien * If setpgid fails at this point that means that 204659243Sobrien * our process leader has died. We flush the current 204759243Sobrien * job and become the process leader ourselves. 204859243Sobrien * The parent will figure that out later. 204959243Sobrien */ 205059243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : pid; 205159243Sobrien if (setpgid(pid, pgrp) == -1 && errno == EPERM) { 205259243Sobrien pcurrjob = NULL; 205359243Sobrien /* 205459243Sobrien * We don't care if this causes an error here; 205559243Sobrien * then we are already in the right process group 205659243Sobrien */ 205759243Sobrien (void) setpgid(pid, pgrp = pid); 205859243Sobrien } 205959243Sobrien } 206059243Sobrien#endif /* POSIXJOBS */ 206159243Sobrien palloc(pid, t); 206259243Sobrien#ifdef SIGSYNCH 206359243Sobrien /* 206459243Sobrien * rfw 8/89 Wait for child to own terminal. Solves half of ugly 206559243Sobrien * synchronization problem. With this change, we know that the only 206659243Sobrien * reason setpgrp to a previous process in a pipeline can fail is that 206759243Sobrien * the previous process has already exited. Without this hack, he may 206859243Sobrien * either have exited or not yet started to run. Two uglies become 206959243Sobrien * one. 207059243Sobrien */ 207159243Sobrien (void) sigpause(omask & ~SYNCHMASK); 207259243Sobrien if (mysigvec(SIGSYNCH, &osv, NULL)) 207359243Sobrien stderror(ERR_SYSTEM, "pfork parent: sigvec restore", 207459243Sobrien strerror(errno)); 207559243Sobrien#endif /* SIGSYNCH */ 207659243Sobrien 207759243Sobrien if (wanttty < 0) { 207859243Sobrien#ifdef BSDSIGS 207959243Sobrien (void) sigsetmask(omask); 208059243Sobrien#else /* !BSDSIGS */ 208159243Sobrien (void) sigrelse(SIGCHLD); 208259243Sobrien#endif /* !BSDSIGS */ 208359243Sobrien } 208459243Sobrien } 208559243Sobrien return (pid); 208659243Sobrien} 208759243Sobrien 208859243Sobrienstatic void 208959243Sobrienokpcntl() 209059243Sobrien{ 209159243Sobrien if (tpgrp == -1) 209259243Sobrien stderror(ERR_JOBCONTROL); 209359243Sobrien if (tpgrp == 0) 209459243Sobrien stderror(ERR_JOBCTRLSUB); 209559243Sobrien} 209659243Sobrien 209759243Sobrien 209859243Sobrienstatic void 209959243Sobriensetttypgrp(pgrp) 210059243Sobrien int pgrp; 210159243Sobrien{ 210259243Sobrien /* 210359243Sobrien * If we are piping out a builtin, eg. 'echo | more' things can go 210459243Sobrien * out of sequence, i.e. the more can run before the echo. This 210559243Sobrien * can happen even if we have vfork, since the echo will be forked 210659243Sobrien * with the regular fork. In this case, we need to set the tty 210759243Sobrien * pgrp ourselves. If that happens, then the process will be still 210859243Sobrien * alive. And the tty process group will already be set. 210959243Sobrien * This should fix the famous sequent problem as a side effect: 211059243Sobrien * The controlling terminal is lost if all processes in the 211159243Sobrien * terminal process group are zombies. In this case tcgetpgrp() 211259243Sobrien * returns 0. If this happens we must set the terminal process 211359243Sobrien * group again. 211459243Sobrien */ 211559243Sobrien if (tcgetpgrp(FSHTTY) != pgrp) { 211659243Sobrien#ifdef POSIXJOBS 211759243Sobrien /* 211859243Sobrien * tcsetpgrp will set SIGTTOU to all the the processes in 211959243Sobrien * the background according to POSIX... We ignore this here. 212059243Sobrien */ 212159243Sobrien signalfun_t old = sigset(SIGTTOU, SIG_IGN); 212259243Sobrien#endif 212359243Sobrien (void) tcsetpgrp(FSHTTY, pgrp); 212459243Sobrien# ifdef POSIXJOBS 212559243Sobrien (void) sigset(SIGTTOU, old); 212659243Sobrien# endif 212759243Sobrien 212859243Sobrien } 212959243Sobrien} 213059243Sobrien 213159243Sobrien 213259243Sobrien/* 213359243Sobrien * if we don't have vfork(), things can still go in the wrong order 213459243Sobrien * resulting in the famous 'Stopped (tty output)'. But some systems 213559243Sobrien * don't permit the setpgid() call, (these are more recent secure 213659243Sobrien * systems such as ibm's aix), when they do. Then we'd rather print 213759243Sobrien * an error message than hang the shell! 213859243Sobrien * I am open to suggestions how to fix that. 213959243Sobrien */ 214059243Sobrienvoid 214159243Sobrienpgetty(wanttty, pgrp) 214259243Sobrien int wanttty, pgrp; 214359243Sobrien{ 214459243Sobrien#ifdef BSDJOBS 214559243Sobrien# if defined(BSDSIGS) && defined(POSIXJOBS) 214659243Sobrien sigmask_t omask = 0; 214759243Sobrien# endif /* BSDSIGS && POSIXJOBS */ 214859243Sobrien 214959243Sobrien# ifdef JOBDEBUG 215059243Sobrien xprintf("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n", 215159243Sobrien wanttty, getpid(), pgrp, mygetpgrp(), tcgetpgrp(FSHTTY)); 215259243Sobrien# endif /* JOBDEBUG */ 215359243Sobrien# ifdef POSIXJOBS 215459243Sobrien /* 215559243Sobrien * christos: I am blocking the tty signals till I've set things 215659243Sobrien * correctly.... 215759243Sobrien */ 215859243Sobrien if (wanttty > 0) 215959243Sobrien# ifdef BSDSIGS 216059243Sobrien omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)); 216159243Sobrien# else /* !BSDSIGS */ 216259243Sobrien { 216359243Sobrien (void) sighold(SIGTSTP); 216459243Sobrien (void) sighold(SIGTTIN); 216559243Sobrien } 216659243Sobrien# endif /* !BSDSIGS */ 216759243Sobrien# endif /* POSIXJOBS */ 216859243Sobrien 216959243Sobrien# ifndef POSIXJOBS 217059243Sobrien if (wanttty > 0) 217159243Sobrien setttypgrp(pgrp); 217259243Sobrien# endif /* !POSIXJOBS */ 217359243Sobrien 217459243Sobrien /* 217559243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 217659243Sobrien * Don't check for tpgrp >= 0 so even non-interactive shells give 217759243Sobrien * background jobs process groups Same for the comparison in the other part 217859243Sobrien * of the #ifdef 217959243Sobrien */ 218059243Sobrien if (wanttty >= 0) { 218159243Sobrien if (setpgid(0, pgrp) == -1) { 218259243Sobrien# ifdef POSIXJOBS 218359243Sobrien /* Walking process group fix; see above */ 218459243Sobrien if (setpgid(0, pgrp = getpid()) == -1) { 218559243Sobrien# endif /* POSIXJOBS */ 218659243Sobrien stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); 218759243Sobrien xexit(0); 218859243Sobrien# ifdef POSIXJOBS 218959243Sobrien } 219059243Sobrien wanttty = pgrp; /* Now we really want the tty, since we became the 219159243Sobrien * the process group leader 219259243Sobrien */ 219359243Sobrien# endif /* POSIXJOBS */ 219459243Sobrien } 219559243Sobrien } 219659243Sobrien 219759243Sobrien# ifdef POSIXJOBS 219859243Sobrien if (wanttty > 0) 219959243Sobrien setttypgrp(pgrp); 220059243Sobrien# ifdef BSDSIGS 220159243Sobrien (void) sigsetmask(omask); 220259243Sobrien# else /* BSDSIGS */ 220359243Sobrien (void) sigrelse(SIGTSTP); 220459243Sobrien (void) sigrelse(SIGTTIN); 220559243Sobrien# endif /* !BSDSIGS */ 220659243Sobrien# endif /* POSIXJOBS */ 220759243Sobrien 220859243Sobrien# ifdef JOBDEBUG 220959243Sobrien xprintf("wanttty %d pid %d pgrp %d tpgrp %d\n", 221059243Sobrien wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY)); 221159243Sobrien# endif /* JOBDEBUG */ 221259243Sobrien 221359243Sobrien if (tpgrp > 0) 221459243Sobrien tpgrp = 0; /* gave tty away */ 221559243Sobrien#endif /* BSDJOBS */ 221659243Sobrien} 2217