159243Sobrien/* 259243Sobrien * sh.proc.c: Job manipulations 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 3459243Sobrien#include "tc.h" 3559243Sobrien#include "tc.wait.h" 3659243Sobrien 3769408Sache#ifdef WINNT_NATIVE 3859243Sobrien#undef POSIX 3959243Sobrien#define POSIX 4069408Sache#endif /* WINNT_NATIVE */ 4159243Sobrien#ifdef aiws 4259243Sobrien# undef HZ 4359243Sobrien# define HZ 16 4459243Sobrien#endif /* aiws */ 4559243Sobrien 46316957Sdchagin#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) 47316957Sdchagin# define BSDWAIT 48316957Sdchagin#endif /* _BSD || (IRIS4D && __STDC__) || __lucid */ 4959243Sobrien#ifndef WTERMSIG 5059243Sobrien# define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 5159243Sobrien# ifndef BSDWAIT 5259243Sobrien# define BSDWAIT 5359243Sobrien# endif /* !BSDWAIT */ 5459243Sobrien#endif /* !WTERMSIG */ 5559243Sobrien#ifndef WEXITSTATUS 5659243Sobrien# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 5759243Sobrien#endif /* !WEXITSTATUS */ 5859243Sobrien#ifndef WSTOPSIG 5959243Sobrien# define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 6059243Sobrien#endif /* !WSTOPSIG */ 6159243Sobrien 6259243Sobrien#ifdef __osf__ 6359243Sobrien# ifndef WCOREDUMP 6459243Sobrien# define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) 6559243Sobrien# endif 6659243Sobrien#endif 6759243Sobrien 6859243Sobrien#ifndef WCOREDUMP 6959243Sobrien# ifdef BSDWAIT 7059243Sobrien# define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 7159243Sobrien# else /* !BSDWAIT */ 7259243Sobrien# define WCOREDUMP(w) ((w) & 0200) 7359243Sobrien# endif /* !BSDWAIT */ 7459243Sobrien#endif /* !WCOREDUMP */ 7559243Sobrien 76167465Smp#ifndef JOBDEBUG 77167465Smp# define jobdebug_xprintf(x) (void)0 78167465Smp# define jobdebug_flush() (void)0 79167465Smp#else 80167465Smp# define jobdebug_xprintf(s) xprintf s 81167465Smp# define jobdebug_flush() flush() 82167465Smp#endif 83167465Smp 8459243Sobrien/* 8559243Sobrien * C Shell - functions that manage processes, handling hanging, termination 8659243Sobrien */ 8759243Sobrien 8859243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 8959243Sobrien 9059243Sobrien#ifdef BSDTIMES 9159243Sobrien# ifdef convex 9259243Sobrien/* use 'cvxrusage' to get parallel statistics */ 9359243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9459243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9559243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 9659243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 9759243Sobrien# else 9859243Sobrienstatic struct rusage zru; 9959243Sobrien# endif /* convex */ 10059243Sobrien#else /* !BSDTIMES */ 10159243Sobrien# ifdef _SEQUENT_ 10259243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 10359243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 10459243Sobrien# else /* !_SEQUENT_ */ 10559243Sobrien# ifdef _SX 10659243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 10759243Sobrien# else /* !_SX */ 10859243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 10959243Sobrien# endif /* !_SX */ 11059243Sobrien# endif /* !_SEQUENT_ */ 11159243Sobrien#endif /* !BSDTIMES */ 11259243Sobrien 113167465Smp#ifndef BSDTIMES 114167465Smpstatic int timesdone; /* shtimes buffer full ? */ 115167465Smp#endif /* BSDTIMES */ 116167465Smp 11759243Sobrien#ifndef RUSAGE_CHILDREN 11859243Sobrien# define RUSAGE_CHILDREN -1 11959243Sobrien#endif /* RUSAGE_CHILDREN */ 12059243Sobrien 121167465Smpstatic void pflushall (void); 122167465Smpstatic void pflush (struct process *); 123167465Smpstatic void pfree (struct process *); 124167465Smpstatic void pclrcurr (struct process *); 125195609Smpstatic void morecommand (size_t); 126167465Smpstatic void padd (struct command *); 127167465Smpstatic int pprint (struct process *, int); 128167465Smpstatic void ptprint (struct process *); 129167465Smpstatic void pads (Char *); 130167465Smpstatic void pkill (Char **, int); 131167465Smpstatic struct process *pgetcurr (struct process *); 132167465Smpstatic void okpcntl (void); 133167465Smpstatic void setttypgrp (int); 13459243Sobrien 13559243Sobrien/* 136167465Smp * pchild - call queued by the SIGCHLD signal 13759243Sobrien * indicating that at least one child has terminated or stopped 13859243Sobrien * thus at least one wait system call will definitely return a 13959243Sobrien * childs status. Top level routines (like pwait) must be sure 14059243Sobrien * to mask interrupts when playing with the proclist data structures! 14159243Sobrien */ 142167465Smpvoid 143167465Smppchild(void) 14459243Sobrien{ 145145479Smp struct process *pp; 146145479Smp struct process *fp; 147167465Smp pid_t pid; 14859243Sobrien#ifdef BSDWAIT 14959243Sobrien union wait w; 15059243Sobrien#else /* !BSDWAIT */ 15159243Sobrien int w; 15259243Sobrien#endif /* !BSDWAIT */ 15359243Sobrien int jobflags; 15459243Sobrien#ifdef BSDTIMES 15559243Sobrien struct sysrusage ru; 15659243Sobrien#else /* !BSDTIMES */ 15759243Sobrien# ifdef _SEQUENT_ 15859243Sobrien struct process_stats ru; 15959243Sobrien struct process_stats cpst1, cpst2; 16059243Sobrien timeval_t tv; 16159243Sobrien# else /* !_SEQUENT_ */ 16259243Sobrien struct tms proctimes; 16359243Sobrien 16459243Sobrien if (!timesdone) { 16559243Sobrien timesdone++; 16659243Sobrien (void) times(&shtimes); 16759243Sobrien } 16859243Sobrien# endif /* !_SEQUENT_ */ 16959243Sobrien#endif /* !BSDTIMES */ 17059243Sobrien 171167465Smp jobdebug_xprintf(("pchild()\n")); 17259243Sobrien 17359243Sobrienloop: 174167465Smp jobdebug_xprintf(("Waiting...\n")); 175167465Smp jobdebug_flush(); 17659243Sobrien errno = 0; /* reset, just in case */ 177167465Smp 17869408Sache#ifndef WINNT_NATIVE 17959243Sobrien# ifdef BSDJOBS 18059243Sobrien# ifdef BSDTIMES 18159243Sobrien# ifdef convex 18259243Sobrien /* use 'cvxwait' to get parallel statistics */ 18359243Sobrien pid = cvxwait(&w, 18459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 18559243Sobrien# else 18659243Sobrien /* both a wait3 and rusage */ 187231990Smp# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 188316957Sdchagin#ifdef __ANDROID__ /* no wait3, only wait4 */ 189316957Sdchagin pid = wait4(-1, &w, 190316957Sdchagin (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 191316957Sdchagin#else 19259243Sobrien pid = wait3(&w, 19359243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 194316957Sdchagin#endif /* __ANDROID__ */ 19559243Sobrien# else /* BSDWAIT */ 19659243Sobrien pid = wait3(&w.w_status, 19759243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 19859243Sobrien# endif /* BSDWAIT */ 19959243Sobrien# endif /* convex */ 20059243Sobrien# else /* !BSDTIMES */ 20159243Sobrien# ifdef _SEQUENT_ 20259243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 20359243Sobrien pid = waitpid(-1, &w, 20459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 20559243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 20659243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 20759243Sobrien# else /* !_SEQUENT_ */ 20859243Sobrien# ifndef POSIX 20959243Sobrien /* we have a wait3, but no rusage stuff */ 21059243Sobrien pid = wait3(&w.w_status, 21159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 21259243Sobrien# else /* POSIX */ 21359243Sobrien pid = waitpid(-1, &w, 21459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 21559243Sobrien# endif /* POSIX */ 21659243Sobrien# endif /* !_SEQUENT_ */ 21759243Sobrien# endif /* !BSDTIMES */ 21859243Sobrien# else /* !BSDJOBS */ 21959243Sobrien# ifdef BSDTIMES 22059243Sobrien# define HAVEwait3 22159243Sobrien /* both a wait3 and rusage */ 22259243Sobrien# ifdef hpux 22359243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 22459243Sobrien# else /* !hpux */ 225231990Smp# ifndef BSDWAIT 226231990Smp pid = wait3(&w, WNOHANG, &ru); 227231990Smp# else 22859243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 229231990Smp# endif /* BSDWAIT */ 23059243Sobrien# endif /* !hpux */ 23159243Sobrien# else /* !BSDTIMES */ 23259243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 23359243Sobrien# define HAVEwait3 234167465Smp pid = waitpid(-1, &w, 23559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 23659243Sobrien# endif /* ODT */ 23759243Sobrien# if defined(aiws) || defined(uts) 23859243Sobrien# define HAVEwait3 23959243Sobrien pid = wait3(&w.w_status, 24059243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 24159243Sobrien# endif /* aiws || uts */ 24259243Sobrien# ifndef HAVEwait3 243167465Smp# ifndef BSDWAIT 24459243Sobrien /* no wait3, therefore no rusage */ 24559243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 246167465Smp pid = wait(&w); 247167465Smp# else /* BSDWAIT */ 24859243Sobrien /* 24959243Sobrien * XXX: for greater than 3 we should use waitpid(). 25059243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 25159243Sobrien */ 252167465Smp pid = wait(&w.w_status); 253167465Smp# endif /* BSDWAIT */ 25459243Sobrien# endif /* !HAVEwait3 */ 25559243Sobrien# endif /* !BSDTIMES */ 25659243Sobrien# endif /* !BSDJOBS */ 25769408Sache#else /* WINNT_NATIVE */ 258167465Smp pid = waitpid(-1, &w, 25959243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 26069408Sache#endif /* WINNT_NATIVE */ 26159243Sobrien 262167465Smp jobdebug_xprintf(("parent %d pid %d, retval %x termsig %x retcode %x\n", 263167465Smp (int)getpid(), (int)pid, w, WTERMSIG(w), 264167465Smp WEXITSTATUS(w))); 265167465Smp jobdebug_flush(); 26659243Sobrien 26759243Sobrien if ((pid == 0) || (pid == -1)) { 268231990Smp (void)handle_pending_signals(); 269167465Smp jobdebug_xprintf(("errno == %d\n", errno)); 270167465Smp if (errno == EINTR) 27159243Sobrien goto loop; 272145479Smp goto end; 27359243Sobrien } 27459243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 27559243Sobrien if (pid == pp->p_procid) 27659243Sobrien goto found; 27769408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 27859243Sobrien /* this should never have happened */ 27959243Sobrien stderror(ERR_SYNC, pid); 28059243Sobrien xexit(0); 28169408Sache#else /* BSDJOBS || WINNT_NATIVE */ 28259243Sobrien goto loop; 28369408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 28459243Sobrienfound: 28559243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 28659243Sobrien if (WIFSTOPPED(w)) { 28759243Sobrien pp->p_flags |= PSTOPPED; 28859243Sobrien pp->p_reason = WSTOPSIG(w); 28959243Sobrien } 29059243Sobrien else { 29159243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 29259243Sobrien#ifndef BSDTIMES 29359243Sobrien# ifdef _SEQUENT_ 29459243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 29559243Sobrien# else /* !_SEQUENT_ */ 29659243Sobrien pp->p_etime = times(&proctimes); 29759243Sobrien# endif /* !_SEQUENT_ */ 29859243Sobrien#else /* BSDTIMES */ 29959243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 30059243Sobrien#endif /* BSDTIMES */ 30159243Sobrien 30259243Sobrien 30359243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 30459243Sobrien pp->p_rusage = ru; 30559243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 30659243Sobrien (void) times(&proctimes); 30759243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 30859243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 30959243Sobrien shtimes = proctimes; 31059243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 31159243Sobrien if (WIFSIGNALED(w)) { 31259243Sobrien if (WTERMSIG(w) == SIGINT) 31359243Sobrien pp->p_flags |= PINTERRUPTED; 31459243Sobrien else 31559243Sobrien pp->p_flags |= PSIGNALED; 31659243Sobrien if (WCOREDUMP(w)) 31759243Sobrien pp->p_flags |= PDUMPED; 31859243Sobrien pp->p_reason = WTERMSIG(w); 31959243Sobrien } 32059243Sobrien else { 32159243Sobrien pp->p_reason = WEXITSTATUS(w); 32259243Sobrien if (pp->p_reason != 0) 32359243Sobrien pp->p_flags |= PAEXITED; 32459243Sobrien else 32559243Sobrien pp->p_flags |= PNEXITED; 32659243Sobrien } 32759243Sobrien } 32859243Sobrien jobflags = 0; 32959243Sobrien fp = pp; 33059243Sobrien do { 33159243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 33259243Sobrien !child && adrof(STRtime) && 33359243Sobrien#ifdef BSDTIMES 33459243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 33559243Sobrien#else /* !BSDTIMES */ 33659243Sobrien# ifdef _SEQUENT_ 33759243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 33859243Sobrien# else /* !_SEQUENT_ */ 33959243Sobrien# ifndef POSIX 34059243Sobrien (fp->p_utime + fp->p_stime) / HZ 34159243Sobrien# else /* POSIX */ 34259243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 34359243Sobrien# endif /* POSIX */ 34459243Sobrien# endif /* !_SEQUENT_ */ 34559243Sobrien#endif /* !BSDTIMES */ 34659243Sobrien >= atoi(short2str(varval(STRtime)))) 34759243Sobrien fp->p_flags |= PTIME; 34859243Sobrien jobflags |= fp->p_flags; 34959243Sobrien } while ((fp = fp->p_friends) != pp); 35059243Sobrien pp->p_flags &= ~PFOREGND; 35159243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 35259243Sobrien pp->p_flags &= ~PPTIME; 35359243Sobrien pp->p_flags |= PTIME; 35459243Sobrien } 35559243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 35659243Sobrien fp = pp; 35759243Sobrien do { 35859243Sobrien if (fp->p_flags & PSTOPPED) 35959243Sobrien fp->p_flags |= PREPORTED; 36059243Sobrien } while ((fp = fp->p_friends) != pp); 36159243Sobrien while (fp->p_procid != fp->p_jobid) 36259243Sobrien fp = fp->p_friends; 36359243Sobrien if (jobflags & PSTOPPED) { 36459243Sobrien if (pcurrent && pcurrent != fp) 36559243Sobrien pprevious = pcurrent; 36659243Sobrien pcurrent = fp; 36759243Sobrien } 36859243Sobrien else 36959243Sobrien pclrcurr(fp); 37059243Sobrien if (jobflags & PFOREGND) { 37159243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 37259243Sobrien#ifdef notdef 37359243Sobrien jobflags & PAEXITED || 37459243Sobrien#endif /* notdef */ 375231990Smp fp->p_cwd == NULL || 37659243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 37759243Sobrien /* PWP: print a newline after ^C */ 37859243Sobrien if (jobflags & PINTERRUPTED) { 379167465Smp xputchar('\r' | QUOTE); 380167465Smp xputchar('\n'); 38159243Sobrien } 38259243Sobrien#ifdef notdef 38359243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 38459243Sobrien ptprint(fp); 38559243Sobrien#endif /* notdef */ 38659243Sobrien } 38759243Sobrien } 38859243Sobrien else { 38959243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 390167465Smp xputchar('\r' | QUOTE); 391167465Smp xputchar('\n'); 39259243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 39359243Sobrien if ((jobflags & PSTOPPED) == 0) 39459243Sobrien pflush(pp); 395167465Smp if (GettingInput) { 396167465Smp errno = 0; 397167465Smp (void) Rawmode(); 39859243Sobrien#ifdef notdef 399167465Smp /* 400167465Smp * don't really want to do that, because it 401167465Smp * will erase our message in case of multi-line 402167465Smp * input 403167465Smp */ 404167465Smp ClearLines(); 40559243Sobrien#endif /* notdef */ 406167465Smp ClearDisp(); 407167465Smp Refresh(); 40859243Sobrien } 40959243Sobrien } 41059243Sobrien else { 41159243Sobrien fp->p_flags |= PNEEDNOTE; 412167465Smp neednote = 1; 41359243Sobrien } 41459243Sobrien } 41559243Sobrien } 416167465Smp#if defined(BSDJOBS) || defined(HAVEwait3) ||defined(WINNT_NATIVE) 41759243Sobrien goto loop; 41859243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 419145479Smp end: 420145479Smp ; 42159243Sobrien} 42259243Sobrien 42359243Sobrienvoid 424167465Smppnote(void) 42559243Sobrien{ 426145479Smp struct process *pp; 42759243Sobrien int flags; 42859243Sobrien 42959243Sobrien neednote = 0; 43059243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 43159243Sobrien if (pp->p_flags & PNEEDNOTE) { 432167465Smp pchild_disabled++; 433167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 43459243Sobrien pp->p_flags &= ~PNEEDNOTE; 43559243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 43659243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 43759243Sobrien pflush(pp); 438167465Smp cleanup_until(&pchild_disabled); 43959243Sobrien } 44059243Sobrien } 44159243Sobrien} 44259243Sobrien 44359243Sobrien 44459243Sobrienstatic void 445167465Smppfree(struct process *pp) 44659243Sobrien{ 447167465Smp xfree(pp->p_command); 44859243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 44959243Sobrien if (pp->p_cwd->di_next == 0) 45059243Sobrien dfree(pp->p_cwd); 451167465Smp xfree(pp); 45259243Sobrien} 45359243Sobrien 45459243Sobrien 45559243Sobrien/* 45659243Sobrien * pwait - wait for current job to terminate, maintaining integrity 45759243Sobrien * of current and previous job indicators. 45859243Sobrien */ 45959243Sobrienvoid 460167465Smppwait(void) 46159243Sobrien{ 462145479Smp struct process *fp, *pp; 46359243Sobrien 46459243Sobrien /* 46559243Sobrien * Here's where dead procs get flushed. 46659243Sobrien */ 46759243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 46859243Sobrien if (pp->p_procid == 0) { 46959243Sobrien fp->p_next = pp->p_next; 47059243Sobrien pfree(pp); 47159243Sobrien pp = fp; 47259243Sobrien } 47359243Sobrien pjwait(pcurrjob); 47459243Sobrien} 47559243Sobrien 47659243Sobrien 47759243Sobrien/* 47859243Sobrien * pjwait - wait for a job to finish or become stopped 47959243Sobrien * It is assumed to be in the foreground state (PFOREGND) 48059243Sobrien */ 48159243Sobrienvoid 482167465Smppjwait(struct process *pp) 48359243Sobrien{ 484145479Smp struct process *fp; 48559243Sobrien int jobflags, reason; 486167465Smp sigset_t oset, set, pause_mask; 487167465Smp Char *reason_str; 488167465Smp 48959243Sobrien while (pp->p_procid != pp->p_jobid) 49059243Sobrien pp = pp->p_friends; 49159243Sobrien fp = pp; 49259243Sobrien 49359243Sobrien do { 49459243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 495195609Smp xprintf("%s", CGETS(17, 1, "BUG: waiting for background job!\n")); 49659243Sobrien } while ((fp = fp->p_friends) != pp); 49759243Sobrien /* 49859243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 49959243Sobrien * target process, or any of its friends, are running 50059243Sobrien */ 50159243Sobrien fp = pp; 502167465Smp sigemptyset(&set); 503167465Smp sigaddset(&set, SIGINT); 504167465Smp sigaddset(&set, SIGCHLD); 505167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 506167465Smp cleanup_push(&oset, sigprocmask_cleanup); 507167465Smp pause_mask = oset; 508167465Smp sigdelset(&pause_mask, SIGCHLD); 509316957Sdchagin sigaddset(&pause_mask, SIGINT); 51059243Sobrien for (;;) { 511231990Smp (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 { 561231990Smp /* In case of pipelines only the result of the last 562231990Smp * command should be taken in account */ 563231990Smp if (!anyerror && !(fp->p_flags & PBRACE) 564231990Smp && ((fp->p_flags & PPOU) || (fp->p_flags & PBACKQ))) 565231990Smp 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); 577231990Smp 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; 596316957Sdchagin 597316957Sdchagin /* the current block mask to be able to restore */ 598316957Sdchagin sigset_t old_mask; 599316957Sdchagin 600316957Sdchagin /* block mask for critical section: OLD_MASK U {SIGCHLD} */ 601316957Sdchagin sigset_t block_mask; 602316957Sdchagin 603316957Sdchagin /* ignore those during blocking sigsuspend: 604316957Sdchagin OLD_MASK / {SIGCHLD, possibly(SIGINT)} */ 605167465Smp sigset_t pause_mask; 606316957Sdchagin 607231990Smp int opintr_disabled, gotsig; 60859243Sobrien 60959243Sobrien USE(c); 61059243Sobrien USE(v); 61159243Sobrien pjobs++; 612316957Sdchagin 613167465Smp sigprocmask(SIG_BLOCK, NULL, &pause_mask); 614167465Smp sigdelset(&pause_mask, SIGCHLD); 61559243Sobrien if (setintr) 616167465Smp sigdelset(&pause_mask, SIGINT); 617316957Sdchagin 618316957Sdchagin /* critical section, block also SIGCHLD */ 619316957Sdchagin sigprocmask(SIG_BLOCK, NULL, &block_mask); 620316957Sdchagin sigaddset(&block_mask, SIGCHLD); 621316957Sdchagin sigprocmask(SIG_BLOCK, &block_mask, &old_mask); 622316957Sdchagin 623316957Sdchagin /* detect older SIGCHLDs and remove PRUNNING flag from proclist */ 624316957Sdchagin (void)handle_pending_signals(); 625316957Sdchagin 62659243Sobrienloop: 62759243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 62859243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 62959243Sobrien pp->p_flags & PRUNNING) { 630316957Sdchagin /* wait for (or pick up alredy blocked) SIGCHLD */ 631167465Smp sigsuspend(&pause_mask); 632316957Sdchagin 633316957Sdchagin /* make the 'wait' interuptable by CTRL-C */ 634231990Smp opintr_disabled = pintr_disabled; 635231990Smp pintr_disabled = 0; 636231990Smp gotsig = handle_pending_signals(); 637231990Smp pintr_disabled = opintr_disabled; 638231990Smp if (gotsig) 639231990Smp break; 64059243Sobrien goto loop; 64159243Sobrien } 64259243Sobrien pjobs = 0; 643316957Sdchagin 644316957Sdchagin sigprocmask(SIG_SETMASK, &old_mask, NULL); 64559243Sobrien} 64659243Sobrien 64759243Sobrien/* 64859243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 64959243Sobrien */ 65059243Sobrienstatic void 651167465Smppflushall(void) 65259243Sobrien{ 653145479Smp struct process *pp; 65459243Sobrien 65559243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 65659243Sobrien if (pp->p_procid) 65759243Sobrien pflush(pp); 65859243Sobrien} 65959243Sobrien 66059243Sobrien/* 66159243Sobrien * pflush - flag all process structures in the same job as the 66259243Sobrien * the argument process for deletion. The actual free of the 66359243Sobrien * space is not done here since pflush is called at interrupt level. 66459243Sobrien */ 66559243Sobrienstatic void 666167465Smppflush(struct process *pp) 66759243Sobrien{ 668145479Smp struct process *np; 669145479Smp int idx; 67059243Sobrien 67159243Sobrien if (pp->p_procid == 0) { 672195609Smp xprintf("%s", CGETS(17, 3, "BUG: process flushed twice")); 67359243Sobrien return; 67459243Sobrien } 67559243Sobrien while (pp->p_procid != pp->p_jobid) 67659243Sobrien pp = pp->p_friends; 67759243Sobrien pclrcurr(pp); 67859243Sobrien if (pp == pcurrjob) 67959243Sobrien pcurrjob = 0; 68059243Sobrien idx = pp->p_index; 68159243Sobrien np = pp; 68259243Sobrien do { 68359243Sobrien np->p_index = np->p_procid = 0; 68459243Sobrien np->p_flags &= ~PNEEDNOTE; 68559243Sobrien } while ((np = np->p_friends) != pp); 68659243Sobrien if (idx == pmaxindex) { 68759243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 68859243Sobrien if (np->p_index > idx) 68959243Sobrien idx = np->p_index; 69059243Sobrien pmaxindex = idx; 69159243Sobrien } 69259243Sobrien} 69359243Sobrien 69459243Sobrien/* 69559243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 69659243Sobrien * pp MUST be the job leader 69759243Sobrien */ 69859243Sobrienstatic void 699167465Smppclrcurr(struct process *pp) 70059243Sobrien{ 70159243Sobrien if (pp == pcurrent) { 70259243Sobrien if (pprevious != NULL) { 70359243Sobrien pcurrent = pprevious; 70459243Sobrien pprevious = pgetcurr(pp); 70559243Sobrien } 70659243Sobrien else { 70759243Sobrien pcurrent = pgetcurr(pp); 70859243Sobrien pprevious = pgetcurr(pp); 70959243Sobrien } 71059243Sobrien } 71159243Sobrien else if (pp == pprevious) 71259243Sobrien pprevious = pgetcurr(pp); 71359243Sobrien} 71459243Sobrien 71559243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 716195609Smpstatic Char *cmdstr; 717195609Smpstatic size_t cmdmax; 718167465Smpstatic size_t cmdlen; 71959243Sobrienstatic Char *cmdp; 720195609Smp#define CMD_INIT 1024 721195609Smp#define CMD_INCR 64 72259243Sobrien 723195609Smpstatic void 724195609Smpmorecommand(size_t s) 725195609Smp{ 726195609Smp Char *ncmdstr; 727195609Smp ptrdiff_t d; 728195609Smp 729195609Smp cmdmax += s; 730195609Smp ncmdstr = xrealloc(cmdstr, cmdmax * sizeof(*cmdstr)); 731195609Smp d = ncmdstr - cmdstr; 732195609Smp cmdstr = ncmdstr; 733195609Smp cmdp += d; 734195609Smp} 735195609Smp 73683098Smp/* GrP 73783098Smp * unparse - Export padd() functionality 73883098Smp */ 73983098SmpChar * 740167465Smpunparse(struct command *t) 74183098Smp{ 742195609Smp if (cmdmax == 0) 743195609Smp morecommand(CMD_INIT); 744195609Smp cmdp = cmdstr; 74583098Smp cmdlen = 0; 74683098Smp padd(t); 74783098Smp *cmdp++ = '\0'; 748195609Smp return Strsave(cmdstr); 74983098Smp} 75083098Smp 75183098Smp 75259243Sobrien/* 75359243Sobrien * palloc - allocate a process structure and fill it up. 75459243Sobrien * an important assumption is made that the process is running. 75559243Sobrien */ 75659243Sobrienvoid 757167465Smppalloc(pid_t pid, struct command *t) 75859243Sobrien{ 759145479Smp struct process *pp; 76059243Sobrien int i; 76159243Sobrien 762167465Smp pp = xcalloc(1, sizeof(struct process)); 76359243Sobrien pp->p_procid = pid; 764231990Smp pp->p_parentid = shpgrp; 76559243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 76659243Sobrien if (t->t_dflg & F_TIME) 76759243Sobrien pp->p_flags |= PPTIME; 76859243Sobrien if (t->t_dflg & F_BACKQ) 76959243Sobrien pp->p_flags |= PBACKQ; 77059243Sobrien if (t->t_dflg & F_HUP) 77159243Sobrien pp->p_flags |= PHUP; 772231990Smp if (t->t_dcom && t->t_dcom[0] && (*t->t_dcom[0] == '{')) 773231990Smp pp->p_flags |= PBRACE; 774195609Smp if (cmdmax == 0) 775195609Smp morecommand(CMD_INIT); 776195609Smp cmdp = cmdstr; 77759243Sobrien cmdlen = 0; 77859243Sobrien padd(t); 77959243Sobrien *cmdp++ = 0; 78059243Sobrien if (t->t_dflg & F_PIPEOUT) { 78159243Sobrien pp->p_flags |= PPOU; 78259243Sobrien if (t->t_dflg & F_STDERR) 78359243Sobrien pp->p_flags |= PDIAG; 78459243Sobrien } 785195609Smp pp->p_command = Strsave(cmdstr); 78659243Sobrien if (pcurrjob) { 78759243Sobrien struct process *fp; 78859243Sobrien 78959243Sobrien /* careful here with interrupt level */ 79059243Sobrien pp->p_cwd = 0; 79159243Sobrien pp->p_index = pcurrjob->p_index; 79259243Sobrien pp->p_friends = pcurrjob; 79359243Sobrien pp->p_jobid = pcurrjob->p_procid; 79459243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 79559243Sobrien continue; 79659243Sobrien fp->p_friends = pp; 79759243Sobrien } 79859243Sobrien else { 79959243Sobrien pcurrjob = pp; 80059243Sobrien pp->p_jobid = pid; 80159243Sobrien pp->p_friends = pp; 80259243Sobrien pp->p_cwd = dcwd; 80359243Sobrien dcwd->di_count++; 80459243Sobrien if (pmaxindex < BIGINDEX) 80559243Sobrien pp->p_index = ++pmaxindex; 80659243Sobrien else { 80759243Sobrien struct process *np; 80859243Sobrien 80959243Sobrien for (i = 1;; i++) { 81059243Sobrien for (np = proclist.p_next; np; np = np->p_next) 81159243Sobrien if (np->p_index == i) 81259243Sobrien goto tryagain; 81359243Sobrien pp->p_index = i; 81459243Sobrien if (i > pmaxindex) 81559243Sobrien pmaxindex = i; 81659243Sobrien break; 81759243Sobrien tryagain:; 81859243Sobrien } 81959243Sobrien } 82059243Sobrien if (pcurrent == NULL) 82159243Sobrien pcurrent = pp; 82259243Sobrien else if (pprevious == NULL) 82359243Sobrien pprevious = pp; 82459243Sobrien } 82559243Sobrien pp->p_next = proclist.p_next; 82659243Sobrien proclist.p_next = pp; 82759243Sobrien#ifdef BSDTIMES 82859243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 82959243Sobrien#else /* !BSDTIMES */ 83059243Sobrien# ifdef _SEQUENT_ 83159243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 83259243Sobrien# else /* !_SEQUENT_ */ 83359243Sobrien { 83459243Sobrien struct tms tmptimes; 83559243Sobrien 83659243Sobrien pp->p_btime = times(&tmptimes); 83759243Sobrien } 83859243Sobrien# endif /* !_SEQUENT_ */ 83959243Sobrien#endif /* !BSDTIMES */ 84059243Sobrien} 84159243Sobrien 84259243Sobrienstatic void 843167465Smppadd(struct command *t) 84459243Sobrien{ 84559243Sobrien Char **argp; 84659243Sobrien 84759243Sobrien if (t == 0) 84859243Sobrien return; 84959243Sobrien switch (t->t_dtyp) { 85059243Sobrien 85159243Sobrien case NODE_PAREN: 85259243Sobrien pads(STRLparensp); 85359243Sobrien padd(t->t_dspr); 85459243Sobrien pads(STRspRparen); 85559243Sobrien break; 85659243Sobrien 85759243Sobrien case NODE_COMMAND: 85859243Sobrien for (argp = t->t_dcom; *argp; argp++) { 85959243Sobrien pads(*argp); 86059243Sobrien if (argp[1]) 86159243Sobrien pads(STRspace); 86259243Sobrien } 86359243Sobrien break; 86459243Sobrien 86559243Sobrien case NODE_OR: 86659243Sobrien case NODE_AND: 86759243Sobrien case NODE_PIPE: 86859243Sobrien case NODE_LIST: 86959243Sobrien padd(t->t_dcar); 87059243Sobrien switch (t->t_dtyp) { 87159243Sobrien case NODE_OR: 87259243Sobrien pads(STRspor2sp); 87359243Sobrien break; 87459243Sobrien case NODE_AND: 87559243Sobrien pads(STRspand2sp); 87659243Sobrien break; 87759243Sobrien case NODE_PIPE: 87859243Sobrien pads(STRsporsp); 87959243Sobrien break; 88059243Sobrien case NODE_LIST: 88159243Sobrien pads(STRsemisp); 88259243Sobrien break; 88359243Sobrien default: 88459243Sobrien break; 88559243Sobrien } 88659243Sobrien padd(t->t_dcdr); 88759243Sobrien return; 88859243Sobrien 88959243Sobrien default: 89059243Sobrien break; 89159243Sobrien } 89259243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 89359243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 89459243Sobrien pads(t->t_dlef); 89559243Sobrien } 89659243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 89759243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 89859243Sobrien if (t->t_dflg & F_STDERR) 89959243Sobrien pads(STRand); 90059243Sobrien pads(STRspace); 90159243Sobrien pads(t->t_drit); 90259243Sobrien } 90359243Sobrien} 90459243Sobrien 90559243Sobrienstatic void 906167465Smppads(Char *cp) 90759243Sobrien{ 908195609Smp size_t i, len; 90959243Sobrien 91059243Sobrien /* 91159243Sobrien * Avoid the Quoted Space alias hack! Reported by: 91259243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 91359243Sobrien */ 91459243Sobrien if (cp[0] == STRQNULL[0]) 91559243Sobrien cp++; 91659243Sobrien 917167465Smp i = Strlen(cp); 91859243Sobrien 919195609Smp len = cmdlen + i + CMD_INCR; 920195609Smp if (len >= cmdmax) 921195609Smp morecommand(len); 92259243Sobrien (void) Strcpy(cmdp, cp); 92359243Sobrien cmdp += i; 92459243Sobrien cmdlen += i; 92559243Sobrien} 92659243Sobrien 92759243Sobrien/* 92859243Sobrien * psavejob - temporarily save the current job on a one level stack 92959243Sobrien * so another job can be created. Used for { } in exp6 93059243Sobrien * and `` in globbing. 93159243Sobrien */ 93259243Sobrienvoid 933167465Smppsavejob(void) 93459243Sobrien{ 93559243Sobrien pholdjob = pcurrjob; 93659243Sobrien pcurrjob = NULL; 93759243Sobrien} 93859243Sobrien 93959243Sobrienvoid 940167465Smppsavejob_cleanup(void *dummy) 94159243Sobrien{ 942167465Smp USE(dummy); 94359243Sobrien pcurrjob = pholdjob; 94459243Sobrien pholdjob = NULL; 94559243Sobrien} 94659243Sobrien 94759243Sobrien/* 94859243Sobrien * pendjob - indicate that a job (set of commands) has been completed 94959243Sobrien * or is about to begin. 95059243Sobrien */ 95159243Sobrienvoid 952167465Smppendjob(void) 95359243Sobrien{ 954145479Smp struct process *pp, *tp; 95559243Sobrien 95659243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 95759243Sobrien pp = pcurrjob; 958231990Smp pcurrjob = NULL; 95959243Sobrien while (pp->p_procid != pp->p_jobid) 96059243Sobrien pp = pp->p_friends; 96159243Sobrien xprintf("[%d]", pp->p_index); 96259243Sobrien tp = pp; 96359243Sobrien do { 96459243Sobrien xprintf(" %d", pp->p_procid); 96559243Sobrien pp = pp->p_friends; 96659243Sobrien } while (pp != tp); 96759243Sobrien xputchar('\n'); 96859243Sobrien } 96959243Sobrien pholdjob = pcurrjob = 0; 97059243Sobrien} 97159243Sobrien 97259243Sobrien/* 97359243Sobrien * pprint - print a job 97459243Sobrien */ 97559243Sobrien 97659243Sobrien/* 97759243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 97859243Sobrien * reverse order 97959243Sobrien * 98059243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 98159243Sobrien */ 98259243Sobrien 98359243Sobrienstatic int 984167465Smppprint(struct process *pp, int flag) 98559243Sobrien{ 98659243Sobrien int status, reason; 98759243Sobrien struct process *tp; 98859243Sobrien int jobflags, pstatus, pcond; 989145479Smp const char *format; 990316957Sdchagin int ohaderr; 99159243Sobrien 99259243Sobrien#ifdef BACKPIPE 99359243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 99459243Sobrien int inpipe = 0; 99559243Sobrien#endif /* BACKPIPE */ 99659243Sobrien 99759243Sobrien while (pp->p_procid != pp->p_jobid) 99859243Sobrien pp = pp->p_friends; 99959243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 100059243Sobrien pp->p_flags &= ~PPTIME; 100159243Sobrien pp->p_flags |= PTIME; 100259243Sobrien } 100359243Sobrien tp = pp; 100459243Sobrien status = reason = -1; 100559243Sobrien jobflags = 0; 1006316957Sdchagin ohaderr = haderr; 1007316957Sdchagin /* Print status to stderr, except for jobs built-in */ 1008316957Sdchagin haderr = !(flag & JOBLIST); 100959243Sobrien do { 101059243Sobrien#ifdef BACKPIPE 101159243Sobrien /* 101259243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 101359243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 101459243Sobrien */ 101559243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 101659243Sobrien inpipe = 1; 101759243Sobrien pipetail = pp; 101859243Sobrien do 101959243Sobrien pp = pp->p_friends; 102059243Sobrien while (pp->p_friends->p_flags & PPOU); 102159243Sobrien pipehead = pp; 102259243Sobrien pmarker = pp; 102359243Sobrien /* 102459243Sobrien * pmarker is used to hold the place of the proc being processed, so 102559243Sobrien * we can search for the next one downstream later. 102659243Sobrien */ 102759243Sobrien } 1028167465Smp pcond = (tp != pp || (inpipe && tp == pp)); 102959243Sobrien#else /* !BACKPIPE */ 1030167465Smp pcond = (tp != pp); 103159243Sobrien#endif /* BACKPIPE */ 103259243Sobrien 103359243Sobrien jobflags |= pp->p_flags; 103459243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 103559243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 103659243Sobrien ((pstatus == status && pp->p_reason == reason) || 103759243Sobrien !(flag & REASON))) 103859243Sobrien xputchar(' '); 103959243Sobrien else { 104059243Sobrien if (pcond && linp != linbuf) 104159243Sobrien xputchar('\n'); 104259243Sobrien if (flag & NUMBER) { 104359243Sobrien#ifdef BACKPIPE 104459243Sobrien pcond = ((pp == tp && !inpipe) || 104559243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 104659243Sobrien#else /* BACKPIPE */ 104759243Sobrien pcond = (pp == tp); 104859243Sobrien#endif /* BACKPIPE */ 104959243Sobrien if (pcond) 105059243Sobrien xprintf("[%d]%s %c ", pp->p_index, 105159243Sobrien pp->p_index < 10 ? " " : "", 105259243Sobrien pp == pcurrent ? '+' : 105359243Sobrien (pp == pprevious ? '-' : ' ')); 105459243Sobrien else 105559243Sobrien xprintf(" "); 105659243Sobrien } 105759243Sobrien if (flag & FANCY) { 105859243Sobrien xprintf("%5d ", pp->p_procid); 105959243Sobrien#ifdef TCF 106059243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 106159243Sobrien#endif /* TCF */ 106259243Sobrien } 106359243Sobrien if (flag & (REASON | AREASON)) { 106459243Sobrien if (flag & NAME) 106559243Sobrien format = "%-30s"; 106659243Sobrien else 106759243Sobrien format = "%s"; 106859243Sobrien if (pstatus == status) { 106959243Sobrien if (pp->p_reason == reason) { 107059243Sobrien xprintf(format, ""); 107159243Sobrien goto prcomd; 107259243Sobrien } 107359243Sobrien else 107459243Sobrien reason = (int) pp->p_reason; 107559243Sobrien } 107659243Sobrien else { 107759243Sobrien status = pstatus; 107859243Sobrien reason = (int) pp->p_reason; 107959243Sobrien } 108059243Sobrien switch (status) { 108159243Sobrien 108259243Sobrien case PRUNNING: 108359243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 108459243Sobrien break; 108559243Sobrien 108659243Sobrien case PINTERRUPTED: 108759243Sobrien case PSTOPPED: 108859243Sobrien case PSIGNALED: 108959243Sobrien /* 109059243Sobrien * tell what happened to the background job 1091167465Smp * From: Michael Schroeder 109259243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 109359243Sobrien */ 109459243Sobrien if ((flag & REASON) 109559243Sobrien || ((flag & AREASON) 109659243Sobrien && reason != SIGINT 109759243Sobrien && (reason != SIGPIPE 109859243Sobrien || (pp->p_flags & PPOU) == 0))) { 1099167465Smp char *ptr; 1100167465Smp int free_ptr; 110159243Sobrien 1102167465Smp free_ptr = 0; 1103167465Smp ptr = (char *)(intptr_t)mesg[pp->p_reason & 0177].pname; 1104167465Smp if (ptr == NULL) { 1105167465Smp ptr = xasprintf("%s %d", CGETS(17, 5, "Signal"), 1106167465Smp pp->p_reason & 0177); 1107167465Smp cleanup_push(ptr, xfree); 1108167465Smp free_ptr = 1; 1109145479Smp } 111059243Sobrien xprintf(format, ptr); 1111167465Smp if (free_ptr != 0) 1112167465Smp cleanup_until(ptr); 111359243Sobrien } 111459243Sobrien else 111559243Sobrien reason = -1; 111659243Sobrien break; 111759243Sobrien 111859243Sobrien case PNEXITED: 111959243Sobrien case PAEXITED: 112059243Sobrien if (flag & REASON) { 112159243Sobrien if (pp->p_reason) 112259243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 112359243Sobrien else 112459243Sobrien xprintf(format, CGETS(17, 7, "Done")); 112559243Sobrien } 112659243Sobrien break; 112759243Sobrien 112859243Sobrien default: 112959243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 113059243Sobrien status); 113159243Sobrien } 113259243Sobrien } 113359243Sobrien } 113459243Sobrienprcomd: 113559243Sobrien if (flag & NAME) { 113659243Sobrien xprintf("%S", pp->p_command); 113759243Sobrien if (pp->p_flags & PPOU) 113859243Sobrien xprintf(" |"); 113959243Sobrien if (pp->p_flags & PDIAG) 114059243Sobrien xprintf("&"); 114159243Sobrien } 114259243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 1143195609Smp xprintf("%s", CGETS(17, 9, " (core dumped)")); 114459243Sobrien if (tp == pp->p_friends) { 114559243Sobrien if (flag & AMPERSAND) 114659243Sobrien xprintf(" &"); 114759243Sobrien if (flag & JOBDIR && 114859243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1149195609Smp xprintf("%s", CGETS(17, 10, " (wd: ")); 115059243Sobrien dtildepr(tp->p_cwd->di_name); 115159243Sobrien xprintf(")"); 115259243Sobrien } 115359243Sobrien } 115459243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 115559243Sobrien if (linp != linbuf) 115659243Sobrien xprintf("\n\t"); 115759243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 115859243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 115959243Sobrien &pp->p_btime); 116059243Sobrien#else /* !BSDTIMES && !SEQUENT */ 116159243Sobrien lru.tms_utime = pp->p_utime; 116259243Sobrien lru.tms_stime = pp->p_stime; 116359243Sobrien lru.tms_cutime = 0; 116459243Sobrien lru.tms_cstime = 0; 116559243Sobrien prusage(&zru, &lru, pp->p_etime, 116659243Sobrien pp->p_btime); 116759243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 116859243Sobrien 116959243Sobrien } 117059243Sobrien#ifdef BACKPIPE 117159243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 117259243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 117359243Sobrien#else /* !BACKPIPE */ 117459243Sobrien pcond = (tp == pp->p_friends); 117559243Sobrien#endif /* BACKPIPE */ 117659243Sobrien if (pcond) { 117759243Sobrien if (linp != linbuf) 117859243Sobrien xputchar('\n'); 117959243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1180195609Smp xprintf("%s", CGETS(17, 11, "(wd now: ")); 118159243Sobrien dtildepr(dcwd->di_name); 118259243Sobrien xprintf(")\n"); 118359243Sobrien } 118459243Sobrien } 118559243Sobrien#ifdef BACKPIPE 118659243Sobrien if (inpipe) { 118759243Sobrien /* 118859243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 118959243Sobrien * can now skip to past the head 119059243Sobrien */ 119159243Sobrien if (pmarker == pipetail) { 119259243Sobrien inpipe = 0; 119359243Sobrien pp = pipehead; 119459243Sobrien } 119559243Sobrien else { 119659243Sobrien /* 119759243Sobrien * set pp to one before the one we want next, so the while below 119859243Sobrien * increments to the correct spot. 119959243Sobrien */ 120059243Sobrien do 120159243Sobrien pp = pp->p_friends; 120259243Sobrien while (pp->p_friends->p_friends != pmarker); 120359243Sobrien pmarker = pp->p_friends; 120459243Sobrien } 120559243Sobrien } 120659243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 120759243Sobrien#else /* !BACKPIPE */ 120859243Sobrien pcond = ((pp = pp->p_friends) != tp); 120959243Sobrien#endif /* BACKPIPE */ 121059243Sobrien } while (pcond); 121159243Sobrien 121259243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 121359243Sobrien if (jobflags & NUMBER) 121459243Sobrien xprintf(" "); 121559243Sobrien ptprint(tp); 121659243Sobrien } 1217316957Sdchagin haderr = ohaderr; 121859243Sobrien return (jobflags); 121959243Sobrien} 122059243Sobrien 122159243Sobrien/* 122259243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 122359243Sobrien * The following implementation produces similar code and works in all 122459243Sobrien * cases. The 4.3BSD one works only for <, >, != 122559243Sobrien */ 122659243Sobrien# undef timercmp 122759243Sobrien# define timercmp(tvp, uvp, cmp) \ 122859243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 122959243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 123059243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 123159243Sobrien 123259243Sobrienstatic void 1233167465Smpptprint(struct process *tp) 123459243Sobrien{ 123559243Sobrien#ifdef BSDTIMES 123659243Sobrien struct timeval tetime, diff; 123759243Sobrien static struct timeval ztime; 123859243Sobrien struct sysrusage ru; 1239145479Smp struct process *pp = tp; 124059243Sobrien 124159243Sobrien ru = zru; 124259243Sobrien tetime = ztime; 124359243Sobrien do { 124459243Sobrien ruadd(&ru, &pp->p_rusage); 124559243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 124659243Sobrien if (timercmp(&diff, &tetime, >)) 124759243Sobrien tetime = diff; 124859243Sobrien } while ((pp = pp->p_friends) != tp); 124959243Sobrien prusage(&zru, &ru, &tetime, &ztime); 125059243Sobrien#else /* !BSDTIMES */ 125159243Sobrien# ifdef _SEQUENT_ 125259243Sobrien timeval_t tetime, diff; 125359243Sobrien static timeval_t ztime; 125459243Sobrien struct process_stats ru; 1255145479Smp struct process *pp = tp; 125659243Sobrien 125759243Sobrien ru = zru; 125859243Sobrien tetime = ztime; 125959243Sobrien do { 126059243Sobrien ruadd(&ru, &pp->p_rusage); 126159243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 126259243Sobrien if (timercmp(&diff, &tetime, >)) 126359243Sobrien tetime = diff; 126459243Sobrien } while ((pp = pp->p_friends) != tp); 126559243Sobrien prusage(&zru, &ru, &tetime, &ztime); 126659243Sobrien# else /* !_SEQUENT_ */ 126759243Sobrien# ifndef POSIX 126859243Sobrien static time_t ztime = 0; 126959243Sobrien static time_t zu_time = 0; 127059243Sobrien static time_t zs_time = 0; 127159243Sobrien time_t tetime, diff; 127259243Sobrien time_t u_time, s_time; 127359243Sobrien 127459243Sobrien# else /* POSIX */ 127559243Sobrien static clock_t ztime = 0; 127659243Sobrien static clock_t zu_time = 0; 127759243Sobrien static clock_t zs_time = 0; 127859243Sobrien clock_t tetime, diff; 127959243Sobrien clock_t u_time, s_time; 128059243Sobrien 128159243Sobrien# endif /* POSIX */ 128259243Sobrien struct tms zts, rts; 1283145479Smp struct process *pp = tp; 128459243Sobrien 128559243Sobrien u_time = zu_time; 128659243Sobrien s_time = zs_time; 128759243Sobrien tetime = ztime; 128859243Sobrien do { 128959243Sobrien u_time += pp->p_utime; 129059243Sobrien s_time += pp->p_stime; 129159243Sobrien diff = pp->p_etime - pp->p_btime; 129259243Sobrien if (diff > tetime) 129359243Sobrien tetime = diff; 129459243Sobrien } while ((pp = pp->p_friends) != tp); 129559243Sobrien zts.tms_utime = zu_time; 129659243Sobrien zts.tms_stime = zs_time; 129759243Sobrien zts.tms_cutime = 0; 129859243Sobrien zts.tms_cstime = 0; 129959243Sobrien rts.tms_utime = u_time; 130059243Sobrien rts.tms_stime = s_time; 130159243Sobrien rts.tms_cutime = 0; 130259243Sobrien rts.tms_cstime = 0; 130359243Sobrien prusage(&zts, &rts, tetime, ztime); 130459243Sobrien# endif /* !_SEQUENT_ */ 130559243Sobrien#endif /* !BSDTIMES */ 130659243Sobrien} 130759243Sobrien 130859243Sobrien/* 130959243Sobrien * dojobs - print all jobs 131059243Sobrien */ 131159243Sobrien/*ARGSUSED*/ 131259243Sobrienvoid 1313167465Smpdojobs(Char **v, struct command *c) 131459243Sobrien{ 1315145479Smp struct process *pp; 1316316957Sdchagin int flag = NUMBER | NAME | REASON | JOBLIST; 131759243Sobrien int i; 131859243Sobrien 131959243Sobrien USE(c); 132059243Sobrien if (chkstop) 132159243Sobrien chkstop = 2; 132259243Sobrien if (*++v) { 132359243Sobrien if (v[1] || !eq(*v, STRml)) 132459243Sobrien stderror(ERR_JOBS); 132559243Sobrien flag |= FANCY | JOBDIR; 132659243Sobrien } 132759243Sobrien for (i = 1; i <= pmaxindex; i++) 132859243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 132959243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 133059243Sobrien pp->p_flags &= ~PNEEDNOTE; 133159243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 133259243Sobrien pflush(pp); 133359243Sobrien break; 133459243Sobrien } 133559243Sobrien} 133659243Sobrien 133759243Sobrien/* 133859243Sobrien * dofg - builtin - put the job into the foreground 133959243Sobrien */ 134059243Sobrien/*ARGSUSED*/ 134159243Sobrienvoid 1342167465Smpdofg(Char **v, struct command *c) 134359243Sobrien{ 1344145479Smp struct process *pp; 134559243Sobrien 134659243Sobrien USE(c); 134759243Sobrien okpcntl(); 134859243Sobrien ++v; 134959243Sobrien do { 135059243Sobrien pp = pfind(*v); 135159243Sobrien if (!pstart(pp, 1)) { 135259243Sobrien pp->p_procid = 0; 135359243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 135459243Sobrien continue; 135559243Sobrien } 135659243Sobrien pjwait(pp); 135759243Sobrien } while (*v && *++v); 135859243Sobrien} 135959243Sobrien 136059243Sobrien/* 136159243Sobrien * %... - builtin - put the job into the foreground 136259243Sobrien */ 136359243Sobrien/*ARGSUSED*/ 136459243Sobrienvoid 1365167465Smpdofg1(Char **v, struct command *c) 136659243Sobrien{ 1367145479Smp struct process *pp; 136859243Sobrien 136959243Sobrien USE(c); 137059243Sobrien okpcntl(); 137159243Sobrien pp = pfind(v[0]); 137259243Sobrien if (!pstart(pp, 1)) { 137359243Sobrien pp->p_procid = 0; 137459243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 137559243Sobrien return; 137659243Sobrien } 137759243Sobrien pjwait(pp); 137859243Sobrien} 137959243Sobrien 138059243Sobrien/* 138159243Sobrien * dobg - builtin - put the job into the background 138259243Sobrien */ 138359243Sobrien/*ARGSUSED*/ 138459243Sobrienvoid 1385167465Smpdobg(Char **v, struct command *c) 138659243Sobrien{ 1387145479Smp struct process *pp; 138859243Sobrien 138959243Sobrien USE(c); 139059243Sobrien okpcntl(); 139159243Sobrien ++v; 139259243Sobrien do { 139359243Sobrien pp = pfind(*v); 139459243Sobrien if (!pstart(pp, 0)) { 139559243Sobrien pp->p_procid = 0; 139659243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 139759243Sobrien } 139859243Sobrien } while (*v && *++v); 139959243Sobrien} 140059243Sobrien 140159243Sobrien/* 140259243Sobrien * %... & - builtin - put the job into the background 140359243Sobrien */ 140459243Sobrien/*ARGSUSED*/ 140559243Sobrienvoid 1406167465Smpdobg1(Char **v, struct command *c) 140759243Sobrien{ 1408145479Smp struct process *pp; 140959243Sobrien 141059243Sobrien USE(c); 141159243Sobrien pp = pfind(v[0]); 141259243Sobrien if (!pstart(pp, 0)) { 141359243Sobrien pp->p_procid = 0; 141459243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 141559243Sobrien } 141659243Sobrien} 141759243Sobrien 141859243Sobrien/* 141959243Sobrien * dostop - builtin - stop the job 142059243Sobrien */ 142159243Sobrien/*ARGSUSED*/ 142259243Sobrienvoid 1423167465Smpdostop(Char **v, struct command *c) 142459243Sobrien{ 142559243Sobrien USE(c); 142659243Sobrien#ifdef BSDJOBS 142759243Sobrien pkill(++v, SIGSTOP); 142859243Sobrien#endif /* BSDJOBS */ 142959243Sobrien} 143059243Sobrien 143159243Sobrien/* 143259243Sobrien * dokill - builtin - superset of kill (1) 143359243Sobrien */ 143459243Sobrien/*ARGSUSED*/ 143559243Sobrienvoid 1436167465Smpdokill(Char **v, struct command *c) 143759243Sobrien{ 1438145479Smp int signum, len = 0; 1439145479Smp const char *name; 144083098Smp Char *sigptr; 144159243Sobrien 144259243Sobrien USE(c); 144359243Sobrien v++; 144459243Sobrien if (v[0] && v[0][0] == '-') { 144559243Sobrien if (v[0][1] == 'l') { 144659243Sobrien for (signum = 0; signum <= nsig; signum++) { 144759243Sobrien if ((name = mesg[signum].iname) != NULL) { 144859243Sobrien len += strlen(name) + 1; 1449167465Smp if (len >= TermH - 1) { 145059243Sobrien xputchar('\n'); 145159243Sobrien len = strlen(name) + 1; 145259243Sobrien } 145359243Sobrien xprintf("%s ", name); 145459243Sobrien } 145559243Sobrien } 145659243Sobrien xputchar('\n'); 145759243Sobrien return; 145859243Sobrien } 145983098Smp sigptr = &v[0][1]; 146083098Smp if (v[0][1] == 's') { 146183098Smp if (v[1]) { 146283098Smp v++; 146383098Smp sigptr = &v[0][0]; 146483098Smp } else { 146583098Smp stderror(ERR_NAME | ERR_TOOFEW); 146683098Smp } 146783098Smp } 146883098Smp if (Isdigit(*sigptr)) { 1469131962Smp char *ep; 1470131962Smp signum = strtoul(short2str(sigptr), &ep, 0); 1471131962Smp if (*ep || signum < 0 || signum > (MAXSIG-1)) 147259243Sobrien stderror(ERR_NAME | ERR_BADSIG); 147359243Sobrien } 147459243Sobrien else { 147559243Sobrien for (signum = 0; signum <= nsig; signum++) 147659243Sobrien if (mesg[signum].iname && 147783098Smp eq(sigptr, str2short(mesg[signum].iname))) 147859243Sobrien goto gotsig; 147983098Smp setname(short2str(sigptr)); 148059243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 148159243Sobrien } 148259243Sobriengotsig: 148359243Sobrien v++; 148459243Sobrien } 148559243Sobrien else 148659243Sobrien signum = SIGTERM; 148759243Sobrien pkill(v, signum); 148859243Sobrien} 148959243Sobrien 149059243Sobrienstatic void 1491167465Smppkill(Char **v, int signum) 149259243Sobrien{ 1493145479Smp struct process *pp, *np; 149459243Sobrien int jobflags = 0, err1 = 0; 149559243Sobrien pid_t pid; 1496167465Smp Char *cp, **vp, **globbed; 149759243Sobrien 149859243Sobrien /* Avoid globbing %?x patterns */ 149959243Sobrien for (vp = v; vp && *vp; vp++) 150059243Sobrien if (**vp == '%') 150159243Sobrien (void) quote(*vp); 150259243Sobrien 1503167465Smp v = glob_all_or_error(v); 1504167465Smp globbed = v; 1505167465Smp cleanup_push(globbed, blk_cleanup); 150659243Sobrien 1507172665Smp pchild_disabled++; 1508172665Smp cleanup_push(&pchild_disabled, disabled_cleanup); 1509172665Smp if (setintr) { 1510172665Smp pintr_disabled++; 1511172665Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1512172665Smp } 151359243Sobrien 151459243Sobrien while (v && (cp = *v)) { 151559243Sobrien if (*cp == '%') { 151659243Sobrien np = pp = pfind(cp); 151759243Sobrien do 151859243Sobrien jobflags |= np->p_flags; 151959243Sobrien while ((np = np->p_friends) != pp); 152059243Sobrien#ifdef BSDJOBS 152159243Sobrien switch (signum) { 152259243Sobrien 152359243Sobrien case SIGSTOP: 152459243Sobrien case SIGTSTP: 152559243Sobrien case SIGTTIN: 152659243Sobrien case SIGTTOU: 152759243Sobrien if ((jobflags & PRUNNING) == 0) { 152859243Sobrien# ifdef SUSPENDED 152959243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 153059243Sobrien# else /* !SUSPENDED */ 153159243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 153259243Sobrien# endif /* !SUSPENDED */ 153359243Sobrien err1++; 153459243Sobrien goto cont; 153559243Sobrien } 153659243Sobrien break; 153759243Sobrien /* 153859243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 153959243Sobrien * says it is suspended, but it is running; thanks jaap.. 154059243Sobrien */ 154159243Sobrien case SIGCONT: 154259243Sobrien if (!pstart(pp, 0)) { 154359243Sobrien pp->p_procid = 0; 154459243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 154559243Sobrien strerror(errno)); 154659243Sobrien } 154759243Sobrien goto cont; 154859243Sobrien default: 154959243Sobrien break; 155059243Sobrien } 155159243Sobrien#endif /* BSDJOBS */ 155259243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 155359243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 155459243Sobrien err1++; 155559243Sobrien } 155659243Sobrien#ifdef BSDJOBS 155759243Sobrien if (signum == SIGTERM || signum == SIGHUP) 155859243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 155959243Sobrien#endif /* BSDJOBS */ 156059243Sobrien } 156159243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 156259243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 156359243Sobrien else { 1564131962Smp char *ep; 156569408Sache#ifndef WINNT_NATIVE 1566131962Smp pid = strtol(short2str(cp), &ep, 10); 156759243Sobrien#else 1568131962Smp pid = strtoul(short2str(cp), &ep, 0); 156969408Sache#endif /* WINNT_NATIVE */ 1570131962Smp if (*ep) 1571131962Smp stderror(ERR_NAME | ERR_JOBARGS); 1572131962Smp else if (kill(pid, signum) < 0) { 157359243Sobrien xprintf("%d: %s\n", pid, strerror(errno)); 157459243Sobrien err1++; 157559243Sobrien goto cont; 157659243Sobrien } 157759243Sobrien#ifdef BSDJOBS 157859243Sobrien if (signum == SIGTERM || signum == SIGHUP) 157959243Sobrien (void) kill(pid, SIGCONT); 158059243Sobrien#endif /* BSDJOBS */ 158159243Sobrien } 158259243Sobriencont: 158359243Sobrien v++; 158459243Sobrien } 1585167465Smp cleanup_until(&pchild_disabled); 158659243Sobrien if (err1) 158759243Sobrien stderror(ERR_SILENT); 158859243Sobrien} 158959243Sobrien 159059243Sobrien/* 159159243Sobrien * pstart - start the job in foreground/background 159259243Sobrien */ 159359243Sobrienint 1594167465Smppstart(struct process *pp, int foregnd) 159559243Sobrien{ 159659243Sobrien int rv = 0; 1597145479Smp struct process *np; 159859243Sobrien /* We don't use jobflags in this function right now (see below) */ 159959243Sobrien /* long jobflags = 0; */ 160059243Sobrien 1601167465Smp pchild_disabled++; 1602167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 160359243Sobrien np = pp; 160459243Sobrien do { 160559243Sobrien /* We don't use jobflags in this function right now (see below) */ 160659243Sobrien /* jobflags |= np->p_flags; */ 160759243Sobrien if (np->p_flags & (PRUNNING | PSTOPPED)) { 160859243Sobrien np->p_flags |= PRUNNING; 160959243Sobrien np->p_flags &= ~PSTOPPED; 161059243Sobrien if (foregnd) 161159243Sobrien np->p_flags |= PFOREGND; 161259243Sobrien else 161359243Sobrien np->p_flags &= ~PFOREGND; 161459243Sobrien } 161559243Sobrien } while ((np = np->p_friends) != pp); 161659243Sobrien if (!foregnd) 161759243Sobrien pclrcurr(pp); 161859243Sobrien (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 161983098Smp 162083098Smp /* GrP run jobcmd hook if foregrounding */ 162183098Smp if (foregnd) { 162283098Smp job_cmd(pp->p_command); 162383098Smp } 162483098Smp 162559243Sobrien#ifdef BSDJOBS 162659243Sobrien if (foregnd) { 162759243Sobrien rv = tcsetpgrp(FSHTTY, pp->p_jobid); 162859243Sobrien } 162959243Sobrien /* 163059243Sobrien * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU 163159243Sobrien * 2. parent process (csh) receives SIGCHLD 163259243Sobrien * 3. The "csh" signal handling function pchild() is invoked 163359243Sobrien * with a SIGCHLD signal. 163459243Sobrien * 4. pchild() calls wait3(WNOHANG) which returns 0. 163559243Sobrien * The child process is NOT ready to be waited for at this time. 163659243Sobrien * pchild() returns without picking-up the correct status 1637167465Smp * for the child process which generated the SIGCHLD. 163859243Sobrien * 5. CONSEQUENCE : csh is UNaware that the process is stopped 163959243Sobrien * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) 164059243Sobrien * (beto@aixwiz.austin.ibm.com - aug/03/91) 164159243Sobrien * 7. I removed the line completely and added extra checks for 164259243Sobrien * pstart, so that if a job gets attached to and dies inside 164359243Sobrien * a debugger it does not confuse the shell. [christos] 164459243Sobrien * 8. on the nec sx-4 there seems to be a problem, which requires 164559243Sobrien * a syscall(151, getpid(), getpid()) in osinit. Don't ask me 164659243Sobrien * what this is doing. [schott@rzg.mpg.de] 164759243Sobrien */ 164859243Sobrien 164959243Sobrien if (rv != -1) 165059243Sobrien rv = killpg(pp->p_jobid, SIGCONT); 165159243Sobrien#endif /* BSDJOBS */ 1652167465Smp cleanup_until(&pchild_disabled); 165359243Sobrien return rv != -1; 165459243Sobrien} 165559243Sobrien 165659243Sobrienvoid 1657167465Smppanystop(int neednl) 165859243Sobrien{ 1659145479Smp struct process *pp; 166059243Sobrien 166159243Sobrien chkstop = 2; 166259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 166359243Sobrien if (pp->p_flags & PSTOPPED) 166459243Sobrien stderror(ERR_STOPPED, neednl ? "\n" : ""); 166559243Sobrien} 166659243Sobrien 166759243Sobrienstruct process * 1668167465Smppfind(Char *cp) 166959243Sobrien{ 1670145479Smp struct process *pp, *np; 167159243Sobrien 167259243Sobrien if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 167359243Sobrien if (pcurrent == NULL) 167459243Sobrien stderror(ERR_NAME | ERR_JOBCUR); 167559243Sobrien return (pcurrent); 167659243Sobrien } 167759243Sobrien if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 167859243Sobrien if (pprevious == NULL) 167959243Sobrien stderror(ERR_NAME | ERR_JOBPREV); 168059243Sobrien return (pprevious); 168159243Sobrien } 168259243Sobrien if (Isdigit(cp[1])) { 168359243Sobrien int idx = atoi(short2str(cp + 1)); 168459243Sobrien 168559243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 168659243Sobrien if (pp->p_index == idx && pp->p_procid == pp->p_jobid) 168759243Sobrien return (pp); 168859243Sobrien stderror(ERR_NAME | ERR_NOSUCHJOB); 168959243Sobrien } 169059243Sobrien np = NULL; 169159243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 169259243Sobrien if (pp->p_procid == pp->p_jobid) { 169359243Sobrien if (cp[1] == '?') { 1694145479Smp Char *dp; 169559243Sobrien 169659243Sobrien for (dp = pp->p_command; *dp; dp++) { 169759243Sobrien if (*dp != cp[2]) 169859243Sobrien continue; 169959243Sobrien if (prefix(cp + 2, dp)) 170059243Sobrien goto match; 170159243Sobrien } 170259243Sobrien } 170359243Sobrien else if (prefix(cp + 1, pp->p_command)) { 170459243Sobrien match: 170559243Sobrien if (np) 170659243Sobrien stderror(ERR_NAME | ERR_AMBIG); 170759243Sobrien np = pp; 170859243Sobrien } 170959243Sobrien } 171059243Sobrien if (np) 171159243Sobrien return (np); 171259243Sobrien stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 171359243Sobrien /* NOTREACHED */ 171459243Sobrien return (0); 171559243Sobrien} 171659243Sobrien 171759243Sobrien 171859243Sobrien/* 171959243Sobrien * pgetcurr - find most recent job that is not pp, preferably stopped 172059243Sobrien */ 172159243Sobrienstatic struct process * 1722167465Smppgetcurr(struct process *pp) 172359243Sobrien{ 1724145479Smp struct process *np; 1725145479Smp struct process *xp = NULL; 172659243Sobrien 172759243Sobrien for (np = proclist.p_next; np; np = np->p_next) 172859243Sobrien if (np != pcurrent && np != pp && np->p_procid && 172959243Sobrien np->p_procid == np->p_jobid) { 173059243Sobrien if (np->p_flags & PSTOPPED) 173159243Sobrien return (np); 173259243Sobrien if (xp == NULL) 173359243Sobrien xp = np; 173459243Sobrien } 173559243Sobrien return (xp); 173659243Sobrien} 173759243Sobrien 173859243Sobrien/* 173959243Sobrien * donotify - flag the job so as to report termination asynchronously 174059243Sobrien */ 174159243Sobrien/*ARGSUSED*/ 174259243Sobrienvoid 1743167465Smpdonotify(Char **v, struct command *c) 174459243Sobrien{ 1745145479Smp struct process *pp; 174659243Sobrien 174759243Sobrien USE(c); 174859243Sobrien pp = pfind(*++v); 174959243Sobrien pp->p_flags |= PNOTIFY; 175059243Sobrien} 175159243Sobrien 1752167465Smp#ifdef SIGSYNCH 1753167465Smpstatic void 1754167465Smpsynch_handler(int sno) 1755167465Smp{ 1756167465Smp USE(sno); 1757167465Smp} 1758167465Smp#endif /* SIGSYNCH */ 1759167465Smp 176059243Sobrien/* 176159243Sobrien * Do the fork and whatever should be done in the child side that 176259243Sobrien * should not be done if we are not forking at all (like for simple builtin's) 176359243Sobrien * Also do everything that needs any signals fiddled with in the parent side 176459243Sobrien * 176559243Sobrien * Wanttty tells whether process and/or tty pgrps are to be manipulated: 176659243Sobrien * -1: leave tty alone; inherit pgrp from parent 176759243Sobrien * 0: already have tty; manipulate process pgrps only 176859243Sobrien * 1: want to claim tty; manipulate process and tty pgrps 176959243Sobrien * It is usually just the value of tpgrp. 177059243Sobrien */ 177159243Sobrien 1772167465Smppid_t 1773167465Smppfork(struct command *t, int wanttty) 177459243Sobrien{ 1775167465Smp pid_t pid; 1776145479Smp int ignint = 0; 1777167465Smp pid_t pgrp; 177859243Sobrien#ifdef SIGSYNCH 1779167465Smp struct sigaction osa, nsa; 178059243Sobrien#endif /* SIGSYNCH */ 178159243Sobrien 178259243Sobrien /* 178359243Sobrien * A child will be uninterruptible only under very special conditions. 178459243Sobrien * Remember that the semantics of '&' is implemented by disconnecting the 178559243Sobrien * process from the tty so signals do not need to ignored just for '&'. 178659243Sobrien * Thus signals are set to default action for children unless: we have had 178759243Sobrien * an "onintr -" (then specifically ignored) we are not playing with 178859243Sobrien * signals (inherit action) 178959243Sobrien */ 179059243Sobrien if (setintr) 179159243Sobrien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 179259243Sobrien || (gointr && eq(gointr, STRminus)); 179359243Sobrien 179459243Sobrien /* 179559243Sobrien * Check for maximum nesting of 16 processes to avoid Forking loops 179659243Sobrien */ 179759243Sobrien if (child == 16) 179859243Sobrien stderror(ERR_NESTING, 16); 179959243Sobrien#ifdef SIGSYNCH 1800167465Smp nsa.sa_handler = synch_handler; 1801167465Smp sigfillset(&nsa.sa_mask); 1802167465Smp nsa.sa_flags = SA_RESTART; 1803167465Smp if (sigaction(SIGSYNCH, &nsa, &osa)) 1804167465Smp stderror(ERR_SYSTEM, "pfork: sigaction set", strerror(errno)); 180559243Sobrien#endif /* SIGSYNCH */ 180659243Sobrien /* 1807167465Smp * Hold pchild() until we have the process installed in our table. 180859243Sobrien */ 180959243Sobrien if (wanttty < 0) { 1810167465Smp pchild_disabled++; 1811167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 181259243Sobrien } 181359243Sobrien while ((pid = fork()) == -1) 181459243Sobrien if (setintr == 0) 181559243Sobrien (void) sleep(FORKSLEEP); 1816167465Smp else 181759243Sobrien stderror(ERR_NOPROC); 181859243Sobrien if (pid == 0) { 1819167465Smp (void)cleanup_push_mark(); /* Never to be popped */ 1820167465Smp pchild_disabled = 0; 182159243Sobrien settimes(); 182259243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 182359243Sobrien pflushall(); 182459243Sobrien pcurrjob = NULL; 182559243Sobrien#if !defined(BSDTIMES) && !defined(_SEQUENT_) 182659243Sobrien timesdone = 0; 182759243Sobrien#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 182859243Sobrien child++; 182959243Sobrien if (setintr) { 183059243Sobrien setintr = 0; /* until I think otherwise */ 183159243Sobrien /* 183259243Sobrien * Children just get blown away on SIGINT, SIGQUIT unless "onintr 183359243Sobrien * -" seen. 183459243Sobrien */ 183559243Sobrien (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 183659243Sobrien (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 183759243Sobrien#ifdef BSDJOBS 183859243Sobrien if (wanttty >= 0) { 183959243Sobrien /* make stoppable */ 184059243Sobrien (void) signal(SIGTSTP, SIG_DFL); 184159243Sobrien (void) signal(SIGTTIN, SIG_DFL); 184259243Sobrien (void) signal(SIGTTOU, SIG_DFL); 184359243Sobrien } 184459243Sobrien#endif /* BSDJOBS */ 1845167465Smp sigaction(SIGTERM, &parterm, NULL); 184659243Sobrien } 184759243Sobrien else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 184859243Sobrien (void) signal(SIGINT, SIG_IGN); 184959243Sobrien (void) signal(SIGQUIT, SIG_IGN); 185059243Sobrien } 185159243Sobrien#ifdef OREO 1852167465Smp signal(SIGIO, SIG_IGN); /* ignore SIGIO in child too */ 185359243Sobrien#endif /* OREO */ 185459243Sobrien 185559243Sobrien pgetty(wanttty, pgrp); 185659243Sobrien /* 185759243Sobrien * Nohup and nice apply only to NODE_COMMAND's but it would be nice 185859243Sobrien * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 185959243Sobrien * to know about nice/nohup/time 186059243Sobrien */ 186159243Sobrien if (t->t_dflg & F_NOHUP) 186259243Sobrien (void) signal(SIGHUP, SIG_IGN); 186359243Sobrien if (t->t_dflg & F_NICE) { 186459243Sobrien int nval = SIGN_EXTEND_CHAR(t->t_nice); 1865316957Sdchagin#if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) 186683098Smp if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 1867167465Smp stderror(ERR_SYSTEM, "setpriority", strerror(errno)); 1868316957Sdchagin#else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ 186959243Sobrien (void) nice(nval); 1870316957Sdchagin#endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ 187159243Sobrien } 187259243Sobrien#ifdef F_VER 187359243Sobrien if (t->t_dflg & F_VER) { 187459243Sobrien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 187559243Sobrien dohash(NULL, NULL); 187659243Sobrien } 187759243Sobrien#endif /* F_VER */ 187859243Sobrien#ifdef SIGSYNCH 187959243Sobrien /* rfw 8/89 now parent can continue */ 188059243Sobrien if (kill(getppid(), SIGSYNCH)) 188159243Sobrien stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 188259243Sobrien#endif /* SIGSYNCH */ 188359243Sobrien 188459243Sobrien } 188559243Sobrien else { 188659243Sobrien#ifdef POSIXJOBS 188759243Sobrien if (wanttty >= 0) { 188859243Sobrien /* 188959243Sobrien * `Walking' process group fix from Beto Appleton. 189059243Sobrien * (beto@aixwiz.austin.ibm.com) 189159243Sobrien * If setpgid fails at this point that means that 189259243Sobrien * our process leader has died. We flush the current 189359243Sobrien * job and become the process leader ourselves. 189459243Sobrien * The parent will figure that out later. 189559243Sobrien */ 189659243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : pid; 189759243Sobrien if (setpgid(pid, pgrp) == -1 && errno == EPERM) { 189859243Sobrien pcurrjob = NULL; 189959243Sobrien /* 190059243Sobrien * We don't care if this causes an error here; 190159243Sobrien * then we are already in the right process group 190259243Sobrien */ 190359243Sobrien (void) setpgid(pid, pgrp = pid); 190459243Sobrien } 190559243Sobrien } 190659243Sobrien#endif /* POSIXJOBS */ 190759243Sobrien palloc(pid, t); 190859243Sobrien#ifdef SIGSYNCH 1909167465Smp { 1910167465Smp sigset_t pause_mask; 1911167465Smp 191259243Sobrien /* 191359243Sobrien * rfw 8/89 Wait for child to own terminal. Solves half of ugly 191459243Sobrien * synchronization problem. With this change, we know that the only 191559243Sobrien * reason setpgrp to a previous process in a pipeline can fail is that 191659243Sobrien * the previous process has already exited. Without this hack, he may 191759243Sobrien * either have exited or not yet started to run. Two uglies become 191859243Sobrien * one. 191959243Sobrien */ 1920167465Smp sigprocmask(SIG_BLOCK, NULL, &pause); 1921167465Smp sigdelset(&pause_mask, SIGCHLD); 1922167465Smp sigdelset(&pause_mask, SIGSYNCH); 1923167465Smp sigsuspend(&pause_mask); 1924231990Smp (void)handle_pending_signals(); 1925167465Smp if (sigaction(SIGSYNCH, &osa, NULL)) 1926167465Smp stderror(ERR_SYSTEM, "pfork parent: sigaction restore", 1927167465Smp strerror(errno)); 1928167465Smp } 192959243Sobrien#endif /* SIGSYNCH */ 193059243Sobrien 1931167465Smp if (wanttty < 0) 1932167465Smp cleanup_until(&pchild_disabled); 193359243Sobrien } 193459243Sobrien return (pid); 193559243Sobrien} 193659243Sobrien 193759243Sobrienstatic void 1938167465Smpokpcntl(void) 193959243Sobrien{ 194059243Sobrien if (tpgrp == -1) 194159243Sobrien stderror(ERR_JOBCONTROL); 194259243Sobrien if (tpgrp == 0) 194359243Sobrien stderror(ERR_JOBCTRLSUB); 194459243Sobrien} 194559243Sobrien 194659243Sobrien 194759243Sobrienstatic void 1948167465Smpsetttypgrp(int pgrp) 194959243Sobrien{ 195059243Sobrien /* 195159243Sobrien * If we are piping out a builtin, eg. 'echo | more' things can go 195259243Sobrien * out of sequence, i.e. the more can run before the echo. This 195359243Sobrien * can happen even if we have vfork, since the echo will be forked 195459243Sobrien * with the regular fork. In this case, we need to set the tty 195559243Sobrien * pgrp ourselves. If that happens, then the process will be still 195659243Sobrien * alive. And the tty process group will already be set. 195759243Sobrien * This should fix the famous sequent problem as a side effect: 195859243Sobrien * The controlling terminal is lost if all processes in the 195959243Sobrien * terminal process group are zombies. In this case tcgetpgrp() 196059243Sobrien * returns 0. If this happens we must set the terminal process 196159243Sobrien * group again. 196259243Sobrien */ 196359243Sobrien if (tcgetpgrp(FSHTTY) != pgrp) { 196459243Sobrien#ifdef POSIXJOBS 1965167465Smp struct sigaction old; 1966167465Smp 196759243Sobrien /* 196859243Sobrien * tcsetpgrp will set SIGTTOU to all the the processes in 196959243Sobrien * the background according to POSIX... We ignore this here. 197059243Sobrien */ 1971167465Smp sigaction(SIGTTOU, NULL, &old); 1972167465Smp signal(SIGTTOU, SIG_IGN); 197359243Sobrien#endif 197459243Sobrien (void) tcsetpgrp(FSHTTY, pgrp); 197559243Sobrien# ifdef POSIXJOBS 1976167465Smp sigaction(SIGTTOU, &old, NULL); 197759243Sobrien# endif 197859243Sobrien 197959243Sobrien } 198059243Sobrien} 198159243Sobrien 198259243Sobrien 198359243Sobrien/* 198459243Sobrien * if we don't have vfork(), things can still go in the wrong order 198559243Sobrien * resulting in the famous 'Stopped (tty output)'. But some systems 198659243Sobrien * don't permit the setpgid() call, (these are more recent secure 198759243Sobrien * systems such as ibm's aix), when they do. Then we'd rather print 198859243Sobrien * an error message than hang the shell! 198959243Sobrien * I am open to suggestions how to fix that. 199059243Sobrien */ 199159243Sobrienvoid 1992167465Smppgetty(int wanttty, pid_t pgrp) 199359243Sobrien{ 199459243Sobrien#ifdef BSDJOBS 1995167465Smp# ifdef POSIXJOBS 1996167465Smp sigset_t oset, set; 1997167465Smp# endif /* POSIXJOBS */ 199859243Sobrien 1999167465Smp jobdebug_xprintf(("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n", 2000167465Smp wanttty, (int)getpid(), (int)pgrp, (int)mygetpgrp(), 2001167465Smp (int)tcgetpgrp(FSHTTY))); 200259243Sobrien# ifdef POSIXJOBS 200359243Sobrien /* 200459243Sobrien * christos: I am blocking the tty signals till I've set things 200559243Sobrien * correctly.... 200659243Sobrien */ 2007167465Smp if (wanttty > 0) { 2008167465Smp sigemptyset(&set); 2009167465Smp sigaddset(&set, SIGTSTP); 2010167465Smp sigaddset(&set, SIGTTIN); 2011167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 2012167465Smp cleanup_push(&oset, sigprocmask_cleanup); 201359243Sobrien } 201459243Sobrien# endif /* POSIXJOBS */ 201559243Sobrien 201659243Sobrien# ifndef POSIXJOBS 201759243Sobrien if (wanttty > 0) 201859243Sobrien setttypgrp(pgrp); 201959243Sobrien# endif /* !POSIXJOBS */ 202059243Sobrien 202159243Sobrien /* 202259243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 202359243Sobrien * Don't check for tpgrp >= 0 so even non-interactive shells give 202459243Sobrien * background jobs process groups Same for the comparison in the other part 202559243Sobrien * of the #ifdef 202659243Sobrien */ 202759243Sobrien if (wanttty >= 0) { 202859243Sobrien if (setpgid(0, pgrp) == -1) { 202959243Sobrien# ifdef POSIXJOBS 203059243Sobrien /* Walking process group fix; see above */ 203159243Sobrien if (setpgid(0, pgrp = getpid()) == -1) { 203259243Sobrien# endif /* POSIXJOBS */ 203359243Sobrien stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); 203459243Sobrien xexit(0); 203559243Sobrien# ifdef POSIXJOBS 203659243Sobrien } 203759243Sobrien wanttty = pgrp; /* Now we really want the tty, since we became the 203859243Sobrien * the process group leader 203959243Sobrien */ 204059243Sobrien# endif /* POSIXJOBS */ 204159243Sobrien } 204259243Sobrien } 204359243Sobrien 204459243Sobrien# ifdef POSIXJOBS 2045167465Smp if (wanttty > 0) { 204659243Sobrien setttypgrp(pgrp); 2047167465Smp cleanup_until(&oset); 2048167465Smp } 204959243Sobrien# endif /* POSIXJOBS */ 205059243Sobrien 2051167465Smp jobdebug_xprintf(("wanttty %d pid %d pgrp %d tpgrp %d\n", 2052167465Smp wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY))); 205359243Sobrien 205459243Sobrien if (tpgrp > 0) 205559243Sobrien tpgrp = 0; /* gave tty away */ 205659243Sobrien#endif /* BSDJOBS */ 205759243Sobrien} 2058