1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.proc.c,v 3.134 2016/09/23 19:17:28 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 35316958SdchaginRCSID("$tcsh: sh.proc.c,v 3.134 2016/09/23 19:17:28 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 50316958Sdchagin#if defined(_BSD) || (defined(IRIS4D) && __STDC__) || defined(__lucid) 51316958Sdchagin# define BSDWAIT 52316958Sdchagin#endif /* _BSD || (IRIS4D && __STDC__) || __lucid */ 5359243Sobrien#ifndef WTERMSIG 5459243Sobrien# define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 5559243Sobrien# ifndef BSDWAIT 5659243Sobrien# define BSDWAIT 5759243Sobrien# endif /* !BSDWAIT */ 5859243Sobrien#endif /* !WTERMSIG */ 5959243Sobrien#ifndef WEXITSTATUS 6059243Sobrien# define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 6159243Sobrien#endif /* !WEXITSTATUS */ 6259243Sobrien#ifndef WSTOPSIG 6359243Sobrien# define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 6459243Sobrien#endif /* !WSTOPSIG */ 6559243Sobrien 6659243Sobrien#ifdef __osf__ 6759243Sobrien# ifndef WCOREDUMP 6859243Sobrien# define WCOREDUMP(x) (_W_INT(x) & WCOREFLAG) 6959243Sobrien# endif 7059243Sobrien#endif 7159243Sobrien 7259243Sobrien#ifndef WCOREDUMP 7359243Sobrien# ifdef BSDWAIT 7459243Sobrien# define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 7559243Sobrien# else /* !BSDWAIT */ 7659243Sobrien# define WCOREDUMP(w) ((w) & 0200) 7759243Sobrien# endif /* !BSDWAIT */ 7859243Sobrien#endif /* !WCOREDUMP */ 7959243Sobrien 80167465Smp#ifndef JOBDEBUG 81167465Smp# define jobdebug_xprintf(x) (void)0 82167465Smp# define jobdebug_flush() (void)0 83167465Smp#else 84167465Smp# define jobdebug_xprintf(s) xprintf s 85167465Smp# define jobdebug_flush() flush() 86167465Smp#endif 87167465Smp 8859243Sobrien/* 8959243Sobrien * C Shell - functions that manage processes, handling hanging, termination 9059243Sobrien */ 9159243Sobrien 9259243Sobrien#define BIGINDEX 9 /* largest desirable job index */ 9359243Sobrien 9459243Sobrien#ifdef BSDTIMES 9559243Sobrien# ifdef convex 9659243Sobrien/* use 'cvxrusage' to get parallel statistics */ 9759243Sobrienstatic struct cvxrusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 9859243Sobrien 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 9959243Sobrien {0L, 0L}, 0LL, 0LL, 0LL, 0LL, 0L, 0L, 0L, 10059243Sobrien 0LL, 0LL, {0L, 0L, 0L, 0L, 0L}}; 10159243Sobrien# else 10259243Sobrienstatic struct rusage zru; 10359243Sobrien# endif /* convex */ 10459243Sobrien#else /* !BSDTIMES */ 10559243Sobrien# ifdef _SEQUENT_ 10659243Sobrienstatic struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 10759243Sobrien 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 10859243Sobrien# else /* !_SEQUENT_ */ 10959243Sobrien# ifdef _SX 11059243Sobrienstatic struct tms zru = {0, 0, 0, 0}, lru = {0, 0, 0, 0}; 11159243Sobrien# else /* !_SX */ 11259243Sobrienstatic struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 11359243Sobrien# endif /* !_SX */ 11459243Sobrien# endif /* !_SEQUENT_ */ 11559243Sobrien#endif /* !BSDTIMES */ 11659243Sobrien 117167465Smp#ifndef BSDTIMES 118167465Smpstatic int timesdone; /* shtimes buffer full ? */ 119167465Smp#endif /* BSDTIMES */ 120167465Smp 12159243Sobrien#ifndef RUSAGE_CHILDREN 12259243Sobrien# define RUSAGE_CHILDREN -1 12359243Sobrien#endif /* RUSAGE_CHILDREN */ 12459243Sobrien 125167465Smpstatic void pflushall (void); 126167465Smpstatic void pflush (struct process *); 127167465Smpstatic void pfree (struct process *); 128167465Smpstatic void pclrcurr (struct process *); 129195609Smpstatic void morecommand (size_t); 130167465Smpstatic void padd (struct command *); 131167465Smpstatic int pprint (struct process *, int); 132167465Smpstatic void ptprint (struct process *); 133167465Smpstatic void pads (Char *); 134167465Smpstatic void pkill (Char **, int); 135167465Smpstatic struct process *pgetcurr (struct process *); 136167465Smpstatic void okpcntl (void); 137167465Smpstatic void setttypgrp (int); 13859243Sobrien 13959243Sobrien/* 140167465Smp * pchild - call queued by the SIGCHLD signal 14159243Sobrien * indicating that at least one child has terminated or stopped 14259243Sobrien * thus at least one wait system call will definitely return a 14359243Sobrien * childs status. Top level routines (like pwait) must be sure 14459243Sobrien * to mask interrupts when playing with the proclist data structures! 14559243Sobrien */ 146167465Smpvoid 147167465Smppchild(void) 14859243Sobrien{ 149145479Smp struct process *pp; 150145479Smp struct process *fp; 151167465Smp pid_t pid; 15259243Sobrien#ifdef BSDWAIT 15359243Sobrien union wait w; 15459243Sobrien#else /* !BSDWAIT */ 15559243Sobrien int w; 15659243Sobrien#endif /* !BSDWAIT */ 15759243Sobrien int jobflags; 15859243Sobrien#ifdef BSDTIMES 15959243Sobrien struct sysrusage ru; 16059243Sobrien#else /* !BSDTIMES */ 16159243Sobrien# ifdef _SEQUENT_ 16259243Sobrien struct process_stats ru; 16359243Sobrien struct process_stats cpst1, cpst2; 16459243Sobrien timeval_t tv; 16559243Sobrien# else /* !_SEQUENT_ */ 16659243Sobrien struct tms proctimes; 16759243Sobrien 16859243Sobrien if (!timesdone) { 16959243Sobrien timesdone++; 17059243Sobrien (void) times(&shtimes); 17159243Sobrien } 17259243Sobrien# endif /* !_SEQUENT_ */ 17359243Sobrien#endif /* !BSDTIMES */ 17459243Sobrien 175167465Smp jobdebug_xprintf(("pchild()\n")); 17659243Sobrien 17759243Sobrienloop: 178167465Smp jobdebug_xprintf(("Waiting...\n")); 179167465Smp jobdebug_flush(); 18059243Sobrien errno = 0; /* reset, just in case */ 181167465Smp 18269408Sache#ifndef WINNT_NATIVE 18359243Sobrien# ifdef BSDJOBS 18459243Sobrien# ifdef BSDTIMES 18559243Sobrien# ifdef convex 18659243Sobrien /* use 'cvxwait' to get parallel statistics */ 18759243Sobrien pid = cvxwait(&w, 18859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 18959243Sobrien# else 19059243Sobrien /* both a wait3 and rusage */ 191231990Smp# if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (defined(IRIS4D) && SYSVREL <= 3) || defined(__lucid) || defined(__osf__) 192316958Sdchagin#ifdef __ANDROID__ /* no wait3, only wait4 */ 193316958Sdchagin pid = wait4(-1, &w, 194316958Sdchagin (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 195316958Sdchagin#else 19659243Sobrien pid = wait3(&w, 19759243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 198316958Sdchagin#endif /* __ANDROID__ */ 19959243Sobrien# else /* BSDWAIT */ 20059243Sobrien pid = wait3(&w.w_status, 20159243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 20259243Sobrien# endif /* BSDWAIT */ 20359243Sobrien# endif /* convex */ 20459243Sobrien# else /* !BSDTIMES */ 20559243Sobrien# ifdef _SEQUENT_ 20659243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); 20759243Sobrien pid = waitpid(-1, &w, 20859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 20959243Sobrien (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); 21059243Sobrien pr_stat_sub(&cpst2, &cpst1, &ru); 21159243Sobrien# else /* !_SEQUENT_ */ 21259243Sobrien# ifndef POSIX 21359243Sobrien /* we have a wait3, but no rusage stuff */ 21459243Sobrien pid = wait3(&w.w_status, 21559243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 21659243Sobrien# else /* POSIX */ 21759243Sobrien pid = waitpid(-1, &w, 21859243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 21959243Sobrien# endif /* POSIX */ 22059243Sobrien# endif /* !_SEQUENT_ */ 22159243Sobrien# endif /* !BSDTIMES */ 22259243Sobrien# else /* !BSDJOBS */ 22359243Sobrien# ifdef BSDTIMES 22459243Sobrien# define HAVEwait3 22559243Sobrien /* both a wait3 and rusage */ 22659243Sobrien# ifdef hpux 22759243Sobrien pid = wait3(&w.w_status, WNOHANG, 0); 22859243Sobrien# else /* !hpux */ 229231990Smp# ifndef BSDWAIT 230231990Smp pid = wait3(&w, WNOHANG, &ru); 231231990Smp# else 23259243Sobrien pid = wait3(&w.w_status, WNOHANG, &ru); 233231990Smp# endif /* BSDWAIT */ 23459243Sobrien# endif /* !hpux */ 23559243Sobrien# else /* !BSDTIMES */ 23659243Sobrien# ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ 23759243Sobrien# define HAVEwait3 238167465Smp pid = waitpid(-1, &w, 23959243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 24059243Sobrien# endif /* ODT */ 24159243Sobrien# if defined(aiws) || defined(uts) 24259243Sobrien# define HAVEwait3 24359243Sobrien pid = wait3(&w.w_status, 24459243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 24559243Sobrien# endif /* aiws || uts */ 24659243Sobrien# ifndef HAVEwait3 247167465Smp# ifndef BSDWAIT 24859243Sobrien /* no wait3, therefore no rusage */ 24959243Sobrien /* on Sys V, this may hang. I hope it's not going to be a problem */ 250167465Smp pid = wait(&w); 251167465Smp# else /* BSDWAIT */ 25259243Sobrien /* 25359243Sobrien * XXX: for greater than 3 we should use waitpid(). 25459243Sobrien * but then again, SVR4 falls into the POSIX/BSDJOBS category. 25559243Sobrien */ 256167465Smp pid = wait(&w.w_status); 257167465Smp# endif /* BSDWAIT */ 25859243Sobrien# endif /* !HAVEwait3 */ 25959243Sobrien# endif /* !BSDTIMES */ 26059243Sobrien# endif /* !BSDJOBS */ 26169408Sache#else /* WINNT_NATIVE */ 262167465Smp pid = waitpid(-1, &w, 26359243Sobrien (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 26469408Sache#endif /* WINNT_NATIVE */ 26559243Sobrien 266167465Smp jobdebug_xprintf(("parent %d pid %d, retval %x termsig %x retcode %x\n", 267167465Smp (int)getpid(), (int)pid, w, WTERMSIG(w), 268167465Smp WEXITSTATUS(w))); 269167465Smp jobdebug_flush(); 27059243Sobrien 27159243Sobrien if ((pid == 0) || (pid == -1)) { 272231990Smp (void)handle_pending_signals(); 273167465Smp jobdebug_xprintf(("errno == %d\n", errno)); 274167465Smp if (errno == EINTR) 27559243Sobrien goto loop; 276145479Smp goto end; 27759243Sobrien } 27859243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 27959243Sobrien if (pid == pp->p_procid) 28059243Sobrien goto found; 28169408Sache#if !defined(BSDJOBS) && !defined(WINNT_NATIVE) 28259243Sobrien /* this should never have happened */ 28359243Sobrien stderror(ERR_SYNC, pid); 28459243Sobrien xexit(0); 28569408Sache#else /* BSDJOBS || WINNT_NATIVE */ 28659243Sobrien goto loop; 28769408Sache#endif /* !BSDJOBS && !WINNT_NATIVE */ 28859243Sobrienfound: 28959243Sobrien pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 29059243Sobrien if (WIFSTOPPED(w)) { 29159243Sobrien pp->p_flags |= PSTOPPED; 29259243Sobrien pp->p_reason = WSTOPSIG(w); 29359243Sobrien } 29459243Sobrien else { 29559243Sobrien if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 29659243Sobrien#ifndef BSDTIMES 29759243Sobrien# ifdef _SEQUENT_ 29859243Sobrien (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); 29959243Sobrien# else /* !_SEQUENT_ */ 30059243Sobrien pp->p_etime = times(&proctimes); 30159243Sobrien# endif /* !_SEQUENT_ */ 30259243Sobrien#else /* BSDTIMES */ 30359243Sobrien (void) gettimeofday(&pp->p_etime, NULL); 30459243Sobrien#endif /* BSDTIMES */ 30559243Sobrien 30659243Sobrien 30759243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 30859243Sobrien pp->p_rusage = ru; 30959243Sobrien#else /* !BSDTIMES && !_SEQUENT_ */ 31059243Sobrien (void) times(&proctimes); 31159243Sobrien pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 31259243Sobrien pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 31359243Sobrien shtimes = proctimes; 31459243Sobrien#endif /* !BSDTIMES && !_SEQUENT_ */ 31559243Sobrien if (WIFSIGNALED(w)) { 31659243Sobrien if (WTERMSIG(w) == SIGINT) 31759243Sobrien pp->p_flags |= PINTERRUPTED; 31859243Sobrien else 31959243Sobrien pp->p_flags |= PSIGNALED; 32059243Sobrien if (WCOREDUMP(w)) 32159243Sobrien pp->p_flags |= PDUMPED; 32259243Sobrien pp->p_reason = WTERMSIG(w); 32359243Sobrien } 32459243Sobrien else { 32559243Sobrien pp->p_reason = WEXITSTATUS(w); 32659243Sobrien if (pp->p_reason != 0) 32759243Sobrien pp->p_flags |= PAEXITED; 32859243Sobrien else 32959243Sobrien pp->p_flags |= PNEXITED; 33059243Sobrien } 33159243Sobrien } 33259243Sobrien jobflags = 0; 33359243Sobrien fp = pp; 33459243Sobrien do { 33559243Sobrien if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 33659243Sobrien !child && adrof(STRtime) && 33759243Sobrien#ifdef BSDTIMES 33859243Sobrien fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 33959243Sobrien#else /* !BSDTIMES */ 34059243Sobrien# ifdef _SEQUENT_ 34159243Sobrien fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 34259243Sobrien# else /* !_SEQUENT_ */ 34359243Sobrien# ifndef POSIX 34459243Sobrien (fp->p_utime + fp->p_stime) / HZ 34559243Sobrien# else /* POSIX */ 34659243Sobrien (fp->p_utime + fp->p_stime) / clk_tck 34759243Sobrien# endif /* POSIX */ 34859243Sobrien# endif /* !_SEQUENT_ */ 34959243Sobrien#endif /* !BSDTIMES */ 35059243Sobrien >= atoi(short2str(varval(STRtime)))) 35159243Sobrien fp->p_flags |= PTIME; 35259243Sobrien jobflags |= fp->p_flags; 35359243Sobrien } while ((fp = fp->p_friends) != pp); 35459243Sobrien pp->p_flags &= ~PFOREGND; 35559243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 35659243Sobrien pp->p_flags &= ~PPTIME; 35759243Sobrien pp->p_flags |= PTIME; 35859243Sobrien } 35959243Sobrien if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 36059243Sobrien fp = pp; 36159243Sobrien do { 36259243Sobrien if (fp->p_flags & PSTOPPED) 36359243Sobrien fp->p_flags |= PREPORTED; 36459243Sobrien } while ((fp = fp->p_friends) != pp); 36559243Sobrien while (fp->p_procid != fp->p_jobid) 36659243Sobrien fp = fp->p_friends; 36759243Sobrien if (jobflags & PSTOPPED) { 36859243Sobrien if (pcurrent && pcurrent != fp) 36959243Sobrien pprevious = pcurrent; 37059243Sobrien pcurrent = fp; 37159243Sobrien } 37259243Sobrien else 37359243Sobrien pclrcurr(fp); 37459243Sobrien if (jobflags & PFOREGND) { 37559243Sobrien if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 37659243Sobrien#ifdef notdef 37759243Sobrien jobflags & PAEXITED || 37859243Sobrien#endif /* notdef */ 379231990Smp fp->p_cwd == NULL || 38059243Sobrien !eq(dcwd->di_name, fp->p_cwd->di_name))) { 38159243Sobrien /* PWP: print a newline after ^C */ 38259243Sobrien if (jobflags & PINTERRUPTED) { 383167465Smp xputchar('\r' | QUOTE); 384167465Smp xputchar('\n'); 38559243Sobrien } 38659243Sobrien#ifdef notdef 38759243Sobrien else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 38859243Sobrien ptprint(fp); 38959243Sobrien#endif /* notdef */ 39059243Sobrien } 39159243Sobrien } 39259243Sobrien else { 39359243Sobrien if (jobflags & PNOTIFY || adrof(STRnotify)) { 394167465Smp xputchar('\r' | QUOTE); 395167465Smp xputchar('\n'); 39659243Sobrien (void) pprint(pp, NUMBER | NAME | REASON); 39759243Sobrien if ((jobflags & PSTOPPED) == 0) 39859243Sobrien pflush(pp); 399167465Smp if (GettingInput) { 400167465Smp errno = 0; 401167465Smp (void) Rawmode(); 40259243Sobrien#ifdef notdef 403167465Smp /* 404167465Smp * don't really want to do that, because it 405167465Smp * will erase our message in case of multi-line 406167465Smp * input 407167465Smp */ 408167465Smp ClearLines(); 40959243Sobrien#endif /* notdef */ 410167465Smp ClearDisp(); 411167465Smp Refresh(); 41259243Sobrien } 41359243Sobrien } 41459243Sobrien else { 41559243Sobrien fp->p_flags |= PNEEDNOTE; 416167465Smp neednote = 1; 41759243Sobrien } 41859243Sobrien } 41959243Sobrien } 420167465Smp#if defined(BSDJOBS) || defined(HAVEwait3) ||defined(WINNT_NATIVE) 42159243Sobrien goto loop; 42259243Sobrien#endif /* BSDJOBS || HAVEwait3 */ 423145479Smp end: 424145479Smp ; 42559243Sobrien} 42659243Sobrien 42759243Sobrienvoid 428167465Smppnote(void) 42959243Sobrien{ 430145479Smp struct process *pp; 43159243Sobrien int flags; 43259243Sobrien 43359243Sobrien neednote = 0; 43459243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 43559243Sobrien if (pp->p_flags & PNEEDNOTE) { 436167465Smp pchild_disabled++; 437167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 43859243Sobrien pp->p_flags &= ~PNEEDNOTE; 43959243Sobrien flags = pprint(pp, NUMBER | NAME | REASON); 44059243Sobrien if ((flags & (PRUNNING | PSTOPPED)) == 0) 44159243Sobrien pflush(pp); 442167465Smp cleanup_until(&pchild_disabled); 44359243Sobrien } 44459243Sobrien } 44559243Sobrien} 44659243Sobrien 44759243Sobrien 44859243Sobrienstatic void 449167465Smppfree(struct process *pp) 45059243Sobrien{ 451167465Smp xfree(pp->p_command); 45259243Sobrien if (pp->p_cwd && --pp->p_cwd->di_count == 0) 45359243Sobrien if (pp->p_cwd->di_next == 0) 45459243Sobrien dfree(pp->p_cwd); 455167465Smp xfree(pp); 45659243Sobrien} 45759243Sobrien 45859243Sobrien 45959243Sobrien/* 46059243Sobrien * pwait - wait for current job to terminate, maintaining integrity 46159243Sobrien * of current and previous job indicators. 46259243Sobrien */ 46359243Sobrienvoid 464167465Smppwait(void) 46559243Sobrien{ 466145479Smp struct process *fp, *pp; 46759243Sobrien 46859243Sobrien /* 46959243Sobrien * Here's where dead procs get flushed. 47059243Sobrien */ 47159243Sobrien for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 47259243Sobrien if (pp->p_procid == 0) { 47359243Sobrien fp->p_next = pp->p_next; 47459243Sobrien pfree(pp); 47559243Sobrien pp = fp; 47659243Sobrien } 47759243Sobrien pjwait(pcurrjob); 47859243Sobrien} 47959243Sobrien 48059243Sobrien 48159243Sobrien/* 48259243Sobrien * pjwait - wait for a job to finish or become stopped 48359243Sobrien * It is assumed to be in the foreground state (PFOREGND) 48459243Sobrien */ 48559243Sobrienvoid 486167465Smppjwait(struct process *pp) 48759243Sobrien{ 488145479Smp struct process *fp; 48959243Sobrien int jobflags, reason; 490167465Smp sigset_t oset, set, pause_mask; 491167465Smp Char *reason_str; 492167465Smp 49359243Sobrien while (pp->p_procid != pp->p_jobid) 49459243Sobrien pp = pp->p_friends; 49559243Sobrien fp = pp; 49659243Sobrien 49759243Sobrien do { 49859243Sobrien if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 499195609Smp xprintf("%s", CGETS(17, 1, "BUG: waiting for background job!\n")); 50059243Sobrien } while ((fp = fp->p_friends) != pp); 50159243Sobrien /* 50259243Sobrien * Now keep pausing as long as we are not interrupted (SIGINT), and the 50359243Sobrien * target process, or any of its friends, are running 50459243Sobrien */ 50559243Sobrien fp = pp; 506167465Smp sigemptyset(&set); 507167465Smp sigaddset(&set, SIGINT); 508167465Smp sigaddset(&set, SIGCHLD); 509167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 510167465Smp cleanup_push(&oset, sigprocmask_cleanup); 511167465Smp pause_mask = oset; 512167465Smp sigdelset(&pause_mask, SIGCHLD); 513316958Sdchagin sigaddset(&pause_mask, SIGINT); 51459243Sobrien for (;;) { 515231990Smp (void)handle_pending_signals(); 51659243Sobrien jobflags = 0; 51759243Sobrien do 51859243Sobrien jobflags |= fp->p_flags; 51959243Sobrien while ((fp = (fp->p_friends)) != pp); 52059243Sobrien if ((jobflags & PRUNNING) == 0) 52159243Sobrien break; 522167465Smp jobdebug_xprintf(("%d starting to sigsuspend for SIGCHLD on %d\n", 523167465Smp getpid(), fp->p_procid)); 524167465Smp sigsuspend(&pause_mask); 52559243Sobrien } 526167465Smp cleanup_until(&oset); 527167465Smp jobdebug_xprintf(("%d returned from sigsuspend loop\n", getpid())); 52859243Sobrien#ifdef BSDJOBS 52959243Sobrien if (tpgrp > 0) /* get tty back */ 53059243Sobrien (void) tcsetpgrp(FSHTTY, tpgrp); 53159243Sobrien#endif /* BSDJOBS */ 53259243Sobrien if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 533195609Smp fp->p_cwd == NULL || !eq(dcwd->di_name, fp->p_cwd->di_name)) { 53459243Sobrien if (jobflags & PSTOPPED) { 53559243Sobrien xputchar('\n'); 53659243Sobrien if (adrof(STRlistjobs)) { 53759243Sobrien Char *jobcommand[3]; 53859243Sobrien 53959243Sobrien jobcommand[0] = STRjobs; 54059243Sobrien if (eq(varval(STRlistjobs), STRlong)) 54159243Sobrien jobcommand[1] = STRml; 54259243Sobrien else 54359243Sobrien jobcommand[1] = NULL; 54459243Sobrien jobcommand[2] = NULL; 54559243Sobrien 54659243Sobrien dojobs(jobcommand, NULL); 54759243Sobrien (void) pprint(pp, SHELLDIR); 54859243Sobrien } 54959243Sobrien else 55059243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 55159243Sobrien } 55259243Sobrien else 55359243Sobrien (void) pprint(pp, AREASON | SHELLDIR); 55459243Sobrien } 55559243Sobrien if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 55659243Sobrien (!gointr || !eq(gointr, STRminus))) { 55759243Sobrien if ((jobflags & PSTOPPED) == 0) 55859243Sobrien pflush(pp); 55959243Sobrien pintr1(0); 56059243Sobrien /* NOTREACHED */ 56159243Sobrien } 56259243Sobrien reason = 0; 56359243Sobrien fp = pp; 56459243Sobrien do { 565231990Smp /* In case of pipelines only the result of the last 566231990Smp * command should be taken in account */ 567231990Smp if (!anyerror && !(fp->p_flags & PBRACE) 568231990Smp && ((fp->p_flags & PPOU) || (fp->p_flags & PBACKQ))) 569231990Smp continue; 57059243Sobrien if (fp->p_reason) 57159243Sobrien reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 57259243Sobrien fp->p_reason | META : fp->p_reason; 57359243Sobrien } while ((fp = fp->p_friends) != pp); 57459243Sobrien /* 57559243Sobrien * Don't report on backquoted jobs, cause it will mess up 57659243Sobrien * their output. 57759243Sobrien */ 57859243Sobrien if ((reason != 0) && (adrof(STRprintexitvalue)) && 57959243Sobrien (pp->p_flags & PBACKQ) == 0) 58059243Sobrien xprintf(CGETS(17, 2, "Exit %d\n"), reason); 581231990Smp reason_str = putn((tcsh_number_t)reason); 582167465Smp cleanup_push(reason_str, xfree); 583167465Smp setv(STRstatus, reason_str, VAR_READWRITE); 584167465Smp cleanup_ignore(reason_str); 585167465Smp cleanup_until(reason_str); 58659243Sobrien if (reason && exiterr) 58759243Sobrien exitstat(); 58859243Sobrien pflush(pp); 58959243Sobrien} 59059243Sobrien 59159243Sobrien/* 59259243Sobrien * dowait - wait for all processes to finish 59359243Sobrien */ 59459243Sobrien 59559243Sobrien/*ARGSUSED*/ 59659243Sobrienvoid 597167465Smpdowait(Char **v, struct command *c) 59859243Sobrien{ 599145479Smp struct process *pp; 600316958Sdchagin 601316958Sdchagin /* the current block mask to be able to restore */ 602316958Sdchagin sigset_t old_mask; 603316958Sdchagin 604316958Sdchagin /* block mask for critical section: OLD_MASK U {SIGCHLD} */ 605316958Sdchagin sigset_t block_mask; 606316958Sdchagin 607316958Sdchagin /* ignore those during blocking sigsuspend: 608316958Sdchagin OLD_MASK / {SIGCHLD, possibly(SIGINT)} */ 609167465Smp sigset_t pause_mask; 610316958Sdchagin 611231990Smp int opintr_disabled, gotsig; 61259243Sobrien 61359243Sobrien USE(c); 61459243Sobrien USE(v); 61559243Sobrien pjobs++; 616316958Sdchagin 617167465Smp sigprocmask(SIG_BLOCK, NULL, &pause_mask); 618167465Smp sigdelset(&pause_mask, SIGCHLD); 61959243Sobrien if (setintr) 620167465Smp sigdelset(&pause_mask, SIGINT); 621316958Sdchagin 622316958Sdchagin /* critical section, block also SIGCHLD */ 623316958Sdchagin sigprocmask(SIG_BLOCK, NULL, &block_mask); 624316958Sdchagin sigaddset(&block_mask, SIGCHLD); 625316958Sdchagin sigprocmask(SIG_BLOCK, &block_mask, &old_mask); 626316958Sdchagin 627316958Sdchagin /* detect older SIGCHLDs and remove PRUNNING flag from proclist */ 628316958Sdchagin (void)handle_pending_signals(); 629316958Sdchagin 63059243Sobrienloop: 63159243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 63259243Sobrien if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ 63359243Sobrien pp->p_flags & PRUNNING) { 634316958Sdchagin /* wait for (or pick up alredy blocked) SIGCHLD */ 635167465Smp sigsuspend(&pause_mask); 636316958Sdchagin 637316958Sdchagin /* make the 'wait' interuptable by CTRL-C */ 638231990Smp opintr_disabled = pintr_disabled; 639231990Smp pintr_disabled = 0; 640231990Smp gotsig = handle_pending_signals(); 641231990Smp pintr_disabled = opintr_disabled; 642231990Smp if (gotsig) 643231990Smp break; 64459243Sobrien goto loop; 64559243Sobrien } 64659243Sobrien pjobs = 0; 647316958Sdchagin 648316958Sdchagin sigprocmask(SIG_SETMASK, &old_mask, NULL); 64959243Sobrien} 65059243Sobrien 65159243Sobrien/* 65259243Sobrien * pflushall - flush all jobs from list (e.g. at fork()) 65359243Sobrien */ 65459243Sobrienstatic void 655167465Smppflushall(void) 65659243Sobrien{ 657145479Smp struct process *pp; 65859243Sobrien 65959243Sobrien for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 66059243Sobrien if (pp->p_procid) 66159243Sobrien pflush(pp); 66259243Sobrien} 66359243Sobrien 66459243Sobrien/* 66559243Sobrien * pflush - flag all process structures in the same job as the 66659243Sobrien * the argument process for deletion. The actual free of the 66759243Sobrien * space is not done here since pflush is called at interrupt level. 66859243Sobrien */ 66959243Sobrienstatic void 670167465Smppflush(struct process *pp) 67159243Sobrien{ 672145479Smp struct process *np; 673145479Smp int idx; 67459243Sobrien 67559243Sobrien if (pp->p_procid == 0) { 676195609Smp xprintf("%s", CGETS(17, 3, "BUG: process flushed twice")); 67759243Sobrien return; 67859243Sobrien } 67959243Sobrien while (pp->p_procid != pp->p_jobid) 68059243Sobrien pp = pp->p_friends; 68159243Sobrien pclrcurr(pp); 68259243Sobrien if (pp == pcurrjob) 68359243Sobrien pcurrjob = 0; 68459243Sobrien idx = pp->p_index; 68559243Sobrien np = pp; 68659243Sobrien do { 68759243Sobrien np->p_index = np->p_procid = 0; 68859243Sobrien np->p_flags &= ~PNEEDNOTE; 68959243Sobrien } while ((np = np->p_friends) != pp); 69059243Sobrien if (idx == pmaxindex) { 69159243Sobrien for (np = proclist.p_next, idx = 0; np; np = np->p_next) 69259243Sobrien if (np->p_index > idx) 69359243Sobrien idx = np->p_index; 69459243Sobrien pmaxindex = idx; 69559243Sobrien } 69659243Sobrien} 69759243Sobrien 69859243Sobrien/* 69959243Sobrien * pclrcurr - make sure the given job is not the current or previous job; 70059243Sobrien * pp MUST be the job leader 70159243Sobrien */ 70259243Sobrienstatic void 703167465Smppclrcurr(struct process *pp) 70459243Sobrien{ 70559243Sobrien if (pp == pcurrent) { 70659243Sobrien if (pprevious != NULL) { 70759243Sobrien pcurrent = pprevious; 70859243Sobrien pprevious = pgetcurr(pp); 70959243Sobrien } 71059243Sobrien else { 71159243Sobrien pcurrent = pgetcurr(pp); 71259243Sobrien pprevious = pgetcurr(pp); 71359243Sobrien } 71459243Sobrien } 71559243Sobrien else if (pp == pprevious) 71659243Sobrien pprevious = pgetcurr(pp); 71759243Sobrien} 71859243Sobrien 71959243Sobrien/* +4 here is 1 for '\0', 1 ea for << >& >> */ 720195609Smpstatic Char *cmdstr; 721195609Smpstatic size_t cmdmax; 722167465Smpstatic size_t cmdlen; 72359243Sobrienstatic Char *cmdp; 724195609Smp#define CMD_INIT 1024 725195609Smp#define CMD_INCR 64 72659243Sobrien 727195609Smpstatic void 728195609Smpmorecommand(size_t s) 729195609Smp{ 730195609Smp Char *ncmdstr; 731195609Smp ptrdiff_t d; 732195609Smp 733195609Smp cmdmax += s; 734195609Smp ncmdstr = xrealloc(cmdstr, cmdmax * sizeof(*cmdstr)); 735195609Smp d = ncmdstr - cmdstr; 736195609Smp cmdstr = ncmdstr; 737195609Smp cmdp += d; 738195609Smp} 739195609Smp 74083098Smp/* GrP 74183098Smp * unparse - Export padd() functionality 74283098Smp */ 74383098SmpChar * 744167465Smpunparse(struct command *t) 74583098Smp{ 746195609Smp if (cmdmax == 0) 747195609Smp morecommand(CMD_INIT); 748195609Smp cmdp = cmdstr; 74983098Smp cmdlen = 0; 75083098Smp padd(t); 75183098Smp *cmdp++ = '\0'; 752195609Smp return Strsave(cmdstr); 75383098Smp} 75483098Smp 75583098Smp 75659243Sobrien/* 75759243Sobrien * palloc - allocate a process structure and fill it up. 75859243Sobrien * an important assumption is made that the process is running. 75959243Sobrien */ 76059243Sobrienvoid 761167465Smppalloc(pid_t pid, struct command *t) 76259243Sobrien{ 763145479Smp struct process *pp; 76459243Sobrien int i; 76559243Sobrien 766167465Smp pp = xcalloc(1, sizeof(struct process)); 76759243Sobrien pp->p_procid = pid; 768231990Smp pp->p_parentid = shpgrp; 76959243Sobrien pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; 77059243Sobrien if (t->t_dflg & F_TIME) 77159243Sobrien pp->p_flags |= PPTIME; 77259243Sobrien if (t->t_dflg & F_BACKQ) 77359243Sobrien pp->p_flags |= PBACKQ; 77459243Sobrien if (t->t_dflg & F_HUP) 77559243Sobrien pp->p_flags |= PHUP; 776231990Smp if (t->t_dcom && t->t_dcom[0] && (*t->t_dcom[0] == '{')) 777231990Smp pp->p_flags |= PBRACE; 778195609Smp if (cmdmax == 0) 779195609Smp morecommand(CMD_INIT); 780195609Smp cmdp = cmdstr; 78159243Sobrien cmdlen = 0; 78259243Sobrien padd(t); 78359243Sobrien *cmdp++ = 0; 78459243Sobrien if (t->t_dflg & F_PIPEOUT) { 78559243Sobrien pp->p_flags |= PPOU; 78659243Sobrien if (t->t_dflg & F_STDERR) 78759243Sobrien pp->p_flags |= PDIAG; 78859243Sobrien } 789195609Smp pp->p_command = Strsave(cmdstr); 79059243Sobrien if (pcurrjob) { 79159243Sobrien struct process *fp; 79259243Sobrien 79359243Sobrien /* careful here with interrupt level */ 79459243Sobrien pp->p_cwd = 0; 79559243Sobrien pp->p_index = pcurrjob->p_index; 79659243Sobrien pp->p_friends = pcurrjob; 79759243Sobrien pp->p_jobid = pcurrjob->p_procid; 79859243Sobrien for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 79959243Sobrien continue; 80059243Sobrien fp->p_friends = pp; 80159243Sobrien } 80259243Sobrien else { 80359243Sobrien pcurrjob = pp; 80459243Sobrien pp->p_jobid = pid; 80559243Sobrien pp->p_friends = pp; 80659243Sobrien pp->p_cwd = dcwd; 80759243Sobrien dcwd->di_count++; 80859243Sobrien if (pmaxindex < BIGINDEX) 80959243Sobrien pp->p_index = ++pmaxindex; 81059243Sobrien else { 81159243Sobrien struct process *np; 81259243Sobrien 81359243Sobrien for (i = 1;; i++) { 81459243Sobrien for (np = proclist.p_next; np; np = np->p_next) 81559243Sobrien if (np->p_index == i) 81659243Sobrien goto tryagain; 81759243Sobrien pp->p_index = i; 81859243Sobrien if (i > pmaxindex) 81959243Sobrien pmaxindex = i; 82059243Sobrien break; 82159243Sobrien tryagain:; 82259243Sobrien } 82359243Sobrien } 82459243Sobrien if (pcurrent == NULL) 82559243Sobrien pcurrent = pp; 82659243Sobrien else if (pprevious == NULL) 82759243Sobrien pprevious = pp; 82859243Sobrien } 82959243Sobrien pp->p_next = proclist.p_next; 83059243Sobrien proclist.p_next = pp; 83159243Sobrien#ifdef BSDTIMES 83259243Sobrien (void) gettimeofday(&pp->p_btime, NULL); 83359243Sobrien#else /* !BSDTIMES */ 83459243Sobrien# ifdef _SEQUENT_ 83559243Sobrien (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); 83659243Sobrien# else /* !_SEQUENT_ */ 83759243Sobrien { 83859243Sobrien struct tms tmptimes; 83959243Sobrien 84059243Sobrien pp->p_btime = times(&tmptimes); 84159243Sobrien } 84259243Sobrien# endif /* !_SEQUENT_ */ 84359243Sobrien#endif /* !BSDTIMES */ 84459243Sobrien} 84559243Sobrien 84659243Sobrienstatic void 847167465Smppadd(struct command *t) 84859243Sobrien{ 84959243Sobrien Char **argp; 85059243Sobrien 85159243Sobrien if (t == 0) 85259243Sobrien return; 85359243Sobrien switch (t->t_dtyp) { 85459243Sobrien 85559243Sobrien case NODE_PAREN: 85659243Sobrien pads(STRLparensp); 85759243Sobrien padd(t->t_dspr); 85859243Sobrien pads(STRspRparen); 85959243Sobrien break; 86059243Sobrien 86159243Sobrien case NODE_COMMAND: 86259243Sobrien for (argp = t->t_dcom; *argp; argp++) { 86359243Sobrien pads(*argp); 86459243Sobrien if (argp[1]) 86559243Sobrien pads(STRspace); 86659243Sobrien } 86759243Sobrien break; 86859243Sobrien 86959243Sobrien case NODE_OR: 87059243Sobrien case NODE_AND: 87159243Sobrien case NODE_PIPE: 87259243Sobrien case NODE_LIST: 87359243Sobrien padd(t->t_dcar); 87459243Sobrien switch (t->t_dtyp) { 87559243Sobrien case NODE_OR: 87659243Sobrien pads(STRspor2sp); 87759243Sobrien break; 87859243Sobrien case NODE_AND: 87959243Sobrien pads(STRspand2sp); 88059243Sobrien break; 88159243Sobrien case NODE_PIPE: 88259243Sobrien pads(STRsporsp); 88359243Sobrien break; 88459243Sobrien case NODE_LIST: 88559243Sobrien pads(STRsemisp); 88659243Sobrien break; 88759243Sobrien default: 88859243Sobrien break; 88959243Sobrien } 89059243Sobrien padd(t->t_dcdr); 89159243Sobrien return; 89259243Sobrien 89359243Sobrien default: 89459243Sobrien break; 89559243Sobrien } 89659243Sobrien if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 89759243Sobrien pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 89859243Sobrien pads(t->t_dlef); 89959243Sobrien } 90059243Sobrien if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 90159243Sobrien pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 90259243Sobrien if (t->t_dflg & F_STDERR) 90359243Sobrien pads(STRand); 90459243Sobrien pads(STRspace); 90559243Sobrien pads(t->t_drit); 90659243Sobrien } 90759243Sobrien} 90859243Sobrien 90959243Sobrienstatic void 910167465Smppads(Char *cp) 91159243Sobrien{ 912195609Smp size_t i, len; 91359243Sobrien 91459243Sobrien /* 91559243Sobrien * Avoid the Quoted Space alias hack! Reported by: 91659243Sobrien * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 91759243Sobrien */ 91859243Sobrien if (cp[0] == STRQNULL[0]) 91959243Sobrien cp++; 92059243Sobrien 921167465Smp i = Strlen(cp); 92259243Sobrien 923195609Smp len = cmdlen + i + CMD_INCR; 924195609Smp if (len >= cmdmax) 925195609Smp morecommand(len); 92659243Sobrien (void) Strcpy(cmdp, cp); 92759243Sobrien cmdp += i; 92859243Sobrien cmdlen += i; 92959243Sobrien} 93059243Sobrien 93159243Sobrien/* 93259243Sobrien * psavejob - temporarily save the current job on a one level stack 93359243Sobrien * so another job can be created. Used for { } in exp6 93459243Sobrien * and `` in globbing. 93559243Sobrien */ 93659243Sobrienvoid 937167465Smppsavejob(void) 93859243Sobrien{ 93959243Sobrien pholdjob = pcurrjob; 94059243Sobrien pcurrjob = NULL; 94159243Sobrien} 94259243Sobrien 94359243Sobrienvoid 944167465Smppsavejob_cleanup(void *dummy) 94559243Sobrien{ 946167465Smp USE(dummy); 94759243Sobrien pcurrjob = pholdjob; 94859243Sobrien pholdjob = NULL; 94959243Sobrien} 95059243Sobrien 95159243Sobrien/* 95259243Sobrien * pendjob - indicate that a job (set of commands) has been completed 95359243Sobrien * or is about to begin. 95459243Sobrien */ 95559243Sobrienvoid 956167465Smppendjob(void) 95759243Sobrien{ 958145479Smp struct process *pp, *tp; 95959243Sobrien 96059243Sobrien if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 96159243Sobrien pp = pcurrjob; 962231990Smp pcurrjob = NULL; 96359243Sobrien while (pp->p_procid != pp->p_jobid) 96459243Sobrien pp = pp->p_friends; 96559243Sobrien xprintf("[%d]", pp->p_index); 96659243Sobrien tp = pp; 96759243Sobrien do { 96859243Sobrien xprintf(" %d", pp->p_procid); 96959243Sobrien pp = pp->p_friends; 97059243Sobrien } while (pp != tp); 97159243Sobrien xputchar('\n'); 97259243Sobrien } 97359243Sobrien pholdjob = pcurrjob = 0; 97459243Sobrien} 97559243Sobrien 97659243Sobrien/* 97759243Sobrien * pprint - print a job 97859243Sobrien */ 97959243Sobrien 98059243Sobrien/* 98159243Sobrien * Hacks have been added for SVR4 to deal with pipe's being spawned in 98259243Sobrien * reverse order 98359243Sobrien * 98459243Sobrien * David Dawes (dawes@physics.su.oz.au) Oct 1991 98559243Sobrien */ 98659243Sobrien 98759243Sobrienstatic int 988167465Smppprint(struct process *pp, int flag) 98959243Sobrien{ 99059243Sobrien int status, reason; 99159243Sobrien struct process *tp; 99259243Sobrien int jobflags, pstatus, pcond; 993145479Smp const char *format; 994316958Sdchagin int ohaderr; 99559243Sobrien 99659243Sobrien#ifdef BACKPIPE 99759243Sobrien struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; 99859243Sobrien int inpipe = 0; 99959243Sobrien#endif /* BACKPIPE */ 100059243Sobrien 100159243Sobrien while (pp->p_procid != pp->p_jobid) 100259243Sobrien pp = pp->p_friends; 100359243Sobrien if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 100459243Sobrien pp->p_flags &= ~PPTIME; 100559243Sobrien pp->p_flags |= PTIME; 100659243Sobrien } 100759243Sobrien tp = pp; 100859243Sobrien status = reason = -1; 100959243Sobrien jobflags = 0; 1010316958Sdchagin ohaderr = haderr; 1011316958Sdchagin /* Print status to stderr, except for jobs built-in */ 1012316958Sdchagin haderr = !(flag & JOBLIST); 101359243Sobrien do { 101459243Sobrien#ifdef BACKPIPE 101559243Sobrien /* 101659243Sobrien * The pipeline is reversed, so locate the real head of the pipeline 101759243Sobrien * if pp is at the tail of a pipe (and not already in a pipeline) 101859243Sobrien */ 101959243Sobrien if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { 102059243Sobrien inpipe = 1; 102159243Sobrien pipetail = pp; 102259243Sobrien do 102359243Sobrien pp = pp->p_friends; 102459243Sobrien while (pp->p_friends->p_flags & PPOU); 102559243Sobrien pipehead = pp; 102659243Sobrien pmarker = pp; 102759243Sobrien /* 102859243Sobrien * pmarker is used to hold the place of the proc being processed, so 102959243Sobrien * we can search for the next one downstream later. 103059243Sobrien */ 103159243Sobrien } 1032167465Smp pcond = (tp != pp || (inpipe && tp == pp)); 103359243Sobrien#else /* !BACKPIPE */ 1034167465Smp pcond = (tp != pp); 103559243Sobrien#endif /* BACKPIPE */ 103659243Sobrien 103759243Sobrien jobflags |= pp->p_flags; 103859243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 103959243Sobrien if (pcond && linp != linbuf && !(flag & FANCY) && 104059243Sobrien ((pstatus == status && pp->p_reason == reason) || 104159243Sobrien !(flag & REASON))) 104259243Sobrien xputchar(' '); 104359243Sobrien else { 104459243Sobrien if (pcond && linp != linbuf) 104559243Sobrien xputchar('\n'); 104659243Sobrien if (flag & NUMBER) { 104759243Sobrien#ifdef BACKPIPE 104859243Sobrien pcond = ((pp == tp && !inpipe) || 104959243Sobrien (inpipe && pipetail == tp && pp == pipehead)); 105059243Sobrien#else /* BACKPIPE */ 105159243Sobrien pcond = (pp == tp); 105259243Sobrien#endif /* BACKPIPE */ 105359243Sobrien if (pcond) 105459243Sobrien xprintf("[%d]%s %c ", pp->p_index, 105559243Sobrien pp->p_index < 10 ? " " : "", 105659243Sobrien pp == pcurrent ? '+' : 105759243Sobrien (pp == pprevious ? '-' : ' ')); 105859243Sobrien else 105959243Sobrien xprintf(" "); 106059243Sobrien } 106159243Sobrien if (flag & FANCY) { 106259243Sobrien xprintf("%5d ", pp->p_procid); 106359243Sobrien#ifdef TCF 106459243Sobrien xprintf("%11s ", sitename(pp->p_procid)); 106559243Sobrien#endif /* TCF */ 106659243Sobrien } 106759243Sobrien if (flag & (REASON | AREASON)) { 106859243Sobrien if (flag & NAME) 106959243Sobrien format = "%-30s"; 107059243Sobrien else 107159243Sobrien format = "%s"; 107259243Sobrien if (pstatus == status) { 107359243Sobrien if (pp->p_reason == reason) { 107459243Sobrien xprintf(format, ""); 107559243Sobrien goto prcomd; 107659243Sobrien } 107759243Sobrien else 107859243Sobrien reason = (int) pp->p_reason; 107959243Sobrien } 108059243Sobrien else { 108159243Sobrien status = pstatus; 108259243Sobrien reason = (int) pp->p_reason; 108359243Sobrien } 108459243Sobrien switch (status) { 108559243Sobrien 108659243Sobrien case PRUNNING: 108759243Sobrien xprintf(format, CGETS(17, 4, "Running ")); 108859243Sobrien break; 108959243Sobrien 109059243Sobrien case PINTERRUPTED: 109159243Sobrien case PSTOPPED: 109259243Sobrien case PSIGNALED: 109359243Sobrien /* 109459243Sobrien * tell what happened to the background job 1095167465Smp * From: Michael Schroeder 109659243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> 109759243Sobrien */ 109859243Sobrien if ((flag & REASON) 109959243Sobrien || ((flag & AREASON) 110059243Sobrien && reason != SIGINT 110159243Sobrien && (reason != SIGPIPE 110259243Sobrien || (pp->p_flags & PPOU) == 0))) { 1103167465Smp char *ptr; 1104167465Smp int free_ptr; 110559243Sobrien 1106167465Smp free_ptr = 0; 1107167465Smp ptr = (char *)(intptr_t)mesg[pp->p_reason & 0177].pname; 1108167465Smp if (ptr == NULL) { 1109167465Smp ptr = xasprintf("%s %d", CGETS(17, 5, "Signal"), 1110167465Smp pp->p_reason & 0177); 1111167465Smp cleanup_push(ptr, xfree); 1112167465Smp free_ptr = 1; 1113145479Smp } 111459243Sobrien xprintf(format, ptr); 1115167465Smp if (free_ptr != 0) 1116167465Smp cleanup_until(ptr); 111759243Sobrien } 111859243Sobrien else 111959243Sobrien reason = -1; 112059243Sobrien break; 112159243Sobrien 112259243Sobrien case PNEXITED: 112359243Sobrien case PAEXITED: 112459243Sobrien if (flag & REASON) { 112559243Sobrien if (pp->p_reason) 112659243Sobrien xprintf(CGETS(17, 6, "Exit %-25d"), pp->p_reason); 112759243Sobrien else 112859243Sobrien xprintf(format, CGETS(17, 7, "Done")); 112959243Sobrien } 113059243Sobrien break; 113159243Sobrien 113259243Sobrien default: 113359243Sobrien xprintf(CGETS(17, 8, "BUG: status=%-9o"), 113459243Sobrien status); 113559243Sobrien } 113659243Sobrien } 113759243Sobrien } 113859243Sobrienprcomd: 113959243Sobrien if (flag & NAME) { 114059243Sobrien xprintf("%S", pp->p_command); 114159243Sobrien if (pp->p_flags & PPOU) 114259243Sobrien xprintf(" |"); 114359243Sobrien if (pp->p_flags & PDIAG) 114459243Sobrien xprintf("&"); 114559243Sobrien } 114659243Sobrien if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 1147195609Smp xprintf("%s", CGETS(17, 9, " (core dumped)")); 114859243Sobrien if (tp == pp->p_friends) { 114959243Sobrien if (flag & AMPERSAND) 115059243Sobrien xprintf(" &"); 115159243Sobrien if (flag & JOBDIR && 115259243Sobrien !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1153195609Smp xprintf("%s", CGETS(17, 10, " (wd: ")); 115459243Sobrien dtildepr(tp->p_cwd->di_name); 115559243Sobrien xprintf(")"); 115659243Sobrien } 115759243Sobrien } 115859243Sobrien if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 115959243Sobrien if (linp != linbuf) 116059243Sobrien xprintf("\n\t"); 116159243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 116259243Sobrien prusage(&zru, &pp->p_rusage, &pp->p_etime, 116359243Sobrien &pp->p_btime); 116459243Sobrien#else /* !BSDTIMES && !SEQUENT */ 116559243Sobrien lru.tms_utime = pp->p_utime; 116659243Sobrien lru.tms_stime = pp->p_stime; 116759243Sobrien lru.tms_cutime = 0; 116859243Sobrien lru.tms_cstime = 0; 116959243Sobrien prusage(&zru, &lru, pp->p_etime, 117059243Sobrien pp->p_btime); 117159243Sobrien#endif /* !BSDTIMES && !SEQUENT */ 117259243Sobrien 117359243Sobrien } 117459243Sobrien#ifdef BACKPIPE 117559243Sobrien pcond = ((tp == pp->p_friends && !inpipe) || 117659243Sobrien (inpipe && pipehead->p_friends == tp && pp == pipetail)); 117759243Sobrien#else /* !BACKPIPE */ 117859243Sobrien pcond = (tp == pp->p_friends); 117959243Sobrien#endif /* BACKPIPE */ 118059243Sobrien if (pcond) { 118159243Sobrien if (linp != linbuf) 118259243Sobrien xputchar('\n'); 118359243Sobrien if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1184195609Smp xprintf("%s", CGETS(17, 11, "(wd now: ")); 118559243Sobrien dtildepr(dcwd->di_name); 118659243Sobrien xprintf(")\n"); 118759243Sobrien } 118859243Sobrien } 118959243Sobrien#ifdef BACKPIPE 119059243Sobrien if (inpipe) { 119159243Sobrien /* 119259243Sobrien * if pmaker == pipetail, we are finished that pipeline, and 119359243Sobrien * can now skip to past the head 119459243Sobrien */ 119559243Sobrien if (pmarker == pipetail) { 119659243Sobrien inpipe = 0; 119759243Sobrien pp = pipehead; 119859243Sobrien } 119959243Sobrien else { 120059243Sobrien /* 120159243Sobrien * set pp to one before the one we want next, so the while below 120259243Sobrien * increments to the correct spot. 120359243Sobrien */ 120459243Sobrien do 120559243Sobrien pp = pp->p_friends; 120659243Sobrien while (pp->p_friends->p_friends != pmarker); 120759243Sobrien pmarker = pp->p_friends; 120859243Sobrien } 120959243Sobrien } 121059243Sobrien pcond = ((pp = pp->p_friends) != tp || inpipe); 121159243Sobrien#else /* !BACKPIPE */ 121259243Sobrien pcond = ((pp = pp->p_friends) != tp); 121359243Sobrien#endif /* BACKPIPE */ 121459243Sobrien } while (pcond); 121559243Sobrien 121659243Sobrien if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 121759243Sobrien if (jobflags & NUMBER) 121859243Sobrien xprintf(" "); 121959243Sobrien ptprint(tp); 122059243Sobrien } 1221316958Sdchagin haderr = ohaderr; 122259243Sobrien return (jobflags); 122359243Sobrien} 122459243Sobrien 122559243Sobrien/* 122659243Sobrien * All 4.3 BSD derived implementations are buggy and I've had enough. 122759243Sobrien * The following implementation produces similar code and works in all 122859243Sobrien * cases. The 4.3BSD one works only for <, >, != 122959243Sobrien */ 123059243Sobrien# undef timercmp 123159243Sobrien# define timercmp(tvp, uvp, cmp) \ 123259243Sobrien (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 123359243Sobrien ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ 123459243Sobrien ((tvp)->tv_sec cmp (uvp)->tv_sec)) 123559243Sobrien 123659243Sobrienstatic void 1237167465Smpptprint(struct process *tp) 123859243Sobrien{ 123959243Sobrien#ifdef BSDTIMES 124059243Sobrien struct timeval tetime, diff; 124159243Sobrien static struct timeval ztime; 124259243Sobrien struct sysrusage ru; 1243145479Smp struct process *pp = tp; 124459243Sobrien 124559243Sobrien ru = zru; 124659243Sobrien tetime = ztime; 124759243Sobrien do { 124859243Sobrien ruadd(&ru, &pp->p_rusage); 124959243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 125059243Sobrien if (timercmp(&diff, &tetime, >)) 125159243Sobrien tetime = diff; 125259243Sobrien } while ((pp = pp->p_friends) != tp); 125359243Sobrien prusage(&zru, &ru, &tetime, &ztime); 125459243Sobrien#else /* !BSDTIMES */ 125559243Sobrien# ifdef _SEQUENT_ 125659243Sobrien timeval_t tetime, diff; 125759243Sobrien static timeval_t ztime; 125859243Sobrien struct process_stats ru; 1259145479Smp struct process *pp = tp; 126059243Sobrien 126159243Sobrien ru = zru; 126259243Sobrien tetime = ztime; 126359243Sobrien do { 126459243Sobrien ruadd(&ru, &pp->p_rusage); 126559243Sobrien tvsub(&diff, &pp->p_etime, &pp->p_btime); 126659243Sobrien if (timercmp(&diff, &tetime, >)) 126759243Sobrien tetime = diff; 126859243Sobrien } while ((pp = pp->p_friends) != tp); 126959243Sobrien prusage(&zru, &ru, &tetime, &ztime); 127059243Sobrien# else /* !_SEQUENT_ */ 127159243Sobrien# ifndef POSIX 127259243Sobrien static time_t ztime = 0; 127359243Sobrien static time_t zu_time = 0; 127459243Sobrien static time_t zs_time = 0; 127559243Sobrien time_t tetime, diff; 127659243Sobrien time_t u_time, s_time; 127759243Sobrien 127859243Sobrien# else /* POSIX */ 127959243Sobrien static clock_t ztime = 0; 128059243Sobrien static clock_t zu_time = 0; 128159243Sobrien static clock_t zs_time = 0; 128259243Sobrien clock_t tetime, diff; 128359243Sobrien clock_t u_time, s_time; 128459243Sobrien 128559243Sobrien# endif /* POSIX */ 128659243Sobrien struct tms zts, rts; 1287145479Smp struct process *pp = tp; 128859243Sobrien 128959243Sobrien u_time = zu_time; 129059243Sobrien s_time = zs_time; 129159243Sobrien tetime = ztime; 129259243Sobrien do { 129359243Sobrien u_time += pp->p_utime; 129459243Sobrien s_time += pp->p_stime; 129559243Sobrien diff = pp->p_etime - pp->p_btime; 129659243Sobrien if (diff > tetime) 129759243Sobrien tetime = diff; 129859243Sobrien } while ((pp = pp->p_friends) != tp); 129959243Sobrien zts.tms_utime = zu_time; 130059243Sobrien zts.tms_stime = zs_time; 130159243Sobrien zts.tms_cutime = 0; 130259243Sobrien zts.tms_cstime = 0; 130359243Sobrien rts.tms_utime = u_time; 130459243Sobrien rts.tms_stime = s_time; 130559243Sobrien rts.tms_cutime = 0; 130659243Sobrien rts.tms_cstime = 0; 130759243Sobrien prusage(&zts, &rts, tetime, ztime); 130859243Sobrien# endif /* !_SEQUENT_ */ 130959243Sobrien#endif /* !BSDTIMES */ 131059243Sobrien} 131159243Sobrien 131259243Sobrien/* 131359243Sobrien * dojobs - print all jobs 131459243Sobrien */ 131559243Sobrien/*ARGSUSED*/ 131659243Sobrienvoid 1317167465Smpdojobs(Char **v, struct command *c) 131859243Sobrien{ 1319145479Smp struct process *pp; 1320316958Sdchagin int flag = NUMBER | NAME | REASON | JOBLIST; 132159243Sobrien int i; 132259243Sobrien 132359243Sobrien USE(c); 132459243Sobrien if (chkstop) 132559243Sobrien chkstop = 2; 132659243Sobrien if (*++v) { 132759243Sobrien if (v[1] || !eq(*v, STRml)) 132859243Sobrien stderror(ERR_JOBS); 132959243Sobrien flag |= FANCY | JOBDIR; 133059243Sobrien } 133159243Sobrien for (i = 1; i <= pmaxindex; i++) 133259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 133359243Sobrien if (pp->p_index == i && pp->p_procid == pp->p_jobid) { 133459243Sobrien pp->p_flags &= ~PNEEDNOTE; 133559243Sobrien if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 133659243Sobrien pflush(pp); 133759243Sobrien break; 133859243Sobrien } 133959243Sobrien} 134059243Sobrien 134159243Sobrien/* 134259243Sobrien * dofg - builtin - put the job into the foreground 134359243Sobrien */ 134459243Sobrien/*ARGSUSED*/ 134559243Sobrienvoid 1346167465Smpdofg(Char **v, struct command *c) 134759243Sobrien{ 1348145479Smp struct process *pp; 134959243Sobrien 135059243Sobrien USE(c); 135159243Sobrien okpcntl(); 135259243Sobrien ++v; 135359243Sobrien do { 135459243Sobrien pp = pfind(*v); 135559243Sobrien if (!pstart(pp, 1)) { 135659243Sobrien pp->p_procid = 0; 135759243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 135859243Sobrien continue; 135959243Sobrien } 136059243Sobrien pjwait(pp); 136159243Sobrien } while (*v && *++v); 136259243Sobrien} 136359243Sobrien 136459243Sobrien/* 136559243Sobrien * %... - builtin - put the job into the foreground 136659243Sobrien */ 136759243Sobrien/*ARGSUSED*/ 136859243Sobrienvoid 1369167465Smpdofg1(Char **v, struct command *c) 137059243Sobrien{ 1371145479Smp struct process *pp; 137259243Sobrien 137359243Sobrien USE(c); 137459243Sobrien okpcntl(); 137559243Sobrien pp = pfind(v[0]); 137659243Sobrien if (!pstart(pp, 1)) { 137759243Sobrien pp->p_procid = 0; 137859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 137959243Sobrien return; 138059243Sobrien } 138159243Sobrien pjwait(pp); 138259243Sobrien} 138359243Sobrien 138459243Sobrien/* 138559243Sobrien * dobg - builtin - put the job into the background 138659243Sobrien */ 138759243Sobrien/*ARGSUSED*/ 138859243Sobrienvoid 1389167465Smpdobg(Char **v, struct command *c) 139059243Sobrien{ 1391145479Smp struct process *pp; 139259243Sobrien 139359243Sobrien USE(c); 139459243Sobrien okpcntl(); 139559243Sobrien ++v; 139659243Sobrien do { 139759243Sobrien pp = pfind(*v); 139859243Sobrien if (!pstart(pp, 0)) { 139959243Sobrien pp->p_procid = 0; 140059243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 140159243Sobrien } 140259243Sobrien } while (*v && *++v); 140359243Sobrien} 140459243Sobrien 140559243Sobrien/* 140659243Sobrien * %... & - builtin - put the job into the background 140759243Sobrien */ 140859243Sobrien/*ARGSUSED*/ 140959243Sobrienvoid 1410167465Smpdobg1(Char **v, struct command *c) 141159243Sobrien{ 1412145479Smp struct process *pp; 141359243Sobrien 141459243Sobrien USE(c); 141559243Sobrien pp = pfind(v[0]); 141659243Sobrien if (!pstart(pp, 0)) { 141759243Sobrien pp->p_procid = 0; 141859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, strerror(errno)); 141959243Sobrien } 142059243Sobrien} 142159243Sobrien 142259243Sobrien/* 142359243Sobrien * dostop - builtin - stop the job 142459243Sobrien */ 142559243Sobrien/*ARGSUSED*/ 142659243Sobrienvoid 1427167465Smpdostop(Char **v, struct command *c) 142859243Sobrien{ 142959243Sobrien USE(c); 143059243Sobrien#ifdef BSDJOBS 143159243Sobrien pkill(++v, SIGSTOP); 143259243Sobrien#endif /* BSDJOBS */ 143359243Sobrien} 143459243Sobrien 143559243Sobrien/* 143659243Sobrien * dokill - builtin - superset of kill (1) 143759243Sobrien */ 143859243Sobrien/*ARGSUSED*/ 143959243Sobrienvoid 1440167465Smpdokill(Char **v, struct command *c) 144159243Sobrien{ 1442145479Smp int signum, len = 0; 1443145479Smp const char *name; 144483098Smp Char *sigptr; 144559243Sobrien 144659243Sobrien USE(c); 144759243Sobrien v++; 144859243Sobrien if (v[0] && v[0][0] == '-') { 144959243Sobrien if (v[0][1] == 'l') { 145059243Sobrien for (signum = 0; signum <= nsig; signum++) { 145159243Sobrien if ((name = mesg[signum].iname) != NULL) { 145259243Sobrien len += strlen(name) + 1; 1453167465Smp if (len >= TermH - 1) { 145459243Sobrien xputchar('\n'); 145559243Sobrien len = strlen(name) + 1; 145659243Sobrien } 145759243Sobrien xprintf("%s ", name); 145859243Sobrien } 145959243Sobrien } 146059243Sobrien xputchar('\n'); 146159243Sobrien return; 146259243Sobrien } 146383098Smp sigptr = &v[0][1]; 146483098Smp if (v[0][1] == 's') { 146583098Smp if (v[1]) { 146683098Smp v++; 146783098Smp sigptr = &v[0][0]; 146883098Smp } else { 146983098Smp stderror(ERR_NAME | ERR_TOOFEW); 147083098Smp } 147183098Smp } 147283098Smp if (Isdigit(*sigptr)) { 1473131962Smp char *ep; 1474131962Smp signum = strtoul(short2str(sigptr), &ep, 0); 1475131962Smp if (*ep || signum < 0 || signum > (MAXSIG-1)) 147659243Sobrien stderror(ERR_NAME | ERR_BADSIG); 147759243Sobrien } 147859243Sobrien else { 147959243Sobrien for (signum = 0; signum <= nsig; signum++) 148059243Sobrien if (mesg[signum].iname && 148183098Smp eq(sigptr, str2short(mesg[signum].iname))) 148259243Sobrien goto gotsig; 148383098Smp setname(short2str(sigptr)); 148459243Sobrien stderror(ERR_NAME | ERR_UNKSIG); 148559243Sobrien } 148659243Sobriengotsig: 148759243Sobrien v++; 148859243Sobrien } 148959243Sobrien else 149059243Sobrien signum = SIGTERM; 149159243Sobrien pkill(v, signum); 149259243Sobrien} 149359243Sobrien 149459243Sobrienstatic void 1495167465Smppkill(Char **v, int signum) 149659243Sobrien{ 1497145479Smp struct process *pp, *np; 149859243Sobrien int jobflags = 0, err1 = 0; 149959243Sobrien pid_t pid; 1500167465Smp Char *cp, **vp, **globbed; 150159243Sobrien 150259243Sobrien /* Avoid globbing %?x patterns */ 150359243Sobrien for (vp = v; vp && *vp; vp++) 150459243Sobrien if (**vp == '%') 150559243Sobrien (void) quote(*vp); 150659243Sobrien 1507167465Smp v = glob_all_or_error(v); 1508167465Smp globbed = v; 1509167465Smp cleanup_push(globbed, blk_cleanup); 151059243Sobrien 1511172665Smp pchild_disabled++; 1512172665Smp cleanup_push(&pchild_disabled, disabled_cleanup); 1513172665Smp if (setintr) { 1514172665Smp pintr_disabled++; 1515172665Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1516172665Smp } 151759243Sobrien 151859243Sobrien while (v && (cp = *v)) { 151959243Sobrien if (*cp == '%') { 152059243Sobrien np = pp = pfind(cp); 152159243Sobrien do 152259243Sobrien jobflags |= np->p_flags; 152359243Sobrien while ((np = np->p_friends) != pp); 152459243Sobrien#ifdef BSDJOBS 152559243Sobrien switch (signum) { 152659243Sobrien 152759243Sobrien case SIGSTOP: 152859243Sobrien case SIGTSTP: 152959243Sobrien case SIGTTIN: 153059243Sobrien case SIGTTOU: 153159243Sobrien if ((jobflags & PRUNNING) == 0) { 153259243Sobrien# ifdef SUSPENDED 153359243Sobrien xprintf(CGETS(17, 12, "%S: Already suspended\n"), cp); 153459243Sobrien# else /* !SUSPENDED */ 153559243Sobrien xprintf(CGETS(17, 13, "%S: Already stopped\n"), cp); 153659243Sobrien# endif /* !SUSPENDED */ 153759243Sobrien err1++; 153859243Sobrien goto cont; 153959243Sobrien } 154059243Sobrien break; 154159243Sobrien /* 154259243Sobrien * suspend a process, kill -CONT %, then type jobs; the shell 154359243Sobrien * says it is suspended, but it is running; thanks jaap.. 154459243Sobrien */ 154559243Sobrien case SIGCONT: 154659243Sobrien if (!pstart(pp, 0)) { 154759243Sobrien pp->p_procid = 0; 154859243Sobrien stderror(ERR_NAME|ERR_BADJOB, pp->p_command, 154959243Sobrien strerror(errno)); 155059243Sobrien } 155159243Sobrien goto cont; 155259243Sobrien default: 155359243Sobrien break; 155459243Sobrien } 155559243Sobrien#endif /* BSDJOBS */ 155659243Sobrien if (killpg(pp->p_jobid, signum) < 0) { 155759243Sobrien xprintf("%S: %s\n", cp, strerror(errno)); 155859243Sobrien err1++; 155959243Sobrien } 156059243Sobrien#ifdef BSDJOBS 156159243Sobrien if (signum == SIGTERM || signum == SIGHUP) 156259243Sobrien (void) killpg(pp->p_jobid, SIGCONT); 156359243Sobrien#endif /* BSDJOBS */ 156459243Sobrien } 156559243Sobrien else if (!(Isdigit(*cp) || *cp == '-')) 156659243Sobrien stderror(ERR_NAME | ERR_JOBARGS); 156759243Sobrien else { 1568131962Smp char *ep; 156969408Sache#ifndef WINNT_NATIVE 1570131962Smp pid = strtol(short2str(cp), &ep, 10); 157159243Sobrien#else 1572131962Smp pid = strtoul(short2str(cp), &ep, 0); 157369408Sache#endif /* WINNT_NATIVE */ 1574131962Smp if (*ep) 1575131962Smp stderror(ERR_NAME | ERR_JOBARGS); 1576131962Smp else if (kill(pid, signum) < 0) { 157759243Sobrien xprintf("%d: %s\n", pid, strerror(errno)); 157859243Sobrien err1++; 157959243Sobrien goto cont; 158059243Sobrien } 158159243Sobrien#ifdef BSDJOBS 158259243Sobrien if (signum == SIGTERM || signum == SIGHUP) 158359243Sobrien (void) kill(pid, SIGCONT); 158459243Sobrien#endif /* BSDJOBS */ 158559243Sobrien } 158659243Sobriencont: 158759243Sobrien v++; 158859243Sobrien } 1589167465Smp cleanup_until(&pchild_disabled); 159059243Sobrien if (err1) 159159243Sobrien stderror(ERR_SILENT); 159259243Sobrien} 159359243Sobrien 159459243Sobrien/* 159559243Sobrien * pstart - start the job in foreground/background 159659243Sobrien */ 159759243Sobrienint 1598167465Smppstart(struct process *pp, int foregnd) 159959243Sobrien{ 160059243Sobrien int rv = 0; 1601145479Smp struct process *np; 160259243Sobrien /* We don't use jobflags in this function right now (see below) */ 160359243Sobrien /* long jobflags = 0; */ 160459243Sobrien 1605167465Smp pchild_disabled++; 1606167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 160759243Sobrien np = pp; 160859243Sobrien do { 160959243Sobrien /* We don't use jobflags in this function right now (see below) */ 161059243Sobrien /* jobflags |= np->p_flags; */ 161159243Sobrien if (np->p_flags & (PRUNNING | PSTOPPED)) { 161259243Sobrien np->p_flags |= PRUNNING; 161359243Sobrien np->p_flags &= ~PSTOPPED; 161459243Sobrien if (foregnd) 161559243Sobrien np->p_flags |= PFOREGND; 161659243Sobrien else 161759243Sobrien np->p_flags &= ~PFOREGND; 161859243Sobrien } 161959243Sobrien } while ((np = np->p_friends) != pp); 162059243Sobrien if (!foregnd) 162159243Sobrien pclrcurr(pp); 162259243Sobrien (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 162383098Smp 162483098Smp /* GrP run jobcmd hook if foregrounding */ 162583098Smp if (foregnd) { 162683098Smp job_cmd(pp->p_command); 162783098Smp } 162883098Smp 162959243Sobrien#ifdef BSDJOBS 163059243Sobrien if (foregnd) { 163159243Sobrien rv = tcsetpgrp(FSHTTY, pp->p_jobid); 163259243Sobrien } 163359243Sobrien /* 163459243Sobrien * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU 163559243Sobrien * 2. parent process (csh) receives SIGCHLD 163659243Sobrien * 3. The "csh" signal handling function pchild() is invoked 163759243Sobrien * with a SIGCHLD signal. 163859243Sobrien * 4. pchild() calls wait3(WNOHANG) which returns 0. 163959243Sobrien * The child process is NOT ready to be waited for at this time. 164059243Sobrien * pchild() returns without picking-up the correct status 1641167465Smp * for the child process which generated the SIGCHLD. 164259243Sobrien * 5. CONSEQUENCE : csh is UNaware that the process is stopped 164359243Sobrien * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) 164459243Sobrien * (beto@aixwiz.austin.ibm.com - aug/03/91) 164559243Sobrien * 7. I removed the line completely and added extra checks for 164659243Sobrien * pstart, so that if a job gets attached to and dies inside 164759243Sobrien * a debugger it does not confuse the shell. [christos] 164859243Sobrien * 8. on the nec sx-4 there seems to be a problem, which requires 164959243Sobrien * a syscall(151, getpid(), getpid()) in osinit. Don't ask me 165059243Sobrien * what this is doing. [schott@rzg.mpg.de] 165159243Sobrien */ 165259243Sobrien 165359243Sobrien if (rv != -1) 165459243Sobrien rv = killpg(pp->p_jobid, SIGCONT); 165559243Sobrien#endif /* BSDJOBS */ 1656167465Smp cleanup_until(&pchild_disabled); 165759243Sobrien return rv != -1; 165859243Sobrien} 165959243Sobrien 166059243Sobrienvoid 1661167465Smppanystop(int neednl) 166259243Sobrien{ 1663145479Smp struct process *pp; 166459243Sobrien 166559243Sobrien chkstop = 2; 166659243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 166759243Sobrien if (pp->p_flags & PSTOPPED) 166859243Sobrien stderror(ERR_STOPPED, neednl ? "\n" : ""); 166959243Sobrien} 167059243Sobrien 167159243Sobrienstruct process * 1672167465Smppfind(Char *cp) 167359243Sobrien{ 1674145479Smp struct process *pp, *np; 167559243Sobrien 167659243Sobrien if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 167759243Sobrien if (pcurrent == NULL) 167859243Sobrien stderror(ERR_NAME | ERR_JOBCUR); 167959243Sobrien return (pcurrent); 168059243Sobrien } 168159243Sobrien if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 168259243Sobrien if (pprevious == NULL) 168359243Sobrien stderror(ERR_NAME | ERR_JOBPREV); 168459243Sobrien return (pprevious); 168559243Sobrien } 168659243Sobrien if (Isdigit(cp[1])) { 168759243Sobrien int idx = atoi(short2str(cp + 1)); 168859243Sobrien 168959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 169059243Sobrien if (pp->p_index == idx && pp->p_procid == pp->p_jobid) 169159243Sobrien return (pp); 169259243Sobrien stderror(ERR_NAME | ERR_NOSUCHJOB); 169359243Sobrien } 169459243Sobrien np = NULL; 169559243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 169659243Sobrien if (pp->p_procid == pp->p_jobid) { 169759243Sobrien if (cp[1] == '?') { 1698145479Smp Char *dp; 169959243Sobrien 170059243Sobrien for (dp = pp->p_command; *dp; dp++) { 170159243Sobrien if (*dp != cp[2]) 170259243Sobrien continue; 170359243Sobrien if (prefix(cp + 2, dp)) 170459243Sobrien goto match; 170559243Sobrien } 170659243Sobrien } 170759243Sobrien else if (prefix(cp + 1, pp->p_command)) { 170859243Sobrien match: 170959243Sobrien if (np) 171059243Sobrien stderror(ERR_NAME | ERR_AMBIG); 171159243Sobrien np = pp; 171259243Sobrien } 171359243Sobrien } 171459243Sobrien if (np) 171559243Sobrien return (np); 171659243Sobrien stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 171759243Sobrien /* NOTREACHED */ 171859243Sobrien return (0); 171959243Sobrien} 172059243Sobrien 172159243Sobrien 172259243Sobrien/* 172359243Sobrien * pgetcurr - find most recent job that is not pp, preferably stopped 172459243Sobrien */ 172559243Sobrienstatic struct process * 1726167465Smppgetcurr(struct process *pp) 172759243Sobrien{ 1728145479Smp struct process *np; 1729145479Smp struct process *xp = NULL; 173059243Sobrien 173159243Sobrien for (np = proclist.p_next; np; np = np->p_next) 173259243Sobrien if (np != pcurrent && np != pp && np->p_procid && 173359243Sobrien np->p_procid == np->p_jobid) { 173459243Sobrien if (np->p_flags & PSTOPPED) 173559243Sobrien return (np); 173659243Sobrien if (xp == NULL) 173759243Sobrien xp = np; 173859243Sobrien } 173959243Sobrien return (xp); 174059243Sobrien} 174159243Sobrien 174259243Sobrien/* 174359243Sobrien * donotify - flag the job so as to report termination asynchronously 174459243Sobrien */ 174559243Sobrien/*ARGSUSED*/ 174659243Sobrienvoid 1747167465Smpdonotify(Char **v, struct command *c) 174859243Sobrien{ 1749145479Smp struct process *pp; 175059243Sobrien 175159243Sobrien USE(c); 175259243Sobrien pp = pfind(*++v); 175359243Sobrien pp->p_flags |= PNOTIFY; 175459243Sobrien} 175559243Sobrien 1756167465Smp#ifdef SIGSYNCH 1757167465Smpstatic void 1758167465Smpsynch_handler(int sno) 1759167465Smp{ 1760167465Smp USE(sno); 1761167465Smp} 1762167465Smp#endif /* SIGSYNCH */ 1763167465Smp 176459243Sobrien/* 176559243Sobrien * Do the fork and whatever should be done in the child side that 176659243Sobrien * should not be done if we are not forking at all (like for simple builtin's) 176759243Sobrien * Also do everything that needs any signals fiddled with in the parent side 176859243Sobrien * 176959243Sobrien * Wanttty tells whether process and/or tty pgrps are to be manipulated: 177059243Sobrien * -1: leave tty alone; inherit pgrp from parent 177159243Sobrien * 0: already have tty; manipulate process pgrps only 177259243Sobrien * 1: want to claim tty; manipulate process and tty pgrps 177359243Sobrien * It is usually just the value of tpgrp. 177459243Sobrien */ 177559243Sobrien 1776167465Smppid_t 1777167465Smppfork(struct command *t, int wanttty) 177859243Sobrien{ 1779167465Smp pid_t pid; 1780145479Smp int ignint = 0; 1781167465Smp pid_t pgrp; 178259243Sobrien#ifdef SIGSYNCH 1783167465Smp struct sigaction osa, nsa; 178459243Sobrien#endif /* SIGSYNCH */ 178559243Sobrien 178659243Sobrien /* 178759243Sobrien * A child will be uninterruptible only under very special conditions. 178859243Sobrien * Remember that the semantics of '&' is implemented by disconnecting the 178959243Sobrien * process from the tty so signals do not need to ignored just for '&'. 179059243Sobrien * Thus signals are set to default action for children unless: we have had 179159243Sobrien * an "onintr -" (then specifically ignored) we are not playing with 179259243Sobrien * signals (inherit action) 179359243Sobrien */ 179459243Sobrien if (setintr) 179559243Sobrien ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 179659243Sobrien || (gointr && eq(gointr, STRminus)); 179759243Sobrien 179859243Sobrien /* 179959243Sobrien * Check for maximum nesting of 16 processes to avoid Forking loops 180059243Sobrien */ 180159243Sobrien if (child == 16) 180259243Sobrien stderror(ERR_NESTING, 16); 180359243Sobrien#ifdef SIGSYNCH 1804167465Smp nsa.sa_handler = synch_handler; 1805167465Smp sigfillset(&nsa.sa_mask); 1806167465Smp nsa.sa_flags = SA_RESTART; 1807167465Smp if (sigaction(SIGSYNCH, &nsa, &osa)) 1808167465Smp stderror(ERR_SYSTEM, "pfork: sigaction set", strerror(errno)); 180959243Sobrien#endif /* SIGSYNCH */ 181059243Sobrien /* 1811167465Smp * Hold pchild() until we have the process installed in our table. 181259243Sobrien */ 181359243Sobrien if (wanttty < 0) { 1814167465Smp pchild_disabled++; 1815167465Smp cleanup_push(&pchild_disabled, disabled_cleanup); 181659243Sobrien } 181759243Sobrien while ((pid = fork()) == -1) 181859243Sobrien if (setintr == 0) 181959243Sobrien (void) sleep(FORKSLEEP); 1820167465Smp else 182159243Sobrien stderror(ERR_NOPROC); 182259243Sobrien if (pid == 0) { 1823167465Smp (void)cleanup_push_mark(); /* Never to be popped */ 1824167465Smp pchild_disabled = 0; 182559243Sobrien settimes(); 182659243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 182759243Sobrien pflushall(); 182859243Sobrien pcurrjob = NULL; 182959243Sobrien#if !defined(BSDTIMES) && !defined(_SEQUENT_) 183059243Sobrien timesdone = 0; 183159243Sobrien#endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 183259243Sobrien child++; 183359243Sobrien if (setintr) { 183459243Sobrien setintr = 0; /* until I think otherwise */ 183559243Sobrien /* 183659243Sobrien * Children just get blown away on SIGINT, SIGQUIT unless "onintr 183759243Sobrien * -" seen. 183859243Sobrien */ 183959243Sobrien (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 184059243Sobrien (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 184159243Sobrien#ifdef BSDJOBS 184259243Sobrien if (wanttty >= 0) { 184359243Sobrien /* make stoppable */ 184459243Sobrien (void) signal(SIGTSTP, SIG_DFL); 184559243Sobrien (void) signal(SIGTTIN, SIG_DFL); 184659243Sobrien (void) signal(SIGTTOU, SIG_DFL); 184759243Sobrien } 184859243Sobrien#endif /* BSDJOBS */ 1849167465Smp sigaction(SIGTERM, &parterm, NULL); 185059243Sobrien } 185159243Sobrien else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 185259243Sobrien (void) signal(SIGINT, SIG_IGN); 185359243Sobrien (void) signal(SIGQUIT, SIG_IGN); 185459243Sobrien } 185559243Sobrien#ifdef OREO 1856167465Smp signal(SIGIO, SIG_IGN); /* ignore SIGIO in child too */ 185759243Sobrien#endif /* OREO */ 185859243Sobrien 185959243Sobrien pgetty(wanttty, pgrp); 186059243Sobrien /* 186159243Sobrien * Nohup and nice apply only to NODE_COMMAND's but it would be nice 186259243Sobrien * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 186359243Sobrien * to know about nice/nohup/time 186459243Sobrien */ 186559243Sobrien if (t->t_dflg & F_NOHUP) 186659243Sobrien (void) signal(SIGHUP, SIG_IGN); 186759243Sobrien if (t->t_dflg & F_NICE) { 186859243Sobrien int nval = SIGN_EXTEND_CHAR(t->t_nice); 1869316958Sdchagin#if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) 187083098Smp if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) 1871167465Smp stderror(ERR_SYSTEM, "setpriority", strerror(errno)); 1872316958Sdchagin#else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ 187359243Sobrien (void) nice(nval); 1874316958Sdchagin#endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ 187559243Sobrien } 187659243Sobrien#ifdef F_VER 187759243Sobrien if (t->t_dflg & F_VER) { 187859243Sobrien tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 187959243Sobrien dohash(NULL, NULL); 188059243Sobrien } 188159243Sobrien#endif /* F_VER */ 188259243Sobrien#ifdef SIGSYNCH 188359243Sobrien /* rfw 8/89 now parent can continue */ 188459243Sobrien if (kill(getppid(), SIGSYNCH)) 188559243Sobrien stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 188659243Sobrien#endif /* SIGSYNCH */ 188759243Sobrien 188859243Sobrien } 188959243Sobrien else { 189059243Sobrien#ifdef POSIXJOBS 189159243Sobrien if (wanttty >= 0) { 189259243Sobrien /* 189359243Sobrien * `Walking' process group fix from Beto Appleton. 189459243Sobrien * (beto@aixwiz.austin.ibm.com) 189559243Sobrien * If setpgid fails at this point that means that 189659243Sobrien * our process leader has died. We flush the current 189759243Sobrien * job and become the process leader ourselves. 189859243Sobrien * The parent will figure that out later. 189959243Sobrien */ 190059243Sobrien pgrp = pcurrjob ? pcurrjob->p_jobid : pid; 190159243Sobrien if (setpgid(pid, pgrp) == -1 && errno == EPERM) { 190259243Sobrien pcurrjob = NULL; 190359243Sobrien /* 190459243Sobrien * We don't care if this causes an error here; 190559243Sobrien * then we are already in the right process group 190659243Sobrien */ 190759243Sobrien (void) setpgid(pid, pgrp = pid); 190859243Sobrien } 190959243Sobrien } 191059243Sobrien#endif /* POSIXJOBS */ 191159243Sobrien palloc(pid, t); 191259243Sobrien#ifdef SIGSYNCH 1913167465Smp { 1914167465Smp sigset_t pause_mask; 1915167465Smp 191659243Sobrien /* 191759243Sobrien * rfw 8/89 Wait for child to own terminal. Solves half of ugly 191859243Sobrien * synchronization problem. With this change, we know that the only 191959243Sobrien * reason setpgrp to a previous process in a pipeline can fail is that 192059243Sobrien * the previous process has already exited. Without this hack, he may 192159243Sobrien * either have exited or not yet started to run. Two uglies become 192259243Sobrien * one. 192359243Sobrien */ 1924167465Smp sigprocmask(SIG_BLOCK, NULL, &pause); 1925167465Smp sigdelset(&pause_mask, SIGCHLD); 1926167465Smp sigdelset(&pause_mask, SIGSYNCH); 1927167465Smp sigsuspend(&pause_mask); 1928231990Smp (void)handle_pending_signals(); 1929167465Smp if (sigaction(SIGSYNCH, &osa, NULL)) 1930167465Smp stderror(ERR_SYSTEM, "pfork parent: sigaction restore", 1931167465Smp strerror(errno)); 1932167465Smp } 193359243Sobrien#endif /* SIGSYNCH */ 193459243Sobrien 1935167465Smp if (wanttty < 0) 1936167465Smp cleanup_until(&pchild_disabled); 193759243Sobrien } 193859243Sobrien return (pid); 193959243Sobrien} 194059243Sobrien 194159243Sobrienstatic void 1942167465Smpokpcntl(void) 194359243Sobrien{ 194459243Sobrien if (tpgrp == -1) 194559243Sobrien stderror(ERR_JOBCONTROL); 194659243Sobrien if (tpgrp == 0) 194759243Sobrien stderror(ERR_JOBCTRLSUB); 194859243Sobrien} 194959243Sobrien 195059243Sobrien 195159243Sobrienstatic void 1952167465Smpsetttypgrp(int pgrp) 195359243Sobrien{ 195459243Sobrien /* 195559243Sobrien * If we are piping out a builtin, eg. 'echo | more' things can go 195659243Sobrien * out of sequence, i.e. the more can run before the echo. This 195759243Sobrien * can happen even if we have vfork, since the echo will be forked 195859243Sobrien * with the regular fork. In this case, we need to set the tty 195959243Sobrien * pgrp ourselves. If that happens, then the process will be still 196059243Sobrien * alive. And the tty process group will already be set. 196159243Sobrien * This should fix the famous sequent problem as a side effect: 196259243Sobrien * The controlling terminal is lost if all processes in the 196359243Sobrien * terminal process group are zombies. In this case tcgetpgrp() 196459243Sobrien * returns 0. If this happens we must set the terminal process 196559243Sobrien * group again. 196659243Sobrien */ 196759243Sobrien if (tcgetpgrp(FSHTTY) != pgrp) { 196859243Sobrien#ifdef POSIXJOBS 1969167465Smp struct sigaction old; 1970167465Smp 197159243Sobrien /* 197259243Sobrien * tcsetpgrp will set SIGTTOU to all the the processes in 197359243Sobrien * the background according to POSIX... We ignore this here. 197459243Sobrien */ 1975167465Smp sigaction(SIGTTOU, NULL, &old); 1976167465Smp signal(SIGTTOU, SIG_IGN); 197759243Sobrien#endif 197859243Sobrien (void) tcsetpgrp(FSHTTY, pgrp); 197959243Sobrien# ifdef POSIXJOBS 1980167465Smp sigaction(SIGTTOU, &old, NULL); 198159243Sobrien# endif 198259243Sobrien 198359243Sobrien } 198459243Sobrien} 198559243Sobrien 198659243Sobrien 198759243Sobrien/* 198859243Sobrien * if we don't have vfork(), things can still go in the wrong order 198959243Sobrien * resulting in the famous 'Stopped (tty output)'. But some systems 199059243Sobrien * don't permit the setpgid() call, (these are more recent secure 199159243Sobrien * systems such as ibm's aix), when they do. Then we'd rather print 199259243Sobrien * an error message than hang the shell! 199359243Sobrien * I am open to suggestions how to fix that. 199459243Sobrien */ 199559243Sobrienvoid 1996167465Smppgetty(int wanttty, pid_t pgrp) 199759243Sobrien{ 199859243Sobrien#ifdef BSDJOBS 1999167465Smp# ifdef POSIXJOBS 2000167465Smp sigset_t oset, set; 2001167465Smp# endif /* POSIXJOBS */ 200259243Sobrien 2003167465Smp jobdebug_xprintf(("wanttty %d pid %d opgrp%d pgrp %d tpgrp %d\n", 2004167465Smp wanttty, (int)getpid(), (int)pgrp, (int)mygetpgrp(), 2005167465Smp (int)tcgetpgrp(FSHTTY))); 200659243Sobrien# ifdef POSIXJOBS 200759243Sobrien /* 200859243Sobrien * christos: I am blocking the tty signals till I've set things 200959243Sobrien * correctly.... 201059243Sobrien */ 2011167465Smp if (wanttty > 0) { 2012167465Smp sigemptyset(&set); 2013167465Smp sigaddset(&set, SIGTSTP); 2014167465Smp sigaddset(&set, SIGTTIN); 2015167465Smp (void)sigprocmask(SIG_BLOCK, &set, &oset); 2016167465Smp cleanup_push(&oset, sigprocmask_cleanup); 201759243Sobrien } 201859243Sobrien# endif /* POSIXJOBS */ 201959243Sobrien 202059243Sobrien# ifndef POSIXJOBS 202159243Sobrien if (wanttty > 0) 202259243Sobrien setttypgrp(pgrp); 202359243Sobrien# endif /* !POSIXJOBS */ 202459243Sobrien 202559243Sobrien /* 202659243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 202759243Sobrien * Don't check for tpgrp >= 0 so even non-interactive shells give 202859243Sobrien * background jobs process groups Same for the comparison in the other part 202959243Sobrien * of the #ifdef 203059243Sobrien */ 203159243Sobrien if (wanttty >= 0) { 203259243Sobrien if (setpgid(0, pgrp) == -1) { 203359243Sobrien# ifdef POSIXJOBS 203459243Sobrien /* Walking process group fix; see above */ 203559243Sobrien if (setpgid(0, pgrp = getpid()) == -1) { 203659243Sobrien# endif /* POSIXJOBS */ 203759243Sobrien stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); 203859243Sobrien xexit(0); 203959243Sobrien# ifdef POSIXJOBS 204059243Sobrien } 204159243Sobrien wanttty = pgrp; /* Now we really want the tty, since we became the 204259243Sobrien * the process group leader 204359243Sobrien */ 204459243Sobrien# endif /* POSIXJOBS */ 204559243Sobrien } 204659243Sobrien } 204759243Sobrien 204859243Sobrien# ifdef POSIXJOBS 2049167465Smp if (wanttty > 0) { 205059243Sobrien setttypgrp(pgrp); 2051167465Smp cleanup_until(&oset); 2052167465Smp } 205359243Sobrien# endif /* POSIXJOBS */ 205459243Sobrien 2055167465Smp jobdebug_xprintf(("wanttty %d pid %d pgrp %d tpgrp %d\n", 2056167465Smp wanttty, getpid(), mygetpgrp(), tcgetpgrp(FSHTTY))); 205759243Sobrien 205859243Sobrien if (tpgrp > 0) 205959243Sobrien tpgrp = 0; /* gave tty away */ 206059243Sobrien#endif /* BSDJOBS */ 206159243Sobrien} 2062