sh.proc.c revision 131962
1131962Smp/* $Header: /src/pub/tcsh/sh.proc.c,v 3.81 2003/11/09 03:02:46 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. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35131962SmpRCSID("$Id: sh.proc.c,v 3.81 2003/11/09 03:02:46 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien#include "tc.h" 3959243Sobrien#include "tc.wait.h" 4059243Sobrien 4169408Sache#ifdef WINNT_NATIVE 4259243Sobrien#undef POSIX 4359243Sobrien#define POSIX 4469408Sache#endif /* WINNT_NATIVE */ 4559243Sobrien#ifdef aiws 4659243Sobrien# undef HZ 4759243Sobrien# define HZ 16 4859243Sobrien#endif /* aiws */ 4959243Sobrien 5059243Sobrien#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) || defined(linux) 5159243Sobrien# define BSDWAIT 5259243Sobrien#endif /* _BSD || (IRIS4D && __STDC__) || __lucid || linux */ 5359243Sobrien#ifndef WTERMSIG 5459243Sobrien# define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 5559243Sobrien# ifndef BSDWAIT 5659243Sobrien# define BSDWAIT 5759243Sobrien# endif /* !BSDWAIT */ 5859243Sobrien#endif /* !WTERMSIG */ 5959243Sobrien#ifndef WEXITSTATUS 6059243Sobrien# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 6159243Sobrien#endif /* !WEXITSTATUS */ 6259243Sobrien#ifndef WSTOPSIG 6359243Sobrien# define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 6459243Sobrien#endif /* !WSTOPSIG */ 6559243Sobrien 6659243Sobrien#ifdef __osf__ 6759243Sobrien# ifndef WCOREDUMP 6859243Sobrien# define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) 6959243Sobrien# endif 7059243Sobrien#endif 7159243Sobrien 7259243Sobrien#ifndef WCOREDUMP 7359243Sobrien# ifdef BSDWAIT 7459243Sobrien# define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 7559243Sobrien# else /* !BSDWAIT */ 7659243Sobrien# define WCOREDUMP(w) ((w) & 0200) 7759243Sobrien# endif /* !BSDWAIT */ 7859243Sobrien#endif /* !WCOREDUMP */ 7959243Sobrien 8059243Sobrien/* 8159243Sobrien * C Shell - functions that manage processes, handling hanging, termination 8259243Sobrien */ 8359243Sobrien 8459243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 8559243Sobrien 8659243Sobrien#ifdef BSDTIMES 8759243Sobrien# ifdef convex 8859243Sobrien/* use 'cvxrusage' to get parallel statistics */ 8959243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9059243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9159243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 9259243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 9359243Sobrien# else 9459243Sobrien# if defined(SUNOS4) || defined(hp9000) || (defined(__alpha) && defined(__osf__)) 9559243Sobrienstatic struct rusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9659243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}; 9759243Sobrien 9859243Sobrien# else /* !SUNOS4 && !hp9000 && !(__alpha && __osf__) */ 9959243Sobrien# ifdef masscomp 10059243Sobrien/* 10159243Sobrien * Initialization of this structure under RTU 4.1A & RTU 5.0 is problematic 10259243Sobrien * because the first two elements are unions of a time_t and a struct timeval. 10359243Sobrien * So we'll just have to trust the loader to do the "right thing", DAS DEC-90. 10459243Sobrien */ 10559243Sobrienstatic struct rusage zru; 10659243Sobrien# else /* masscomp */ 10759243Sobrienstatic struct rusage zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 10859243Sobrien 0, 0, 0, 0, 0, 0}; 10959243Sobrien# endif /* masscomp */ 11059243Sobrien# endif /* SUNOS4 || hp9000 || (__alpha && __osf__) */ 11159243Sobrien# endif /* convex */ 11259243Sobrien#else /* !BSDTIMES */ 11359243Sobrien# ifdef _SEQUENT_ 11459243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 11559243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 11659243Sobrien# else /* !_SEQUENT_ */ 11759243Sobrien# ifdef _SX 11859243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 11959243Sobrien# else /* !_SX */ 12059243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 12159243Sobrien# endif /* !_SX */ 12259243Sobrien# endif /* !_SEQUENT_ */ 12359243Sobrien#endif /* !BSDTIMES */ 12459243Sobrien 12559243Sobrien#ifndef RUSAGE_CHILDREN 12659243Sobrien# define RUSAGE_CHILDREN -1 12759243Sobrien#endif /* RUSAGE_CHILDREN */ 12859243Sobrien 12959243Sobrienstatic void pflushall __P((void)); 13059243Sobrienstatic void pflush __P((struct process *)); 13159243Sobrienstatic void pfree __P((struct process *)); 13259243Sobrienstatic void pclrcurr __P((struct process *)); 13359243Sobrienstatic void padd __P((struct command *)); 13459243Sobrienstatic int pprint __P((struct process *, int)); 13559243Sobrienstatic void ptprint __P((struct process *)); 13659243Sobrienstatic void pads __P((Char *)); 13759243Sobrienstatic void pkill __P((Char **, int)); 13859243Sobrienstatic struct process *pgetcurr __P((struct process *)); 13959243Sobrienstatic void okpcntl __P((void)); 14059243Sobrienstatic void setttypgrp __P((int)); 14159243Sobrien 14259243Sobrien/* 14359243Sobrien * pchild - called at interrupt level by the SIGCHLD signal 14459243Sobrien * indicating that at least one child has terminated or stopped 14559243Sobrien * thus at least one wait system call will definitely return a 14659243Sobrien * childs status. Top level routines (like pwait) must be sure 14759243Sobrien * to mask interrupts when playing with the proclist data structures! 14859243Sobrien */ 14959243Sobriensigret_t 15059243Sobrien/*ARGSUSED*/ 15159243Sobrienpchild(snum) 15259243Sobrienint snum; 15359243Sobrien{ 15459243Sobrien register struct process *pp; 15559243Sobrien register struct process *fp; 15659243Sobrien register int pid; 15759243Sobrien#if defined(BSDJOBS) || (!defined(BSDTIMES) && (defined(ODT) || defined(aiws) || defined(uts))) 15859243Sobrien extern int insource; 15959243Sobrien#endif /* BSDJOBS || (!BSDTIMES && (ODT || aiws || uts)) */ 16059243Sobrien#ifdef BSDWAIT 16159243Sobrien union wait w; 16259243Sobrien#else /* !BSDWAIT */ 16359243Sobrien int w; 16459243Sobrien#endif /* !BSDWAIT */ 16559243Sobrien int jobflags; 16659243Sobrien#ifdef BSDTIMES 16759243Sobrien struct sysrusage ru; 16859243Sobrien#else /* !BSDTIMES */ 16959243Sobrien# ifdef _SEQUENT_ 17059243Sobrien struct process_stats ru; 17159243Sobrien struct process_stats cpst1, cpst2; 17259243Sobrien timeval_t tv; 17359243Sobrien# else /* !_SEQUENT_ */ 17459243Sobrien struct tms proctimes; 17559243Sobrien 17659243Sobrien USE(snum); 17759243Sobrien if (!timesdone) { 17859243Sobrien timesdone++; 17959243Sobrien (void) times(&shtimes); 18059243Sobrien } 18159243Sobrien# endif /* !_SEQUENT_ */ 18259243Sobrien#endif /* !BSDTIMES */ 18359243Sobrien 18459243Sobrien#ifdef JOBDEBUG 18559243Sobrien xprintf("pchild()\n"); 18659243Sobrien#endif /* JOBDEBUG */ 18759243Sobrien 18859243Sobrien/* Christos on where the signal(SIGCHLD, pchild) shoud be: 18959243Sobrien * 19059243Sobrien * I think that it should go *after* the wait, unlike most signal handlers. 19159243Sobrien * 19259243Sobrien * In release two (for which I have manuals), it says that wait will remove 19359243Sobrien * the first child from the queue of dead children. 19459243Sobrien * All the rest of the children that die while in the signal handler of the 19559243Sobrien * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish 19659243Sobrien * the signal handler, and there are items in the queue, the process will 19759243Sobrien * receive another SIGC(H)LD before signal returns. BTW this is from the 19859243Sobrien * manual page on comp-sim... Maybe it is not applicable to the hp's, but 19959243Sobrien * I read on the news in comp.unix.wizards or comp.unix.questions yesterday 20059243Sobrien * that another person was claiming the the signal() call should be after 20159243Sobrien * the wait(). 20259243Sobrien */ 20359243Sobrien 20459243Sobrienloop: 20559243Sobrien errno = 0; /* reset, just in case */ 20659243Sobrien#ifdef JOBDEBUG 20759243Sobrien xprintf("Waiting...\n"); 20859243Sobrien flush(); 20959243Sobrien#endif /* JOBDEBUG */ 21069408Sache#ifndef WINNT_NATIVE 21159243Sobrien# ifdef BSDJOBS 21259243Sobrien# ifdef BSDTIMES 21359243Sobrien# ifdef convex 21459243Sobrien /* use 'cvxwait' to get parallel statistics */ 21559243Sobrien pid = cvxwait(&w, 21659243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 21759243Sobrien# else 21859243Sobrien /* both a wait3 and rusage */ 21959243Sobrien# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(linux) || (defined(IRIS4D) && (__STDC__ || defined(FUNCPROTO)) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 22059243Sobrien pid = wait3(&w, 22159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 22259243Sobrien# else /* BSDWAIT */ 22359243Sobrien pid = wait3(&w.w_status, 22459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 22559243Sobrien# endif /* BSDWAIT */ 22659243Sobrien# endif /* convex */ 22759243Sobrien# else /* !BSDTIMES */ 22859243Sobrien# ifdef _SEQUENT_ 22959243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 23059243Sobrien pid = waitpid(-1, &w, 23159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 23259243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 23359243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 23459243Sobrien# else /* !_SEQUENT_ */ 23559243Sobrien# ifndef POSIX 23659243Sobrien /* we have a wait3, but no rusage stuff */ 23759243Sobrien pid = wait3(&w.w_status, 23859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 23959243Sobrien# else /* POSIX */ 24059243Sobrien pid = waitpid(-1, &w, 24159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 24259243Sobrien# endif /* POSIX */ 24359243Sobrien# endif /* !_SEQUENT_ */ 24459243Sobrien# endif /* !BSDTIMES */ 24559243Sobrien# else /* !BSDJOBS */ 24659243Sobrien# ifdef BSDTIMES 24759243Sobrien# define HAVEwait3 24859243Sobrien /* both a wait3 and rusage */ 24959243Sobrien# ifdef hpux 25059243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 25159243Sobrien# else /* !hpux */ 25259243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 25359243Sobrien# endif /* !hpux */ 25459243Sobrien# else /* !BSDTIMES */ 25559243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 25659243Sobrien# define HAVEwait3 25759243Sobrien pid = waitpid(-1, &w, 25859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 25959243Sobrien# endif /* ODT */ 26059243Sobrien# if defined(aiws) || defined(uts) 26159243Sobrien# define HAVEwait3 26259243Sobrien pid = wait3(&w.w_status, 26359243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 26459243Sobrien# endif /* aiws || uts */ 26559243Sobrien# ifndef HAVEwait3 26659243Sobrien# ifdef UNRELSIGS 26759243Sobrien /* no wait3, therefore no rusage */ 26859243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 26959243Sobrien# ifdef _MINIX 27059243Sobrien pid = wait(&w); 27159243Sobrien# else /* !_MINIX */ 27259243Sobrien pid = ourwait(&w.w_status); 27359243Sobrien# endif /* _MINIX */ 27459243Sobrien# else /* !UNRELSIGS */ 27559243Sobrien /* 27659243Sobrien * XXX: for greater than 3 we should use waitpid(). 27759243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 27859243Sobrien */ 27959243Sobrien pid = wait(&w.w_status); 28059243Sobrien# endif /* !UNRELSIGS */ 28159243Sobrien# endif /* !HAVEwait3 */ 28259243Sobrien# endif /* !BSDTIMES */ 28359243Sobrien# ifndef BSDSIGS 28459243Sobrien (void) sigset(SIGCHLD, pchild); 28559243Sobrien# endif /* !BSDSIGS */ 28659243Sobrien# endif /* !BSDJOBS */ 28769408Sache#else /* WINNT_NATIVE */ 28859243Sobrien { 28959243Sobrien extern int insource; 29059243Sobrien pid = waitpid(-1, &w, 29159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 29259243Sobrien } 29369408Sache#endif /* WINNT_NATIVE */ 29459243Sobrien 29559243Sobrien#ifdef JOBDEBUG 29659243Sobrien xprintf("parent %d pid %d, retval %x termsig %x retcode %x\n", 29759243Sobrien getpid(), pid, w, WTERMSIG(w), WEXITSTATUS(w)); 29859243Sobrien flush(); 29959243Sobrien#endif /* JOBDEBUG */ 30059243Sobrien 30159243Sobrien if ((pid == 0) || (pid == -1)) { 30259243Sobrien#ifdef JOBDEBUG 30359243Sobrien xprintf("errno == %d\n", errno); 30459243Sobrien#endif /* JOBDEBUG */ 30559243Sobrien if (errno == EINTR) { 30659243Sobrien errno = 0; 30759243Sobrien goto loop; 30859243Sobrien } 30959243Sobrien pnoprocesses = pid == -1; 31059243Sobrien#ifndef SIGVOID 31159243Sobrien return (0); 31259243Sobrien#else /* !SIGVOID */ 31359243Sobrien return; 31459243Sobrien#endif /* !SIGVOID */ 31559243Sobrien } 31659243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 31759243Sobrien if (pid == pp->p_procid) 31859243Sobrien goto found; 31969408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 32059243Sobrien /* this should never have happened */ 32159243Sobrien stderror(ERR_SYNC, pid); 32259243Sobrien xexit(0); 32369408Sache#else /* BSDJOBS || WINNT_NATIVE */ 32459243Sobrien goto loop; 32569408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 32659243Sobrienfound: 32759243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 32859243Sobrien if (WIFSTOPPED(w)) { 32959243Sobrien pp->p_flags |= PSTOPPED; 33059243Sobrien pp->p_reason = WSTOPSIG(w); 33159243Sobrien } 33259243Sobrien else { 33359243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 33459243Sobrien#ifndef BSDTIMES 33559243Sobrien# ifdef _SEQUENT_ 33659243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 33759243Sobrien# else /* !_SEQUENT_ */ 33859243Sobrien# ifndef COHERENT 33959243Sobrien pp->p_etime = times(&proctimes); 34059243Sobrien# else /* COHERENT */ 34159243Sobrien pp->p_etime = HZ * time(NULL); 34259243Sobrien times(&proctimes); 34359243Sobrien# endif /* COHERENT */ 34459243Sobrien# endif /* !_SEQUENT_ */ 34559243Sobrien#else /* BSDTIMES */ 34659243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 34759243Sobrien#endif /* BSDTIMES */ 34859243Sobrien 34959243Sobrien 35059243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 35159243Sobrien pp->p_rusage = ru; 35259243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 35359243Sobrien (void) times(&proctimes); 35459243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 35559243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 35659243Sobrien shtimes = proctimes; 35759243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 35859243Sobrien if (WIFSIGNALED(w)) { 35959243Sobrien if (WTERMSIG(w) == SIGINT) 36059243Sobrien pp->p_flags |= PINTERRUPTED; 36159243Sobrien else 36259243Sobrien pp->p_flags |= PSIGNALED; 36359243Sobrien if (WCOREDUMP(w)) 36459243Sobrien pp->p_flags |= PDUMPED; 36559243Sobrien pp->p_reason = WTERMSIG(w); 36659243Sobrien } 36759243Sobrien else { 36859243Sobrien pp->p_reason = WEXITSTATUS(w); 36959243Sobrien if (pp->p_reason != 0) 37059243Sobrien pp->p_flags |= PAEXITED; 37159243Sobrien else 37259243Sobrien pp->p_flags |= PNEXITED; 37359243Sobrien } 37459243Sobrien } 37559243Sobrien jobflags = 0; 37659243Sobrien fp = pp; 37759243Sobrien do { 37859243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 37959243Sobrien !child && adrof(STRtime) && 38059243Sobrien#ifdef BSDTIMES 38159243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 38259243Sobrien#else /* !BSDTIMES */ 38359243Sobrien# ifdef _SEQUENT_ 38459243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 38559243Sobrien# else /* !_SEQUENT_ */ 38659243Sobrien# ifndef POSIX 38759243Sobrien (fp->p_utime + fp->p_stime) / HZ 38859243Sobrien# else /* POSIX */ 38959243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 39059243Sobrien# endif /* POSIX */ 39159243Sobrien# endif /* !_SEQUENT_ */ 39259243Sobrien#endif /* !BSDTIMES */ 39359243Sobrien >= atoi(short2str(varval(STRtime)))) 39459243Sobrien fp->p_flags |= PTIME; 39559243Sobrien jobflags |= fp->p_flags; 39659243Sobrien } while ((fp = fp->p_friends) != pp); 39759243Sobrien pp->p_flags &= ~PFOREGND; 39859243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 39959243Sobrien pp->p_flags &= ~PPTIME; 40059243Sobrien pp->p_flags |= PTIME; 40159243Sobrien } 40259243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 40359243Sobrien fp = pp; 40459243Sobrien do { 40559243Sobrien if (fp->p_flags & PSTOPPED) 40659243Sobrien fp->p_flags |= PREPORTED; 40759243Sobrien } while ((fp = fp->p_friends) != pp); 40859243Sobrien while (fp->p_procid != fp->p_jobid) 40959243Sobrien fp = fp->p_friends; 41059243Sobrien if (jobflags & PSTOPPED) { 41159243Sobrien if (pcurrent && pcurrent != fp) 41259243Sobrien pprevious = pcurrent; 41359243Sobrien pcurrent = fp; 41459243Sobrien } 41559243Sobrien else 41659243Sobrien pclrcurr(fp); 41759243Sobrien if (jobflags & PFOREGND) { 41859243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 41959243Sobrien#ifdef notdef 42059243Sobrien jobflags & PAEXITED || 42159243Sobrien#endif /* notdef */ 42259243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 42359243Sobrien /* PWP: print a newline after ^C */ 42459243Sobrien if (jobflags & PINTERRUPTED) { 42559243Sobrien#ifdef SHORT_STRINGS 42659243Sobrien xputchar('\r' | QUOTE), xputchar('\n'); 42759243Sobrien#else /* !SHORT_STRINGS */ 42859243Sobrien xprintf("\215\n"); /* \215 is a quoted ^M */ 42959243Sobrien#endif /* !SHORT_STRINGS */ 43059243Sobrien } 43159243Sobrien#ifdef notdef 43259243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 43359243Sobrien ptprint(fp); 43459243Sobrien#endif /* notdef */ 43559243Sobrien } 43659243Sobrien } 43759243Sobrien else { 43859243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 43959243Sobrien#ifdef SHORT_STRINGS 44059243Sobrien xputchar('\r' | QUOTE), xputchar('\n'); 44159243Sobrien#else /* !SHORT_STRINGS */ 44259243Sobrien xprintf("\215\n"); /* \215 is a quoted ^M */ 44359243Sobrien#endif /* !SHORT_STRINGS */ 44459243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 44559243Sobrien if ((jobflags & PSTOPPED) == 0) 44659243Sobrien pflush(pp); 44759243Sobrien { 44859243Sobrien extern Char GettingInput; 44959243Sobrien 45059243Sobrien if (GettingInput) { 45159243Sobrien errno = 0; 45259243Sobrien (void) Rawmode(); 45359243Sobrien#ifdef notdef 45459243Sobrien /* 45559243Sobrien * don't really want to do that, because it 45659243Sobrien * will erase our message in case of multi-line 45759243Sobrien * input 45859243Sobrien */ 45959243Sobrien ClearLines(); 46059243Sobrien#endif /* notdef */ 46159243Sobrien ClearDisp(); 46259243Sobrien Refresh(); 46359243Sobrien } 46459243Sobrien } 46559243Sobrien } 46659243Sobrien else { 46759243Sobrien fp->p_flags |= PNEEDNOTE; 46859243Sobrien neednote++; 46959243Sobrien } 47059243Sobrien } 47159243Sobrien } 47259243Sobrien#if defined(BSDJOBS) || defined(HAVEwait3) 47359243Sobrien goto loop; 47459243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 47559243Sobrien} 47659243Sobrien 47759243Sobrienvoid 47859243Sobrienpnote() 47959243Sobrien{ 48059243Sobrien register struct process *pp; 48159243Sobrien int flags; 48259243Sobrien#ifdef BSDSIGS 48359243Sobrien sigmask_t omask; 48459243Sobrien#endif /* BSDSIGS */ 48559243Sobrien 48659243Sobrien neednote = 0; 48759243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 48859243Sobrien if (pp->p_flags & PNEEDNOTE) { 48959243Sobrien#ifdef BSDSIGS 49059243Sobrien omask = sigblock(sigmask(SIGCHLD)); 49159243Sobrien#else /* !BSDSIGS */ 49259243Sobrien (void) sighold(SIGCHLD); 49359243Sobrien#endif /* !BSDSIGS */ 49459243Sobrien pp->p_flags &= ~PNEEDNOTE; 49559243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 49659243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 49759243Sobrien pflush(pp); 49859243Sobrien#ifdef BSDSIGS 49959243Sobrien (void) sigsetmask(omask); 50059243Sobrien#else /* !BSDSIGS */ 50159243Sobrien (void) sigrelse(SIGCHLD); 50259243Sobrien#endif /* !BSDSIGS */ 50359243Sobrien } 50459243Sobrien } 50559243Sobrien} 50659243Sobrien 50759243Sobrien 50859243Sobrienstatic void 50959243Sobrienpfree(pp) 51059243Sobrien struct process *pp; 51159243Sobrien{ 51259243Sobrien xfree((ptr_t) pp->p_command); 51359243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 51459243Sobrien if (pp->p_cwd->di_next == 0) 51559243Sobrien dfree(pp->p_cwd); 51659243Sobrien xfree((ptr_t) pp); 51759243Sobrien} 51859243Sobrien 51959243Sobrien 52059243Sobrien/* 52159243Sobrien * pwait - wait for current job to terminate, maintaining integrity 52259243Sobrien * of current and previous job indicators. 52359243Sobrien */ 52459243Sobrienvoid 52559243Sobrienpwait() 52659243Sobrien{ 52759243Sobrien register struct process *fp, *pp; 52859243Sobrien#ifdef BSDSIGS 52959243Sobrien sigmask_t omask; 53059243Sobrien#endif /* BSDSIGS */ 53159243Sobrien 53259243Sobrien /* 53359243Sobrien * Here's where dead procs get flushed. 53459243Sobrien */ 53559243Sobrien#ifdef BSDSIGS 53659243Sobrien omask = sigblock(sigmask(SIGCHLD)); 53759243Sobrien#else /* !BSDSIGS */ 53859243Sobrien (void) sighold(SIGCHLD); 53959243Sobrien#endif /* !BSDSIGS */ 54059243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 54159243Sobrien if (pp->p_procid == 0) { 54259243Sobrien fp->p_next = pp->p_next; 54359243Sobrien pfree(pp); 54459243Sobrien pp = fp; 54559243Sobrien } 54659243Sobrien#ifdef BSDSIGS 54759243Sobrien (void) sigsetmask(omask); 54859243Sobrien#else /* !BSDSIGS */ 54959243Sobrien (void) sigrelse(SIGCHLD); 55059243Sobrien# ifdef notdef 55159243Sobrien if (setintr) 55259243Sobrien sigignore(SIGINT); 55359243Sobrien# endif /* notdef */ 55459243Sobrien#endif /* !BSDSIGS */ 55559243Sobrien pjwait(pcurrjob); 55659243Sobrien} 55759243Sobrien 55859243Sobrien 55959243Sobrien/* 56059243Sobrien * pjwait - wait for a job to finish or become stopped 56159243Sobrien * It is assumed to be in the foreground state (PFOREGND) 56259243Sobrien */ 56359243Sobrienvoid 56459243Sobrienpjwait(pp) 56559243Sobrien register struct process *pp; 56659243Sobrien{ 56759243Sobrien register struct process *fp; 56859243Sobrien int jobflags, reason; 56959243Sobrien#ifdef BSDSIGS 57059243Sobrien sigmask_t omask; 57159243Sobrien#endif /* BSDSIGS */ 57259243Sobrien#ifdef UNRELSIGS 57359243Sobrien signalfun_t inthandler; 57459243Sobrien#endif /* UNRELSIGS */ 57559243Sobrien while (pp->p_procid != pp->p_jobid) 57659243Sobrien pp = pp->p_friends; 57759243Sobrien fp = pp; 57859243Sobrien 57959243Sobrien do { 58059243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 58159243Sobrien xprintf(CGETS(17, 1, "BUG: waiting for background job!\n")); 58259243Sobrien } while ((fp = fp->p_friends) != pp); 58359243Sobrien /* 58459243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 58559243Sobrien * target process, or any of its friends, are running 58659243Sobrien */ 58759243Sobrien fp = pp; 58859243Sobrien#ifdef BSDSIGS 58959243Sobrien omask = sigblock(sigmask(SIGCHLD)); 59059243Sobrien#endif /* BSDSIGS */ 59159243Sobrien#ifdef UNRELSIGS 59259243Sobrien if (setintr) 59359243Sobrien inthandler = signal(SIGINT, SIG_IGN); 59459243Sobrien#endif /* UNRELSIGS */ 59559243Sobrien for (;;) { 59659243Sobrien#ifndef BSDSIGS 59759243Sobrien (void) sighold(SIGCHLD); 59859243Sobrien#endif /* !BSDSIGS */ 59959243Sobrien jobflags = 0; 60059243Sobrien do 60159243Sobrien jobflags |= fp->p_flags; 60259243Sobrien while ((fp = (fp->p_friends)) != pp); 60359243Sobrien if ((jobflags & PRUNNING) == 0) 60459243Sobrien break; 60559243Sobrien#ifdef JOBDEBUG 606131962Smp xprintf("%d starting to sigpause for SIGCHLD on %d\n", 60759243Sobrien getpid(), fp->p_procid); 60859243Sobrien#endif /* JOBDEBUG */ 60959243Sobrien#ifdef BSDSIGS 61059243Sobrien /* (void) sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */ 61159243Sobrien (void) sigpause(omask & ~sigmask(SIGCHLD)); 61259243Sobrien#else /* !BSDSIGS */ 61359243Sobrien (void) sigpause(SIGCHLD); 61459243Sobrien#endif /* !BSDSIGS */ 61559243Sobrien } 61659243Sobrien#ifdef JOBDEBUG 61759243Sobrien xprintf("%d returned from sigpause loop\n", getpid()); 61859243Sobrien#endif /* JOBDEBUG */ 61959243Sobrien#ifdef BSDSIGS 62059243Sobrien (void) sigsetmask(omask); 62159243Sobrien#else /* !BSDSIGS */ 62259243Sobrien (void) sigrelse(SIGCHLD); 62359243Sobrien#endif /* !BSDSIGS */ 62459243Sobrien#ifdef UNRELSIGS 62559243Sobrien if (setintr) 62659243Sobrien (void) signal(SIGINT, inthandler); 62759243Sobrien#endif /* UNRELSIGS */ 62859243Sobrien#ifdef BSDJOBS 62959243Sobrien if (tpgrp > 0) /* get tty back */ 63059243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 63159243Sobrien#endif /* BSDJOBS */ 63259243Sobrien if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 63359243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name)) { 63459243Sobrien if (jobflags & PSTOPPED) { 63559243Sobrien xputchar('\n'); 63659243Sobrien if (adrof(STRlistjobs)) { 63759243Sobrien Char *jobcommand[3]; 63859243Sobrien 63959243Sobrien jobcommand[0] = STRjobs; 64059243Sobrien if (eq(varval(STRlistjobs), STRlong)) 64159243Sobrien jobcommand[1] = STRml; 64259243Sobrien else 64359243Sobrien jobcommand[1] = NULL; 64459243Sobrien jobcommand[2] = NULL; 64559243Sobrien 64659243Sobrien dojobs(jobcommand, NULL); 64759243Sobrien (void) pprint(pp, SHELLDIR); 64859243Sobrien } 64959243Sobrien else 65059243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 65159243Sobrien } 65259243Sobrien else 65359243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 65459243Sobrien } 65559243Sobrien if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 65659243Sobrien (!gointr || !eq(gointr, STRminus))) { 65759243Sobrien if ((jobflags & PSTOPPED) == 0) 65859243Sobrien pflush(pp); 65959243Sobrien pintr1(0); 66059243Sobrien /* NOTREACHED */ 66159243Sobrien } 66259243Sobrien reason = 0; 66359243Sobrien fp = pp; 66459243Sobrien do { 66559243Sobrien if (fp->p_reason) 66659243Sobrien reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 66759243Sobrien fp->p_reason | META : fp->p_reason; 66859243Sobrien } while ((fp = fp->p_friends) != pp); 66959243Sobrien /* 67059243Sobrien * Don't report on backquoted jobs, cause it will mess up 67159243Sobrien * their output. 67259243Sobrien */ 67359243Sobrien if ((reason != 0) && (adrof(STRprintexitvalue)) && 67459243Sobrien (pp->p_flags & PBACKQ) == 0) 67559243Sobrien xprintf(CGETS(17, 2, "Exit %d\n"), reason); 67659243Sobrien set(STRstatus, putn(reason), VAR_READWRITE); 67759243Sobrien if (reason && exiterr) 67859243Sobrien exitstat(); 67959243Sobrien pflush(pp); 68059243Sobrien} 68159243Sobrien 68259243Sobrien/* 68359243Sobrien * dowait - wait for all processes to finish 68459243Sobrien */ 68559243Sobrien 68659243Sobrien/*ARGSUSED*/ 68759243Sobrienvoid 68859243Sobriendowait(v, c) 68959243Sobrien Char **v; 69059243Sobrien struct command *c; 69159243Sobrien{ 69259243Sobrien register struct process *pp; 69359243Sobrien#ifdef BSDSIGS 69459243Sobrien sigmask_t omask; 69559243Sobrien#endif /* BSDSIGS */ 69659243Sobrien 69759243Sobrien USE(c); 69859243Sobrien USE(v); 69959243Sobrien pjobs++; 70059243Sobrien#ifdef BSDSIGS 70159243Sobrien omask = sigblock(sigmask(SIGCHLD)); 70259243Sobrienloop: 70359243Sobrien#else /* !BSDSIGS */ 70459243Sobrien if (setintr) 70559243Sobrien (void) sigrelse(SIGINT); 70659243Sobrienloop: 70759243Sobrien (void) sighold(SIGCHLD); 70859243Sobrien#endif /* !BSDSIGS */ 70959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 71059243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 71159243Sobrien pp->p_flags & PRUNNING) { 71259243Sobrien#ifdef BSDSIGS 71359243Sobrien (void) sigpause((sigmask_t) 0); 71459243Sobrien#else /* !BSDSIGS */ 71559243Sobrien (void) sigpause(SIGCHLD); 71659243Sobrien#endif /* !BSDSIGS */ 71759243Sobrien goto loop; 71859243Sobrien } 71959243Sobrien#ifdef BSDSIGS 72059243Sobrien (void) sigsetmask(omask); 72159243Sobrien#else /* !BSDSIGS */ 72259243Sobrien (void) sigrelse(SIGCHLD); 72359243Sobrien#endif /* !BSDSIGS */ 72459243Sobrien pjobs = 0; 72559243Sobrien} 72659243Sobrien 72759243Sobrien/* 72859243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 72959243Sobrien */ 73059243Sobrienstatic void 73159243Sobrienpflushall() 73259243Sobrien{ 73359243Sobrien register struct process *pp; 73459243Sobrien 73559243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 73659243Sobrien if (pp->p_procid) 73759243Sobrien pflush(pp); 73859243Sobrien} 73959243Sobrien 74059243Sobrien/* 74159243Sobrien * pflush - flag all process structures in the same job as the 74259243Sobrien * the argument process for deletion. The actual free of the 74359243Sobrien * space is not done here since pflush is called at interrupt level. 74459243Sobrien */ 74559243Sobrienstatic void 74659243Sobrienpflush(pp) 74759243Sobrien register struct process *pp; 74859243Sobrien{ 74959243Sobrien register struct process *np; 75059243Sobrien register int idx; 75159243Sobrien 75259243Sobrien if (pp->p_procid == 0) { 75359243Sobrien xprintf(CGETS(17, 3, "BUG: process flushed twice")); 75459243Sobrien return; 75559243Sobrien } 75659243Sobrien while (pp->p_procid != pp->p_jobid) 75759243Sobrien pp = pp->p_friends; 75859243Sobrien pclrcurr(pp); 75959243Sobrien if (pp == pcurrjob) 76059243Sobrien pcurrjob = 0; 76159243Sobrien idx = pp->p_index; 76259243Sobrien np = pp; 76359243Sobrien do { 76459243Sobrien np->p_index = np->p_procid = 0; 76559243Sobrien np->p_flags &= ~PNEEDNOTE; 76659243Sobrien } while ((np = np->p_friends) != pp); 76759243Sobrien if (idx == pmaxindex) { 76859243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 76959243Sobrien if (np->p_index > idx) 77059243Sobrien idx = np->p_index; 77159243Sobrien pmaxindex = idx; 77259243Sobrien } 77359243Sobrien} 77459243Sobrien 77559243Sobrien/* 77659243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 77759243Sobrien * pp MUST be the job leader 77859243Sobrien */ 77959243Sobrienstatic void 78059243Sobrienpclrcurr(pp) 78159243Sobrien register struct process *pp; 78259243Sobrien{ 78359243Sobrien if (pp == pcurrent) { 78459243Sobrien if (pprevious != NULL) { 78559243Sobrien pcurrent = pprevious; 78659243Sobrien pprevious = pgetcurr(pp); 78759243Sobrien } 78859243Sobrien else { 78959243Sobrien pcurrent = pgetcurr(pp); 79059243Sobrien pprevious = pgetcurr(pp); 79159243Sobrien } 79259243Sobrien } 79359243Sobrien else if (pp == pprevious) 79459243Sobrien pprevious = pgetcurr(pp); 79559243Sobrien} 79659243Sobrien 79759243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 79859243Sobrienstatic Char command[PMAXLEN + 4]; 79959243Sobrienstatic int cmdlen; 80059243Sobrienstatic Char *cmdp; 80159243Sobrien 80283098Smp/* GrP 80383098Smp * unparse - Export padd() functionality 80483098Smp */ 80583098SmpChar * 80683098Smpunparse(t) 80783098Smp register struct command *t; 80883098Smp{ 80983098Smp cmdp = command; 81083098Smp cmdlen = 0; 81183098Smp padd(t); 81283098Smp *cmdp++ = '\0'; 81383098Smp return Strsave(command); 81483098Smp} 81583098Smp 81683098Smp 81759243Sobrien/* 81859243Sobrien * palloc - allocate a process structure and fill it up. 81959243Sobrien * an important assumption is made that the process is running. 82059243Sobrien */ 82159243Sobrienvoid 82259243Sobrienpalloc(pid, t) 82359243Sobrien int pid; 82459243Sobrien register struct command *t; 82559243Sobrien{ 82659243Sobrien register struct process *pp; 82759243Sobrien int i; 82859243Sobrien 82959243Sobrien pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 83059243Sobrien pp->p_procid = pid; 83159243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 83259243Sobrien if (t->t_dflg & F_TIME) 83359243Sobrien pp->p_flags |= PPTIME; 83459243Sobrien if (t->t_dflg & F_BACKQ) 83559243Sobrien pp->p_flags |= PBACKQ; 83659243Sobrien if (t->t_dflg & F_HUP) 83759243Sobrien pp->p_flags |= PHUP; 83859243Sobrien cmdp = command; 83959243Sobrien cmdlen = 0; 84059243Sobrien padd(t); 84159243Sobrien *cmdp++ = 0; 84259243Sobrien if (t->t_dflg & F_PIPEOUT) { 84359243Sobrien pp->p_flags |= PPOU; 84459243Sobrien if (t->t_dflg & F_STDERR) 84559243Sobrien pp->p_flags |= PDIAG; 84659243Sobrien } 84759243Sobrien pp->p_command = Strsave(command); 84859243Sobrien if (pcurrjob) { 84959243Sobrien struct process *fp; 85059243Sobrien 85159243Sobrien /* careful here with interrupt level */ 85259243Sobrien pp->p_cwd = 0; 85359243Sobrien pp->p_index = pcurrjob->p_index; 85459243Sobrien pp->p_friends = pcurrjob; 85559243Sobrien pp->p_jobid = pcurrjob->p_procid; 85659243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 85759243Sobrien continue; 85859243Sobrien fp->p_friends = pp; 85959243Sobrien } 86059243Sobrien else { 86159243Sobrien pcurrjob = pp; 86259243Sobrien pp->p_jobid = pid; 86359243Sobrien pp->p_friends = pp; 86459243Sobrien pp->p_cwd = dcwd; 86559243Sobrien dcwd->di_count++; 86659243Sobrien if (pmaxindex < BIGINDEX) 86759243Sobrien pp->p_index = ++pmaxindex; 86859243Sobrien else { 86959243Sobrien struct process *np; 87059243Sobrien 87159243Sobrien for (i = 1;; i++) { 87259243Sobrien for (np = proclist.p_next; np; np = np->p_next) 87359243Sobrien if (np->p_index == i) 87459243Sobrien goto tryagain; 87559243Sobrien pp->p_index = i; 87659243Sobrien if (i > pmaxindex) 87759243Sobrien pmaxindex = i; 87859243Sobrien break; 87959243Sobrien tryagain:; 88059243Sobrien } 88159243Sobrien } 88259243Sobrien if (pcurrent == NULL) 88359243Sobrien pcurrent = pp; 88459243Sobrien else if (pprevious == NULL) 88559243Sobrien pprevious = pp; 88659243Sobrien } 88759243Sobrien pp->p_next = proclist.p_next; 88859243Sobrien proclist.p_next = pp; 88959243Sobrien#ifdef BSDTIMES 89059243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 89159243Sobrien#else /* !BSDTIMES */ 89259243Sobrien# ifdef _SEQUENT_ 89359243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 89459243Sobrien# else /* !_SEQUENT_ */ 89559243Sobrien { 89659243Sobrien struct tms tmptimes; 89759243Sobrien 89859243Sobrien# ifndef COHERENT 89959243Sobrien pp->p_btime = times(&tmptimes); 90059243Sobrien# else /* !COHERENT */ 90159243Sobrien pp->p_btime = HZ * time(NULL); 90259243Sobrien times(&tmptimes); 90359243Sobrien# endif /* !COHERENT */ 90459243Sobrien } 90559243Sobrien# endif /* !_SEQUENT_ */ 90659243Sobrien#endif /* !BSDTIMES */ 90759243Sobrien} 90859243Sobrien 90959243Sobrienstatic void 91059243Sobrienpadd(t) 91159243Sobrien register struct command *t; 91259243Sobrien{ 91359243Sobrien Char **argp; 91459243Sobrien 91559243Sobrien if (t == 0) 91659243Sobrien return; 91759243Sobrien switch (t->t_dtyp) { 91859243Sobrien 91959243Sobrien case NODE_PAREN: 92059243Sobrien pads(STRLparensp); 92159243Sobrien padd(t->t_dspr); 92259243Sobrien pads(STRspRparen); 92359243Sobrien break; 92459243Sobrien 92559243Sobrien case NODE_COMMAND: 92659243Sobrien for (argp = t->t_dcom; *argp; argp++) { 92759243Sobrien pads(*argp); 92859243Sobrien if (argp[1]) 92959243Sobrien pads(STRspace); 93059243Sobrien } 93159243Sobrien break; 93259243Sobrien 93359243Sobrien case NODE_OR: 93459243Sobrien case NODE_AND: 93559243Sobrien case NODE_PIPE: 93659243Sobrien case NODE_LIST: 93759243Sobrien padd(t->t_dcar); 93859243Sobrien switch (t->t_dtyp) { 93959243Sobrien case NODE_OR: 94059243Sobrien pads(STRspor2sp); 94159243Sobrien break; 94259243Sobrien case NODE_AND: 94359243Sobrien pads(STRspand2sp); 94459243Sobrien break; 94559243Sobrien case NODE_PIPE: 94659243Sobrien pads(STRsporsp); 94759243Sobrien break; 94859243Sobrien case NODE_LIST: 94959243Sobrien pads(STRsemisp); 95059243Sobrien break; 95159243Sobrien default: 95259243Sobrien break; 95359243Sobrien } 95459243Sobrien padd(t->t_dcdr); 95559243Sobrien return; 95659243Sobrien 95759243Sobrien default: 95859243Sobrien break; 95959243Sobrien } 96059243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 96159243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 96259243Sobrien pads(t->t_dlef); 96359243Sobrien } 96459243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 96559243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 96659243Sobrien if (t->t_dflg & F_STDERR) 96759243Sobrien pads(STRand); 96859243Sobrien pads(STRspace); 96959243Sobrien pads(t->t_drit); 97059243Sobrien } 97159243Sobrien} 97259243Sobrien 97359243Sobrienstatic void 97459243Sobrienpads(cp) 97559243Sobrien Char *cp; 97659243Sobrien{ 97759243Sobrien register int i; 97859243Sobrien 97959243Sobrien /* 98059243Sobrien * Avoid the Quoted Space alias hack! Reported by: 98159243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 98259243Sobrien */ 98359243Sobrien if (cp[0] == STRQNULL[0]) 98459243Sobrien cp++; 98559243Sobrien 98659243Sobrien i = (int) Strlen(cp); 98759243Sobrien 98859243Sobrien if (cmdlen >= PMAXLEN) 98959243Sobrien return; 99059243Sobrien if (cmdlen + i >= PMAXLEN) { 99159243Sobrien (void) Strcpy(cmdp, STRsp3dots); 99259243Sobrien cmdlen = PMAXLEN; 99359243Sobrien cmdp += 4; 99459243Sobrien return; 99559243Sobrien } 99659243Sobrien (void) Strcpy(cmdp, cp); 99759243Sobrien cmdp += i; 99859243Sobrien cmdlen += i; 99959243Sobrien} 100059243Sobrien 100159243Sobrien/* 100259243Sobrien * psavejob - temporarily save the current job on a one level stack 100359243Sobrien * so another job can be created. Used for { } in exp6 100459243Sobrien * and `` in globbing. 100559243Sobrien */ 100659243Sobrienvoid 100759243Sobrienpsavejob() 100859243Sobrien{ 100959243Sobrien pholdjob = pcurrjob; 101059243Sobrien pcurrjob = NULL; 101159243Sobrien} 101259243Sobrien 101359243Sobrien/* 101459243Sobrien * prestjob - opposite of psavejob. This may be missed if we are interrupted 101559243Sobrien * somewhere, but pendjob cleans up anyway. 101659243Sobrien */ 101759243Sobrienvoid 101859243Sobrienprestjob() 101959243Sobrien{ 102059243Sobrien pcurrjob = pholdjob; 102159243Sobrien pholdjob = NULL; 102259243Sobrien} 102359243Sobrien 102459243Sobrien/* 102559243Sobrien * pendjob - indicate that a job (set of commands) has been completed 102659243Sobrien * or is about to begin. 102759243Sobrien */ 102859243Sobrienvoid 102959243Sobrienpendjob() 103059243Sobrien{ 103159243Sobrien register struct process *pp, *tp; 103259243Sobrien 103359243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 103459243Sobrien pp = pcurrjob; 103559243Sobrien while (pp->p_procid != pp->p_jobid) 103659243Sobrien pp = pp->p_friends; 103759243Sobrien xprintf("[%d]", pp->p_index); 103859243Sobrien tp = pp; 103959243Sobrien do { 104059243Sobrien xprintf(" %d", pp->p_procid); 104159243Sobrien pp = pp->p_friends; 104259243Sobrien } while (pp != tp); 104359243Sobrien xputchar('\n'); 104459243Sobrien } 104559243Sobrien pholdjob = pcurrjob = 0; 104659243Sobrien} 104759243Sobrien 104859243Sobrien/* 104959243Sobrien * pprint - print a job 105059243Sobrien */ 105159243Sobrien 105259243Sobrien/* 105359243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 105459243Sobrien * reverse order 105559243Sobrien * 105659243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 105759243Sobrien */ 105859243Sobrien 105959243Sobrienstatic int 106059243Sobrienpprint(pp, flag) 106159243Sobrien register struct process *pp; 106259243Sobrien bool flag; 106359243Sobrien{ 106459243Sobrien int status, reason; 106559243Sobrien struct process *tp; 106659243Sobrien extern char *linp, linbuf[]; 106759243Sobrien int jobflags, pstatus, pcond; 106859243Sobrien char *format; 106959243Sobrien 107059243Sobrien#ifdef BACKPIPE 107159243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 107259243Sobrien int inpipe = 0; 107359243Sobrien#endif /* BACKPIPE */ 107459243Sobrien 107559243Sobrien while (pp->p_procid != pp->p_jobid) 107659243Sobrien pp = pp->p_friends; 107759243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 107859243Sobrien pp->p_flags &= ~PPTIME; 107959243Sobrien pp->p_flags |= PTIME; 108059243Sobrien } 108159243Sobrien tp = pp; 108259243Sobrien status = reason = -1; 108359243Sobrien jobflags = 0; 108459243Sobrien do { 108559243Sobrien#ifdef BACKPIPE 108659243Sobrien /* 108759243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 108859243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 108959243Sobrien */ 109059243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 109159243Sobrien inpipe = 1; 109259243Sobrien pipetail = pp; 109359243Sobrien do 109459243Sobrien pp = pp->p_friends; 109559243Sobrien while (pp->p_friends->p_flags & PPOU); 109659243Sobrien pipehead = pp; 109759243Sobrien pmarker = pp; 109859243Sobrien /* 109959243Sobrien * pmarker is used to hold the place of the proc being processed, so 110059243Sobrien * we can search for the next one downstream later. 110159243Sobrien */ 110259243Sobrien } 110359243Sobrien pcond = (int) (tp != pp || (inpipe && tp == pp)); 110459243Sobrien#else /* !BACKPIPE */ 110559243Sobrien pcond = (int) (tp != pp); 110659243Sobrien#endif /* BACKPIPE */ 110759243Sobrien 110859243Sobrien jobflags |= pp->p_flags; 110959243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 111059243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 111159243Sobrien ((pstatus == status && pp->p_reason == reason) || 111259243Sobrien !(flag & REASON))) 111359243Sobrien xputchar(' '); 111459243Sobrien else { 111559243Sobrien if (pcond && linp != linbuf) 111659243Sobrien xputchar('\n'); 111759243Sobrien if (flag & NUMBER) { 111859243Sobrien#ifdef BACKPIPE 111959243Sobrien pcond = ((pp == tp && !inpipe) || 112059243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 112159243Sobrien#else /* BACKPIPE */ 112259243Sobrien pcond = (pp == tp); 112359243Sobrien#endif /* BACKPIPE */ 112459243Sobrien if (pcond) 112559243Sobrien xprintf("[%d]%s %c ", pp->p_index, 112659243Sobrien pp->p_index < 10 ? " " : "", 112759243Sobrien pp == pcurrent ? '+' : 112859243Sobrien (pp == pprevious ? '-' : ' ')); 112959243Sobrien else 113059243Sobrien xprintf(" "); 113159243Sobrien } 113259243Sobrien if (flag & FANCY) { 113359243Sobrien#ifdef TCF 113459243Sobrien extern char *sitename(); 113559243Sobrien 113659243Sobrien#endif /* TCF */ 113759243Sobrien xprintf("%5d ", pp->p_procid); 113859243Sobrien#ifdef TCF 113959243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 114059243Sobrien#endif /* TCF */ 114159243Sobrien } 114259243Sobrien if (flag & (REASON | AREASON)) { 114359243Sobrien if (flag & NAME) 114459243Sobrien format = "%-30s"; 114559243Sobrien else 114659243Sobrien format = "%s"; 114759243Sobrien if (pstatus == status) { 114859243Sobrien if (pp->p_reason == reason) { 114959243Sobrien xprintf(format, ""); 115059243Sobrien goto prcomd; 115159243Sobrien } 115259243Sobrien else 115359243Sobrien reason = (int) pp->p_reason; 115459243Sobrien } 115559243Sobrien else { 115659243Sobrien status = pstatus; 115759243Sobrien reason = (int) pp->p_reason; 115859243Sobrien } 115959243Sobrien switch (status) { 116059243Sobrien 116159243Sobrien case PRUNNING: 116259243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 116359243Sobrien break; 116459243Sobrien 116559243Sobrien case PINTERRUPTED: 116659243Sobrien case PSTOPPED: 116759243Sobrien case PSIGNALED: 116859243Sobrien /* 116959243Sobrien * tell what happened to the background job 117059243Sobrien * From: Michael Schroeder 117159243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 117259243Sobrien */ 117359243Sobrien if ((flag & REASON) 117459243Sobrien || ((flag & AREASON) 117559243Sobrien && reason != SIGINT 117659243Sobrien && (reason != SIGPIPE 117759243Sobrien || (pp->p_flags & PPOU) == 0))) { 117859243Sobrien char *ptr; 117959243Sobrien char buf[1024]; 118059243Sobrien 118159243Sobrien if ((ptr = mesg[pp->p_reason & ASCII].pname) == NULL) 118259243Sobrien xsnprintf(ptr = buf, sizeof(buf), "%s %d", 118359243Sobrien CGETS(17, 5, "Signal"), pp->p_reason & ASCII); 118459243Sobrien xprintf(format, ptr); 118559243Sobrien } 118659243Sobrien else 118759243Sobrien reason = -1; 118859243Sobrien break; 118959243Sobrien 119059243Sobrien case PNEXITED: 119159243Sobrien case PAEXITED: 119259243Sobrien if (flag & REASON) { 119359243Sobrien if (pp->p_reason) 119459243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 119559243Sobrien else 119659243Sobrien xprintf(format, CGETS(17, 7, "Done")); 119759243Sobrien } 119859243Sobrien break; 119959243Sobrien 120059243Sobrien default: 120159243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 120259243Sobrien status); 120359243Sobrien } 120459243Sobrien } 120559243Sobrien } 120659243Sobrienprcomd: 120759243Sobrien if (flag & NAME) { 120859243Sobrien xprintf("%S", pp->p_command); 120959243Sobrien if (pp->p_flags & PPOU) 121059243Sobrien xprintf(" |"); 121159243Sobrien if (pp->p_flags & PDIAG) 121259243Sobrien xprintf("&"); 121359243Sobrien } 121459243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 121559243Sobrien xprintf(CGETS(17, 9, " (core dumped)")); 121659243Sobrien if (tp == pp->p_friends) { 121759243Sobrien if (flag & AMPERSAND) 121859243Sobrien xprintf(" &"); 121959243Sobrien if (flag & JOBDIR && 122059243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 122159243Sobrien xprintf(CGETS(17, 10, " (wd: ")); 122259243Sobrien dtildepr(tp->p_cwd->di_name); 122359243Sobrien xprintf(")"); 122459243Sobrien } 122559243Sobrien } 122659243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 122759243Sobrien if (linp != linbuf) 122859243Sobrien xprintf("\n\t"); 122959243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 123059243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 123159243Sobrien &pp->p_btime); 123259243Sobrien#else /* !BSDTIMES && !SEQUENT */ 123359243Sobrien lru.tms_utime = pp->p_utime; 123459243Sobrien lru.tms_stime = pp->p_stime; 123559243Sobrien lru.tms_cutime = 0; 123659243Sobrien lru.tms_cstime = 0; 123759243Sobrien prusage(&zru, &lru, pp->p_etime, 123859243Sobrien pp->p_btime); 123959243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 124059243Sobrien 124159243Sobrien } 124259243Sobrien#ifdef BACKPIPE 124359243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 124459243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 124559243Sobrien#else /* !BACKPIPE */ 124659243Sobrien pcond = (tp == pp->p_friends); 124759243Sobrien#endif /* BACKPIPE */ 124859243Sobrien if (pcond) { 124959243Sobrien if (linp != linbuf) 125059243Sobrien xputchar('\n'); 125159243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 125259243Sobrien xprintf(CGETS(17, 11, "(wd now: ")); 125359243Sobrien dtildepr(dcwd->di_name); 125459243Sobrien xprintf(")\n"); 125559243Sobrien } 125659243Sobrien } 125759243Sobrien#ifdef BACKPIPE 125859243Sobrien if (inpipe) { 125959243Sobrien /* 126059243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 126159243Sobrien * can now skip to past the head 126259243Sobrien */ 126359243Sobrien if (pmarker == pipetail) { 126459243Sobrien inpipe = 0; 126559243Sobrien pp = pipehead; 126659243Sobrien } 126759243Sobrien else { 126859243Sobrien /* 126959243Sobrien * set pp to one before the one we want next, so the while below 127059243Sobrien * increments to the correct spot. 127159243Sobrien */ 127259243Sobrien do 127359243Sobrien pp = pp->p_friends; 127459243Sobrien while (pp->p_friends->p_friends != pmarker); 127559243Sobrien pmarker = pp->p_friends; 127659243Sobrien } 127759243Sobrien } 127859243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 127959243Sobrien#else /* !BACKPIPE */ 128059243Sobrien pcond = ((pp = pp->p_friends) != tp); 128159243Sobrien#endif /* BACKPIPE */ 128259243Sobrien } while (pcond); 128359243Sobrien 128459243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 128559243Sobrien if (jobflags & NUMBER) 128659243Sobrien xprintf(" "); 128759243Sobrien ptprint(tp); 128859243Sobrien } 128959243Sobrien return (jobflags); 129059243Sobrien} 129159243Sobrien 129259243Sobrien/* 129359243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 129459243Sobrien * The following implementation produces similar code and works in all 129559243Sobrien * cases. The 4.3BSD one works only for <, >, != 129659243Sobrien */ 129759243Sobrien# undef timercmp 129859243Sobrien# define timercmp(tvp, uvp, cmp) \ 129959243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 130059243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 130159243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 130259243Sobrien 130359243Sobrienstatic void 130459243Sobrienptprint(tp) 130559243Sobrien register struct process *tp; 130659243Sobrien{ 130759243Sobrien#ifdef BSDTIMES 130859243Sobrien struct timeval tetime, diff; 130959243Sobrien static struct timeval ztime; 131059243Sobrien struct sysrusage ru; 131159243Sobrien register struct process *pp = tp; 131259243Sobrien 131359243Sobrien ru = zru; 131459243Sobrien tetime = ztime; 131559243Sobrien do { 131659243Sobrien ruadd(&ru, &pp->p_rusage); 131759243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 131859243Sobrien if (timercmp(&diff, &tetime, >)) 131959243Sobrien tetime = diff; 132059243Sobrien } while ((pp = pp->p_friends) != tp); 132159243Sobrien prusage(&zru, &ru, &tetime, &ztime); 132259243Sobrien#else /* !BSDTIMES */ 132359243Sobrien# ifdef _SEQUENT_ 132459243Sobrien timeval_t tetime, diff; 132559243Sobrien static timeval_t ztime; 132659243Sobrien struct process_stats ru; 132759243Sobrien register struct process *pp = tp; 132859243Sobrien 132959243Sobrien ru = zru; 133059243Sobrien tetime = ztime; 133159243Sobrien do { 133259243Sobrien ruadd(&ru, &pp->p_rusage); 133359243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 133459243Sobrien if (timercmp(&diff, &tetime, >)) 133559243Sobrien tetime = diff; 133659243Sobrien } while ((pp = pp->p_friends) != tp); 133759243Sobrien prusage(&zru, &ru, &tetime, &ztime); 133859243Sobrien# else /* !_SEQUENT_ */ 133959243Sobrien# ifndef POSIX 134059243Sobrien static time_t ztime = 0; 134159243Sobrien static time_t zu_time = 0; 134259243Sobrien static time_t zs_time = 0; 134359243Sobrien time_t tetime, diff; 134459243Sobrien time_t u_time, s_time; 134559243Sobrien 134659243Sobrien# else /* POSIX */ 134759243Sobrien static clock_t ztime = 0; 134859243Sobrien static clock_t zu_time = 0; 134959243Sobrien static clock_t zs_time = 0; 135059243Sobrien clock_t tetime, diff; 135159243Sobrien clock_t u_time, s_time; 135259243Sobrien 135359243Sobrien# endif /* POSIX */ 135459243Sobrien struct tms zts, rts; 135559243Sobrien register struct process *pp = tp; 135659243Sobrien 135759243Sobrien u_time = zu_time; 135859243Sobrien s_time = zs_time; 135959243Sobrien tetime = ztime; 136059243Sobrien do { 136159243Sobrien u_time += pp->p_utime; 136259243Sobrien s_time += pp->p_stime; 136359243Sobrien diff = pp->p_etime - pp->p_btime; 136459243Sobrien if (diff > tetime) 136559243Sobrien tetime = diff; 136659243Sobrien } while ((pp = pp->p_friends) != tp); 136759243Sobrien zts.tms_utime = zu_time; 136859243Sobrien zts.tms_stime = zs_time; 136959243Sobrien zts.tms_cutime = 0; 137059243Sobrien zts.tms_cstime = 0; 137159243Sobrien rts.tms_utime = u_time; 137259243Sobrien rts.tms_stime = s_time; 137359243Sobrien rts.tms_cutime = 0; 137459243Sobrien rts.tms_cstime = 0; 137559243Sobrien prusage(&zts, &rts, tetime, ztime); 137659243Sobrien# endif /* !_SEQUENT_ */ 137759243Sobrien#endif /* !BSDTIMES */ 137859243Sobrien} 137959243Sobrien 138059243Sobrien/* 138159243Sobrien * dojobs - print all jobs 138259243Sobrien */ 138359243Sobrien/*ARGSUSED*/ 138459243Sobrienvoid 138559243Sobriendojobs(v, c) 138659243Sobrien Char **v; 138759243Sobrien struct command *c; 138859243Sobrien{ 138959243Sobrien register struct process *pp; 139059243Sobrien register int flag = NUMBER | NAME | REASON; 139159243Sobrien int i; 139259243Sobrien 139359243Sobrien USE(c); 139459243Sobrien if (chkstop) 139559243Sobrien chkstop = 2; 139659243Sobrien if (*++v) { 139759243Sobrien if (v[1] || !eq(*v, STRml)) 139859243Sobrien stderror(ERR_JOBS); 139959243Sobrien flag |= FANCY | JOBDIR; 140059243Sobrien } 140159243Sobrien for (i = 1; i <= pmaxindex; i++) 140259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 140359243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 140459243Sobrien pp->p_flags &= ~PNEEDNOTE; 140559243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 140659243Sobrien pflush(pp); 140759243Sobrien break; 140859243Sobrien } 140959243Sobrien} 141059243Sobrien 141159243Sobrien/* 141259243Sobrien * dofg - builtin - put the job into the foreground 141359243Sobrien */ 141459243Sobrien/*ARGSUSED*/ 141559243Sobrienvoid 141659243Sobriendofg(v, c) 141759243Sobrien Char **v; 141859243Sobrien struct command *c; 141959243Sobrien{ 142059243Sobrien register struct process *pp; 142159243Sobrien 142259243Sobrien USE(c); 142359243Sobrien okpcntl(); 142459243Sobrien ++v; 142559243Sobrien do { 142659243Sobrien pp = pfind(*v); 142759243Sobrien if (!pstart(pp, 1)) { 142859243Sobrien pp->p_procid = 0; 142959243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 143059243Sobrien continue; 143159243Sobrien } 143259243Sobrien#ifndef BSDSIGS 143359243Sobrien# ifdef notdef 143459243Sobrien if (setintr) 143559243Sobrien sigignore(SIGINT); 143659243Sobrien# endif 143759243Sobrien#endif /* !BSDSIGS */ 143859243Sobrien pjwait(pp); 143959243Sobrien } while (*v && *++v); 144059243Sobrien} 144159243Sobrien 144259243Sobrien/* 144359243Sobrien * %... - builtin - put the job into the foreground 144459243Sobrien */ 144559243Sobrien/*ARGSUSED*/ 144659243Sobrienvoid 144759243Sobriendofg1(v, c) 144859243Sobrien Char **v; 144959243Sobrien struct command *c; 145059243Sobrien{ 145159243Sobrien register struct process *pp; 145259243Sobrien 145359243Sobrien USE(c); 145459243Sobrien okpcntl(); 145559243Sobrien pp = pfind(v[0]); 145659243Sobrien if (!pstart(pp, 1)) { 145759243Sobrien pp->p_procid = 0; 145859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 145959243Sobrien return; 146059243Sobrien } 146159243Sobrien#ifndef BSDSIGS 146259243Sobrien# ifdef notdef 146359243Sobrien if (setintr) 146459243Sobrien sigignore(SIGINT); 146559243Sobrien# endif 146659243Sobrien#endif /* !BSDSIGS */ 146759243Sobrien pjwait(pp); 146859243Sobrien} 146959243Sobrien 147059243Sobrien/* 147159243Sobrien * dobg - builtin - put the job into the background 147259243Sobrien */ 147359243Sobrien/*ARGSUSED*/ 147459243Sobrienvoid 147559243Sobriendobg(v, c) 147659243Sobrien Char **v; 147759243Sobrien struct command *c; 147859243Sobrien{ 147959243Sobrien register struct process *pp; 148059243Sobrien 148159243Sobrien USE(c); 148259243Sobrien okpcntl(); 148359243Sobrien ++v; 148459243Sobrien do { 148559243Sobrien pp = pfind(*v); 148659243Sobrien if (!pstart(pp, 0)) { 148759243Sobrien pp->p_procid = 0; 148859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 148959243Sobrien } 149059243Sobrien } while (*v && *++v); 149159243Sobrien} 149259243Sobrien 149359243Sobrien/* 149459243Sobrien * %... & - builtin - put the job into the background 149559243Sobrien */ 149659243Sobrien/*ARGSUSED*/ 149759243Sobrienvoid 149859243Sobriendobg1(v, c) 149959243Sobrien Char **v; 150059243Sobrien struct command *c; 150159243Sobrien{ 150259243Sobrien register struct process *pp; 150359243Sobrien 150459243Sobrien USE(c); 150559243Sobrien pp = pfind(v[0]); 150659243Sobrien if (!pstart(pp, 0)) { 150759243Sobrien pp->p_procid = 0; 150859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 150959243Sobrien } 151059243Sobrien} 151159243Sobrien 151259243Sobrien/* 151359243Sobrien * dostop - builtin - stop the job 151459243Sobrien */ 151559243Sobrien/*ARGSUSED*/ 151659243Sobrienvoid 151759243Sobriendostop(v, c) 151859243Sobrien Char **v; 151959243Sobrien struct command *c; 152059243Sobrien{ 152159243Sobrien USE(c); 152259243Sobrien#ifdef BSDJOBS 152359243Sobrien pkill(++v, SIGSTOP); 152459243Sobrien#endif /* BSDJOBS */ 152559243Sobrien} 152659243Sobrien 152759243Sobrien/* 152859243Sobrien * dokill - builtin - superset of kill (1) 152959243Sobrien */ 153059243Sobrien/*ARGSUSED*/ 153159243Sobrienvoid 153259243Sobriendokill(v, c) 153359243Sobrien Char **v; 153459243Sobrien struct command *c; 153559243Sobrien{ 153659243Sobrien register int signum, len = 0; 153759243Sobrien register char *name; 153883098Smp Char *sigptr; 153959243Sobrien extern int T_Cols; 154059243Sobrien extern int nsig; 154159243Sobrien 154259243Sobrien USE(c); 154359243Sobrien v++; 154459243Sobrien if (v[0] && v[0][0] == '-') { 154559243Sobrien if (v[0][1] == 'l') { 154659243Sobrien for (signum = 0; signum <= nsig; signum++) { 154759243Sobrien if ((name = mesg[signum].iname) != NULL) { 154859243Sobrien len += strlen(name) + 1; 154959243Sobrien if (len >= T_Cols - 1) { 155059243Sobrien xputchar('\n'); 155159243Sobrien len = strlen(name) + 1; 155259243Sobrien } 155359243Sobrien xprintf("%s ", name); 155459243Sobrien } 155559243Sobrien } 155659243Sobrien xputchar('\n'); 155759243Sobrien return; 155859243Sobrien } 155983098Smp sigptr = &v[0][1]; 156083098Smp if (v[0][1] == 's') { 156183098Smp if (v[1]) { 156283098Smp v++; 156383098Smp sigptr = &v[0][0]; 156483098Smp } else { 156583098Smp stderror(ERR_NAME | ERR_TOOFEW); 156683098Smp } 156783098Smp } 156883098Smp if (Isdigit(*sigptr)) { 1569131962Smp char *ep; 1570131962Smp signum = strtoul(short2str(sigptr), &ep, 0); 1571131962Smp if (*ep || signum < 0 || signum > (MAXSIG-1)) 157259243Sobrien stderror(ERR_NAME | ERR_BADSIG); 157359243Sobrien } 157459243Sobrien else { 157559243Sobrien for (signum = 0; signum <= nsig; signum++) 157659243Sobrien if (mesg[signum].iname && 157783098Smp eq(sigptr, str2short(mesg[signum].iname))) 157859243Sobrien goto gotsig; 157983098Smp setname(short2str(sigptr)); 158059243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 158159243Sobrien } 158259243Sobriengotsig: 158359243Sobrien v++; 158459243Sobrien } 158559243Sobrien else 158659243Sobrien signum = SIGTERM; 158759243Sobrien pkill(v, signum); 158859243Sobrien} 158959243Sobrien 159059243Sobrienstatic void 159159243Sobrienpkill(v, signum) 159259243Sobrien Char **v; 159359243Sobrien int signum; 159459243Sobrien{ 159559243Sobrien register struct process *pp, *np; 159659243Sobrien int jobflags = 0, err1 = 0; 159759243Sobrien pid_t pid; 159859243Sobrien#ifdef BSDSIGS 159959243Sobrien sigmask_t omask; 160059243Sobrien#endif /* BSDSIGS */ 160159243Sobrien Char *cp, **vp; 160259243Sobrien 160359243Sobrien#ifdef BSDSIGS 160459243Sobrien omask = sigmask(SIGCHLD); 160559243Sobrien if (setintr) 160659243Sobrien omask |= sigmask(SIGINT); 160759243Sobrien omask = sigblock(omask) & ~omask; 160859243Sobrien#else /* !BSDSIGS */ 160959243Sobrien if (setintr) 161059243Sobrien (void) sighold(SIGINT); 161159243Sobrien (void) sighold(SIGCHLD); 161259243Sobrien#endif /* !BSDSIGS */ 161359243Sobrien 161459243Sobrien /* Avoid globbing %?x patterns */ 161559243Sobrien for (vp = v; vp && *vp; vp++) 161659243Sobrien if (**vp == '%') 161759243Sobrien (void) quote(*vp); 161859243Sobrien 161959243Sobrien gflag = 0, tglob(v); 162059243Sobrien if (gflag) { 162159243Sobrien v = globall(v); 162259243Sobrien if (v == 0) 162359243Sobrien stderror(ERR_NAME | ERR_NOMATCH); 162459243Sobrien } 162559243Sobrien else { 162659243Sobrien v = gargv = saveblk(v); 162759243Sobrien trim(v); 162859243Sobrien } 162959243Sobrien 163059243Sobrien 163159243Sobrien while (v && (cp = *v)) { 163259243Sobrien if (*cp == '%') { 163359243Sobrien np = pp = pfind(cp); 163459243Sobrien do 163559243Sobrien jobflags |= np->p_flags; 163659243Sobrien while ((np = np->p_friends) != pp); 163759243Sobrien#ifdef BSDJOBS 163859243Sobrien switch (signum) { 163959243Sobrien 164059243Sobrien case SIGSTOP: 164159243Sobrien case SIGTSTP: 164259243Sobrien case SIGTTIN: 164359243Sobrien case SIGTTOU: 164459243Sobrien if ((jobflags & PRUNNING) == 0) { 164559243Sobrien# ifdef SUSPENDED 164659243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 164759243Sobrien# else /* !SUSPENDED */ 164859243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 164959243Sobrien# endif /* !SUSPENDED */ 165059243Sobrien err1++; 165159243Sobrien goto cont; 165259243Sobrien } 165359243Sobrien break; 165459243Sobrien /* 165559243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 165659243Sobrien * says it is suspended, but it is running; thanks jaap.. 165759243Sobrien */ 165859243Sobrien case SIGCONT: 165959243Sobrien if (!pstart(pp, 0)) { 166059243Sobrien pp->p_procid = 0; 166159243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 166259243Sobrien strerror(errno)); 166359243Sobrien } 166459243Sobrien goto cont; 166559243Sobrien default: 166659243Sobrien break; 166759243Sobrien } 166859243Sobrien#endif /* BSDJOBS */ 166959243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 167059243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 167159243Sobrien err1++; 167259243Sobrien } 167359243Sobrien#ifdef BSDJOBS 167459243Sobrien if (signum == SIGTERM || signum == SIGHUP) 167559243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 167659243Sobrien#endif /* BSDJOBS */ 167759243Sobrien } 167859243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 167959243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 168059243Sobrien else { 1681131962Smp char *ep; 168269408Sache#ifndef WINNT_NATIVE 1683131962Smp pid = strtol(short2str(cp), &ep, 10); 168459243Sobrien#else 1685131962Smp pid = strtoul(short2str(cp), &ep, 0); 168669408Sache#endif /* WINNT_NATIVE */ 1687131962Smp if (*ep) 1688131962Smp stderror(ERR_NAME | ERR_JOBARGS); 1689131962Smp else 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