sh.proc.c revision 172665
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.proc.c,v 3.104 2006/09/27 16:59:04 mitr 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 35167465SmpRCSID("$tcsh: sh.proc.c,v 3.104 2006/09/27 16:59:04 mitr 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 50145479Smp#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) || defined(linux) || defined(__GNU__) || defined(__GLIBC__) 5159243Sobrien# define BSDWAIT 52145479Smp#endif /* _BSD || (IRIS4D && __STDC__) || __lucid || glibc */ 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 80167465Smp#ifndef JOBDEBUG 81167465Smp# define jobdebug_xprintf(x) (void)0 82167465Smp# define jobdebug_flush() (void)0 83167465Smp#else 84167465Smp# define jobdebug_xprintf(s) xprintf s 85167465Smp# define jobdebug_flush() flush() 86167465Smp#endif 87167465Smp 8859243Sobrien/* 8959243Sobrien * C Shell - functions that manage processes, handling hanging, termination 9059243Sobrien */ 9159243Sobrien 9259243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 9359243Sobrien 9459243Sobrien#ifdef BSDTIMES 9559243Sobrien# ifdef convex 9659243Sobrien/* use 'cvxrusage' to get parallel statistics */ 9759243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9859243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9959243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 10059243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 10159243Sobrien# else 10259243Sobrienstatic struct rusage zru; 10359243Sobrien# endif /* convex */ 10459243Sobrien#else /* !BSDTIMES */ 10559243Sobrien# ifdef _SEQUENT_ 10659243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 10759243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 10859243Sobrien# else /* !_SEQUENT_ */ 10959243Sobrien# ifdef _SX 11059243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 11159243Sobrien# else /* !_SX */ 11259243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 11359243Sobrien# endif /* !_SX */ 11459243Sobrien# endif /* !_SEQUENT_ */ 11559243Sobrien#endif /* !BSDTIMES */ 11659243Sobrien 117167465Smp#ifndef BSDTIMES 118167465Smpstatic int timesdone; /* shtimes buffer full ? */ 119167465Smp#endif /* BSDTIMES */ 120167465Smp 12159243Sobrien#ifndef RUSAGE_CHILDREN 12259243Sobrien# define RUSAGE_CHILDREN -1 12359243Sobrien#endif /* RUSAGE_CHILDREN */ 12459243Sobrien 125167465Smpstatic void pflushall (void); 126167465Smpstatic void pflush (struct process *); 127167465Smpstatic void pfree (struct process *); 128167465Smpstatic void pclrcurr (struct process *); 129167465Smpstatic void padd (struct command *); 130167465Smpstatic int pprint (struct process *, int); 131167465Smpstatic void ptprint (struct process *); 132167465Smpstatic void pads (Char *); 133167465Smpstatic void pkill (Char **, int); 134167465Smpstatic struct process *pgetcurr (struct process *); 135167465Smpstatic void okpcntl (void); 136167465Smpstatic void setttypgrp (int); 13759243Sobrien 13859243Sobrien/* 139167465Smp * pchild - call queued by the SIGCHLD signal 14059243Sobrien * indicating that at least one child has terminated or stopped 14159243Sobrien * thus at least one wait system call will definitely return a 14259243Sobrien * childs status. Top level routines (like pwait) must be sure 14359243Sobrien * to mask interrupts when playing with the proclist data structures! 14459243Sobrien */ 145167465Smpvoid 146167465Smppchild(void) 14759243Sobrien{ 148145479Smp struct process *pp; 149145479Smp struct process *fp; 150167465Smp pid_t pid; 15159243Sobrien#ifdef BSDWAIT 15259243Sobrien union wait w; 15359243Sobrien#else /* !BSDWAIT */ 15459243Sobrien int w; 15559243Sobrien#endif /* !BSDWAIT */ 15659243Sobrien int jobflags; 15759243Sobrien#ifdef BSDTIMES 15859243Sobrien struct sysrusage ru; 15959243Sobrien#else /* !BSDTIMES */ 16059243Sobrien# ifdef _SEQUENT_ 16159243Sobrien struct process_stats ru; 16259243Sobrien struct process_stats cpst1, cpst2; 16359243Sobrien timeval_t tv; 16459243Sobrien# else /* !_SEQUENT_ */ 16559243Sobrien struct tms proctimes; 16659243Sobrien 16759243Sobrien if (!timesdone) { 16859243Sobrien timesdone++; 16959243Sobrien (void) times(&shtimes); 17059243Sobrien } 17159243Sobrien# endif /* !_SEQUENT_ */ 17259243Sobrien#endif /* !BSDTIMES */ 17359243Sobrien 174167465Smp jobdebug_xprintf(("pchild()\n")); 17559243Sobrien 17659243Sobrienloop: 177167465Smp jobdebug_xprintf(("Waiting...\n")); 178167465Smp jobdebug_flush(); 17959243Sobrien errno = 0; /* reset, just in case */ 180167465Smp 18169408Sache#ifndef WINNT_NATIVE 18259243Sobrien# ifdef BSDJOBS 18359243Sobrien# ifdef BSDTIMES 18459243Sobrien# ifdef convex 18559243Sobrien /* use 'cvxwait' to get parallel statistics */ 18659243Sobrien pid = cvxwait(&w, 18759243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 18859243Sobrien# else 18959243Sobrien /* both a wait3 and rusage */ 190167465Smp# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(linux) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 19159243Sobrien pid = wait3(&w, 19259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19359243Sobrien# else /* BSDWAIT */ 19459243Sobrien pid = wait3(&w.w_status, 19559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19659243Sobrien# endif /* BSDWAIT */ 19759243Sobrien# endif /* convex */ 19859243Sobrien# else /* !BSDTIMES */ 19959243Sobrien# ifdef _SEQUENT_ 20059243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 20159243Sobrien pid = waitpid(-1, &w, 20259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 20359243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 20459243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 20559243Sobrien# else /* !_SEQUENT_ */ 20659243Sobrien# ifndef POSIX 20759243Sobrien /* we have a wait3, but no rusage stuff */ 20859243Sobrien pid = wait3(&w.w_status, 20959243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 21059243Sobrien# else /* POSIX */ 21159243Sobrien pid = waitpid(-1, &w, 21259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 21359243Sobrien# endif /* POSIX */ 21459243Sobrien# endif /* !_SEQUENT_ */ 21559243Sobrien# endif /* !BSDTIMES */ 21659243Sobrien# else /* !BSDJOBS */ 21759243Sobrien# ifdef BSDTIMES 21859243Sobrien# define HAVEwait3 21959243Sobrien /* both a wait3 and rusage */ 22059243Sobrien# ifdef hpux 22159243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 22259243Sobrien# else /* !hpux */ 22359243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 22459243Sobrien# endif /* !hpux */ 22559243Sobrien# else /* !BSDTIMES */ 22659243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 22759243Sobrien# define HAVEwait3 228167465Smp pid = waitpid(-1, &w, 22959243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 23059243Sobrien# endif /* ODT */ 23159243Sobrien# if defined(aiws) || defined(uts) 23259243Sobrien# define HAVEwait3 23359243Sobrien pid = wait3(&w.w_status, 23459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 23559243Sobrien# endif /* aiws || uts */ 23659243Sobrien# ifndef HAVEwait3 237167465Smp# ifndef BSDWAIT 23859243Sobrien /* no wait3, therefore no rusage */ 23959243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 240167465Smp pid = wait(&w); 241167465Smp# else /* BSDWAIT */ 24259243Sobrien /* 24359243Sobrien * XXX: for greater than 3 we should use waitpid(). 24459243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 24559243Sobrien */ 246167465Smp pid = wait(&w.w_status); 247167465Smp# endif /* BSDWAIT */ 24859243Sobrien# endif /* !HAVEwait3 */ 24959243Sobrien# endif /* !BSDTIMES */ 25059243Sobrien# endif /* !BSDJOBS */ 25169408Sache#else /* WINNT_NATIVE */ 252167465Smp pid = waitpid(-1, &w, 25359243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 25469408Sache#endif /* WINNT_NATIVE */ 25559243Sobrien 256167465Smp jobdebug_xprintf(("parent %d pid %d, retval %x termsig %x retcode %x\n", 257167465Smp (int)getpid(), (int)pid, w, WTERMSIG(w), 258167465Smp WEXITSTATUS(w))); 259167465Smp jobdebug_flush(); 26059243Sobrien 26159243Sobrien if ((pid == 0) || (pid == -1)) { 262167465Smp handle_pending_signals(); 263167465Smp jobdebug_xprintf(("errno == %d\n", errno)); 264167465Smp if (errno == EINTR) 26559243Sobrien goto loop; 266145479Smp goto end; 26759243Sobrien } 26859243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 26959243Sobrien if (pid == pp->p_procid) 27059243Sobrien goto found; 27169408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 27259243Sobrien /* this should never have happened */ 27359243Sobrien stderror(ERR_SYNC, pid); 27459243Sobrien xexit(0); 27569408Sache#else /* BSDJOBS || WINNT_NATIVE */ 27659243Sobrien goto loop; 27769408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 27859243Sobrienfound: 27959243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 28059243Sobrien if (WIFSTOPPED(w)) { 28159243Sobrien pp->p_flags |= PSTOPPED; 28259243Sobrien pp->p_reason = WSTOPSIG(w); 28359243Sobrien } 28459243Sobrien else { 28559243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 28659243Sobrien#ifndef BSDTIMES 28759243Sobrien# ifdef _SEQUENT_ 28859243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 28959243Sobrien# else /* !_SEQUENT_ */ 29059243Sobrien pp->p_etime = times(&proctimes); 29159243Sobrien# endif /* !_SEQUENT_ */ 29259243Sobrien#else /* BSDTIMES */ 29359243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 29459243Sobrien#endif /* BSDTIMES */ 29559243Sobrien 29659243Sobrien 29759243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 29859243Sobrien pp->p_rusage = ru; 29959243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 30059243Sobrien (void) times(&proctimes); 30159243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 30259243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 30359243Sobrien shtimes = proctimes; 30459243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 30559243Sobrien if (WIFSIGNALED(w)) { 30659243Sobrien if (WTERMSIG(w) == SIGINT) 30759243Sobrien pp->p_flags |= PINTERRUPTED; 30859243Sobrien else 30959243Sobrien pp->p_flags |= PSIGNALED; 31059243Sobrien if (WCOREDUMP(w)) 31159243Sobrien pp->p_flags |= PDUMPED; 31259243Sobrien pp->p_reason = WTERMSIG(w); 31359243Sobrien } 31459243Sobrien else { 31559243Sobrien pp->p_reason = WEXITSTATUS(w); 31659243Sobrien if (pp->p_reason != 0) 31759243Sobrien pp->p_flags |= PAEXITED; 31859243Sobrien else 31959243Sobrien pp->p_flags |= PNEXITED; 32059243Sobrien } 32159243Sobrien } 32259243Sobrien jobflags = 0; 32359243Sobrien fp = pp; 32459243Sobrien do { 32559243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 32659243Sobrien !child && adrof(STRtime) && 32759243Sobrien#ifdef BSDTIMES 32859243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 32959243Sobrien#else /* !BSDTIMES */ 33059243Sobrien# ifdef _SEQUENT_ 33159243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 33259243Sobrien# else /* !_SEQUENT_ */ 33359243Sobrien# ifndef POSIX 33459243Sobrien (fp->p_utime + fp->p_stime) / HZ 33559243Sobrien# else /* POSIX */ 33659243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 33759243Sobrien# endif /* POSIX */ 33859243Sobrien# endif /* !_SEQUENT_ */ 33959243Sobrien#endif /* !BSDTIMES */ 34059243Sobrien >= atoi(short2str(varval(STRtime)))) 34159243Sobrien fp->p_flags |= PTIME; 34259243Sobrien jobflags |= fp->p_flags; 34359243Sobrien } while ((fp = fp->p_friends) != pp); 34459243Sobrien pp->p_flags &= ~PFOREGND; 34559243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 34659243Sobrien pp->p_flags &= ~PPTIME; 34759243Sobrien pp->p_flags |= PTIME; 34859243Sobrien } 34959243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 35059243Sobrien fp = pp; 35159243Sobrien do { 35259243Sobrien if (fp->p_flags & PSTOPPED) 35359243Sobrien fp->p_flags |= PREPORTED; 35459243Sobrien } while ((fp = fp->p_friends) != pp); 35559243Sobrien while (fp->p_procid != fp->p_jobid) 35659243Sobrien fp = fp->p_friends; 35759243Sobrien if (jobflags & PSTOPPED) { 35859243Sobrien if (pcurrent && pcurrent != fp) 35959243Sobrien pprevious = pcurrent; 36059243Sobrien pcurrent = fp; 36159243Sobrien } 36259243Sobrien else 36359243Sobrien pclrcurr(fp); 36459243Sobrien if (jobflags & PFOREGND) { 36559243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 36659243Sobrien#ifdef notdef 36759243Sobrien jobflags & PAEXITED || 36859243Sobrien#endif /* notdef */ 36959243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 37059243Sobrien /* PWP: print a newline after ^C */ 37159243Sobrien if (jobflags & PINTERRUPTED) { 372167465Smp xputchar('\r' | QUOTE); 373167465Smp xputchar('\n'); 37459243Sobrien } 37559243Sobrien#ifdef notdef 37659243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 37759243Sobrien ptprint(fp); 37859243Sobrien#endif /* notdef */ 37959243Sobrien } 38059243Sobrien } 38159243Sobrien else { 38259243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 383167465Smp xputchar('\r' | QUOTE); 384167465Smp xputchar('\n'); 38559243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 38659243Sobrien if ((jobflags & PSTOPPED) == 0) 38759243Sobrien pflush(pp); 388167465Smp if (GettingInput) { 389167465Smp errno = 0; 390167465Smp (void) Rawmode(); 39159243Sobrien#ifdef notdef 392167465Smp /* 393167465Smp * don't really want to do that, because it 394167465Smp * will erase our message in case of multi-line 395167465Smp * input 396167465Smp */ 397167465Smp ClearLines(); 39859243Sobrien#endif /* notdef */ 399167465Smp ClearDisp(); 400167465Smp Refresh(); 40159243Sobrien } 40259243Sobrien } 40359243Sobrien else { 40459243Sobrien fp->p_flags |= PNEEDNOTE; 405167465Smp neednote = 1; 40659243Sobrien } 40759243Sobrien } 40859243Sobrien } 409167465Smp#if defined(BSDJOBS) || defined(HAVEwait3) ||defined(WINNT_NATIVE) 41059243Sobrien goto loop; 41159243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 412145479Smp end: 413145479Smp ; 41459243Sobrien} 41559243Sobrien 41659243Sobrienvoid 417167465Smppnote(void) 41859243Sobrien{ 419145479Smp struct process *pp; 42059243Sobrien int flags; 42159243Sobrien 42259243Sobrien neednote = 0; 42359243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 42459243Sobrien if (pp->p_flags & PNEEDNOTE) { 425167465Smp pchild_disabled++; 426167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 42759243Sobrien pp->p_flags &= ~PNEEDNOTE; 42859243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 42959243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 43059243Sobrien pflush(pp); 431167465Smp cleanup_until(&pchild_disabled); 43259243Sobrien } 43359243Sobrien } 43459243Sobrien} 43559243Sobrien 43659243Sobrien 43759243Sobrienstatic void 438167465Smppfree(struct process *pp) 43959243Sobrien{ 440167465Smp xfree(pp->p_command); 44159243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 44259243Sobrien if (pp->p_cwd->di_next == 0) 44359243Sobrien dfree(pp->p_cwd); 444167465Smp xfree(pp); 44559243Sobrien} 44659243Sobrien 44759243Sobrien 44859243Sobrien/* 44959243Sobrien * pwait - wait for current job to terminate, maintaining integrity 45059243Sobrien * of current and previous job indicators. 45159243Sobrien */ 45259243Sobrienvoid 453167465Smppwait(void) 45459243Sobrien{ 455145479Smp struct process *fp, *pp; 45659243Sobrien 45759243Sobrien /* 45859243Sobrien * Here's where dead procs get flushed. 45959243Sobrien */ 46059243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 46159243Sobrien if (pp->p_procid == 0) { 46259243Sobrien fp->p_next = pp->p_next; 46359243Sobrien pfree(pp); 46459243Sobrien pp = fp; 46559243Sobrien } 46659243Sobrien pjwait(pcurrjob); 46759243Sobrien} 46859243Sobrien 46959243Sobrien 47059243Sobrien/* 47159243Sobrien * pjwait - wait for a job to finish or become stopped 47259243Sobrien * It is assumed to be in the foreground state (PFOREGND) 47359243Sobrien */ 47459243Sobrienvoid 475167465Smppjwait(struct process *pp) 47659243Sobrien{ 477145479Smp struct process *fp; 47859243Sobrien int jobflags, reason; 479167465Smp sigset_t oset, set, pause_mask; 480167465Smp Char *reason_str; 481167465Smp 48259243Sobrien while (pp->p_procid != pp->p_jobid) 48359243Sobrien pp = pp->p_friends; 48459243Sobrien fp = pp; 48559243Sobrien 48659243Sobrien do { 48759243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 488167465Smp xprintf(CGETS(17, 1, "BUG: waiting for background job!\n")); 48959243Sobrien } while ((fp = fp->p_friends) != pp); 49059243Sobrien /* 49159243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 49259243Sobrien * target process, or any of its friends, are running 49359243Sobrien */ 49459243Sobrien fp = pp; 495167465Smp sigemptyset(&set); 496167465Smp sigaddset(&set, SIGINT); 497167465Smp sigaddset(&set, SIGCHLD); 498167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 499167465Smp cleanup_push(&oset, sigprocmask_cleanup); 500167465Smp pause_mask = oset; 501167465Smp sigdelset(&pause_mask, SIGCHLD); 50259243Sobrien for (;;) { 503167465Smp handle_pending_signals(); 50459243Sobrien jobflags = 0; 50559243Sobrien do 50659243Sobrien jobflags |= fp->p_flags; 50759243Sobrien while ((fp = (fp->p_friends)) != pp); 50859243Sobrien if ((jobflags & PRUNNING) == 0) 50959243Sobrien break; 510167465Smp jobdebug_xprintf(("%d starting to sigsuspend for SIGCHLD on %d\n", 511167465Smp getpid(), fp->p_procid)); 512167465Smp sigsuspend(&pause_mask); 51359243Sobrien } 514167465Smp cleanup_until(&oset); 515167465Smp jobdebug_xprintf(("%d returned from sigsuspend loop\n", getpid())); 51659243Sobrien#ifdef BSDJOBS 51759243Sobrien if (tpgrp > 0) /* get tty back */ 51859243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 51959243Sobrien#endif /* BSDJOBS */ 52059243Sobrien if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 52159243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name)) { 52259243Sobrien if (jobflags & PSTOPPED) { 52359243Sobrien xputchar('\n'); 52459243Sobrien if (adrof(STRlistjobs)) { 52559243Sobrien Char *jobcommand[3]; 52659243Sobrien 52759243Sobrien jobcommand[0] = STRjobs; 52859243Sobrien if (eq(varval(STRlistjobs), STRlong)) 52959243Sobrien jobcommand[1] = STRml; 53059243Sobrien else 53159243Sobrien jobcommand[1] = NULL; 53259243Sobrien jobcommand[2] = NULL; 53359243Sobrien 53459243Sobrien dojobs(jobcommand, NULL); 53559243Sobrien (void) pprint(pp, SHELLDIR); 53659243Sobrien } 53759243Sobrien else 53859243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 53959243Sobrien } 54059243Sobrien else 54159243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 54259243Sobrien } 54359243Sobrien if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 54459243Sobrien (!gointr || !eq(gointr, STRminus))) { 54559243Sobrien if ((jobflags & PSTOPPED) == 0) 54659243Sobrien pflush(pp); 54759243Sobrien pintr1(0); 54859243Sobrien /* NOTREACHED */ 54959243Sobrien } 55059243Sobrien reason = 0; 55159243Sobrien fp = pp; 55259243Sobrien do { 55359243Sobrien if (fp->p_reason) 55459243Sobrien reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 55559243Sobrien fp->p_reason | META : fp->p_reason; 55659243Sobrien } while ((fp = fp->p_friends) != pp); 55759243Sobrien /* 55859243Sobrien * Don't report on backquoted jobs, cause it will mess up 55959243Sobrien * their output. 56059243Sobrien */ 56159243Sobrien if ((reason != 0) && (adrof(STRprintexitvalue)) && 56259243Sobrien (pp->p_flags & PBACKQ) == 0) 56359243Sobrien xprintf(CGETS(17, 2, "Exit %d\n"), reason); 564167465Smp reason_str = putn(reason); 565167465Smp cleanup_push(reason_str, xfree); 566167465Smp setv(STRstatus, reason_str, VAR_READWRITE); 567167465Smp cleanup_ignore(reason_str); 568167465Smp cleanup_until(reason_str); 56959243Sobrien if (reason && exiterr) 57059243Sobrien exitstat(); 57159243Sobrien pflush(pp); 57259243Sobrien} 57359243Sobrien 57459243Sobrien/* 57559243Sobrien * dowait - wait for all processes to finish 57659243Sobrien */ 57759243Sobrien 57859243Sobrien/*ARGSUSED*/ 57959243Sobrienvoid 580167465Smpdowait(Char **v, struct command *c) 58159243Sobrien{ 582145479Smp struct process *pp; 583167465Smp sigset_t pause_mask; 58459243Sobrien 58559243Sobrien USE(c); 58659243Sobrien USE(v); 58759243Sobrien pjobs++; 588167465Smp sigprocmask(SIG_BLOCK, NULL, &pause_mask); 589167465Smp sigdelset(&pause_mask, SIGCHLD); 59059243Sobrien if (setintr) 591167465Smp sigdelset(&pause_mask, SIGINT); 59259243Sobrienloop: 59359243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 59459243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 59559243Sobrien pp->p_flags & PRUNNING) { 596167465Smp handle_pending_signals(); 597167465Smp sigsuspend(&pause_mask); 598167465Smp handle_pending_signals(); 59959243Sobrien goto loop; 60059243Sobrien } 60159243Sobrien pjobs = 0; 60259243Sobrien} 60359243Sobrien 60459243Sobrien/* 60559243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 60659243Sobrien */ 60759243Sobrienstatic void 608167465Smppflushall(void) 60959243Sobrien{ 610145479Smp struct process *pp; 61159243Sobrien 61259243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 61359243Sobrien if (pp->p_procid) 61459243Sobrien pflush(pp); 61559243Sobrien} 61659243Sobrien 61759243Sobrien/* 61859243Sobrien * pflush - flag all process structures in the same job as the 61959243Sobrien * the argument process for deletion. The actual free of the 62059243Sobrien * space is not done here since pflush is called at interrupt level. 62159243Sobrien */ 62259243Sobrienstatic void 623167465Smppflush(struct process *pp) 62459243Sobrien{ 625145479Smp struct process *np; 626145479Smp int idx; 62759243Sobrien 62859243Sobrien if (pp->p_procid == 0) { 62959243Sobrien xprintf(CGETS(17, 3, "BUG: process flushed twice")); 63059243Sobrien return; 63159243Sobrien } 63259243Sobrien while (pp->p_procid != pp->p_jobid) 63359243Sobrien pp = pp->p_friends; 63459243Sobrien pclrcurr(pp); 63559243Sobrien if (pp == pcurrjob) 63659243Sobrien pcurrjob = 0; 63759243Sobrien idx = pp->p_index; 63859243Sobrien np = pp; 63959243Sobrien do { 64059243Sobrien np->p_index = np->p_procid = 0; 64159243Sobrien np->p_flags &= ~PNEEDNOTE; 64259243Sobrien } while ((np = np->p_friends) != pp); 64359243Sobrien if (idx == pmaxindex) { 64459243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 64559243Sobrien if (np->p_index > idx) 64659243Sobrien idx = np->p_index; 64759243Sobrien pmaxindex = idx; 64859243Sobrien } 64959243Sobrien} 65059243Sobrien 65159243Sobrien/* 65259243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 65359243Sobrien * pp MUST be the job leader 65459243Sobrien */ 65559243Sobrienstatic void 656167465Smppclrcurr(struct process *pp) 65759243Sobrien{ 65859243Sobrien if (pp == pcurrent) { 65959243Sobrien if (pprevious != NULL) { 66059243Sobrien pcurrent = pprevious; 66159243Sobrien pprevious = pgetcurr(pp); 66259243Sobrien } 66359243Sobrien else { 66459243Sobrien pcurrent = pgetcurr(pp); 66559243Sobrien pprevious = pgetcurr(pp); 66659243Sobrien } 66759243Sobrien } 66859243Sobrien else if (pp == pprevious) 66959243Sobrien pprevious = pgetcurr(pp); 67059243Sobrien} 67159243Sobrien 67259243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 67359243Sobrienstatic Char command[PMAXLEN + 4]; 674167465Smpstatic size_t cmdlen; 67559243Sobrienstatic Char *cmdp; 67659243Sobrien 67783098Smp/* GrP 67883098Smp * unparse - Export padd() functionality 67983098Smp */ 68083098SmpChar * 681167465Smpunparse(struct command *t) 68283098Smp{ 68383098Smp cmdp = command; 68483098Smp cmdlen = 0; 68583098Smp padd(t); 68683098Smp *cmdp++ = '\0'; 68783098Smp return Strsave(command); 68883098Smp} 68983098Smp 69083098Smp 69159243Sobrien/* 69259243Sobrien * palloc - allocate a process structure and fill it up. 69359243Sobrien * an important assumption is made that the process is running. 69459243Sobrien */ 69559243Sobrienvoid 696167465Smppalloc(pid_t pid, struct command *t) 69759243Sobrien{ 698145479Smp struct process *pp; 69959243Sobrien int i; 70059243Sobrien 701167465Smp pp = xcalloc(1, sizeof(struct process)); 70259243Sobrien pp->p_procid = pid; 70359243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 70459243Sobrien if (t->t_dflg & F_TIME) 70559243Sobrien pp->p_flags |= PPTIME; 70659243Sobrien if (t->t_dflg & F_BACKQ) 70759243Sobrien pp->p_flags |= PBACKQ; 70859243Sobrien if (t->t_dflg & F_HUP) 70959243Sobrien pp->p_flags |= PHUP; 71059243Sobrien cmdp = command; 71159243Sobrien cmdlen = 0; 71259243Sobrien padd(t); 71359243Sobrien *cmdp++ = 0; 71459243Sobrien if (t->t_dflg & F_PIPEOUT) { 71559243Sobrien pp->p_flags |= PPOU; 71659243Sobrien if (t->t_dflg & F_STDERR) 71759243Sobrien pp->p_flags |= PDIAG; 71859243Sobrien } 71959243Sobrien pp->p_command = Strsave(command); 72059243Sobrien if (pcurrjob) { 72159243Sobrien struct process *fp; 72259243Sobrien 72359243Sobrien /* careful here with interrupt level */ 72459243Sobrien pp->p_cwd = 0; 72559243Sobrien pp->p_index = pcurrjob->p_index; 72659243Sobrien pp->p_friends = pcurrjob; 72759243Sobrien pp->p_jobid = pcurrjob->p_procid; 72859243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 72959243Sobrien continue; 73059243Sobrien fp->p_friends = pp; 73159243Sobrien } 73259243Sobrien else { 73359243Sobrien pcurrjob = pp; 73459243Sobrien pp->p_jobid = pid; 73559243Sobrien pp->p_friends = pp; 73659243Sobrien pp->p_cwd = dcwd; 73759243Sobrien dcwd->di_count++; 73859243Sobrien if (pmaxindex < BIGINDEX) 73959243Sobrien pp->p_index = ++pmaxindex; 74059243Sobrien else { 74159243Sobrien struct process *np; 74259243Sobrien 74359243Sobrien for (i = 1;; i++) { 74459243Sobrien for (np = proclist.p_next; np; np = np->p_next) 74559243Sobrien if (np->p_index == i) 74659243Sobrien goto tryagain; 74759243Sobrien pp->p_index = i; 74859243Sobrien if (i > pmaxindex) 74959243Sobrien pmaxindex = i; 75059243Sobrien break; 75159243Sobrien tryagain:; 75259243Sobrien } 75359243Sobrien } 75459243Sobrien if (pcurrent == NULL) 75559243Sobrien pcurrent = pp; 75659243Sobrien else if (pprevious == NULL) 75759243Sobrien pprevious = pp; 75859243Sobrien } 75959243Sobrien pp->p_next = proclist.p_next; 76059243Sobrien proclist.p_next = pp; 76159243Sobrien#ifdef BSDTIMES 76259243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 76359243Sobrien#else /* !BSDTIMES */ 76459243Sobrien# ifdef _SEQUENT_ 76559243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 76659243Sobrien# else /* !_SEQUENT_ */ 76759243Sobrien { 76859243Sobrien struct tms tmptimes; 76959243Sobrien 77059243Sobrien pp->p_btime = times(&tmptimes); 77159243Sobrien } 77259243Sobrien# endif /* !_SEQUENT_ */ 77359243Sobrien#endif /* !BSDTIMES */ 77459243Sobrien} 77559243Sobrien 77659243Sobrienstatic void 777167465Smppadd(struct command *t) 77859243Sobrien{ 77959243Sobrien Char **argp; 78059243Sobrien 78159243Sobrien if (t == 0) 78259243Sobrien return; 78359243Sobrien switch (t->t_dtyp) { 78459243Sobrien 78559243Sobrien case NODE_PAREN: 78659243Sobrien pads(STRLparensp); 78759243Sobrien padd(t->t_dspr); 78859243Sobrien pads(STRspRparen); 78959243Sobrien break; 79059243Sobrien 79159243Sobrien case NODE_COMMAND: 79259243Sobrien for (argp = t->t_dcom; *argp; argp++) { 79359243Sobrien pads(*argp); 79459243Sobrien if (argp[1]) 79559243Sobrien pads(STRspace); 79659243Sobrien } 79759243Sobrien break; 79859243Sobrien 79959243Sobrien case NODE_OR: 80059243Sobrien case NODE_AND: 80159243Sobrien case NODE_PIPE: 80259243Sobrien case NODE_LIST: 80359243Sobrien padd(t->t_dcar); 80459243Sobrien switch (t->t_dtyp) { 80559243Sobrien case NODE_OR: 80659243Sobrien pads(STRspor2sp); 80759243Sobrien break; 80859243Sobrien case NODE_AND: 80959243Sobrien pads(STRspand2sp); 81059243Sobrien break; 81159243Sobrien case NODE_PIPE: 81259243Sobrien pads(STRsporsp); 81359243Sobrien break; 81459243Sobrien case NODE_LIST: 81559243Sobrien pads(STRsemisp); 81659243Sobrien break; 81759243Sobrien default: 81859243Sobrien break; 81959243Sobrien } 82059243Sobrien padd(t->t_dcdr); 82159243Sobrien return; 82259243Sobrien 82359243Sobrien default: 82459243Sobrien break; 82559243Sobrien } 82659243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 82759243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 82859243Sobrien pads(t->t_dlef); 82959243Sobrien } 83059243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 83159243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 83259243Sobrien if (t->t_dflg & F_STDERR) 83359243Sobrien pads(STRand); 83459243Sobrien pads(STRspace); 83559243Sobrien pads(t->t_drit); 83659243Sobrien } 83759243Sobrien} 83859243Sobrien 83959243Sobrienstatic void 840167465Smppads(Char *cp) 84159243Sobrien{ 842167465Smp size_t i; 84359243Sobrien 84459243Sobrien /* 84559243Sobrien * Avoid the Quoted Space alias hack! Reported by: 84659243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 84759243Sobrien */ 84859243Sobrien if (cp[0] == STRQNULL[0]) 84959243Sobrien cp++; 85059243Sobrien 851167465Smp i = Strlen(cp); 85259243Sobrien 85359243Sobrien if (cmdlen >= PMAXLEN) 85459243Sobrien return; 85559243Sobrien if (cmdlen + i >= PMAXLEN) { 85659243Sobrien (void) Strcpy(cmdp, STRsp3dots); 85759243Sobrien cmdlen = PMAXLEN; 85859243Sobrien cmdp += 4; 85959243Sobrien return; 86059243Sobrien } 86159243Sobrien (void) Strcpy(cmdp, cp); 86259243Sobrien cmdp += i; 86359243Sobrien cmdlen += i; 86459243Sobrien} 86559243Sobrien 86659243Sobrien/* 86759243Sobrien * psavejob - temporarily save the current job on a one level stack 86859243Sobrien * so another job can be created. Used for { } in exp6 86959243Sobrien * and `` in globbing. 87059243Sobrien */ 87159243Sobrienvoid 872167465Smppsavejob(void) 87359243Sobrien{ 87459243Sobrien pholdjob = pcurrjob; 87559243Sobrien pcurrjob = NULL; 87659243Sobrien} 87759243Sobrien 87859243Sobrienvoid 879167465Smppsavejob_cleanup(void *dummy) 88059243Sobrien{ 881167465Smp USE(dummy); 88259243Sobrien pcurrjob = pholdjob; 88359243Sobrien pholdjob = NULL; 88459243Sobrien} 88559243Sobrien 88659243Sobrien/* 88759243Sobrien * pendjob - indicate that a job (set of commands) has been completed 88859243Sobrien * or is about to begin. 88959243Sobrien */ 89059243Sobrienvoid 891167465Smppendjob(void) 89259243Sobrien{ 893145479Smp struct process *pp, *tp; 89459243Sobrien 89559243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 89659243Sobrien pp = pcurrjob; 89759243Sobrien while (pp->p_procid != pp->p_jobid) 89859243Sobrien pp = pp->p_friends; 89959243Sobrien xprintf("[%d]", pp->p_index); 90059243Sobrien tp = pp; 90159243Sobrien do { 90259243Sobrien xprintf(" %d", pp->p_procid); 90359243Sobrien pp = pp->p_friends; 90459243Sobrien } while (pp != tp); 90559243Sobrien xputchar('\n'); 90659243Sobrien } 90759243Sobrien pholdjob = pcurrjob = 0; 90859243Sobrien} 90959243Sobrien 91059243Sobrien/* 91159243Sobrien * pprint - print a job 91259243Sobrien */ 91359243Sobrien 91459243Sobrien/* 91559243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 91659243Sobrien * reverse order 91759243Sobrien * 91859243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 91959243Sobrien */ 92059243Sobrien 92159243Sobrienstatic int 922167465Smppprint(struct process *pp, int flag) 92359243Sobrien{ 92459243Sobrien int status, reason; 92559243Sobrien struct process *tp; 92659243Sobrien int jobflags, pstatus, pcond; 927145479Smp const char *format; 92859243Sobrien 92959243Sobrien#ifdef BACKPIPE 93059243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 93159243Sobrien int inpipe = 0; 93259243Sobrien#endif /* BACKPIPE */ 93359243Sobrien 93459243Sobrien while (pp->p_procid != pp->p_jobid) 93559243Sobrien pp = pp->p_friends; 93659243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 93759243Sobrien pp->p_flags &= ~PPTIME; 93859243Sobrien pp->p_flags |= PTIME; 93959243Sobrien } 94059243Sobrien tp = pp; 94159243Sobrien status = reason = -1; 94259243Sobrien jobflags = 0; 94359243Sobrien do { 94459243Sobrien#ifdef BACKPIPE 94559243Sobrien /* 94659243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 94759243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 94859243Sobrien */ 94959243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 95059243Sobrien inpipe = 1; 95159243Sobrien pipetail = pp; 95259243Sobrien do 95359243Sobrien pp = pp->p_friends; 95459243Sobrien while (pp->p_friends->p_flags & PPOU); 95559243Sobrien pipehead = pp; 95659243Sobrien pmarker = pp; 95759243Sobrien /* 95859243Sobrien * pmarker is used to hold the place of the proc being processed, so 95959243Sobrien * we can search for the next one downstream later. 96059243Sobrien */ 96159243Sobrien } 962167465Smp pcond = (tp != pp || (inpipe && tp == pp)); 96359243Sobrien#else /* !BACKPIPE */ 964167465Smp pcond = (tp != pp); 96559243Sobrien#endif /* BACKPIPE */ 96659243Sobrien 96759243Sobrien jobflags |= pp->p_flags; 96859243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 96959243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 97059243Sobrien ((pstatus == status && pp->p_reason == reason) || 97159243Sobrien !(flag & REASON))) 97259243Sobrien xputchar(' '); 97359243Sobrien else { 97459243Sobrien if (pcond && linp != linbuf) 97559243Sobrien xputchar('\n'); 97659243Sobrien if (flag & NUMBER) { 97759243Sobrien#ifdef BACKPIPE 97859243Sobrien pcond = ((pp == tp && !inpipe) || 97959243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 98059243Sobrien#else /* BACKPIPE */ 98159243Sobrien pcond = (pp == tp); 98259243Sobrien#endif /* BACKPIPE */ 98359243Sobrien if (pcond) 98459243Sobrien xprintf("[%d]%s %c ", pp->p_index, 98559243Sobrien pp->p_index < 10 ? " " : "", 98659243Sobrien pp == pcurrent ? '+' : 98759243Sobrien (pp == pprevious ? '-' : ' ')); 98859243Sobrien else 98959243Sobrien xprintf(" "); 99059243Sobrien } 99159243Sobrien if (flag & FANCY) { 99259243Sobrien xprintf("%5d ", pp->p_procid); 99359243Sobrien#ifdef TCF 99459243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 99559243Sobrien#endif /* TCF */ 99659243Sobrien } 99759243Sobrien if (flag & (REASON | AREASON)) { 99859243Sobrien if (flag & NAME) 99959243Sobrien format = "%-30s"; 100059243Sobrien else 100159243Sobrien format = "%s"; 100259243Sobrien if (pstatus == status) { 100359243Sobrien if (pp->p_reason == reason) { 100459243Sobrien xprintf(format, ""); 100559243Sobrien goto prcomd; 100659243Sobrien } 100759243Sobrien else 100859243Sobrien reason = (int) pp->p_reason; 100959243Sobrien } 101059243Sobrien else { 101159243Sobrien status = pstatus; 101259243Sobrien reason = (int) pp->p_reason; 101359243Sobrien } 101459243Sobrien switch (status) { 101559243Sobrien 101659243Sobrien case PRUNNING: 101759243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 101859243Sobrien break; 101959243Sobrien 102059243Sobrien case PINTERRUPTED: 102159243Sobrien case PSTOPPED: 102259243Sobrien case PSIGNALED: 102359243Sobrien /* 102459243Sobrien * tell what happened to the background job 1025167465Smp * From: Michael Schroeder 102659243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 102759243Sobrien */ 102859243Sobrien if ((flag & REASON) 102959243Sobrien || ((flag & AREASON) 103059243Sobrien && reason != SIGINT 103159243Sobrien && (reason != SIGPIPE 103259243Sobrien || (pp->p_flags & PPOU) == 0))) { 1033167465Smp char *ptr; 1034167465Smp int free_ptr; 103559243Sobrien 1036167465Smp free_ptr = 0; 1037167465Smp ptr = (char *)(intptr_t)mesg[pp->p_reason & 0177].pname; 1038167465Smp if (ptr == NULL) { 1039167465Smp ptr = xasprintf("%s %d", CGETS(17, 5, "Signal"), 1040167465Smp pp->p_reason & 0177); 1041167465Smp cleanup_push(ptr, xfree); 1042167465Smp free_ptr = 1; 1043145479Smp } 104459243Sobrien xprintf(format, ptr); 1045167465Smp if (free_ptr != 0) 1046167465Smp cleanup_until(ptr); 104759243Sobrien } 104859243Sobrien else 104959243Sobrien reason = -1; 105059243Sobrien break; 105159243Sobrien 105259243Sobrien case PNEXITED: 105359243Sobrien case PAEXITED: 105459243Sobrien if (flag & REASON) { 105559243Sobrien if (pp->p_reason) 105659243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 105759243Sobrien else 105859243Sobrien xprintf(format, CGETS(17, 7, "Done")); 105959243Sobrien } 106059243Sobrien break; 106159243Sobrien 106259243Sobrien default: 106359243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 106459243Sobrien status); 106559243Sobrien } 106659243Sobrien } 106759243Sobrien } 106859243Sobrienprcomd: 106959243Sobrien if (flag & NAME) { 107059243Sobrien xprintf("%S", pp->p_command); 107159243Sobrien if (pp->p_flags & PPOU) 107259243Sobrien xprintf(" |"); 107359243Sobrien if (pp->p_flags & PDIAG) 107459243Sobrien xprintf("&"); 107559243Sobrien } 107659243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 107759243Sobrien xprintf(CGETS(17, 9, " (core dumped)")); 107859243Sobrien if (tp == pp->p_friends) { 107959243Sobrien if (flag & AMPERSAND) 108059243Sobrien xprintf(" &"); 108159243Sobrien if (flag & JOBDIR && 108259243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 108359243Sobrien xprintf(CGETS(17, 10, " (wd: ")); 108459243Sobrien dtildepr(tp->p_cwd->di_name); 108559243Sobrien xprintf(")"); 108659243Sobrien } 108759243Sobrien } 108859243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 108959243Sobrien if (linp != linbuf) 109059243Sobrien xprintf("\n\t"); 109159243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 109259243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 109359243Sobrien &pp->p_btime); 109459243Sobrien#else /* !BSDTIMES && !SEQUENT */ 109559243Sobrien lru.tms_utime = pp->p_utime; 109659243Sobrien lru.tms_stime = pp->p_stime; 109759243Sobrien lru.tms_cutime = 0; 109859243Sobrien lru.tms_cstime = 0; 109959243Sobrien prusage(&zru, &lru, pp->p_etime, 110059243Sobrien pp->p_btime); 110159243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 110259243Sobrien 110359243Sobrien } 110459243Sobrien#ifdef BACKPIPE 110559243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 110659243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 110759243Sobrien#else /* !BACKPIPE */ 110859243Sobrien pcond = (tp == pp->p_friends); 110959243Sobrien#endif /* BACKPIPE */ 111059243Sobrien if (pcond) { 111159243Sobrien if (linp != linbuf) 111259243Sobrien xputchar('\n'); 111359243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 111459243Sobrien xprintf(CGETS(17, 11, "(wd now: ")); 111559243Sobrien dtildepr(dcwd->di_name); 111659243Sobrien xprintf(")\n"); 111759243Sobrien } 111859243Sobrien } 111959243Sobrien#ifdef BACKPIPE 112059243Sobrien if (inpipe) { 112159243Sobrien /* 112259243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 112359243Sobrien * can now skip to past the head 112459243Sobrien */ 112559243Sobrien if (pmarker == pipetail) { 112659243Sobrien inpipe = 0; 112759243Sobrien pp = pipehead; 112859243Sobrien } 112959243Sobrien else { 113059243Sobrien /* 113159243Sobrien * set pp to one before the one we want next, so the while below 113259243Sobrien * increments to the correct spot. 113359243Sobrien */ 113459243Sobrien do 113559243Sobrien pp = pp->p_friends; 113659243Sobrien while (pp->p_friends->p_friends != pmarker); 113759243Sobrien pmarker = pp->p_friends; 113859243Sobrien } 113959243Sobrien } 114059243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 114159243Sobrien#else /* !BACKPIPE */ 114259243Sobrien pcond = ((pp = pp->p_friends) != tp); 114359243Sobrien#endif /* BACKPIPE */ 114459243Sobrien } while (pcond); 114559243Sobrien 114659243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 114759243Sobrien if (jobflags & NUMBER) 114859243Sobrien xprintf(" "); 114959243Sobrien ptprint(tp); 115059243Sobrien } 115159243Sobrien return (jobflags); 115259243Sobrien} 115359243Sobrien 115459243Sobrien/* 115559243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 115659243Sobrien * The following implementation produces similar code and works in all 115759243Sobrien * cases. The 4.3BSD one works only for <, >, != 115859243Sobrien */ 115959243Sobrien# undef timercmp 116059243Sobrien# define timercmp(tvp, uvp, cmp) \ 116159243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 116259243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 116359243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 116459243Sobrien 116559243Sobrienstatic void 1166167465Smpptprint(struct process *tp) 116759243Sobrien{ 116859243Sobrien#ifdef BSDTIMES 116959243Sobrien struct timeval tetime, diff; 117059243Sobrien static struct timeval ztime; 117159243Sobrien struct sysrusage ru; 1172145479Smp struct process *pp = tp; 117359243Sobrien 117459243Sobrien ru = zru; 117559243Sobrien tetime = ztime; 117659243Sobrien do { 117759243Sobrien ruadd(&ru, &pp->p_rusage); 117859243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 117959243Sobrien if (timercmp(&diff, &tetime, >)) 118059243Sobrien tetime = diff; 118159243Sobrien } while ((pp = pp->p_friends) != tp); 118259243Sobrien prusage(&zru, &ru, &tetime, &ztime); 118359243Sobrien#else /* !BSDTIMES */ 118459243Sobrien# ifdef _SEQUENT_ 118559243Sobrien timeval_t tetime, diff; 118659243Sobrien static timeval_t ztime; 118759243Sobrien struct process_stats ru; 1188145479Smp struct process *pp = tp; 118959243Sobrien 119059243Sobrien ru = zru; 119159243Sobrien tetime = ztime; 119259243Sobrien do { 119359243Sobrien ruadd(&ru, &pp->p_rusage); 119459243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 119559243Sobrien if (timercmp(&diff, &tetime, >)) 119659243Sobrien tetime = diff; 119759243Sobrien } while ((pp = pp->p_friends) != tp); 119859243Sobrien prusage(&zru, &ru, &tetime, &ztime); 119959243Sobrien# else /* !_SEQUENT_ */ 120059243Sobrien# ifndef POSIX 120159243Sobrien static time_t ztime = 0; 120259243Sobrien static time_t zu_time = 0; 120359243Sobrien static time_t zs_time = 0; 120459243Sobrien time_t tetime, diff; 120559243Sobrien time_t u_time, s_time; 120659243Sobrien 120759243Sobrien# else /* POSIX */ 120859243Sobrien static clock_t ztime = 0; 120959243Sobrien static clock_t zu_time = 0; 121059243Sobrien static clock_t zs_time = 0; 121159243Sobrien clock_t tetime, diff; 121259243Sobrien clock_t u_time, s_time; 121359243Sobrien 121459243Sobrien# endif /* POSIX */ 121559243Sobrien struct tms zts, rts; 1216145479Smp struct process *pp = tp; 121759243Sobrien 121859243Sobrien u_time = zu_time; 121959243Sobrien s_time = zs_time; 122059243Sobrien tetime = ztime; 122159243Sobrien do { 122259243Sobrien u_time += pp->p_utime; 122359243Sobrien s_time += pp->p_stime; 122459243Sobrien diff = pp->p_etime - pp->p_btime; 122559243Sobrien if (diff > tetime) 122659243Sobrien tetime = diff; 122759243Sobrien } while ((pp = pp->p_friends) != tp); 122859243Sobrien zts.tms_utime = zu_time; 122959243Sobrien zts.tms_stime = zs_time; 123059243Sobrien zts.tms_cutime = 0; 123159243Sobrien zts.tms_cstime = 0; 123259243Sobrien rts.tms_utime = u_time; 123359243Sobrien rts.tms_stime = s_time; 123459243Sobrien rts.tms_cutime = 0; 123559243Sobrien rts.tms_cstime = 0; 123659243Sobrien prusage(&zts, &rts, tetime, ztime); 123759243Sobrien# endif /* !_SEQUENT_ */ 123859243Sobrien#endif /* !BSDTIMES */ 123959243Sobrien} 124059243Sobrien 124159243Sobrien/* 124259243Sobrien * dojobs - print all jobs 124359243Sobrien */ 124459243Sobrien/*ARGSUSED*/ 124559243Sobrienvoid 1246167465Smpdojobs(Char **v, struct command *c) 124759243Sobrien{ 1248145479Smp struct process *pp; 1249145479Smp int flag = NUMBER | NAME | REASON; 125059243Sobrien int i; 125159243Sobrien 125259243Sobrien USE(c); 125359243Sobrien if (chkstop) 125459243Sobrien chkstop = 2; 125559243Sobrien if (*++v) { 125659243Sobrien if (v[1] || !eq(*v, STRml)) 125759243Sobrien stderror(ERR_JOBS); 125859243Sobrien flag |= FANCY | JOBDIR; 125959243Sobrien } 126059243Sobrien for (i = 1; i <= pmaxindex; i++) 126159243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 126259243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 126359243Sobrien pp->p_flags &= ~PNEEDNOTE; 126459243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 126559243Sobrien pflush(pp); 126659243Sobrien break; 126759243Sobrien } 126859243Sobrien} 126959243Sobrien 127059243Sobrien/* 127159243Sobrien * dofg - builtin - put the job into the foreground 127259243Sobrien */ 127359243Sobrien/*ARGSUSED*/ 127459243Sobrienvoid 1275167465Smpdofg(Char **v, struct command *c) 127659243Sobrien{ 1277145479Smp struct process *pp; 127859243Sobrien 127959243Sobrien USE(c); 128059243Sobrien okpcntl(); 128159243Sobrien ++v; 128259243Sobrien do { 128359243Sobrien pp = pfind(*v); 128459243Sobrien if (!pstart(pp, 1)) { 128559243Sobrien pp->p_procid = 0; 128659243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 128759243Sobrien continue; 128859243Sobrien } 128959243Sobrien pjwait(pp); 129059243Sobrien } while (*v && *++v); 129159243Sobrien} 129259243Sobrien 129359243Sobrien/* 129459243Sobrien * %... - builtin - put the job into the foreground 129559243Sobrien */ 129659243Sobrien/*ARGSUSED*/ 129759243Sobrienvoid 1298167465Smpdofg1(Char **v, struct command *c) 129959243Sobrien{ 1300145479Smp struct process *pp; 130159243Sobrien 130259243Sobrien USE(c); 130359243Sobrien okpcntl(); 130459243Sobrien pp = pfind(v[0]); 130559243Sobrien if (!pstart(pp, 1)) { 130659243Sobrien pp->p_procid = 0; 130759243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 130859243Sobrien return; 130959243Sobrien } 131059243Sobrien pjwait(pp); 131159243Sobrien} 131259243Sobrien 131359243Sobrien/* 131459243Sobrien * dobg - builtin - put the job into the background 131559243Sobrien */ 131659243Sobrien/*ARGSUSED*/ 131759243Sobrienvoid 1318167465Smpdobg(Char **v, struct command *c) 131959243Sobrien{ 1320145479Smp struct process *pp; 132159243Sobrien 132259243Sobrien USE(c); 132359243Sobrien okpcntl(); 132459243Sobrien ++v; 132559243Sobrien do { 132659243Sobrien pp = pfind(*v); 132759243Sobrien if (!pstart(pp, 0)) { 132859243Sobrien pp->p_procid = 0; 132959243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 133059243Sobrien } 133159243Sobrien } while (*v && *++v); 133259243Sobrien} 133359243Sobrien 133459243Sobrien/* 133559243Sobrien * %... & - builtin - put the job into the background 133659243Sobrien */ 133759243Sobrien/*ARGSUSED*/ 133859243Sobrienvoid 1339167465Smpdobg1(Char **v, struct command *c) 134059243Sobrien{ 1341145479Smp struct process *pp; 134259243Sobrien 134359243Sobrien USE(c); 134459243Sobrien pp = pfind(v[0]); 134559243Sobrien if (!pstart(pp, 0)) { 134659243Sobrien pp->p_procid = 0; 134759243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 134859243Sobrien } 134959243Sobrien} 135059243Sobrien 135159243Sobrien/* 135259243Sobrien * dostop - builtin - stop the job 135359243Sobrien */ 135459243Sobrien/*ARGSUSED*/ 135559243Sobrienvoid 1356167465Smpdostop(Char **v, struct command *c) 135759243Sobrien{ 135859243Sobrien USE(c); 135959243Sobrien#ifdef BSDJOBS 136059243Sobrien pkill(++v, SIGSTOP); 136159243Sobrien#endif /* BSDJOBS */ 136259243Sobrien} 136359243Sobrien 136459243Sobrien/* 136559243Sobrien * dokill - builtin - superset of kill (1) 136659243Sobrien */ 136759243Sobrien/*ARGSUSED*/ 136859243Sobrienvoid 1369167465Smpdokill(Char **v, struct command *c) 137059243Sobrien{ 1371145479Smp int signum, len = 0; 1372145479Smp const char *name; 137383098Smp Char *sigptr; 137459243Sobrien 137559243Sobrien USE(c); 137659243Sobrien v++; 137759243Sobrien if (v[0] && v[0][0] == '-') { 137859243Sobrien if (v[0][1] == 'l') { 137959243Sobrien for (signum = 0; signum <= nsig; signum++) { 138059243Sobrien if ((name = mesg[signum].iname) != NULL) { 138159243Sobrien len += strlen(name) + 1; 1382167465Smp if (len >= TermH - 1) { 138359243Sobrien xputchar('\n'); 138459243Sobrien len = strlen(name) + 1; 138559243Sobrien } 138659243Sobrien xprintf("%s ", name); 138759243Sobrien } 138859243Sobrien } 138959243Sobrien xputchar('\n'); 139059243Sobrien return; 139159243Sobrien } 139283098Smp sigptr = &v[0][1]; 139383098Smp if (v[0][1] == 's') { 139483098Smp if (v[1]) { 139583098Smp v++; 139683098Smp sigptr = &v[0][0]; 139783098Smp } else { 139883098Smp stderror(ERR_NAME | ERR_TOOFEW); 139983098Smp } 140083098Smp } 140183098Smp if (Isdigit(*sigptr)) { 1402131962Smp char *ep; 1403131962Smp signum = strtoul(short2str(sigptr), &ep, 0); 1404131962Smp if (*ep || signum < 0 || signum > (MAXSIG-1)) 140559243Sobrien stderror(ERR_NAME | ERR_BADSIG); 140659243Sobrien } 140759243Sobrien else { 140859243Sobrien for (signum = 0; signum <= nsig; signum++) 140959243Sobrien if (mesg[signum].iname && 141083098Smp eq(sigptr, str2short(mesg[signum].iname))) 141159243Sobrien goto gotsig; 141283098Smp setname(short2str(sigptr)); 141359243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 141459243Sobrien } 141559243Sobriengotsig: 141659243Sobrien v++; 141759243Sobrien } 141859243Sobrien else 141959243Sobrien signum = SIGTERM; 142059243Sobrien pkill(v, signum); 142159243Sobrien} 142259243Sobrien 142359243Sobrienstatic void 1424167465Smppkill(Char **v, int signum) 142559243Sobrien{ 1426145479Smp struct process *pp, *np; 142759243Sobrien int jobflags = 0, err1 = 0; 142859243Sobrien pid_t pid; 1429167465Smp Char *cp, **vp, **globbed; 143059243Sobrien 143159243Sobrien /* Avoid globbing %?x patterns */ 143259243Sobrien for (vp = v; vp && *vp; vp++) 143359243Sobrien if (**vp == '%') 143459243Sobrien (void) quote(*vp); 143559243Sobrien 1436167465Smp v = glob_all_or_error(v); 1437167465Smp globbed = v; 1438167465Smp cleanup_push(globbed, blk_cleanup); 143959243Sobrien 1440172665Smp pchild_disabled++; 1441172665Smp cleanup_push(&pchild_disabled, disabled_cleanup); 1442172665Smp if (setintr) { 1443172665Smp pintr_disabled++; 1444172665Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1445172665Smp } 144659243Sobrien 144759243Sobrien while (v && (cp = *v)) { 144859243Sobrien if (*cp == '%') { 144959243Sobrien np = pp = pfind(cp); 145059243Sobrien do 145159243Sobrien jobflags |= np->p_flags; 145259243Sobrien while ((np = np->p_friends) != pp); 145359243Sobrien#ifdef BSDJOBS 145459243Sobrien switch (signum) { 145559243Sobrien 145659243Sobrien case SIGSTOP: 145759243Sobrien case SIGTSTP: 145859243Sobrien case SIGTTIN: 145959243Sobrien case SIGTTOU: 146059243Sobrien if ((jobflags & PRUNNING) == 0) { 146159243Sobrien# ifdef SUSPENDED 146259243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 146359243Sobrien# else /* !SUSPENDED */ 146459243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 146559243Sobrien# endif /* !SUSPENDED */ 146659243Sobrien err1++; 146759243Sobrien goto cont; 146859243Sobrien } 146959243Sobrien break; 147059243Sobrien /* 147159243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 147259243Sobrien * says it is suspended, but it is running; thanks jaap.. 147359243Sobrien */ 147459243Sobrien case SIGCONT: 147559243Sobrien if (!pstart(pp, 0)) { 147659243Sobrien pp->p_procid = 0; 147759243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 147859243Sobrien strerror(errno)); 147959243Sobrien } 148059243Sobrien goto cont; 148159243Sobrien default: 148259243Sobrien break; 148359243Sobrien } 148459243Sobrien#endif /* BSDJOBS */ 148559243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 148659243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 148759243Sobrien err1++; 148859243Sobrien } 148959243Sobrien#ifdef BSDJOBS 149059243Sobrien if (signum == SIGTERM || signum == SIGHUP) 149159243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 149259243Sobrien#endif /* BSDJOBS */ 149359243Sobrien } 149459243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 149559243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 149659243Sobrien else { 1497131962Smp char *ep; 149869408Sache#ifndef WINNT_NATIVE 1499131962Smp pid = strtol(short2str(cp), &ep, 10); 150059243Sobrien#else 1501131962Smp pid = strtoul(short2str(cp), &ep, 0); 150269408Sache#endif /* WINNT_NATIVE */ 1503131962Smp if (*ep) 1504131962Smp stderror(ERR_NAME | ERR_JOBARGS); 1505131962Smp else if (kill(pid, signum) < 0) { 150659243Sobrien xprintf("%d: %s\n", pid, strerror(errno)); 150759243Sobrien err1++; 150859243Sobrien goto cont; 150959243Sobrien } 151059243Sobrien#ifdef BSDJOBS 151159243Sobrien if (signum == SIGTERM || signum == SIGHUP) 151259243Sobrien (void) kill(pid, SIGCONT); 151359243Sobrien#endif /* BSDJOBS */ 151459243Sobrien } 151559243Sobriencont: 151659243Sobrien v++; 151759243Sobrien } 1518167465Smp cleanup_until(&pchild_disabled); 151959243Sobrien if (err1) 152059243Sobrien stderror(ERR_SILENT); 152159243Sobrien} 152259243Sobrien 152359243Sobrien/* 152459243Sobrien * pstart - start the job in foreground/background 152559243Sobrien */ 152659243Sobrienint 1527167465Smppstart(struct process *pp, int foregnd) 152859243Sobrien{ 152959243Sobrien int rv = 0; 1530145479Smp struct process *np; 153159243Sobrien /* We don't use jobflags in this function right now (see below) */ 153259243Sobrien /* long jobflags = 0; */ 153359243Sobrien 1534167465Smp pchild_disabled++; 1535167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 153659243Sobrien np = pp; 153759243Sobrien do { 153859243Sobrien /* We don't use jobflags in this function right now (see below) */ 153959243Sobrien /* jobflags |= np->p_flags; */ 154059243Sobrien if (np->p_flags & (PRUNNING | PSTOPPED)) { 154159243Sobrien np->p_flags |= PRUNNING; 154259243Sobrien np->p_flags &= ~PSTOPPED; 154359243Sobrien if (foregnd) 154459243Sobrien np->p_flags |= PFOREGND; 154559243Sobrien else 154659243Sobrien np->p_flags &= ~PFOREGND; 154759243Sobrien } 154859243Sobrien } while ((np = np->p_friends) != pp); 154959243Sobrien if (!foregnd) 155059243Sobrien pclrcurr(pp); 155159243Sobrien (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 155283098Smp 155383098Smp /* GrP run jobcmd hook if foregrounding */ 155483098Smp if (foregnd) { 155583098Smp job_cmd(pp->p_command); 155683098Smp } 155783098Smp 155859243Sobrien#ifdef BSDJOBS 155959243Sobrien if (foregnd) { 156059243Sobrien rv = tcsetpgrp(FSHTTY, pp->p_jobid); 156159243Sobrien } 156259243Sobrien /* 156359243Sobrien * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU 156459243Sobrien * 2. parent process (csh) receives SIGCHLD 156559243Sobrien * 3. The "csh" signal handling function pchild() is invoked 156659243Sobrien * with a SIGCHLD signal. 156759243Sobrien * 4. pchild() calls wait3(WNOHANG) which returns 0. 156859243Sobrien * The child process is NOT ready to be waited for at this time. 156959243Sobrien * pchild() returns without picking-up the correct status 1570167465Smp * for the child process which generated the SIGCHLD. 157159243Sobrien * 5. CONSEQUENCE : csh is UNaware that the process is stopped 157259243Sobrien * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) 157359243Sobrien * (beto@aixwiz.austin.ibm.com - aug/03/91) 157459243Sobrien * 7. I removed the line completely and added extra checks for 157559243Sobrien * pstart, so that if a job gets attached to and dies inside 157659243Sobrien * a debugger it does not confuse the shell. [christos] 157759243Sobrien * 8. on the nec sx-4 there seems to be a problem, which requires 157859243Sobrien * a syscall(151, getpid(), getpid()) in osinit. Don't ask me 157959243Sobrien * what this is doing. [schott@rzg.mpg.de] 158059243Sobrien */ 158159243Sobrien 158259243Sobrien if (rv != -1) 158359243Sobrien rv = killpg(pp->p_jobid, SIGCONT); 158459243Sobrien#endif /* BSDJOBS */ 1585167465Smp cleanup_until(&pchild_disabled); 158659243Sobrien return rv != -1; 158759243Sobrien} 158859243Sobrien 158959243Sobrienvoid 1590167465Smppanystop(int neednl) 159159243Sobrien{ 1592145479Smp struct process *pp; 159359243Sobrien 159459243Sobrien chkstop = 2; 159559243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 159659243Sobrien if (pp->p_flags & PSTOPPED) 159759243Sobrien stderror(ERR_STOPPED, neednl ? "\n" : ""); 159859243Sobrien} 159959243Sobrien 160059243Sobrienstruct process * 1601167465Smppfind(Char *cp) 160259243Sobrien{ 1603145479Smp struct process *pp, *np; 160459243Sobrien 160559243Sobrien if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 160659243Sobrien if (pcurrent == NULL) 160759243Sobrien stderror(ERR_NAME | ERR_JOBCUR); 160859243Sobrien return (pcurrent); 160959243Sobrien } 161059243Sobrien if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 161159243Sobrien if (pprevious == NULL) 161259243Sobrien stderror(ERR_NAME | ERR_JOBPREV); 161359243Sobrien return (pprevious); 161459243Sobrien } 161559243Sobrien if (Isdigit(cp[1])) { 161659243Sobrien int idx = atoi(short2str(cp + 1)); 161759243Sobrien 161859243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 161959243Sobrien if (pp->p_index == idx && pp->p_procid == pp->p_jobid) 162059243Sobrien return (pp); 162159243Sobrien stderror(ERR_NAME | ERR_NOSUCHJOB); 162259243Sobrien } 162359243Sobrien np = NULL; 162459243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 162559243Sobrien if (pp->p_procid == pp->p_jobid) { 162659243Sobrien if (cp[1] == '?') { 1627145479Smp Char *dp; 162859243Sobrien 162959243Sobrien for (dp = pp->p_command; *dp; dp++) { 163059243Sobrien if (*dp != cp[2]) 163159243Sobrien continue; 163259243Sobrien if (prefix(cp + 2, dp)) 163359243Sobrien goto match; 163459243Sobrien } 163559243Sobrien } 163659243Sobrien else if (prefix(cp + 1, pp->p_command)) { 163759243Sobrien match: 163859243Sobrien if (np) 163959243Sobrien stderror(ERR_NAME | ERR_AMBIG); 164059243Sobrien np = pp; 164159243Sobrien } 164259243Sobrien } 164359243Sobrien if (np) 164459243Sobrien return (np); 164559243Sobrien stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 164659243Sobrien /* NOTREACHED */ 164759243Sobrien return (0); 164859243Sobrien} 164959243Sobrien 165059243Sobrien 165159243Sobrien/* 165259243Sobrien * pgetcurr - find most recent job that is not pp, preferably stopped 165359243Sobrien */ 165459243Sobrienstatic struct process * 1655167465Smppgetcurr(struct process *pp) 165659243Sobrien{ 1657145479Smp struct process *np; 1658145479Smp struct process *xp = NULL; 165959243Sobrien 166059243Sobrien for (np = proclist.p_next; np; np = np->p_next) 166159243Sobrien if (np != pcurrent && np != pp && np->p_procid && 166259243Sobrien np->p_procid == np->p_jobid) { 166359243Sobrien if (np->p_flags & PSTOPPED) 166459243Sobrien return (np); 166559243Sobrien if (xp == NULL) 166659243Sobrien xp = np; 166759243Sobrien } 166859243Sobrien return (xp); 166959243Sobrien} 167059243Sobrien 167159243Sobrien/* 167259243Sobrien * donotify - flag the job so as to report termination asynchronously 167359243Sobrien */ 167459243Sobrien/*ARGSUSED*/ 167559243Sobrienvoid 1676167465Smpdonotify(Char **v, struct command *c) 167759243Sobrien{ 1678145479Smp struct process *pp; 167959243Sobrien 168059243Sobrien USE(c); 168159243Sobrien pp = pfind(*++v); 168259243Sobrien pp->p_flags |= PNOTIFY; 168359243Sobrien} 168459243Sobrien 1685167465Smp#ifdef SIGSYNCH 1686167465Smpstatic void 1687167465Smpsynch_handler(int sno) 1688167465Smp{ 1689167465Smp USE(sno); 1690167465Smp} 1691167465Smp#endif /* SIGSYNCH */ 1692167465Smp 169359243Sobrien/* 169459243Sobrien * Do the fork and whatever should be done in the child side that 169559243Sobrien * should not be done if we are not forking at all (like for simple builtin's) 169659243Sobrien * Also do everything that needs any signals fiddled with in the parent side 169759243Sobrien * 169859243Sobrien * Wanttty tells whether process and/or tty pgrps are to be manipulated: 169959243Sobrien * -1: leave tty alone; inherit pgrp from parent 170059243Sobrien * 0: already have tty; manipulate process pgrps only 170159243Sobrien * 1: want to claim tty; manipulate process and tty pgrps 170259243Sobrien * It is usually just the value of tpgrp. 170359243Sobrien */ 170459243Sobrien 1705167465Smppid_t 1706167465Smppfork(struct command *t, int wanttty) 170759243Sobrien{ 1708167465Smp pid_t pid; 1709145479Smp int ignint = 0; 1710167465Smp pid_t pgrp; 171159243Sobrien#ifdef SIGSYNCH 1712167465Smp struct sigaction osa, nsa; 171359243Sobrien#endif /* SIGSYNCH */ 171459243Sobrien 171559243Sobrien /* 171659243Sobrien * A child will be uninterruptible only under very special conditions. 171759243Sobrien * Remember that the semantics of '&' is implemented by disconnecting the 171859243Sobrien * process from the tty so signals do not need to ignored just for '&'. 171959243Sobrien * Thus signals are set to default action for children unless: we have had 172059243Sobrien * an "onintr -" (then specifically ignored) we are not playing with 172159243Sobrien * signals (inherit action) 172259243Sobrien */ 172359243Sobrien if (setintr) 172459243Sobrien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 172559243Sobrien || (gointr && eq(gointr, STRminus)); 172659243Sobrien 172759243Sobrien /* 172859243Sobrien * Check for maximum nesting of 16 processes to avoid Forking loops 172959243Sobrien */ 173059243Sobrien if (child == 16) 173159243Sobrien stderror(ERR_NESTING, 16); 173259243Sobrien#ifdef SIGSYNCH 1733167465Smp nsa.sa_handler = synch_handler; 1734167465Smp sigfillset(&nsa.sa_mask); 1735167465Smp nsa.sa_flags = SA_RESTART; 1736167465Smp if (sigaction(SIGSYNCH, &nsa, &osa)) 1737167465Smp stderror(ERR_SYSTEM, "pfork: sigaction set", strerror(errno)); 173859243Sobrien#endif /* SIGSYNCH */ 173959243Sobrien /* 1740167465Smp * Hold pchild() until we have the process installed in our table. 174159243Sobrien */ 174259243Sobrien if (wanttty < 0) { 1743167465Smp pchild_disabled++; 1744167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 174559243Sobrien } 174659243Sobrien while ((pid = fork()) == -1) 174759243Sobrien if (setintr == 0) 174859243Sobrien (void) sleep(FORKSLEEP); 1749167465Smp else 175059243Sobrien stderror(ERR_NOPROC); 175159243Sobrien if (pid == 0) { 1752167465Smp (void)cleanup_push_mark(); /* Never to be popped */ 1753167465Smp pchild_disabled = 0; 175459243Sobrien settimes(); 175559243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 175659243Sobrien pflushall(); 175759243Sobrien pcurrjob = NULL; 175859243Sobrien#if !defined(BSDTIMES) && !defined(_SEQUENT_) 175959243Sobrien timesdone = 0; 176059243Sobrien#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 176159243Sobrien child++; 176259243Sobrien if (setintr) { 176359243Sobrien setintr = 0; /* until I think otherwise */ 176459243Sobrien /* 176559243Sobrien * Children just get blown away on SIGINT, SIGQUIT unless "onintr 176659243Sobrien * -" seen. 176759243Sobrien */ 176859243Sobrien (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 176959243Sobrien (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 177059243Sobrien#ifdef BSDJOBS 177159243Sobrien if (wanttty >= 0) { 177259243Sobrien /* make stoppable */ 177359243Sobrien (void) signal(SIGTSTP, SIG_DFL); 177459243Sobrien (void) signal(SIGTTIN, SIG_DFL); 177559243Sobrien (void) signal(SIGTTOU, SIG_DFL); 177659243Sobrien } 177759243Sobrien#endif /* BSDJOBS */ 1778167465Smp sigaction(SIGTERM, &parterm, NULL); 177959243Sobrien } 178059243Sobrien else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 178159243Sobrien (void) signal(SIGINT, SIG_IGN); 178259243Sobrien (void) signal(SIGQUIT, SIG_IGN); 178359243Sobrien } 178459243Sobrien#ifdef OREO 1785167465Smp signal(SIGIO, SIG_IGN); /* ignore SIGIO in child too */ 178659243Sobrien#endif /* OREO */ 178759243Sobrien 178859243Sobrien pgetty(wanttty, pgrp); 178959243Sobrien /* 179059243Sobrien * Nohup and nice apply only to NODE_COMMAND's but it would be nice 179159243Sobrien * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 179259243Sobrien * to know about nice/nohup/time 179359243Sobrien */ 179459243Sobrien if (t->t_dflg & F_NOHUP) 179559243Sobrien (void) signal(SIGHUP, SIG_IGN); 179659243Sobrien if (t->t_dflg & F_NICE) { 179759243Sobrien int nval = SIGN_EXTEND_CHAR(t->t_nice); 1798145479Smp#ifdef HAVE_SETPRIORITY 179983098Smp if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 1800167465Smp stderror(ERR_SYSTEM, "setpriority", strerror(errno)); 1801145479Smp#else /* !HAVE_SETPRIORITY */ 180259243Sobrien (void) nice(nval); 1803145479Smp#endif /* !HAVE_SETPRIORITY */ 180459243Sobrien } 180559243Sobrien#ifdef F_VER 180659243Sobrien if (t->t_dflg & F_VER) { 180759243Sobrien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 180859243Sobrien dohash(NULL, NULL); 180959243Sobrien } 181059243Sobrien#endif /* F_VER */ 181159243Sobrien#ifdef SIGSYNCH 181259243Sobrien /* rfw 8/89 now parent can continue */ 181359243Sobrien if (kill(getppid(), SIGSYNCH)) 181459243Sobrien stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 181559243Sobrien#endif /* SIGSYNCH */ 181659243Sobrien 181759243Sobrien } 181859243Sobrien else { 181959243Sobrien#ifdef POSIXJOBS 182059243Sobrien if (wanttty >= 0) { 182159243Sobrien /* 182259243Sobrien * `Walking' process group fix from Beto Appleton. 182359243Sobrien * (beto@aixwiz.austin.ibm.com) 182459243Sobrien * If setpgid fails at this point that means that 182559243Sobrien * our process leader has died. We flush the current 182659243Sobrien * job and become the process leader ourselves. 182759243Sobrien * The parent will figure that out later. 182859243Sobrien */ 182959243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : pid; 183059243Sobrien if (setpgid(pid, pgrp) == -1 && errno == EPERM) { 183159243Sobrien pcurrjob = NULL; 183259243Sobrien /* 183359243Sobrien * We don't care if this causes an error here; 183459243Sobrien * then we are already in the right process group 183559243Sobrien */ 183659243Sobrien (void) setpgid(pid, pgrp = pid); 183759243Sobrien } 183859243Sobrien } 183959243Sobrien#endif /* POSIXJOBS */ 184059243Sobrien palloc(pid, t); 184159243Sobrien#ifdef SIGSYNCH 1842167465Smp { 1843167465Smp sigset_t pause_mask; 1844167465Smp 184559243Sobrien /* 184659243Sobrien * rfw 8/89 Wait for child to own terminal. Solves half of ugly 184759243Sobrien * synchronization problem. With this change, we know that the only 184859243Sobrien * reason setpgrp to a previous process in a pipeline can fail is that 184959243Sobrien * the previous process has already exited. Without this hack, he may 185059243Sobrien * either have exited or not yet started to run. Two uglies become 185159243Sobrien * one. 185259243Sobrien */ 1853167465Smp sigprocmask(SIG_BLOCK, NULL, &pause); 1854167465Smp sigdelset(&pause_mask, SIGCHLD); 1855167465Smp sigdelset(&pause_mask, SIGSYNCH); 1856167465Smp sigsuspend(&pause_mask); 1857167465Smp handle_pending_signals(); 1858167465Smp if (sigaction(SIGSYNCH, &osa, NULL)) 1859167465Smp stderror(ERR_SYSTEM, "pfork parent: sigaction restore", 1860167465Smp strerror(errno)); 1861167465Smp } 186259243Sobrien#endif /* SIGSYNCH */ 186359243Sobrien 1864167465Smp if (wanttty < 0) 1865167465Smp cleanup_until(&pchild_disabled); 186659243Sobrien } 186759243Sobrien return (pid); 186859243Sobrien} 186959243Sobrien 187059243Sobrienstatic void 1871167465Smpokpcntl(void) 187259243Sobrien{ 187359243Sobrien if (tpgrp == -1) 187459243Sobrien stderror(ERR_JOBCONTROL); 187559243Sobrien if (tpgrp == 0) 187659243Sobrien stderror(ERR_JOBCTRLSUB); 187759243Sobrien} 187859243Sobrien 187959243Sobrien 188059243Sobrienstatic void 1881167465Smpsetttypgrp(int pgrp) 188259243Sobrien{ 188359243Sobrien /* 188459243Sobrien * If we are piping out a builtin, eg. 'echo | more' things can go 188559243Sobrien * out of sequence, i.e. the more can run before the echo. This 188659243Sobrien * can happen even if we have vfork, since the echo will be forked 188759243Sobrien * with the regular fork. In this case, we need to set the tty 188859243Sobrien * pgrp ourselves. If that happens, then the process will be still 188959243Sobrien * alive. And the tty process group will already be set. 189059243Sobrien * This should fix the famous sequent problem as a side effect: 189159243Sobrien * The controlling terminal is lost if all processes in the 189259243Sobrien * terminal process group are zombies. In this case tcgetpgrp() 189359243Sobrien * returns 0. If this happens we must set the terminal process 189459243Sobrien * group again. 189559243Sobrien */ 189659243Sobrien if (tcgetpgrp(FSHTTY) != pgrp) { 189759243Sobrien#ifdef POSIXJOBS 1898167465Smp struct sigaction old; 1899167465Smp 190059243Sobrien /* 190159243Sobrien * tcsetpgrp will set SIGTTOU to all the the processes in 190259243Sobrien * the background according to POSIX... We ignore this here. 190359243Sobrien */ 1904167465Smp sigaction(SIGTTOU, NULL, &old); 1905167465Smp signal(SIGTTOU, SIG_IGN); 190659243Sobrien#endif 190759243Sobrien (void) tcsetpgrp(FSHTTY, pgrp); 190859243Sobrien# ifdef POSIXJOBS 1909167465Smp sigaction(SIGTTOU, &old, NULL); 191059243Sobrien# endif 191159243Sobrien 191259243Sobrien } 191359243Sobrien} 191459243Sobrien 191559243Sobrien 191659243Sobrien/* 191759243Sobrien * if we don't have vfork(), things can still go in the wrong order 191859243Sobrien * resulting in the famous 'Stopped (tty output)'. But some systems 191959243Sobrien * don't permit the setpgid() call, (these are more recent secure 192059243Sobrien * systems such as ibm's aix), when they do. Then we'd rather print 192159243Sobrien * an error message than hang the shell! 192259243Sobrien * I am open to suggestions how to fix that. 192359243Sobrien */ 192459243Sobrienvoid 1925167465Smppgetty(int wanttty, pid_t pgrp) 192659243Sobrien{ 192759243Sobrien#ifdef BSDJOBS 1928167465Smp# ifdef POSIXJOBS 1929167465Smp sigset_t oset, set; 1930167465Smp# endif /* POSIXJOBS */ 193159243Sobrien 1932167465Smp jobdebug_xprintf(("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n", 1933167465Smp wanttty, (int)getpid(), (int)pgrp, (int)mygetpgrp(), 1934167465Smp (int)tcgetpgrp(FSHTTY))); 193559243Sobrien# ifdef POSIXJOBS 193659243Sobrien /* 193759243Sobrien * christos: I am blocking the tty signals till I've set things 193859243Sobrien * correctly.... 193959243Sobrien */ 1940167465Smp if (wanttty > 0) { 1941167465Smp sigemptyset(&set); 1942167465Smp sigaddset(&set, SIGTSTP); 1943167465Smp sigaddset(&set, SIGTTIN); 1944167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 1945167465Smp cleanup_push(&oset, sigprocmask_cleanup); 194659243Sobrien } 194759243Sobrien# endif /* POSIXJOBS */ 194859243Sobrien 194959243Sobrien# ifndef POSIXJOBS 195059243Sobrien if (wanttty > 0) 195159243Sobrien setttypgrp(pgrp); 195259243Sobrien# endif /* !POSIXJOBS */ 195359243Sobrien 195459243Sobrien /* 195559243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 195659243Sobrien * Don't check for tpgrp >= 0 so even non-interactive shells give 195759243Sobrien * background jobs process groups Same for the comparison in the other part 195859243Sobrien * of the #ifdef 195959243Sobrien */ 196059243Sobrien if (wanttty >= 0) { 196159243Sobrien if (setpgid(0, pgrp) == -1) { 196259243Sobrien# ifdef POSIXJOBS 196359243Sobrien /* Walking process group fix; see above */ 196459243Sobrien if (setpgid(0, pgrp = getpid()) == -1) { 196559243Sobrien# endif /* POSIXJOBS */ 196659243Sobrien stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); 196759243Sobrien xexit(0); 196859243Sobrien# ifdef POSIXJOBS 196959243Sobrien } 197059243Sobrien wanttty = pgrp; /* Now we really want the tty, since we became the 197159243Sobrien * the process group leader 197259243Sobrien */ 197359243Sobrien# endif /* POSIXJOBS */ 197459243Sobrien } 197559243Sobrien } 197659243Sobrien 197759243Sobrien# ifdef POSIXJOBS 1978167465Smp if (wanttty > 0) { 197959243Sobrien setttypgrp(pgrp); 1980167465Smp cleanup_until(&oset); 1981167465Smp } 198259243Sobrien# endif /* POSIXJOBS */ 198359243Sobrien 1984167465Smp jobdebug_xprintf(("wanttty %d pid %d pgrp %d tpgrp %d\n", 1985167465Smp wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY))); 198659243Sobrien 198759243Sobrien if (tpgrp > 0) 198859243Sobrien tpgrp = 0; /* gave tty away */ 198959243Sobrien#endif /* BSDJOBS */ 199059243Sobrien} 1991