1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.proc.c,v 3.121 2012/01/25 15:34:41 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 35232633SmpRCSID("$tcsh: sh.proc.c,v 3.121 2012/01/25 15:34:41 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 50232633Smp#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) 51232633Smp# if !defined(__ANDROID__) 52232633Smp# define BSDWAIT 53232633Smp# endif 54145479Smp#endif /* _BSD || (IRIS4D && __STDC__) || __lucid || glibc */ 5559243Sobrien#ifndef WTERMSIG 5659243Sobrien# define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 5759243Sobrien# ifndef BSDWAIT 5859243Sobrien# define BSDWAIT 5959243Sobrien# endif /* !BSDWAIT */ 6059243Sobrien#endif /* !WTERMSIG */ 6159243Sobrien#ifndef WEXITSTATUS 6259243Sobrien# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 6359243Sobrien#endif /* !WEXITSTATUS */ 6459243Sobrien#ifndef WSTOPSIG 6559243Sobrien# define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 6659243Sobrien#endif /* !WSTOPSIG */ 6759243Sobrien 6859243Sobrien#ifdef __osf__ 6959243Sobrien# ifndef WCOREDUMP 7059243Sobrien# define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) 7159243Sobrien# endif 7259243Sobrien#endif 7359243Sobrien 7459243Sobrien#ifndef WCOREDUMP 7559243Sobrien# ifdef BSDWAIT 7659243Sobrien# define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 7759243Sobrien# else /* !BSDWAIT */ 7859243Sobrien# define WCOREDUMP(w) ((w) & 0200) 7959243Sobrien# endif /* !BSDWAIT */ 8059243Sobrien#endif /* !WCOREDUMP */ 8159243Sobrien 82167465Smp#ifndef JOBDEBUG 83167465Smp# define jobdebug_xprintf(x) (void)0 84167465Smp# define jobdebug_flush() (void)0 85167465Smp#else 86167465Smp# define jobdebug_xprintf(s) xprintf s 87167465Smp# define jobdebug_flush() flush() 88167465Smp#endif 89167465Smp 9059243Sobrien/* 9159243Sobrien * C Shell - functions that manage processes, handling hanging, termination 9259243Sobrien */ 9359243Sobrien 9459243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 9559243Sobrien 9659243Sobrien#ifdef BSDTIMES 9759243Sobrien# ifdef convex 9859243Sobrien/* use 'cvxrusage' to get parallel statistics */ 9959243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 10059243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 10159243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 10259243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 10359243Sobrien# else 10459243Sobrienstatic struct rusage zru; 10559243Sobrien# endif /* convex */ 10659243Sobrien#else /* !BSDTIMES */ 10759243Sobrien# ifdef _SEQUENT_ 10859243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 10959243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 11059243Sobrien# else /* !_SEQUENT_ */ 11159243Sobrien# ifdef _SX 11259243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 11359243Sobrien# else /* !_SX */ 11459243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 11559243Sobrien# endif /* !_SX */ 11659243Sobrien# endif /* !_SEQUENT_ */ 11759243Sobrien#endif /* !BSDTIMES */ 11859243Sobrien 119167465Smp#ifndef BSDTIMES 120167465Smpstatic int timesdone; /* shtimes buffer full ? */ 121167465Smp#endif /* BSDTIMES */ 122167465Smp 12359243Sobrien#ifndef RUSAGE_CHILDREN 12459243Sobrien# define RUSAGE_CHILDREN -1 12559243Sobrien#endif /* RUSAGE_CHILDREN */ 12659243Sobrien 127167465Smpstatic void pflushall (void); 128167465Smpstatic void pflush (struct process *); 129167465Smpstatic void pfree (struct process *); 130167465Smpstatic void pclrcurr (struct process *); 131195609Smpstatic void morecommand (size_t); 132167465Smpstatic void padd (struct command *); 133167465Smpstatic int pprint (struct process *, int); 134167465Smpstatic void ptprint (struct process *); 135167465Smpstatic void pads (Char *); 136167465Smpstatic void pkill (Char **, int); 137167465Smpstatic struct process *pgetcurr (struct process *); 138167465Smpstatic void okpcntl (void); 139167465Smpstatic void setttypgrp (int); 14059243Sobrien 14159243Sobrien/* 142167465Smp * pchild - call queued by the SIGCHLD signal 14359243Sobrien * indicating that at least one child has terminated or stopped 14459243Sobrien * thus at least one wait system call will definitely return a 14559243Sobrien * childs status. Top level routines (like pwait) must be sure 14659243Sobrien * to mask interrupts when playing with the proclist data structures! 14759243Sobrien */ 148167465Smpvoid 149167465Smppchild(void) 15059243Sobrien{ 151145479Smp struct process *pp; 152145479Smp struct process *fp; 153167465Smp pid_t pid; 15459243Sobrien#ifdef BSDWAIT 15559243Sobrien union wait w; 15659243Sobrien#else /* !BSDWAIT */ 15759243Sobrien int w; 15859243Sobrien#endif /* !BSDWAIT */ 15959243Sobrien int jobflags; 16059243Sobrien#ifdef BSDTIMES 16159243Sobrien struct sysrusage ru; 16259243Sobrien#else /* !BSDTIMES */ 16359243Sobrien# ifdef _SEQUENT_ 16459243Sobrien struct process_stats ru; 16559243Sobrien struct process_stats cpst1, cpst2; 16659243Sobrien timeval_t tv; 16759243Sobrien# else /* !_SEQUENT_ */ 16859243Sobrien struct tms proctimes; 16959243Sobrien 17059243Sobrien if (!timesdone) { 17159243Sobrien timesdone++; 17259243Sobrien (void) times(&shtimes); 17359243Sobrien } 17459243Sobrien# endif /* !_SEQUENT_ */ 17559243Sobrien#endif /* !BSDTIMES */ 17659243Sobrien 177167465Smp jobdebug_xprintf(("pchild()\n")); 17859243Sobrien 17959243Sobrienloop: 180167465Smp jobdebug_xprintf(("Waiting...\n")); 181167465Smp jobdebug_flush(); 18259243Sobrien errno = 0; /* reset, just in case */ 183167465Smp 18469408Sache#ifndef WINNT_NATIVE 18559243Sobrien# ifdef BSDJOBS 18659243Sobrien# ifdef BSDTIMES 18759243Sobrien# ifdef convex 18859243Sobrien /* use 'cvxwait' to get parallel statistics */ 18959243Sobrien pid = cvxwait(&w, 19059243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19159243Sobrien# else 19259243Sobrien /* both a wait3 and rusage */ 193232633Smp# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 19459243Sobrien pid = wait3(&w, 19559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19659243Sobrien# else /* BSDWAIT */ 19759243Sobrien pid = wait3(&w.w_status, 19859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19959243Sobrien# endif /* BSDWAIT */ 20059243Sobrien# endif /* convex */ 20159243Sobrien# else /* !BSDTIMES */ 20259243Sobrien# ifdef _SEQUENT_ 20359243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 20459243Sobrien pid = waitpid(-1, &w, 20559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 20659243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 20759243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 20859243Sobrien# else /* !_SEQUENT_ */ 20959243Sobrien# ifndef POSIX 21059243Sobrien /* we have a wait3, but no rusage stuff */ 21159243Sobrien pid = wait3(&w.w_status, 21259243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 21359243Sobrien# else /* POSIX */ 21459243Sobrien pid = waitpid(-1, &w, 21559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 21659243Sobrien# endif /* POSIX */ 21759243Sobrien# endif /* !_SEQUENT_ */ 21859243Sobrien# endif /* !BSDTIMES */ 21959243Sobrien# else /* !BSDJOBS */ 22059243Sobrien# ifdef BSDTIMES 22159243Sobrien# define HAVEwait3 22259243Sobrien /* both a wait3 and rusage */ 22359243Sobrien# ifdef hpux 22459243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 22559243Sobrien# else /* !hpux */ 226232633Smp# ifndef BSDWAIT 227232633Smp pid = wait3(&w, WNOHANG, &ru); 228232633Smp# else 22959243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 230232633Smp# endif /* BSDWAIT */ 23159243Sobrien# endif /* !hpux */ 23259243Sobrien# else /* !BSDTIMES */ 23359243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 23459243Sobrien# define HAVEwait3 235167465Smp pid = waitpid(-1, &w, 23659243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 23759243Sobrien# endif /* ODT */ 23859243Sobrien# if defined(aiws) || defined(uts) 23959243Sobrien# define HAVEwait3 24059243Sobrien pid = wait3(&w.w_status, 24159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 24259243Sobrien# endif /* aiws || uts */ 24359243Sobrien# ifndef HAVEwait3 244167465Smp# ifndef BSDWAIT 24559243Sobrien /* no wait3, therefore no rusage */ 24659243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 247167465Smp pid = wait(&w); 248167465Smp# else /* BSDWAIT */ 24959243Sobrien /* 25059243Sobrien * XXX: for greater than 3 we should use waitpid(). 25159243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 25259243Sobrien */ 253167465Smp pid = wait(&w.w_status); 254167465Smp# endif /* BSDWAIT */ 25559243Sobrien# endif /* !HAVEwait3 */ 25659243Sobrien# endif /* !BSDTIMES */ 25759243Sobrien# endif /* !BSDJOBS */ 25869408Sache#else /* WINNT_NATIVE */ 259167465Smp pid = waitpid(-1, &w, 26059243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 26169408Sache#endif /* WINNT_NATIVE */ 26259243Sobrien 263167465Smp jobdebug_xprintf(("parent %d pid %d, retval %x termsig %x retcode %x\n", 264167465Smp (int)getpid(), (int)pid, w, WTERMSIG(w), 265167465Smp WEXITSTATUS(w))); 266167465Smp jobdebug_flush(); 26759243Sobrien 26859243Sobrien if ((pid == 0) || (pid == -1)) { 269232633Smp (void)handle_pending_signals(); 270167465Smp jobdebug_xprintf(("errno == %d\n", errno)); 271167465Smp if (errno == EINTR) 27259243Sobrien goto loop; 273145479Smp goto end; 27459243Sobrien } 27559243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 27659243Sobrien if (pid == pp->p_procid) 27759243Sobrien goto found; 27869408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 27959243Sobrien /* this should never have happened */ 28059243Sobrien stderror(ERR_SYNC, pid); 28159243Sobrien xexit(0); 28269408Sache#else /* BSDJOBS || WINNT_NATIVE */ 28359243Sobrien goto loop; 28469408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 28559243Sobrienfound: 28659243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 28759243Sobrien if (WIFSTOPPED(w)) { 28859243Sobrien pp->p_flags |= PSTOPPED; 28959243Sobrien pp->p_reason = WSTOPSIG(w); 29059243Sobrien } 29159243Sobrien else { 29259243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 29359243Sobrien#ifndef BSDTIMES 29459243Sobrien# ifdef _SEQUENT_ 29559243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 29659243Sobrien# else /* !_SEQUENT_ */ 29759243Sobrien pp->p_etime = times(&proctimes); 29859243Sobrien# endif /* !_SEQUENT_ */ 29959243Sobrien#else /* BSDTIMES */ 30059243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 30159243Sobrien#endif /* BSDTIMES */ 30259243Sobrien 30359243Sobrien 30459243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 30559243Sobrien pp->p_rusage = ru; 30659243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 30759243Sobrien (void) times(&proctimes); 30859243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 30959243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 31059243Sobrien shtimes = proctimes; 31159243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 31259243Sobrien if (WIFSIGNALED(w)) { 31359243Sobrien if (WTERMSIG(w) == SIGINT) 31459243Sobrien pp->p_flags |= PINTERRUPTED; 31559243Sobrien else 31659243Sobrien pp->p_flags |= PSIGNALED; 31759243Sobrien if (WCOREDUMP(w)) 31859243Sobrien pp->p_flags |= PDUMPED; 31959243Sobrien pp->p_reason = WTERMSIG(w); 32059243Sobrien } 32159243Sobrien else { 32259243Sobrien pp->p_reason = WEXITSTATUS(w); 32359243Sobrien if (pp->p_reason != 0) 32459243Sobrien pp->p_flags |= PAEXITED; 32559243Sobrien else 32659243Sobrien pp->p_flags |= PNEXITED; 32759243Sobrien } 32859243Sobrien } 32959243Sobrien jobflags = 0; 33059243Sobrien fp = pp; 33159243Sobrien do { 33259243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 33359243Sobrien !child && adrof(STRtime) && 33459243Sobrien#ifdef BSDTIMES 33559243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 33659243Sobrien#else /* !BSDTIMES */ 33759243Sobrien# ifdef _SEQUENT_ 33859243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 33959243Sobrien# else /* !_SEQUENT_ */ 34059243Sobrien# ifndef POSIX 34159243Sobrien (fp->p_utime + fp->p_stime) / HZ 34259243Sobrien# else /* POSIX */ 34359243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 34459243Sobrien# endif /* POSIX */ 34559243Sobrien# endif /* !_SEQUENT_ */ 34659243Sobrien#endif /* !BSDTIMES */ 34759243Sobrien >= atoi(short2str(varval(STRtime)))) 34859243Sobrien fp->p_flags |= PTIME; 34959243Sobrien jobflags |= fp->p_flags; 35059243Sobrien } while ((fp = fp->p_friends) != pp); 35159243Sobrien pp->p_flags &= ~PFOREGND; 35259243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 35359243Sobrien pp->p_flags &= ~PPTIME; 35459243Sobrien pp->p_flags |= PTIME; 35559243Sobrien } 35659243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 35759243Sobrien fp = pp; 35859243Sobrien do { 35959243Sobrien if (fp->p_flags & PSTOPPED) 36059243Sobrien fp->p_flags |= PREPORTED; 36159243Sobrien } while ((fp = fp->p_friends) != pp); 36259243Sobrien while (fp->p_procid != fp->p_jobid) 36359243Sobrien fp = fp->p_friends; 36459243Sobrien if (jobflags & PSTOPPED) { 36559243Sobrien if (pcurrent && pcurrent != fp) 36659243Sobrien pprevious = pcurrent; 36759243Sobrien pcurrent = fp; 36859243Sobrien } 36959243Sobrien else 37059243Sobrien pclrcurr(fp); 37159243Sobrien if (jobflags & PFOREGND) { 37259243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 37359243Sobrien#ifdef notdef 37459243Sobrien jobflags & PAEXITED || 37559243Sobrien#endif /* notdef */ 376232633Smp fp->p_cwd == NULL || 37759243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 37859243Sobrien /* PWP: print a newline after ^C */ 37959243Sobrien if (jobflags & PINTERRUPTED) { 380167465Smp xputchar('\r' | QUOTE); 381167465Smp xputchar('\n'); 38259243Sobrien } 38359243Sobrien#ifdef notdef 38459243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 38559243Sobrien ptprint(fp); 38659243Sobrien#endif /* notdef */ 38759243Sobrien } 38859243Sobrien } 38959243Sobrien else { 39059243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 391167465Smp xputchar('\r' | QUOTE); 392167465Smp xputchar('\n'); 39359243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 39459243Sobrien if ((jobflags & PSTOPPED) == 0) 39559243Sobrien pflush(pp); 396167465Smp if (GettingInput) { 397167465Smp errno = 0; 398167465Smp (void) Rawmode(); 39959243Sobrien#ifdef notdef 400167465Smp /* 401167465Smp * don't really want to do that, because it 402167465Smp * will erase our message in case of multi-line 403167465Smp * input 404167465Smp */ 405167465Smp ClearLines(); 40659243Sobrien#endif /* notdef */ 407167465Smp ClearDisp(); 408167465Smp Refresh(); 40959243Sobrien } 41059243Sobrien } 41159243Sobrien else { 41259243Sobrien fp->p_flags |= PNEEDNOTE; 413167465Smp neednote = 1; 41459243Sobrien } 41559243Sobrien } 41659243Sobrien } 417167465Smp#if defined(BSDJOBS) || defined(HAVEwait3) ||defined(WINNT_NATIVE) 41859243Sobrien goto loop; 41959243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 420145479Smp end: 421145479Smp ; 42259243Sobrien} 42359243Sobrien 42459243Sobrienvoid 425167465Smppnote(void) 42659243Sobrien{ 427145479Smp struct process *pp; 42859243Sobrien int flags; 42959243Sobrien 43059243Sobrien neednote = 0; 43159243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 43259243Sobrien if (pp->p_flags & PNEEDNOTE) { 433167465Smp pchild_disabled++; 434167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 43559243Sobrien pp->p_flags &= ~PNEEDNOTE; 43659243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 43759243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 43859243Sobrien pflush(pp); 439167465Smp cleanup_until(&pchild_disabled); 44059243Sobrien } 44159243Sobrien } 44259243Sobrien} 44359243Sobrien 44459243Sobrien 44559243Sobrienstatic void 446167465Smppfree(struct process *pp) 44759243Sobrien{ 448167465Smp xfree(pp->p_command); 44959243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 45059243Sobrien if (pp->p_cwd->di_next == 0) 45159243Sobrien dfree(pp->p_cwd); 452167465Smp xfree(pp); 45359243Sobrien} 45459243Sobrien 45559243Sobrien 45659243Sobrien/* 45759243Sobrien * pwait - wait for current job to terminate, maintaining integrity 45859243Sobrien * of current and previous job indicators. 45959243Sobrien */ 46059243Sobrienvoid 461167465Smppwait(void) 46259243Sobrien{ 463145479Smp struct process *fp, *pp; 46459243Sobrien 46559243Sobrien /* 46659243Sobrien * Here's where dead procs get flushed. 46759243Sobrien */ 46859243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 46959243Sobrien if (pp->p_procid == 0) { 47059243Sobrien fp->p_next = pp->p_next; 47159243Sobrien pfree(pp); 47259243Sobrien pp = fp; 47359243Sobrien } 47459243Sobrien pjwait(pcurrjob); 47559243Sobrien} 47659243Sobrien 47759243Sobrien 47859243Sobrien/* 47959243Sobrien * pjwait - wait for a job to finish or become stopped 48059243Sobrien * It is assumed to be in the foreground state (PFOREGND) 48159243Sobrien */ 48259243Sobrienvoid 483167465Smppjwait(struct process *pp) 48459243Sobrien{ 485145479Smp struct process *fp; 48659243Sobrien int jobflags, reason; 487167465Smp sigset_t oset, set, pause_mask; 488167465Smp Char *reason_str; 489167465Smp 49059243Sobrien while (pp->p_procid != pp->p_jobid) 49159243Sobrien pp = pp->p_friends; 49259243Sobrien fp = pp; 49359243Sobrien 49459243Sobrien do { 49559243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 496195609Smp xprintf("%s", CGETS(17, 1, "BUG: waiting for background job!\n")); 49759243Sobrien } while ((fp = fp->p_friends) != pp); 49859243Sobrien /* 49959243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 50059243Sobrien * target process, or any of its friends, are running 50159243Sobrien */ 50259243Sobrien fp = pp; 503167465Smp sigemptyset(&set); 504167465Smp sigaddset(&set, SIGINT); 505167465Smp sigaddset(&set, SIGCHLD); 506167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 507167465Smp cleanup_push(&oset, sigprocmask_cleanup); 508167465Smp pause_mask = oset; 509167465Smp sigdelset(&pause_mask, SIGCHLD); 51059243Sobrien for (;;) { 511232633Smp (void)handle_pending_signals(); 51259243Sobrien jobflags = 0; 51359243Sobrien do 51459243Sobrien jobflags |= fp->p_flags; 51559243Sobrien while ((fp = (fp->p_friends)) != pp); 51659243Sobrien if ((jobflags & PRUNNING) == 0) 51759243Sobrien break; 518167465Smp jobdebug_xprintf(("%d starting to sigsuspend for SIGCHLD on %d\n", 519167465Smp getpid(), fp->p_procid)); 520167465Smp sigsuspend(&pause_mask); 52159243Sobrien } 522167465Smp cleanup_until(&oset); 523167465Smp jobdebug_xprintf(("%d returned from sigsuspend loop\n", getpid())); 52459243Sobrien#ifdef BSDJOBS 52559243Sobrien if (tpgrp > 0) /* get tty back */ 52659243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 52759243Sobrien#endif /* BSDJOBS */ 52859243Sobrien if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 529195609Smp fp->p_cwd == NULL || !eq(dcwd->di_name, fp->p_cwd->di_name)) { 53059243Sobrien if (jobflags & PSTOPPED) { 53159243Sobrien xputchar('\n'); 53259243Sobrien if (adrof(STRlistjobs)) { 53359243Sobrien Char *jobcommand[3]; 53459243Sobrien 53559243Sobrien jobcommand[0] = STRjobs; 53659243Sobrien if (eq(varval(STRlistjobs), STRlong)) 53759243Sobrien jobcommand[1] = STRml; 53859243Sobrien else 53959243Sobrien jobcommand[1] = NULL; 54059243Sobrien jobcommand[2] = NULL; 54159243Sobrien 54259243Sobrien dojobs(jobcommand, NULL); 54359243Sobrien (void) pprint(pp, SHELLDIR); 54459243Sobrien } 54559243Sobrien else 54659243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 54759243Sobrien } 54859243Sobrien else 54959243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 55059243Sobrien } 55159243Sobrien if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 55259243Sobrien (!gointr || !eq(gointr, STRminus))) { 55359243Sobrien if ((jobflags & PSTOPPED) == 0) 55459243Sobrien pflush(pp); 55559243Sobrien pintr1(0); 55659243Sobrien /* NOTREACHED */ 55759243Sobrien } 55859243Sobrien reason = 0; 55959243Sobrien fp = pp; 56059243Sobrien do { 561232633Smp /* In case of pipelines only the result of the last 562232633Smp * command should be taken in account */ 563232633Smp if (!anyerror && !(fp->p_flags & PBRACE) 564232633Smp && ((fp->p_flags & PPOU) || (fp->p_flags & PBACKQ))) 565232633Smp continue; 56659243Sobrien if (fp->p_reason) 56759243Sobrien reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 56859243Sobrien fp->p_reason | META : fp->p_reason; 56959243Sobrien } while ((fp = fp->p_friends) != pp); 57059243Sobrien /* 57159243Sobrien * Don't report on backquoted jobs, cause it will mess up 57259243Sobrien * their output. 57359243Sobrien */ 57459243Sobrien if ((reason != 0) && (adrof(STRprintexitvalue)) && 57559243Sobrien (pp->p_flags & PBACKQ) == 0) 57659243Sobrien xprintf(CGETS(17, 2, "Exit %d\n"), reason); 577232633Smp reason_str = putn((tcsh_number_t)reason); 578167465Smp cleanup_push(reason_str, xfree); 579167465Smp setv(STRstatus, reason_str, VAR_READWRITE); 580167465Smp cleanup_ignore(reason_str); 581167465Smp cleanup_until(reason_str); 58259243Sobrien if (reason && exiterr) 58359243Sobrien exitstat(); 58459243Sobrien pflush(pp); 58559243Sobrien} 58659243Sobrien 58759243Sobrien/* 58859243Sobrien * dowait - wait for all processes to finish 58959243Sobrien */ 59059243Sobrien 59159243Sobrien/*ARGSUSED*/ 59259243Sobrienvoid 593167465Smpdowait(Char **v, struct command *c) 59459243Sobrien{ 595145479Smp struct process *pp; 596167465Smp sigset_t pause_mask; 597232633Smp int opintr_disabled, gotsig; 59859243Sobrien 59959243Sobrien USE(c); 60059243Sobrien USE(v); 60159243Sobrien pjobs++; 602167465Smp sigprocmask(SIG_BLOCK, NULL, &pause_mask); 603167465Smp sigdelset(&pause_mask, SIGCHLD); 60459243Sobrien if (setintr) 605167465Smp sigdelset(&pause_mask, SIGINT); 60659243Sobrienloop: 60759243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 60859243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 60959243Sobrien pp->p_flags & PRUNNING) { 610232633Smp (void)handle_pending_signals(); 611167465Smp sigsuspend(&pause_mask); 612232633Smp opintr_disabled = pintr_disabled; 613232633Smp pintr_disabled = 0; 614232633Smp gotsig = handle_pending_signals(); 615232633Smp pintr_disabled = opintr_disabled; 616232633Smp if (gotsig) 617232633Smp break; 61859243Sobrien goto loop; 61959243Sobrien } 62059243Sobrien pjobs = 0; 62159243Sobrien} 62259243Sobrien 62359243Sobrien/* 62459243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 62559243Sobrien */ 62659243Sobrienstatic void 627167465Smppflushall(void) 62859243Sobrien{ 629145479Smp struct process *pp; 63059243Sobrien 63159243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 63259243Sobrien if (pp->p_procid) 63359243Sobrien pflush(pp); 63459243Sobrien} 63559243Sobrien 63659243Sobrien/* 63759243Sobrien * pflush - flag all process structures in the same job as the 63859243Sobrien * the argument process for deletion. The actual free of the 63959243Sobrien * space is not done here since pflush is called at interrupt level. 64059243Sobrien */ 64159243Sobrienstatic void 642167465Smppflush(struct process *pp) 64359243Sobrien{ 644145479Smp struct process *np; 645145479Smp int idx; 64659243Sobrien 64759243Sobrien if (pp->p_procid == 0) { 648195609Smp xprintf("%s", CGETS(17, 3, "BUG: process flushed twice")); 64959243Sobrien return; 65059243Sobrien } 65159243Sobrien while (pp->p_procid != pp->p_jobid) 65259243Sobrien pp = pp->p_friends; 65359243Sobrien pclrcurr(pp); 65459243Sobrien if (pp == pcurrjob) 65559243Sobrien pcurrjob = 0; 65659243Sobrien idx = pp->p_index; 65759243Sobrien np = pp; 65859243Sobrien do { 65959243Sobrien np->p_index = np->p_procid = 0; 66059243Sobrien np->p_flags &= ~PNEEDNOTE; 66159243Sobrien } while ((np = np->p_friends) != pp); 66259243Sobrien if (idx == pmaxindex) { 66359243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 66459243Sobrien if (np->p_index > idx) 66559243Sobrien idx = np->p_index; 66659243Sobrien pmaxindex = idx; 66759243Sobrien } 66859243Sobrien} 66959243Sobrien 67059243Sobrien/* 67159243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 67259243Sobrien * pp MUST be the job leader 67359243Sobrien */ 67459243Sobrienstatic void 675167465Smppclrcurr(struct process *pp) 67659243Sobrien{ 67759243Sobrien if (pp == pcurrent) { 67859243Sobrien if (pprevious != NULL) { 67959243Sobrien pcurrent = pprevious; 68059243Sobrien pprevious = pgetcurr(pp); 68159243Sobrien } 68259243Sobrien else { 68359243Sobrien pcurrent = pgetcurr(pp); 68459243Sobrien pprevious = pgetcurr(pp); 68559243Sobrien } 68659243Sobrien } 68759243Sobrien else if (pp == pprevious) 68859243Sobrien pprevious = pgetcurr(pp); 68959243Sobrien} 69059243Sobrien 69159243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 692195609Smpstatic Char *cmdstr; 693195609Smpstatic size_t cmdmax; 694167465Smpstatic size_t cmdlen; 69559243Sobrienstatic Char *cmdp; 696195609Smp#define CMD_INIT 1024 697195609Smp#define CMD_INCR 64 69859243Sobrien 699195609Smpstatic void 700195609Smpmorecommand(size_t s) 701195609Smp{ 702195609Smp Char *ncmdstr; 703195609Smp ptrdiff_t d; 704195609Smp 705195609Smp cmdmax += s; 706195609Smp ncmdstr = xrealloc(cmdstr, cmdmax * sizeof(*cmdstr)); 707195609Smp d = ncmdstr - cmdstr; 708195609Smp cmdstr = ncmdstr; 709195609Smp cmdp += d; 710195609Smp} 711195609Smp 71283098Smp/* GrP 71383098Smp * unparse - Export padd() functionality 71483098Smp */ 71583098SmpChar * 716167465Smpunparse(struct command *t) 71783098Smp{ 718195609Smp if (cmdmax == 0) 719195609Smp morecommand(CMD_INIT); 720195609Smp cmdp = cmdstr; 72183098Smp cmdlen = 0; 72283098Smp padd(t); 72383098Smp *cmdp++ = '\0'; 724195609Smp return Strsave(cmdstr); 72583098Smp} 72683098Smp 72783098Smp 72859243Sobrien/* 72959243Sobrien * palloc - allocate a process structure and fill it up. 73059243Sobrien * an important assumption is made that the process is running. 73159243Sobrien */ 73259243Sobrienvoid 733167465Smppalloc(pid_t pid, struct command *t) 73459243Sobrien{ 735145479Smp struct process *pp; 73659243Sobrien int i; 73759243Sobrien 738167465Smp pp = xcalloc(1, sizeof(struct process)); 73959243Sobrien pp->p_procid = pid; 740232633Smp pp->p_parentid = shpgrp; 74159243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 74259243Sobrien if (t->t_dflg & F_TIME) 74359243Sobrien pp->p_flags |= PPTIME; 74459243Sobrien if (t->t_dflg & F_BACKQ) 74559243Sobrien pp->p_flags |= PBACKQ; 74659243Sobrien if (t->t_dflg & F_HUP) 74759243Sobrien pp->p_flags |= PHUP; 748232633Smp if (t->t_dcom && t->t_dcom[0] && (*t->t_dcom[0] == '{')) 749232633Smp pp->p_flags |= PBRACE; 750195609Smp if (cmdmax == 0) 751195609Smp morecommand(CMD_INIT); 752195609Smp cmdp = cmdstr; 75359243Sobrien cmdlen = 0; 75459243Sobrien padd(t); 75559243Sobrien *cmdp++ = 0; 75659243Sobrien if (t->t_dflg & F_PIPEOUT) { 75759243Sobrien pp->p_flags |= PPOU; 75859243Sobrien if (t->t_dflg & F_STDERR) 75959243Sobrien pp->p_flags |= PDIAG; 76059243Sobrien } 761195609Smp pp->p_command = Strsave(cmdstr); 76259243Sobrien if (pcurrjob) { 76359243Sobrien struct process *fp; 76459243Sobrien 76559243Sobrien /* careful here with interrupt level */ 76659243Sobrien pp->p_cwd = 0; 76759243Sobrien pp->p_index = pcurrjob->p_index; 76859243Sobrien pp->p_friends = pcurrjob; 76959243Sobrien pp->p_jobid = pcurrjob->p_procid; 77059243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 77159243Sobrien continue; 77259243Sobrien fp->p_friends = pp; 77359243Sobrien } 77459243Sobrien else { 77559243Sobrien pcurrjob = pp; 77659243Sobrien pp->p_jobid = pid; 77759243Sobrien pp->p_friends = pp; 77859243Sobrien pp->p_cwd = dcwd; 77959243Sobrien dcwd->di_count++; 78059243Sobrien if (pmaxindex < BIGINDEX) 78159243Sobrien pp->p_index = ++pmaxindex; 78259243Sobrien else { 78359243Sobrien struct process *np; 78459243Sobrien 78559243Sobrien for (i = 1;; i++) { 78659243Sobrien for (np = proclist.p_next; np; np = np->p_next) 78759243Sobrien if (np->p_index == i) 78859243Sobrien goto tryagain; 78959243Sobrien pp->p_index = i; 79059243Sobrien if (i > pmaxindex) 79159243Sobrien pmaxindex = i; 79259243Sobrien break; 79359243Sobrien tryagain:; 79459243Sobrien } 79559243Sobrien } 79659243Sobrien if (pcurrent == NULL) 79759243Sobrien pcurrent = pp; 79859243Sobrien else if (pprevious == NULL) 79959243Sobrien pprevious = pp; 80059243Sobrien } 80159243Sobrien pp->p_next = proclist.p_next; 80259243Sobrien proclist.p_next = pp; 80359243Sobrien#ifdef BSDTIMES 80459243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 80559243Sobrien#else /* !BSDTIMES */ 80659243Sobrien# ifdef _SEQUENT_ 80759243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 80859243Sobrien# else /* !_SEQUENT_ */ 80959243Sobrien { 81059243Sobrien struct tms tmptimes; 81159243Sobrien 81259243Sobrien pp->p_btime = times(&tmptimes); 81359243Sobrien } 81459243Sobrien# endif /* !_SEQUENT_ */ 81559243Sobrien#endif /* !BSDTIMES */ 81659243Sobrien} 81759243Sobrien 81859243Sobrienstatic void 819167465Smppadd(struct command *t) 82059243Sobrien{ 82159243Sobrien Char **argp; 82259243Sobrien 82359243Sobrien if (t == 0) 82459243Sobrien return; 82559243Sobrien switch (t->t_dtyp) { 82659243Sobrien 82759243Sobrien case NODE_PAREN: 82859243Sobrien pads(STRLparensp); 82959243Sobrien padd(t->t_dspr); 83059243Sobrien pads(STRspRparen); 83159243Sobrien break; 83259243Sobrien 83359243Sobrien case NODE_COMMAND: 83459243Sobrien for (argp = t->t_dcom; *argp; argp++) { 83559243Sobrien pads(*argp); 83659243Sobrien if (argp[1]) 83759243Sobrien pads(STRspace); 83859243Sobrien } 83959243Sobrien break; 84059243Sobrien 84159243Sobrien case NODE_OR: 84259243Sobrien case NODE_AND: 84359243Sobrien case NODE_PIPE: 84459243Sobrien case NODE_LIST: 84559243Sobrien padd(t->t_dcar); 84659243Sobrien switch (t->t_dtyp) { 84759243Sobrien case NODE_OR: 84859243Sobrien pads(STRspor2sp); 84959243Sobrien break; 85059243Sobrien case NODE_AND: 85159243Sobrien pads(STRspand2sp); 85259243Sobrien break; 85359243Sobrien case NODE_PIPE: 85459243Sobrien pads(STRsporsp); 85559243Sobrien break; 85659243Sobrien case NODE_LIST: 85759243Sobrien pads(STRsemisp); 85859243Sobrien break; 85959243Sobrien default: 86059243Sobrien break; 86159243Sobrien } 86259243Sobrien padd(t->t_dcdr); 86359243Sobrien return; 86459243Sobrien 86559243Sobrien default: 86659243Sobrien break; 86759243Sobrien } 86859243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 86959243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 87059243Sobrien pads(t->t_dlef); 87159243Sobrien } 87259243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 87359243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 87459243Sobrien if (t->t_dflg & F_STDERR) 87559243Sobrien pads(STRand); 87659243Sobrien pads(STRspace); 87759243Sobrien pads(t->t_drit); 87859243Sobrien } 87959243Sobrien} 88059243Sobrien 88159243Sobrienstatic void 882167465Smppads(Char *cp) 88359243Sobrien{ 884195609Smp size_t i, len; 88559243Sobrien 88659243Sobrien /* 88759243Sobrien * Avoid the Quoted Space alias hack! Reported by: 88859243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 88959243Sobrien */ 89059243Sobrien if (cp[0] == STRQNULL[0]) 89159243Sobrien cp++; 89259243Sobrien 893167465Smp i = Strlen(cp); 89459243Sobrien 895195609Smp len = cmdlen + i + CMD_INCR; 896195609Smp if (len >= cmdmax) 897195609Smp morecommand(len); 89859243Sobrien (void) Strcpy(cmdp, cp); 89959243Sobrien cmdp += i; 90059243Sobrien cmdlen += i; 90159243Sobrien} 90259243Sobrien 90359243Sobrien/* 90459243Sobrien * psavejob - temporarily save the current job on a one level stack 90559243Sobrien * so another job can be created. Used for { } in exp6 90659243Sobrien * and `` in globbing. 90759243Sobrien */ 90859243Sobrienvoid 909167465Smppsavejob(void) 91059243Sobrien{ 91159243Sobrien pholdjob = pcurrjob; 91259243Sobrien pcurrjob = NULL; 91359243Sobrien} 91459243Sobrien 91559243Sobrienvoid 916167465Smppsavejob_cleanup(void *dummy) 91759243Sobrien{ 918167465Smp USE(dummy); 91959243Sobrien pcurrjob = pholdjob; 92059243Sobrien pholdjob = NULL; 92159243Sobrien} 92259243Sobrien 92359243Sobrien/* 92459243Sobrien * pendjob - indicate that a job (set of commands) has been completed 92559243Sobrien * or is about to begin. 92659243Sobrien */ 92759243Sobrienvoid 928167465Smppendjob(void) 92959243Sobrien{ 930145479Smp struct process *pp, *tp; 93159243Sobrien 93259243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 93359243Sobrien pp = pcurrjob; 934232633Smp pcurrjob = NULL; 93559243Sobrien while (pp->p_procid != pp->p_jobid) 93659243Sobrien pp = pp->p_friends; 93759243Sobrien xprintf("[%d]", pp->p_index); 93859243Sobrien tp = pp; 93959243Sobrien do { 94059243Sobrien xprintf(" %d", pp->p_procid); 94159243Sobrien pp = pp->p_friends; 94259243Sobrien } while (pp != tp); 94359243Sobrien xputchar('\n'); 94459243Sobrien } 94559243Sobrien pholdjob = pcurrjob = 0; 94659243Sobrien} 94759243Sobrien 94859243Sobrien/* 94959243Sobrien * pprint - print a job 95059243Sobrien */ 95159243Sobrien 95259243Sobrien/* 95359243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 95459243Sobrien * reverse order 95559243Sobrien * 95659243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 95759243Sobrien */ 95859243Sobrien 95959243Sobrienstatic int 960167465Smppprint(struct process *pp, int flag) 96159243Sobrien{ 96259243Sobrien int status, reason; 96359243Sobrien struct process *tp; 96459243Sobrien int jobflags, pstatus, pcond; 965145479Smp const char *format; 96659243Sobrien 96759243Sobrien#ifdef BACKPIPE 96859243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 96959243Sobrien int inpipe = 0; 97059243Sobrien#endif /* BACKPIPE */ 97159243Sobrien 97259243Sobrien while (pp->p_procid != pp->p_jobid) 97359243Sobrien pp = pp->p_friends; 97459243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 97559243Sobrien pp->p_flags &= ~PPTIME; 97659243Sobrien pp->p_flags |= PTIME; 97759243Sobrien } 97859243Sobrien tp = pp; 97959243Sobrien status = reason = -1; 98059243Sobrien jobflags = 0; 98159243Sobrien do { 98259243Sobrien#ifdef BACKPIPE 98359243Sobrien /* 98459243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 98559243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 98659243Sobrien */ 98759243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 98859243Sobrien inpipe = 1; 98959243Sobrien pipetail = pp; 99059243Sobrien do 99159243Sobrien pp = pp->p_friends; 99259243Sobrien while (pp->p_friends->p_flags & PPOU); 99359243Sobrien pipehead = pp; 99459243Sobrien pmarker = pp; 99559243Sobrien /* 99659243Sobrien * pmarker is used to hold the place of the proc being processed, so 99759243Sobrien * we can search for the next one downstream later. 99859243Sobrien */ 99959243Sobrien } 1000167465Smp pcond = (tp != pp || (inpipe && tp == pp)); 100159243Sobrien#else /* !BACKPIPE */ 1002167465Smp pcond = (tp != pp); 100359243Sobrien#endif /* BACKPIPE */ 100459243Sobrien 100559243Sobrien jobflags |= pp->p_flags; 100659243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 100759243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 100859243Sobrien ((pstatus == status && pp->p_reason == reason) || 100959243Sobrien !(flag & REASON))) 101059243Sobrien xputchar(' '); 101159243Sobrien else { 101259243Sobrien if (pcond && linp != linbuf) 101359243Sobrien xputchar('\n'); 101459243Sobrien if (flag & NUMBER) { 101559243Sobrien#ifdef BACKPIPE 101659243Sobrien pcond = ((pp == tp && !inpipe) || 101759243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 101859243Sobrien#else /* BACKPIPE */ 101959243Sobrien pcond = (pp == tp); 102059243Sobrien#endif /* BACKPIPE */ 102159243Sobrien if (pcond) 102259243Sobrien xprintf("[%d]%s %c ", pp->p_index, 102359243Sobrien pp->p_index < 10 ? " " : "", 102459243Sobrien pp == pcurrent ? '+' : 102559243Sobrien (pp == pprevious ? '-' : ' ')); 102659243Sobrien else 102759243Sobrien xprintf(" "); 102859243Sobrien } 102959243Sobrien if (flag & FANCY) { 103059243Sobrien xprintf("%5d ", pp->p_procid); 103159243Sobrien#ifdef TCF 103259243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 103359243Sobrien#endif /* TCF */ 103459243Sobrien } 103559243Sobrien if (flag & (REASON | AREASON)) { 103659243Sobrien if (flag & NAME) 103759243Sobrien format = "%-30s"; 103859243Sobrien else 103959243Sobrien format = "%s"; 104059243Sobrien if (pstatus == status) { 104159243Sobrien if (pp->p_reason == reason) { 104259243Sobrien xprintf(format, ""); 104359243Sobrien goto prcomd; 104459243Sobrien } 104559243Sobrien else 104659243Sobrien reason = (int) pp->p_reason; 104759243Sobrien } 104859243Sobrien else { 104959243Sobrien status = pstatus; 105059243Sobrien reason = (int) pp->p_reason; 105159243Sobrien } 105259243Sobrien switch (status) { 105359243Sobrien 105459243Sobrien case PRUNNING: 105559243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 105659243Sobrien break; 105759243Sobrien 105859243Sobrien case PINTERRUPTED: 105959243Sobrien case PSTOPPED: 106059243Sobrien case PSIGNALED: 106159243Sobrien /* 106259243Sobrien * tell what happened to the background job 1063167465Smp * From: Michael Schroeder 106459243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 106559243Sobrien */ 106659243Sobrien if ((flag & REASON) 106759243Sobrien || ((flag & AREASON) 106859243Sobrien && reason != SIGINT 106959243Sobrien && (reason != SIGPIPE 107059243Sobrien || (pp->p_flags & PPOU) == 0))) { 1071167465Smp char *ptr; 1072167465Smp int free_ptr; 107359243Sobrien 1074167465Smp free_ptr = 0; 1075167465Smp ptr = (char *)(intptr_t)mesg[pp->p_reason & 0177].pname; 1076167465Smp if (ptr == NULL) { 1077167465Smp ptr = xasprintf("%s %d", CGETS(17, 5, "Signal"), 1078167465Smp pp->p_reason & 0177); 1079167465Smp cleanup_push(ptr, xfree); 1080167465Smp free_ptr = 1; 1081145479Smp } 108259243Sobrien xprintf(format, ptr); 1083167465Smp if (free_ptr != 0) 1084167465Smp cleanup_until(ptr); 108559243Sobrien } 108659243Sobrien else 108759243Sobrien reason = -1; 108859243Sobrien break; 108959243Sobrien 109059243Sobrien case PNEXITED: 109159243Sobrien case PAEXITED: 109259243Sobrien if (flag & REASON) { 109359243Sobrien if (pp->p_reason) 109459243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 109559243Sobrien else 109659243Sobrien xprintf(format, CGETS(17, 7, "Done")); 109759243Sobrien } 109859243Sobrien break; 109959243Sobrien 110059243Sobrien default: 110159243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 110259243Sobrien status); 110359243Sobrien } 110459243Sobrien } 110559243Sobrien } 110659243Sobrienprcomd: 110759243Sobrien if (flag & NAME) { 110859243Sobrien xprintf("%S", pp->p_command); 110959243Sobrien if (pp->p_flags & PPOU) 111059243Sobrien xprintf(" |"); 111159243Sobrien if (pp->p_flags & PDIAG) 111259243Sobrien xprintf("&"); 111359243Sobrien } 111459243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 1115195609Smp xprintf("%s", CGETS(17, 9, " (core dumped)")); 111659243Sobrien if (tp == pp->p_friends) { 111759243Sobrien if (flag & AMPERSAND) 111859243Sobrien xprintf(" &"); 111959243Sobrien if (flag & JOBDIR && 112059243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1121195609Smp xprintf("%s", CGETS(17, 10, " (wd: ")); 112259243Sobrien dtildepr(tp->p_cwd->di_name); 112359243Sobrien xprintf(")"); 112459243Sobrien } 112559243Sobrien } 112659243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 112759243Sobrien if (linp != linbuf) 112859243Sobrien xprintf("\n\t"); 112959243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 113059243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 113159243Sobrien &pp->p_btime); 113259243Sobrien#else /* !BSDTIMES && !SEQUENT */ 113359243Sobrien lru.tms_utime = pp->p_utime; 113459243Sobrien lru.tms_stime = pp->p_stime; 113559243Sobrien lru.tms_cutime = 0; 113659243Sobrien lru.tms_cstime = 0; 113759243Sobrien prusage(&zru, &lru, pp->p_etime, 113859243Sobrien pp->p_btime); 113959243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 114059243Sobrien 114159243Sobrien } 114259243Sobrien#ifdef BACKPIPE 114359243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 114459243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 114559243Sobrien#else /* !BACKPIPE */ 114659243Sobrien pcond = (tp == pp->p_friends); 114759243Sobrien#endif /* BACKPIPE */ 114859243Sobrien if (pcond) { 114959243Sobrien if (linp != linbuf) 115059243Sobrien xputchar('\n'); 115159243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1152195609Smp xprintf("%s", CGETS(17, 11, "(wd now: ")); 115359243Sobrien dtildepr(dcwd->di_name); 115459243Sobrien xprintf(")\n"); 115559243Sobrien } 115659243Sobrien } 115759243Sobrien#ifdef BACKPIPE 115859243Sobrien if (inpipe) { 115959243Sobrien /* 116059243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 116159243Sobrien * can now skip to past the head 116259243Sobrien */ 116359243Sobrien if (pmarker == pipetail) { 116459243Sobrien inpipe = 0; 116559243Sobrien pp = pipehead; 116659243Sobrien } 116759243Sobrien else { 116859243Sobrien /* 116959243Sobrien * set pp to one before the one we want next, so the while below 117059243Sobrien * increments to the correct spot. 117159243Sobrien */ 117259243Sobrien do 117359243Sobrien pp = pp->p_friends; 117459243Sobrien while (pp->p_friends->p_friends != pmarker); 117559243Sobrien pmarker = pp->p_friends; 117659243Sobrien } 117759243Sobrien } 117859243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 117959243Sobrien#else /* !BACKPIPE */ 118059243Sobrien pcond = ((pp = pp->p_friends) != tp); 118159243Sobrien#endif /* BACKPIPE */ 118259243Sobrien } while (pcond); 118359243Sobrien 118459243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 118559243Sobrien if (jobflags & NUMBER) 118659243Sobrien xprintf(" "); 118759243Sobrien ptprint(tp); 118859243Sobrien } 118959243Sobrien return (jobflags); 119059243Sobrien} 119159243Sobrien 119259243Sobrien/* 119359243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 119459243Sobrien * The following implementation produces similar code and works in all 119559243Sobrien * cases. The 4.3BSD one works only for <, >, != 119659243Sobrien */ 119759243Sobrien# undef timercmp 119859243Sobrien# define timercmp(tvp, uvp, cmp) \ 119959243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 120059243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 120159243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 120259243Sobrien 120359243Sobrienstatic void 1204167465Smpptprint(struct process *tp) 120559243Sobrien{ 120659243Sobrien#ifdef BSDTIMES 120759243Sobrien struct timeval tetime, diff; 120859243Sobrien static struct timeval ztime; 120959243Sobrien struct sysrusage ru; 1210145479Smp struct process *pp = tp; 121159243Sobrien 121259243Sobrien ru = zru; 121359243Sobrien tetime = ztime; 121459243Sobrien do { 121559243Sobrien ruadd(&ru, &pp->p_rusage); 121659243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 121759243Sobrien if (timercmp(&diff, &tetime, >)) 121859243Sobrien tetime = diff; 121959243Sobrien } while ((pp = pp->p_friends) != tp); 122059243Sobrien prusage(&zru, &ru, &tetime, &ztime); 122159243Sobrien#else /* !BSDTIMES */ 122259243Sobrien# ifdef _SEQUENT_ 122359243Sobrien timeval_t tetime, diff; 122459243Sobrien static timeval_t ztime; 122559243Sobrien struct process_stats ru; 1226145479Smp struct process *pp = tp; 122759243Sobrien 122859243Sobrien ru = zru; 122959243Sobrien tetime = ztime; 123059243Sobrien do { 123159243Sobrien ruadd(&ru, &pp->p_rusage); 123259243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 123359243Sobrien if (timercmp(&diff, &tetime, >)) 123459243Sobrien tetime = diff; 123559243Sobrien } while ((pp = pp->p_friends) != tp); 123659243Sobrien prusage(&zru, &ru, &tetime, &ztime); 123759243Sobrien# else /* !_SEQUENT_ */ 123859243Sobrien# ifndef POSIX 123959243Sobrien static time_t ztime = 0; 124059243Sobrien static time_t zu_time = 0; 124159243Sobrien static time_t zs_time = 0; 124259243Sobrien time_t tetime, diff; 124359243Sobrien time_t u_time, s_time; 124459243Sobrien 124559243Sobrien# else /* POSIX */ 124659243Sobrien static clock_t ztime = 0; 124759243Sobrien static clock_t zu_time = 0; 124859243Sobrien static clock_t zs_time = 0; 124959243Sobrien clock_t tetime, diff; 125059243Sobrien clock_t u_time, s_time; 125159243Sobrien 125259243Sobrien# endif /* POSIX */ 125359243Sobrien struct tms zts, rts; 1254145479Smp struct process *pp = tp; 125559243Sobrien 125659243Sobrien u_time = zu_time; 125759243Sobrien s_time = zs_time; 125859243Sobrien tetime = ztime; 125959243Sobrien do { 126059243Sobrien u_time += pp->p_utime; 126159243Sobrien s_time += pp->p_stime; 126259243Sobrien diff = pp->p_etime - pp->p_btime; 126359243Sobrien if (diff > tetime) 126459243Sobrien tetime = diff; 126559243Sobrien } while ((pp = pp->p_friends) != tp); 126659243Sobrien zts.tms_utime = zu_time; 126759243Sobrien zts.tms_stime = zs_time; 126859243Sobrien zts.tms_cutime = 0; 126959243Sobrien zts.tms_cstime = 0; 127059243Sobrien rts.tms_utime = u_time; 127159243Sobrien rts.tms_stime = s_time; 127259243Sobrien rts.tms_cutime = 0; 127359243Sobrien rts.tms_cstime = 0; 127459243Sobrien prusage(&zts, &rts, tetime, ztime); 127559243Sobrien# endif /* !_SEQUENT_ */ 127659243Sobrien#endif /* !BSDTIMES */ 127759243Sobrien} 127859243Sobrien 127959243Sobrien/* 128059243Sobrien * dojobs - print all jobs 128159243Sobrien */ 128259243Sobrien/*ARGSUSED*/ 128359243Sobrienvoid 1284167465Smpdojobs(Char **v, struct command *c) 128559243Sobrien{ 1286145479Smp struct process *pp; 1287145479Smp int flag = NUMBER | NAME | REASON; 128859243Sobrien int i; 128959243Sobrien 129059243Sobrien USE(c); 129159243Sobrien if (chkstop) 129259243Sobrien chkstop = 2; 129359243Sobrien if (*++v) { 129459243Sobrien if (v[1] || !eq(*v, STRml)) 129559243Sobrien stderror(ERR_JOBS); 129659243Sobrien flag |= FANCY | JOBDIR; 129759243Sobrien } 129859243Sobrien for (i = 1; i <= pmaxindex; i++) 129959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 130059243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 130159243Sobrien pp->p_flags &= ~PNEEDNOTE; 130259243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 130359243Sobrien pflush(pp); 130459243Sobrien break; 130559243Sobrien } 130659243Sobrien} 130759243Sobrien 130859243Sobrien/* 130959243Sobrien * dofg - builtin - put the job into the foreground 131059243Sobrien */ 131159243Sobrien/*ARGSUSED*/ 131259243Sobrienvoid 1313167465Smpdofg(Char **v, struct command *c) 131459243Sobrien{ 1315145479Smp struct process *pp; 131659243Sobrien 131759243Sobrien USE(c); 131859243Sobrien okpcntl(); 131959243Sobrien ++v; 132059243Sobrien do { 132159243Sobrien pp = pfind(*v); 132259243Sobrien if (!pstart(pp, 1)) { 132359243Sobrien pp->p_procid = 0; 132459243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 132559243Sobrien continue; 132659243Sobrien } 132759243Sobrien pjwait(pp); 132859243Sobrien } while (*v && *++v); 132959243Sobrien} 133059243Sobrien 133159243Sobrien/* 133259243Sobrien * %... - builtin - put the job into the foreground 133359243Sobrien */ 133459243Sobrien/*ARGSUSED*/ 133559243Sobrienvoid 1336167465Smpdofg1(Char **v, struct command *c) 133759243Sobrien{ 1338145479Smp struct process *pp; 133959243Sobrien 134059243Sobrien USE(c); 134159243Sobrien okpcntl(); 134259243Sobrien pp = pfind(v[0]); 134359243Sobrien if (!pstart(pp, 1)) { 134459243Sobrien pp->p_procid = 0; 134559243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 134659243Sobrien return; 134759243Sobrien } 134859243Sobrien pjwait(pp); 134959243Sobrien} 135059243Sobrien 135159243Sobrien/* 135259243Sobrien * dobg - builtin - put the job into the background 135359243Sobrien */ 135459243Sobrien/*ARGSUSED*/ 135559243Sobrienvoid 1356167465Smpdobg(Char **v, struct command *c) 135759243Sobrien{ 1358145479Smp struct process *pp; 135959243Sobrien 136059243Sobrien USE(c); 136159243Sobrien okpcntl(); 136259243Sobrien ++v; 136359243Sobrien do { 136459243Sobrien pp = pfind(*v); 136559243Sobrien if (!pstart(pp, 0)) { 136659243Sobrien pp->p_procid = 0; 136759243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 136859243Sobrien } 136959243Sobrien } while (*v && *++v); 137059243Sobrien} 137159243Sobrien 137259243Sobrien/* 137359243Sobrien * %... & - builtin - put the job into the background 137459243Sobrien */ 137559243Sobrien/*ARGSUSED*/ 137659243Sobrienvoid 1377167465Smpdobg1(Char **v, struct command *c) 137859243Sobrien{ 1379145479Smp struct process *pp; 138059243Sobrien 138159243Sobrien USE(c); 138259243Sobrien pp = pfind(v[0]); 138359243Sobrien if (!pstart(pp, 0)) { 138459243Sobrien pp->p_procid = 0; 138559243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 138659243Sobrien } 138759243Sobrien} 138859243Sobrien 138959243Sobrien/* 139059243Sobrien * dostop - builtin - stop the job 139159243Sobrien */ 139259243Sobrien/*ARGSUSED*/ 139359243Sobrienvoid 1394167465Smpdostop(Char **v, struct command *c) 139559243Sobrien{ 139659243Sobrien USE(c); 139759243Sobrien#ifdef BSDJOBS 139859243Sobrien pkill(++v, SIGSTOP); 139959243Sobrien#endif /* BSDJOBS */ 140059243Sobrien} 140159243Sobrien 140259243Sobrien/* 140359243Sobrien * dokill - builtin - superset of kill (1) 140459243Sobrien */ 140559243Sobrien/*ARGSUSED*/ 140659243Sobrienvoid 1407167465Smpdokill(Char **v, struct command *c) 140859243Sobrien{ 1409145479Smp int signum, len = 0; 1410145479Smp const char *name; 141183098Smp Char *sigptr; 141259243Sobrien 141359243Sobrien USE(c); 141459243Sobrien v++; 141559243Sobrien if (v[0] && v[0][0] == '-') { 141659243Sobrien if (v[0][1] == 'l') { 141759243Sobrien for (signum = 0; signum <= nsig; signum++) { 141859243Sobrien if ((name = mesg[signum].iname) != NULL) { 141959243Sobrien len += strlen(name) + 1; 1420167465Smp if (len >= TermH - 1) { 142159243Sobrien xputchar('\n'); 142259243Sobrien len = strlen(name) + 1; 142359243Sobrien } 142459243Sobrien xprintf("%s ", name); 142559243Sobrien } 142659243Sobrien } 142759243Sobrien xputchar('\n'); 142859243Sobrien return; 142959243Sobrien } 143083098Smp sigptr = &v[0][1]; 143183098Smp if (v[0][1] == 's') { 143283098Smp if (v[1]) { 143383098Smp v++; 143483098Smp sigptr = &v[0][0]; 143583098Smp } else { 143683098Smp stderror(ERR_NAME | ERR_TOOFEW); 143783098Smp } 143883098Smp } 143983098Smp if (Isdigit(*sigptr)) { 1440131962Smp char *ep; 1441131962Smp signum = strtoul(short2str(sigptr), &ep, 0); 1442131962Smp if (*ep || signum < 0 || signum > (MAXSIG-1)) 144359243Sobrien stderror(ERR_NAME | ERR_BADSIG); 144459243Sobrien } 144559243Sobrien else { 144659243Sobrien for (signum = 0; signum <= nsig; signum++) 144759243Sobrien if (mesg[signum].iname && 144883098Smp eq(sigptr, str2short(mesg[signum].iname))) 144959243Sobrien goto gotsig; 145083098Smp setname(short2str(sigptr)); 145159243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 145259243Sobrien } 145359243Sobriengotsig: 145459243Sobrien v++; 145559243Sobrien } 145659243Sobrien else 145759243Sobrien signum = SIGTERM; 145859243Sobrien pkill(v, signum); 145959243Sobrien} 146059243Sobrien 146159243Sobrienstatic void 1462167465Smppkill(Char **v, int signum) 146359243Sobrien{ 1464145479Smp struct process *pp, *np; 146559243Sobrien int jobflags = 0, err1 = 0; 146659243Sobrien pid_t pid; 1467167465Smp Char *cp, **vp, **globbed; 146859243Sobrien 146959243Sobrien /* Avoid globbing %?x patterns */ 147059243Sobrien for (vp = v; vp && *vp; vp++) 147159243Sobrien if (**vp == '%') 147259243Sobrien (void) quote(*vp); 147359243Sobrien 1474167465Smp v = glob_all_or_error(v); 1475167465Smp globbed = v; 1476167465Smp cleanup_push(globbed, blk_cleanup); 147759243Sobrien 1478172665Smp pchild_disabled++; 1479172665Smp cleanup_push(&pchild_disabled, disabled_cleanup); 1480172665Smp if (setintr) { 1481172665Smp pintr_disabled++; 1482172665Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1483172665Smp } 148459243Sobrien 148559243Sobrien while (v && (cp = *v)) { 148659243Sobrien if (*cp == '%') { 148759243Sobrien np = pp = pfind(cp); 148859243Sobrien do 148959243Sobrien jobflags |= np->p_flags; 149059243Sobrien while ((np = np->p_friends) != pp); 149159243Sobrien#ifdef BSDJOBS 149259243Sobrien switch (signum) { 149359243Sobrien 149459243Sobrien case SIGSTOP: 149559243Sobrien case SIGTSTP: 149659243Sobrien case SIGTTIN: 149759243Sobrien case SIGTTOU: 149859243Sobrien if ((jobflags & PRUNNING) == 0) { 149959243Sobrien# ifdef SUSPENDED 150059243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 150159243Sobrien# else /* !SUSPENDED */ 150259243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 150359243Sobrien# endif /* !SUSPENDED */ 150459243Sobrien err1++; 150559243Sobrien goto cont; 150659243Sobrien } 150759243Sobrien break; 150859243Sobrien /* 150959243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 151059243Sobrien * says it is suspended, but it is running; thanks jaap.. 151159243Sobrien */ 151259243Sobrien case SIGCONT: 151359243Sobrien if (!pstart(pp, 0)) { 151459243Sobrien pp->p_procid = 0; 151559243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 151659243Sobrien strerror(errno)); 151759243Sobrien } 151859243Sobrien goto cont; 151959243Sobrien default: 152059243Sobrien break; 152159243Sobrien } 152259243Sobrien#endif /* BSDJOBS */ 152359243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 152459243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 152559243Sobrien err1++; 152659243Sobrien } 152759243Sobrien#ifdef BSDJOBS 152859243Sobrien if (signum == SIGTERM || signum == SIGHUP) 152959243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 153059243Sobrien#endif /* BSDJOBS */ 153159243Sobrien } 153259243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 153359243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 153459243Sobrien else { 1535131962Smp char *ep; 153669408Sache#ifndef WINNT_NATIVE 1537131962Smp pid = strtol(short2str(cp), &ep, 10); 153859243Sobrien#else 1539131962Smp pid = strtoul(short2str(cp), &ep, 0); 154069408Sache#endif /* WINNT_NATIVE */ 1541131962Smp if (*ep) 1542131962Smp stderror(ERR_NAME | ERR_JOBARGS); 1543131962Smp else if (kill(pid, signum) < 0) { 154459243Sobrien xprintf("%d: %s\n", pid, strerror(errno)); 154559243Sobrien err1++; 154659243Sobrien goto cont; 154759243Sobrien } 154859243Sobrien#ifdef BSDJOBS 154959243Sobrien if (signum == SIGTERM || signum == SIGHUP) 155059243Sobrien (void) kill(pid, SIGCONT); 155159243Sobrien#endif /* BSDJOBS */ 155259243Sobrien } 155359243Sobriencont: 155459243Sobrien v++; 155559243Sobrien } 1556167465Smp cleanup_until(&pchild_disabled); 155759243Sobrien if (err1) 155859243Sobrien stderror(ERR_SILENT); 155959243Sobrien} 156059243Sobrien 156159243Sobrien/* 156259243Sobrien * pstart - start the job in foreground/background 156359243Sobrien */ 156459243Sobrienint 1565167465Smppstart(struct process *pp, int foregnd) 156659243Sobrien{ 156759243Sobrien int rv = 0; 1568145479Smp struct process *np; 156959243Sobrien /* We don't use jobflags in this function right now (see below) */ 157059243Sobrien /* long jobflags = 0; */ 157159243Sobrien 1572167465Smp pchild_disabled++; 1573167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 157459243Sobrien np = pp; 157559243Sobrien do { 157659243Sobrien /* We don't use jobflags in this function right now (see below) */ 157759243Sobrien /* jobflags |= np->p_flags; */ 157859243Sobrien if (np->p_flags & (PRUNNING | PSTOPPED)) { 157959243Sobrien np->p_flags |= PRUNNING; 158059243Sobrien np->p_flags &= ~PSTOPPED; 158159243Sobrien if (foregnd) 158259243Sobrien np->p_flags |= PFOREGND; 158359243Sobrien else 158459243Sobrien np->p_flags &= ~PFOREGND; 158559243Sobrien } 158659243Sobrien } while ((np = np->p_friends) != pp); 158759243Sobrien if (!foregnd) 158859243Sobrien pclrcurr(pp); 158959243Sobrien (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 159083098Smp 159183098Smp /* GrP run jobcmd hook if foregrounding */ 159283098Smp if (foregnd) { 159383098Smp job_cmd(pp->p_command); 159483098Smp } 159583098Smp 159659243Sobrien#ifdef BSDJOBS 159759243Sobrien if (foregnd) { 159859243Sobrien rv = tcsetpgrp(FSHTTY, pp->p_jobid); 159959243Sobrien } 160059243Sobrien /* 160159243Sobrien * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU 160259243Sobrien * 2. parent process (csh) receives SIGCHLD 160359243Sobrien * 3. The "csh" signal handling function pchild() is invoked 160459243Sobrien * with a SIGCHLD signal. 160559243Sobrien * 4. pchild() calls wait3(WNOHANG) which returns 0. 160659243Sobrien * The child process is NOT ready to be waited for at this time. 160759243Sobrien * pchild() returns without picking-up the correct status 1608167465Smp * for the child process which generated the SIGCHLD. 160959243Sobrien * 5. CONSEQUENCE : csh is UNaware that the process is stopped 161059243Sobrien * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) 161159243Sobrien * (beto@aixwiz.austin.ibm.com - aug/03/91) 161259243Sobrien * 7. I removed the line completely and added extra checks for 161359243Sobrien * pstart, so that if a job gets attached to and dies inside 161459243Sobrien * a debugger it does not confuse the shell. [christos] 161559243Sobrien * 8. on the nec sx-4 there seems to be a problem, which requires 161659243Sobrien * a syscall(151, getpid(), getpid()) in osinit. Don't ask me 161759243Sobrien * what this is doing. [schott@rzg.mpg.de] 161859243Sobrien */ 161959243Sobrien 162059243Sobrien if (rv != -1) 162159243Sobrien rv = killpg(pp->p_jobid, SIGCONT); 162259243Sobrien#endif /* BSDJOBS */ 1623167465Smp cleanup_until(&pchild_disabled); 162459243Sobrien return rv != -1; 162559243Sobrien} 162659243Sobrien 162759243Sobrienvoid 1628167465Smppanystop(int neednl) 162959243Sobrien{ 1630145479Smp struct process *pp; 163159243Sobrien 163259243Sobrien chkstop = 2; 163359243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 163459243Sobrien if (pp->p_flags & PSTOPPED) 163559243Sobrien stderror(ERR_STOPPED, neednl ? "\n" : ""); 163659243Sobrien} 163759243Sobrien 163859243Sobrienstruct process * 1639167465Smppfind(Char *cp) 164059243Sobrien{ 1641145479Smp struct process *pp, *np; 164259243Sobrien 164359243Sobrien if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 164459243Sobrien if (pcurrent == NULL) 164559243Sobrien stderror(ERR_NAME | ERR_JOBCUR); 164659243Sobrien return (pcurrent); 164759243Sobrien } 164859243Sobrien if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 164959243Sobrien if (pprevious == NULL) 165059243Sobrien stderror(ERR_NAME | ERR_JOBPREV); 165159243Sobrien return (pprevious); 165259243Sobrien } 165359243Sobrien if (Isdigit(cp[1])) { 165459243Sobrien int idx = atoi(short2str(cp + 1)); 165559243Sobrien 165659243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 165759243Sobrien if (pp->p_index == idx && pp->p_procid == pp->p_jobid) 165859243Sobrien return (pp); 165959243Sobrien stderror(ERR_NAME | ERR_NOSUCHJOB); 166059243Sobrien } 166159243Sobrien np = NULL; 166259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 166359243Sobrien if (pp->p_procid == pp->p_jobid) { 166459243Sobrien if (cp[1] == '?') { 1665145479Smp Char *dp; 166659243Sobrien 166759243Sobrien for (dp = pp->p_command; *dp; dp++) { 166859243Sobrien if (*dp != cp[2]) 166959243Sobrien continue; 167059243Sobrien if (prefix(cp + 2, dp)) 167159243Sobrien goto match; 167259243Sobrien } 167359243Sobrien } 167459243Sobrien else if (prefix(cp + 1, pp->p_command)) { 167559243Sobrien match: 167659243Sobrien if (np) 167759243Sobrien stderror(ERR_NAME | ERR_AMBIG); 167859243Sobrien np = pp; 167959243Sobrien } 168059243Sobrien } 168159243Sobrien if (np) 168259243Sobrien return (np); 168359243Sobrien stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 168459243Sobrien /* NOTREACHED */ 168559243Sobrien return (0); 168659243Sobrien} 168759243Sobrien 168859243Sobrien 168959243Sobrien/* 169059243Sobrien * pgetcurr - find most recent job that is not pp, preferably stopped 169159243Sobrien */ 169259243Sobrienstatic struct process * 1693167465Smppgetcurr(struct process *pp) 169459243Sobrien{ 1695145479Smp struct process *np; 1696145479Smp struct process *xp = NULL; 169759243Sobrien 169859243Sobrien for (np = proclist.p_next; np; np = np->p_next) 169959243Sobrien if (np != pcurrent && np != pp && np->p_procid && 170059243Sobrien np->p_procid == np->p_jobid) { 170159243Sobrien if (np->p_flags & PSTOPPED) 170259243Sobrien return (np); 170359243Sobrien if (xp == NULL) 170459243Sobrien xp = np; 170559243Sobrien } 170659243Sobrien return (xp); 170759243Sobrien} 170859243Sobrien 170959243Sobrien/* 171059243Sobrien * donotify - flag the job so as to report termination asynchronously 171159243Sobrien */ 171259243Sobrien/*ARGSUSED*/ 171359243Sobrienvoid 1714167465Smpdonotify(Char **v, struct command *c) 171559243Sobrien{ 1716145479Smp struct process *pp; 171759243Sobrien 171859243Sobrien USE(c); 171959243Sobrien pp = pfind(*++v); 172059243Sobrien pp->p_flags |= PNOTIFY; 172159243Sobrien} 172259243Sobrien 1723167465Smp#ifdef SIGSYNCH 1724167465Smpstatic void 1725167465Smpsynch_handler(int sno) 1726167465Smp{ 1727167465Smp USE(sno); 1728167465Smp} 1729167465Smp#endif /* SIGSYNCH */ 1730167465Smp 173159243Sobrien/* 173259243Sobrien * Do the fork and whatever should be done in the child side that 173359243Sobrien * should not be done if we are not forking at all (like for simple builtin's) 173459243Sobrien * Also do everything that needs any signals fiddled with in the parent side 173559243Sobrien * 173659243Sobrien * Wanttty tells whether process and/or tty pgrps are to be manipulated: 173759243Sobrien * -1: leave tty alone; inherit pgrp from parent 173859243Sobrien * 0: already have tty; manipulate process pgrps only 173959243Sobrien * 1: want to claim tty; manipulate process and tty pgrps 174059243Sobrien * It is usually just the value of tpgrp. 174159243Sobrien */ 174259243Sobrien 1743167465Smppid_t 1744167465Smppfork(struct command *t, int wanttty) 174559243Sobrien{ 1746167465Smp pid_t pid; 1747145479Smp int ignint = 0; 1748167465Smp pid_t pgrp; 174959243Sobrien#ifdef SIGSYNCH 1750167465Smp struct sigaction osa, nsa; 175159243Sobrien#endif /* SIGSYNCH */ 175259243Sobrien 175359243Sobrien /* 175459243Sobrien * A child will be uninterruptible only under very special conditions. 175559243Sobrien * Remember that the semantics of '&' is implemented by disconnecting the 175659243Sobrien * process from the tty so signals do not need to ignored just for '&'. 175759243Sobrien * Thus signals are set to default action for children unless: we have had 175859243Sobrien * an "onintr -" (then specifically ignored) we are not playing with 175959243Sobrien * signals (inherit action) 176059243Sobrien */ 176159243Sobrien if (setintr) 176259243Sobrien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 176359243Sobrien || (gointr && eq(gointr, STRminus)); 176459243Sobrien 176559243Sobrien /* 176659243Sobrien * Check for maximum nesting of 16 processes to avoid Forking loops 176759243Sobrien */ 176859243Sobrien if (child == 16) 176959243Sobrien stderror(ERR_NESTING, 16); 177059243Sobrien#ifdef SIGSYNCH 1771167465Smp nsa.sa_handler = synch_handler; 1772167465Smp sigfillset(&nsa.sa_mask); 1773167465Smp nsa.sa_flags = SA_RESTART; 1774167465Smp if (sigaction(SIGSYNCH, &nsa, &osa)) 1775167465Smp stderror(ERR_SYSTEM, "pfork: sigaction set", strerror(errno)); 177659243Sobrien#endif /* SIGSYNCH */ 177759243Sobrien /* 1778167465Smp * Hold pchild() until we have the process installed in our table. 177959243Sobrien */ 178059243Sobrien if (wanttty < 0) { 1781167465Smp pchild_disabled++; 1782167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 178359243Sobrien } 178459243Sobrien while ((pid = fork()) == -1) 178559243Sobrien if (setintr == 0) 178659243Sobrien (void) sleep(FORKSLEEP); 1787167465Smp else 178859243Sobrien stderror(ERR_NOPROC); 178959243Sobrien if (pid == 0) { 1790167465Smp (void)cleanup_push_mark(); /* Never to be popped */ 1791167465Smp pchild_disabled = 0; 179259243Sobrien settimes(); 179359243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 179459243Sobrien pflushall(); 179559243Sobrien pcurrjob = NULL; 179659243Sobrien#if !defined(BSDTIMES) && !defined(_SEQUENT_) 179759243Sobrien timesdone = 0; 179859243Sobrien#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 179959243Sobrien child++; 180059243Sobrien if (setintr) { 180159243Sobrien setintr = 0; /* until I think otherwise */ 180259243Sobrien /* 180359243Sobrien * Children just get blown away on SIGINT, SIGQUIT unless "onintr 180459243Sobrien * -" seen. 180559243Sobrien */ 180659243Sobrien (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 180759243Sobrien (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 180859243Sobrien#ifdef BSDJOBS 180959243Sobrien if (wanttty >= 0) { 181059243Sobrien /* make stoppable */ 181159243Sobrien (void) signal(SIGTSTP, SIG_DFL); 181259243Sobrien (void) signal(SIGTTIN, SIG_DFL); 181359243Sobrien (void) signal(SIGTTOU, SIG_DFL); 181459243Sobrien } 181559243Sobrien#endif /* BSDJOBS */ 1816167465Smp sigaction(SIGTERM, &parterm, NULL); 181759243Sobrien } 181859243Sobrien else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 181959243Sobrien (void) signal(SIGINT, SIG_IGN); 182059243Sobrien (void) signal(SIGQUIT, SIG_IGN); 182159243Sobrien } 182259243Sobrien#ifdef OREO 1823167465Smp signal(SIGIO, SIG_IGN); /* ignore SIGIO in child too */ 182459243Sobrien#endif /* OREO */ 182559243Sobrien 182659243Sobrien pgetty(wanttty, pgrp); 182759243Sobrien /* 182859243Sobrien * Nohup and nice apply only to NODE_COMMAND's but it would be nice 182959243Sobrien * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 183059243Sobrien * to know about nice/nohup/time 183159243Sobrien */ 183259243Sobrien if (t->t_dflg & F_NOHUP) 183359243Sobrien (void) signal(SIGHUP, SIG_IGN); 183459243Sobrien if (t->t_dflg & F_NICE) { 183559243Sobrien int nval = SIGN_EXTEND_CHAR(t->t_nice); 1836145479Smp#ifdef HAVE_SETPRIORITY 183783098Smp if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 1838167465Smp stderror(ERR_SYSTEM, "setpriority", strerror(errno)); 1839145479Smp#else /* !HAVE_SETPRIORITY */ 184059243Sobrien (void) nice(nval); 1841145479Smp#endif /* !HAVE_SETPRIORITY */ 184259243Sobrien } 184359243Sobrien#ifdef F_VER 184459243Sobrien if (t->t_dflg & F_VER) { 184559243Sobrien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 184659243Sobrien dohash(NULL, NULL); 184759243Sobrien } 184859243Sobrien#endif /* F_VER */ 184959243Sobrien#ifdef SIGSYNCH 185059243Sobrien /* rfw 8/89 now parent can continue */ 185159243Sobrien if (kill(getppid(), SIGSYNCH)) 185259243Sobrien stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 185359243Sobrien#endif /* SIGSYNCH */ 185459243Sobrien 185559243Sobrien } 185659243Sobrien else { 185759243Sobrien#ifdef POSIXJOBS 185859243Sobrien if (wanttty >= 0) { 185959243Sobrien /* 186059243Sobrien * `Walking' process group fix from Beto Appleton. 186159243Sobrien * (beto@aixwiz.austin.ibm.com) 186259243Sobrien * If setpgid fails at this point that means that 186359243Sobrien * our process leader has died. We flush the current 186459243Sobrien * job and become the process leader ourselves. 186559243Sobrien * The parent will figure that out later. 186659243Sobrien */ 186759243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : pid; 186859243Sobrien if (setpgid(pid, pgrp) == -1 && errno == EPERM) { 186959243Sobrien pcurrjob = NULL; 187059243Sobrien /* 187159243Sobrien * We don't care if this causes an error here; 187259243Sobrien * then we are already in the right process group 187359243Sobrien */ 187459243Sobrien (void) setpgid(pid, pgrp = pid); 187559243Sobrien } 187659243Sobrien } 187759243Sobrien#endif /* POSIXJOBS */ 187859243Sobrien palloc(pid, t); 187959243Sobrien#ifdef SIGSYNCH 1880167465Smp { 1881167465Smp sigset_t pause_mask; 1882167465Smp 188359243Sobrien /* 188459243Sobrien * rfw 8/89 Wait for child to own terminal. Solves half of ugly 188559243Sobrien * synchronization problem. With this change, we know that the only 188659243Sobrien * reason setpgrp to a previous process in a pipeline can fail is that 188759243Sobrien * the previous process has already exited. Without this hack, he may 188859243Sobrien * either have exited or not yet started to run. Two uglies become 188959243Sobrien * one. 189059243Sobrien */ 1891167465Smp sigprocmask(SIG_BLOCK, NULL, &pause); 1892167465Smp sigdelset(&pause_mask, SIGCHLD); 1893167465Smp sigdelset(&pause_mask, SIGSYNCH); 1894167465Smp sigsuspend(&pause_mask); 1895232633Smp (void)handle_pending_signals(); 1896167465Smp if (sigaction(SIGSYNCH, &osa, NULL)) 1897167465Smp stderror(ERR_SYSTEM, "pfork parent: sigaction restore", 1898167465Smp strerror(errno)); 1899167465Smp } 190059243Sobrien#endif /* SIGSYNCH */ 190159243Sobrien 1902167465Smp if (wanttty < 0) 1903167465Smp cleanup_until(&pchild_disabled); 190459243Sobrien } 190559243Sobrien return (pid); 190659243Sobrien} 190759243Sobrien 190859243Sobrienstatic void 1909167465Smpokpcntl(void) 191059243Sobrien{ 191159243Sobrien if (tpgrp == -1) 191259243Sobrien stderror(ERR_JOBCONTROL); 191359243Sobrien if (tpgrp == 0) 191459243Sobrien stderror(ERR_JOBCTRLSUB); 191559243Sobrien} 191659243Sobrien 191759243Sobrien 191859243Sobrienstatic void 1919167465Smpsetttypgrp(int pgrp) 192059243Sobrien{ 192159243Sobrien /* 192259243Sobrien * If we are piping out a builtin, eg. 'echo | more' things can go 192359243Sobrien * out of sequence, i.e. the more can run before the echo. This 192459243Sobrien * can happen even if we have vfork, since the echo will be forked 192559243Sobrien * with the regular fork. In this case, we need to set the tty 192659243Sobrien * pgrp ourselves. If that happens, then the process will be still 192759243Sobrien * alive. And the tty process group will already be set. 192859243Sobrien * This should fix the famous sequent problem as a side effect: 192959243Sobrien * The controlling terminal is lost if all processes in the 193059243Sobrien * terminal process group are zombies. In this case tcgetpgrp() 193159243Sobrien * returns 0. If this happens we must set the terminal process 193259243Sobrien * group again. 193359243Sobrien */ 193459243Sobrien if (tcgetpgrp(FSHTTY) != pgrp) { 193559243Sobrien#ifdef POSIXJOBS 1936167465Smp struct sigaction old; 1937167465Smp 193859243Sobrien /* 193959243Sobrien * tcsetpgrp will set SIGTTOU to all the the processes in 194059243Sobrien * the background according to POSIX... We ignore this here. 194159243Sobrien */ 1942167465Smp sigaction(SIGTTOU, NULL, &old); 1943167465Smp signal(SIGTTOU, SIG_IGN); 194459243Sobrien#endif 194559243Sobrien (void) tcsetpgrp(FSHTTY, pgrp); 194659243Sobrien# ifdef POSIXJOBS 1947167465Smp sigaction(SIGTTOU, &old, NULL); 194859243Sobrien# endif 194959243Sobrien 195059243Sobrien } 195159243Sobrien} 195259243Sobrien 195359243Sobrien 195459243Sobrien/* 195559243Sobrien * if we don't have vfork(), things can still go in the wrong order 195659243Sobrien * resulting in the famous 'Stopped (tty output)'. But some systems 195759243Sobrien * don't permit the setpgid() call, (these are more recent secure 195859243Sobrien * systems such as ibm's aix), when they do. Then we'd rather print 195959243Sobrien * an error message than hang the shell! 196059243Sobrien * I am open to suggestions how to fix that. 196159243Sobrien */ 196259243Sobrienvoid 1963167465Smppgetty(int wanttty, pid_t pgrp) 196459243Sobrien{ 196559243Sobrien#ifdef BSDJOBS 1966167465Smp# ifdef POSIXJOBS 1967167465Smp sigset_t oset, set; 1968167465Smp# endif /* POSIXJOBS */ 196959243Sobrien 1970167465Smp jobdebug_xprintf(("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n", 1971167465Smp wanttty, (int)getpid(), (int)pgrp, (int)mygetpgrp(), 1972167465Smp (int)tcgetpgrp(FSHTTY))); 197359243Sobrien# ifdef POSIXJOBS 197459243Sobrien /* 197559243Sobrien * christos: I am blocking the tty signals till I've set things 197659243Sobrien * correctly.... 197759243Sobrien */ 1978167465Smp if (wanttty > 0) { 1979167465Smp sigemptyset(&set); 1980167465Smp sigaddset(&set, SIGTSTP); 1981167465Smp sigaddset(&set, SIGTTIN); 1982167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 1983167465Smp cleanup_push(&oset, sigprocmask_cleanup); 198459243Sobrien } 198559243Sobrien# endif /* POSIXJOBS */ 198659243Sobrien 198759243Sobrien# ifndef POSIXJOBS 198859243Sobrien if (wanttty > 0) 198959243Sobrien setttypgrp(pgrp); 199059243Sobrien# endif /* !POSIXJOBS */ 199159243Sobrien 199259243Sobrien /* 199359243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 199459243Sobrien * Don't check for tpgrp >= 0 so even non-interactive shells give 199559243Sobrien * background jobs process groups Same for the comparison in the other part 199659243Sobrien * of the #ifdef 199759243Sobrien */ 199859243Sobrien if (wanttty >= 0) { 199959243Sobrien if (setpgid(0, pgrp) == -1) { 200059243Sobrien# ifdef POSIXJOBS 200159243Sobrien /* Walking process group fix; see above */ 200259243Sobrien if (setpgid(0, pgrp = getpid()) == -1) { 200359243Sobrien# endif /* POSIXJOBS */ 200459243Sobrien stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); 200559243Sobrien xexit(0); 200659243Sobrien# ifdef POSIXJOBS 200759243Sobrien } 200859243Sobrien wanttty = pgrp; /* Now we really want the tty, since we became the 200959243Sobrien * the process group leader 201059243Sobrien */ 201159243Sobrien# endif /* POSIXJOBS */ 201259243Sobrien } 201359243Sobrien } 201459243Sobrien 201559243Sobrien# ifdef POSIXJOBS 2016167465Smp if (wanttty > 0) { 201759243Sobrien setttypgrp(pgrp); 2018167465Smp cleanup_until(&oset); 2019167465Smp } 202059243Sobrien# endif /* POSIXJOBS */ 202159243Sobrien 2022167465Smp jobdebug_xprintf(("wanttty %d pid %d pgrp %d tpgrp %d\n", 2023167465Smp wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY))); 202459243Sobrien 202559243Sobrien if (tpgrp > 0) 202659243Sobrien tpgrp = 0; /* gave tty away */ 202759243Sobrien#endif /* BSDJOBS */ 202859243Sobrien} 2029