1*324a3c8cSderaadt /* $OpenBSD: proc.c,v 1.36 2024/07/28 15:31:22 deraadt Exp $ */ 2df930be7Sderaadt /* $NetBSD: proc.c,v 1.9 1995/04/29 23:21:33 mycroft Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1980, 1991, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 1629295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 17df930be7Sderaadt * may be used to endorse or promote products derived from this software 18df930be7Sderaadt * without specific prior written permission. 19df930be7Sderaadt * 20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df930be7Sderaadt * SUCH DAMAGE. 31df930be7Sderaadt */ 32df930be7Sderaadt 33df930be7Sderaadt #include <sys/types.h> 34df930be7Sderaadt #include <sys/wait.h> 35df930be7Sderaadt #include <errno.h> 36df930be7Sderaadt #include <unistd.h> 37a47b6461Sderaadt #include <limits.h> 38df930be7Sderaadt #include <stdlib.h> 39df930be7Sderaadt #include <string.h> 40df930be7Sderaadt #include <stdarg.h> 41df930be7Sderaadt 42df930be7Sderaadt #include "csh.h" 43df930be7Sderaadt #include "dir.h" 44df930be7Sderaadt #include "proc.h" 45df930be7Sderaadt #include "extern.h" 46df930be7Sderaadt 47df930be7Sderaadt #define BIGINDEX 9 /* largest desirable job index */ 48df930be7Sderaadt 49914fbe0cSmortimer struct process proclist; /* list head of all processes */ 50914fbe0cSmortimer bool pnoprocesses; /* pchild found nothing to wait for */ 51914fbe0cSmortimer 52914fbe0cSmortimer struct process *pholdjob; /* one level stack of current jobs */ 53914fbe0cSmortimer 54914fbe0cSmortimer struct process *pcurrjob; /* current job */ 55914fbe0cSmortimer struct process *pcurrent; /* current job in table */ 56914fbe0cSmortimer struct process *pprevious; /* previous job in table */ 57914fbe0cSmortimer 58914fbe0cSmortimer int pmaxindex; /* current maximum job index */ 59914fbe0cSmortimer 60df930be7Sderaadt static struct rusage zru; 61df930be7Sderaadt 62c72b5b24Smillert static void pflushall(void); 63c72b5b24Smillert static void pflush(struct process *); 64c72b5b24Smillert static void pclrcurr(struct process *); 65c72b5b24Smillert static void padd(struct command *); 66c72b5b24Smillert static int pprint(struct process *, int); 67c72b5b24Smillert static void ptprint(struct process *); 68c72b5b24Smillert static void pads(Char *); 69c72b5b24Smillert static void pkill(Char **v, int); 70df930be7Sderaadt static struct process 71c72b5b24Smillert *pgetcurr(struct process *); 72c72b5b24Smillert static void okpcntl(void); 73df930be7Sderaadt 74df930be7Sderaadt /* 75df930be7Sderaadt * pchild - called at interrupt level by the SIGCHLD signal 76df930be7Sderaadt * indicating that at least one child has terminated or stopped 77df930be7Sderaadt * thus at least one wait system call will definitely return a 78df930be7Sderaadt * childs status. Top level routines (like pwait) must be sure 79df930be7Sderaadt * to mask interrupts when playing with the proclist data structures! 80df930be7Sderaadt */ 81df930be7Sderaadt /* ARGUSED */ 82df930be7Sderaadt void 83e757c91eSderaadt pchild(int notused) 84df930be7Sderaadt { 85e757c91eSderaadt struct process *pp; 86e757c91eSderaadt struct process *fp; 87e757c91eSderaadt int pid; 88df930be7Sderaadt extern int insource; 896dccf94eSderaadt int save_errno = errno; 905105d5e3Sguenther int w; 91df930be7Sderaadt int jobflags; 92df930be7Sderaadt struct rusage ru; 93df930be7Sderaadt 94df930be7Sderaadt loop: 95df930be7Sderaadt errno = 0; /* reset, just in case */ 965105d5e3Sguenther pid = wait3(&w, 97df930be7Sderaadt (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 98df930be7Sderaadt 99df930be7Sderaadt if (pid <= 0) { 100df930be7Sderaadt if (errno == EINTR) { 101df930be7Sderaadt errno = 0; 102df930be7Sderaadt goto loop; 103df930be7Sderaadt } 104df930be7Sderaadt pnoprocesses = pid == -1; 1056dccf94eSderaadt errno = save_errno; 106df930be7Sderaadt return; 107df930be7Sderaadt } 108df930be7Sderaadt for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 109df930be7Sderaadt if (pid == pp->p_pid) 110df930be7Sderaadt goto found; 111df930be7Sderaadt goto loop; 112df930be7Sderaadt found: 113df930be7Sderaadt if (pid == atoi(short2str(value(STRchild)))) 114df930be7Sderaadt unsetv(STRchild); 115df930be7Sderaadt pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 116df930be7Sderaadt if (WIFSTOPPED(w)) { 117df930be7Sderaadt pp->p_flags |= PSTOPPED; 1185105d5e3Sguenther pp->p_reason = WSTOPSIG(w); 119df930be7Sderaadt } 120df930be7Sderaadt else { 121df930be7Sderaadt if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 122833a4d71Santon (void) clock_gettime(CLOCK_MONOTONIC, &pp->p_etime); 123df930be7Sderaadt 124df930be7Sderaadt pp->p_rusage = ru; 125df930be7Sderaadt if (WIFSIGNALED(w)) { 1265105d5e3Sguenther if (WTERMSIG(w) == SIGINT) 127df930be7Sderaadt pp->p_flags |= PINTERRUPTED; 128df930be7Sderaadt else 129df930be7Sderaadt pp->p_flags |= PSIGNALED; 1305105d5e3Sguenther if (WCOREDUMP(w)) 131df930be7Sderaadt pp->p_flags |= PDUMPED; 1325105d5e3Sguenther pp->p_reason = WTERMSIG(w); 133df930be7Sderaadt } 134df930be7Sderaadt else { 1355105d5e3Sguenther pp->p_reason = WEXITSTATUS(w); 136df930be7Sderaadt if (pp->p_reason != 0) 137df930be7Sderaadt pp->p_flags |= PAEXITED; 138df930be7Sderaadt else 139df930be7Sderaadt pp->p_flags |= PNEXITED; 140df930be7Sderaadt } 141df930be7Sderaadt } 142df930be7Sderaadt jobflags = 0; 143df930be7Sderaadt fp = pp; 144df930be7Sderaadt do { 145df930be7Sderaadt if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 146df930be7Sderaadt !child && adrof(STRtime) && 147df930be7Sderaadt fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 148df930be7Sderaadt >= atoi(short2str(value(STRtime)))) 149df930be7Sderaadt fp->p_flags |= PTIME; 150df930be7Sderaadt jobflags |= fp->p_flags; 151df930be7Sderaadt } while ((fp = fp->p_friends) != pp); 152df930be7Sderaadt pp->p_flags &= ~PFOREGND; 153df930be7Sderaadt if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 154df930be7Sderaadt pp->p_flags &= ~PPTIME; 155df930be7Sderaadt pp->p_flags |= PTIME; 156df930be7Sderaadt } 157df930be7Sderaadt if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 158df930be7Sderaadt fp = pp; 159df930be7Sderaadt do { 160df930be7Sderaadt if (fp->p_flags & PSTOPPED) 161df930be7Sderaadt fp->p_flags |= PREPORTED; 162df930be7Sderaadt } while ((fp = fp->p_friends) != pp); 163df930be7Sderaadt while (fp->p_pid != fp->p_jobid) 164df930be7Sderaadt fp = fp->p_friends; 165df930be7Sderaadt if (jobflags & PSTOPPED) { 166df930be7Sderaadt if (pcurrent && pcurrent != fp) 167df930be7Sderaadt pprevious = pcurrent; 168df930be7Sderaadt pcurrent = fp; 169df930be7Sderaadt } 170df930be7Sderaadt else 171df930be7Sderaadt pclrcurr(fp); 172df930be7Sderaadt if (jobflags & PFOREGND) { 173df930be7Sderaadt if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 174df930be7Sderaadt !eq(dcwd->di_name, fp->p_cwd->di_name)) { 175df930be7Sderaadt ; /* print in pjwait */ 176df930be7Sderaadt } 177df930be7Sderaadt /* PWP: print a newline after ^C */ 178df930be7Sderaadt else if (jobflags & PINTERRUPTED) { 179df930be7Sderaadt (void) vis_fputc('\r' | QUOTE, cshout); 180df930be7Sderaadt (void) fputc('\n', cshout); 181df930be7Sderaadt } 182df930be7Sderaadt } 183df930be7Sderaadt else { 184df930be7Sderaadt if (jobflags & PNOTIFY || adrof(STRnotify)) { 185df930be7Sderaadt (void) vis_fputc('\r' | QUOTE, cshout); 186df930be7Sderaadt (void) fputc('\n', cshout); 187df930be7Sderaadt (void) pprint(pp, NUMBER | NAME | REASON); 188df930be7Sderaadt if ((jobflags & PSTOPPED) == 0) 189df930be7Sderaadt pflush(pp); 190df930be7Sderaadt } 191df930be7Sderaadt else { 192df930be7Sderaadt fp->p_flags |= PNEEDNOTE; 193df930be7Sderaadt neednote++; 194df930be7Sderaadt } 195df930be7Sderaadt } 196df930be7Sderaadt } 197df930be7Sderaadt goto loop; 198df930be7Sderaadt } 199df930be7Sderaadt 200df930be7Sderaadt void 201e757c91eSderaadt pnote(void) 202df930be7Sderaadt { 203e757c91eSderaadt struct process *pp; 204df930be7Sderaadt int flags; 205df930be7Sderaadt sigset_t sigset, osigset; 206df930be7Sderaadt 207df930be7Sderaadt neednote = 0; 208df930be7Sderaadt sigemptyset(&sigset); 209df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 210*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 211df930be7Sderaadt for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { 212df930be7Sderaadt if (pp->p_flags & PNEEDNOTE) { 213df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 214df930be7Sderaadt pp->p_flags &= ~PNEEDNOTE; 215df930be7Sderaadt flags = pprint(pp, NUMBER | NAME | REASON); 216df930be7Sderaadt if ((flags & (PRUNNING | PSTOPPED)) == 0) 217df930be7Sderaadt pflush(pp); 218df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 219df930be7Sderaadt } 220df930be7Sderaadt } 221df930be7Sderaadt } 222df930be7Sderaadt 223df930be7Sderaadt /* 224df930be7Sderaadt * pwait - wait for current job to terminate, maintaining integrity 225df930be7Sderaadt * of current and previous job indicators. 226df930be7Sderaadt */ 227df930be7Sderaadt void 228e757c91eSderaadt pwait(void) 229df930be7Sderaadt { 230e757c91eSderaadt struct process *fp, *pp; 231df930be7Sderaadt sigset_t sigset, osigset; 232df930be7Sderaadt 233df930be7Sderaadt /* 234df930be7Sderaadt * Here's where dead procs get flushed. 235df930be7Sderaadt */ 236df930be7Sderaadt sigemptyset(&sigset); 237df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 238*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 239df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 240df930be7Sderaadt for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) 241df930be7Sderaadt if (pp->p_pid == 0) { 242df930be7Sderaadt fp->p_next = pp->p_next; 243acdb3202Smestre free(pp->p_command); 244df930be7Sderaadt if (pp->p_cwd && --pp->p_cwd->di_count == 0) 245df930be7Sderaadt if (pp->p_cwd->di_next == 0) 246df930be7Sderaadt dfree(pp->p_cwd); 247acdb3202Smestre free(pp); 248df930be7Sderaadt pp = fp; 249df930be7Sderaadt } 250df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 251df930be7Sderaadt pjwait(pcurrjob); 252df930be7Sderaadt } 253df930be7Sderaadt 254df930be7Sderaadt 255df930be7Sderaadt /* 256df930be7Sderaadt * pjwait - wait for a job to finish or become stopped 257df930be7Sderaadt * It is assumed to be in the foreground state (PFOREGND) 258df930be7Sderaadt */ 259df930be7Sderaadt void 260e757c91eSderaadt pjwait(struct process *pp) 261df930be7Sderaadt { 262e757c91eSderaadt struct process *fp; 263df930be7Sderaadt int jobflags, reason; 264df930be7Sderaadt sigset_t sigset, osigset; 265df930be7Sderaadt 266df930be7Sderaadt while (pp->p_pid != pp->p_jobid) 267df930be7Sderaadt pp = pp->p_friends; 268df930be7Sderaadt fp = pp; 269df930be7Sderaadt 270df930be7Sderaadt do { 271df930be7Sderaadt if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 272df930be7Sderaadt (void) fprintf(csherr, "BUG: waiting for background job!\n"); 273df930be7Sderaadt } while ((fp = fp->p_friends) != pp); 274df930be7Sderaadt /* 275df930be7Sderaadt * Now keep pausing as long as we are not interrupted (SIGINT), and the 276df930be7Sderaadt * target process, or any of its friends, are running 277df930be7Sderaadt */ 278df930be7Sderaadt fp = pp; 279df930be7Sderaadt sigemptyset(&sigset); 280df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 281*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 282df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 283df930be7Sderaadt for (;;) { 284df930be7Sderaadt sigemptyset(&sigset); 285df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 286*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 287df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, NULL); 288df930be7Sderaadt jobflags = 0; 289df930be7Sderaadt do 290df930be7Sderaadt jobflags |= fp->p_flags; 291df930be7Sderaadt while ((fp = (fp->p_friends)) != pp); 292df930be7Sderaadt if ((jobflags & PRUNNING) == 0) 293df930be7Sderaadt break; 294df930be7Sderaadt sigset = osigset; 295df930be7Sderaadt sigdelset(&sigset, SIGCHLD); 296*324a3c8cSderaadt sigdelset(&sigset, SIGHUP); 297df930be7Sderaadt sigsuspend(&sigset); 298df930be7Sderaadt } 299df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 300df930be7Sderaadt if (tpgrp > 0) /* get tty back */ 301df930be7Sderaadt (void) tcsetpgrp(FSHTTY, tpgrp); 302df930be7Sderaadt if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 303df930be7Sderaadt !eq(dcwd->di_name, fp->p_cwd->di_name)) { 304df930be7Sderaadt if (jobflags & PSTOPPED) { 305df930be7Sderaadt (void) fputc('\n', cshout); 306df930be7Sderaadt if (adrof(STRlistjobs)) { 307df930be7Sderaadt Char *jobcommand[3]; 308df930be7Sderaadt 309df930be7Sderaadt jobcommand[0] = STRjobs; 310df930be7Sderaadt if (eq(value(STRlistjobs), STRlong)) 311df930be7Sderaadt jobcommand[1] = STRml; 312df930be7Sderaadt else 313df930be7Sderaadt jobcommand[1] = NULL; 314df930be7Sderaadt jobcommand[2] = NULL; 315df930be7Sderaadt 316df930be7Sderaadt dojobs(jobcommand, NULL); 317df930be7Sderaadt (void) pprint(pp, SHELLDIR); 318df930be7Sderaadt } 319df930be7Sderaadt else 320df930be7Sderaadt (void) pprint(pp, AREASON | SHELLDIR); 321df930be7Sderaadt } 322df930be7Sderaadt else 323df930be7Sderaadt (void) pprint(pp, AREASON | SHELLDIR); 324df930be7Sderaadt } 325df930be7Sderaadt if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 326df930be7Sderaadt (!gointr || !eq(gointr, STRminus))) { 327df930be7Sderaadt if ((jobflags & PSTOPPED) == 0) 328df930be7Sderaadt pflush(pp); 329df930be7Sderaadt pintr1(0); 330df930be7Sderaadt /* NOTREACHED */ 331df930be7Sderaadt } 332df930be7Sderaadt reason = 0; 333df930be7Sderaadt fp = pp; 334df930be7Sderaadt do { 335df930be7Sderaadt if (fp->p_reason) 336df930be7Sderaadt reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 337df930be7Sderaadt fp->p_reason | META : fp->p_reason; 338df930be7Sderaadt } while ((fp = fp->p_friends) != pp); 339df930be7Sderaadt if ((reason != 0) && (adrof(STRprintexitvalue))) { 340df930be7Sderaadt (void) fprintf(cshout, "Exit %d\n", reason); 341df930be7Sderaadt } 342df930be7Sderaadt set(STRstatus, putn(reason)); 343df930be7Sderaadt if (reason && exiterr) 344df930be7Sderaadt exitstat(); 345df930be7Sderaadt pflush(pp); 346df930be7Sderaadt } 347df930be7Sderaadt 348df930be7Sderaadt /* 349df930be7Sderaadt * dowait - wait for all processes to finish 350df930be7Sderaadt */ 351df930be7Sderaadt void 352e757c91eSderaadt dowait(Char **v, struct command *t) 353df930be7Sderaadt { 354e757c91eSderaadt struct process *pp; 355df930be7Sderaadt sigset_t sigset, osigset; 356df930be7Sderaadt 357df930be7Sderaadt pjobs++; 358df930be7Sderaadt sigemptyset(&sigset); 359df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 360*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 361df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 362df930be7Sderaadt loop: 363df930be7Sderaadt for (pp = proclist.p_next; pp; pp = pp->p_next) 364df930be7Sderaadt if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 365df930be7Sderaadt pp->p_flags & PRUNNING) { 366df930be7Sderaadt sigemptyset(&sigset); 367df930be7Sderaadt sigsuspend(&sigset); 368df930be7Sderaadt goto loop; 369df930be7Sderaadt } 370df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 371df930be7Sderaadt pjobs = 0; 372df930be7Sderaadt } 373df930be7Sderaadt 374df930be7Sderaadt /* 375df930be7Sderaadt * pflushall - flush all jobs from list (e.g. at fork()) 376df930be7Sderaadt */ 377df930be7Sderaadt static void 378e757c91eSderaadt pflushall(void) 379df930be7Sderaadt { 380e757c91eSderaadt struct process *pp; 381df930be7Sderaadt 382df930be7Sderaadt for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) 383df930be7Sderaadt if (pp->p_pid) 384df930be7Sderaadt pflush(pp); 385df930be7Sderaadt } 386df930be7Sderaadt 387df930be7Sderaadt /* 388df930be7Sderaadt * pflush - flag all process structures in the same job as the 389df930be7Sderaadt * the argument process for deletion. The actual free of the 390df930be7Sderaadt * space is not done here since pflush is called at interrupt level. 391df930be7Sderaadt */ 392df930be7Sderaadt static void 393e757c91eSderaadt pflush(struct process *pp) 394df930be7Sderaadt { 395e757c91eSderaadt struct process *np; 396e757c91eSderaadt int idx; 397df930be7Sderaadt 398df930be7Sderaadt if (pp->p_pid == 0) { 399df930be7Sderaadt (void) fprintf(csherr, "BUG: process flushed twice"); 400df930be7Sderaadt return; 401df930be7Sderaadt } 402df930be7Sderaadt while (pp->p_pid != pp->p_jobid) 403df930be7Sderaadt pp = pp->p_friends; 404df930be7Sderaadt pclrcurr(pp); 405df930be7Sderaadt if (pp == pcurrjob) 406df930be7Sderaadt pcurrjob = 0; 407df930be7Sderaadt idx = pp->p_index; 408df930be7Sderaadt np = pp; 409df930be7Sderaadt do { 410df930be7Sderaadt np->p_index = np->p_pid = 0; 411df930be7Sderaadt np->p_flags &= ~PNEEDNOTE; 412df930be7Sderaadt } while ((np = np->p_friends) != pp); 413df930be7Sderaadt if (idx == pmaxindex) { 414df930be7Sderaadt for (np = proclist.p_next, idx = 0; np; np = np->p_next) 415df930be7Sderaadt if (np->p_index > idx) 416df930be7Sderaadt idx = np->p_index; 417df930be7Sderaadt pmaxindex = idx; 418df930be7Sderaadt } 419df930be7Sderaadt } 420df930be7Sderaadt 421df930be7Sderaadt /* 422df930be7Sderaadt * pclrcurr - make sure the given job is not the current or previous job; 423df930be7Sderaadt * pp MUST be the job leader 424df930be7Sderaadt */ 425df930be7Sderaadt static void 426e757c91eSderaadt pclrcurr(struct process *pp) 427df930be7Sderaadt { 428df930be7Sderaadt 429df930be7Sderaadt if (pp == pcurrent) 430df930be7Sderaadt if (pprevious != NULL) { 431df930be7Sderaadt pcurrent = pprevious; 432df930be7Sderaadt pprevious = pgetcurr(pp); 433df930be7Sderaadt } 434df930be7Sderaadt else { 435df930be7Sderaadt pcurrent = pgetcurr(pp); 436df930be7Sderaadt pprevious = pgetcurr(pp); 437df930be7Sderaadt } 438df930be7Sderaadt else if (pp == pprevious) 439df930be7Sderaadt pprevious = pgetcurr(pp); 440df930be7Sderaadt } 441df930be7Sderaadt 442df930be7Sderaadt /* +4 here is 1 for '\0', 1 ea for << >& >> */ 443df930be7Sderaadt static Char command[PMAXLEN + 4]; 444df930be7Sderaadt static int cmdlen; 445df930be7Sderaadt static Char *cmdp; 446df930be7Sderaadt 447df930be7Sderaadt /* 448df930be7Sderaadt * palloc - allocate a process structure and fill it up. 449df930be7Sderaadt * an important assumption is made that the process is running. 450df930be7Sderaadt */ 451df930be7Sderaadt void 452e757c91eSderaadt palloc(int pid, struct command *t) 453df930be7Sderaadt { 454e757c91eSderaadt struct process *pp; 455df930be7Sderaadt int i; 456df930be7Sderaadt 457d29fd0a0Stedu pp = xcalloc(1, (size_t) sizeof(struct process)); 458df930be7Sderaadt pp->p_pid = pid; 459df930be7Sderaadt pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 460df930be7Sderaadt if (t->t_dflg & F_TIME) 461df930be7Sderaadt pp->p_flags |= PPTIME; 462df930be7Sderaadt cmdp = command; 463df930be7Sderaadt cmdlen = 0; 464df930be7Sderaadt padd(t); 465df930be7Sderaadt *cmdp++ = 0; 466df930be7Sderaadt if (t->t_dflg & F_PIPEOUT) { 467df930be7Sderaadt pp->p_flags |= PPOU; 468df930be7Sderaadt if (t->t_dflg & F_STDERR) 469df930be7Sderaadt pp->p_flags |= PERR; 470df930be7Sderaadt } 471df930be7Sderaadt pp->p_command = Strsave(command); 472df930be7Sderaadt if (pcurrjob) { 473df930be7Sderaadt struct process *fp; 474df930be7Sderaadt 475df930be7Sderaadt /* careful here with interrupt level */ 476df930be7Sderaadt pp->p_cwd = 0; 477df930be7Sderaadt pp->p_index = pcurrjob->p_index; 478df930be7Sderaadt pp->p_friends = pcurrjob; 479df930be7Sderaadt pp->p_jobid = pcurrjob->p_pid; 480df930be7Sderaadt for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) 481df930be7Sderaadt continue; 482df930be7Sderaadt fp->p_friends = pp; 483df930be7Sderaadt } 484df930be7Sderaadt else { 485df930be7Sderaadt pcurrjob = pp; 486df930be7Sderaadt pp->p_jobid = pid; 487df930be7Sderaadt pp->p_friends = pp; 488df930be7Sderaadt pp->p_cwd = dcwd; 489df930be7Sderaadt dcwd->di_count++; 490df930be7Sderaadt if (pmaxindex < BIGINDEX) 491df930be7Sderaadt pp->p_index = ++pmaxindex; 492df930be7Sderaadt else { 493df930be7Sderaadt struct process *np; 494df930be7Sderaadt 495df930be7Sderaadt for (i = 1;; i++) { 496df930be7Sderaadt for (np = proclist.p_next; np; np = np->p_next) 497df930be7Sderaadt if (np->p_index == i) 498df930be7Sderaadt goto tryagain; 499df930be7Sderaadt pp->p_index = i; 500df930be7Sderaadt if (i > pmaxindex) 501df930be7Sderaadt pmaxindex = i; 502df930be7Sderaadt break; 503df930be7Sderaadt tryagain:; 504df930be7Sderaadt } 505df930be7Sderaadt } 506df930be7Sderaadt if (pcurrent == NULL) 507df930be7Sderaadt pcurrent = pp; 508df930be7Sderaadt else if (pprevious == NULL) 509df930be7Sderaadt pprevious = pp; 510df930be7Sderaadt } 511df930be7Sderaadt pp->p_next = proclist.p_next; 512df930be7Sderaadt proclist.p_next = pp; 513833a4d71Santon (void) clock_gettime(CLOCK_MONOTONIC, &pp->p_btime); 514df930be7Sderaadt } 515df930be7Sderaadt 516df930be7Sderaadt static void 517e757c91eSderaadt padd(struct command *t) 518df930be7Sderaadt { 519df930be7Sderaadt Char **argp; 520df930be7Sderaadt 521df930be7Sderaadt if (t == 0) 522df930be7Sderaadt return; 523df930be7Sderaadt switch (t->t_dtyp) { 524df930be7Sderaadt 525df930be7Sderaadt case NODE_PAREN: 526df930be7Sderaadt pads(STRLparensp); 527df930be7Sderaadt padd(t->t_dspr); 528df930be7Sderaadt pads(STRspRparen); 529df930be7Sderaadt break; 530df930be7Sderaadt 531df930be7Sderaadt case NODE_COMMAND: 532df930be7Sderaadt for (argp = t->t_dcom; *argp; argp++) { 533df930be7Sderaadt pads(*argp); 534df930be7Sderaadt if (argp[1]) 535df930be7Sderaadt pads(STRspace); 536df930be7Sderaadt } 537df930be7Sderaadt break; 538df930be7Sderaadt 539df930be7Sderaadt case NODE_OR: 540df930be7Sderaadt case NODE_AND: 541df930be7Sderaadt case NODE_PIPE: 542df930be7Sderaadt case NODE_LIST: 543df930be7Sderaadt padd(t->t_dcar); 544df930be7Sderaadt switch (t->t_dtyp) { 545df930be7Sderaadt case NODE_OR: 546df930be7Sderaadt pads(STRspor2sp); 547df930be7Sderaadt break; 548df930be7Sderaadt case NODE_AND: 549df930be7Sderaadt pads(STRspand2sp); 550df930be7Sderaadt break; 551df930be7Sderaadt case NODE_PIPE: 552df930be7Sderaadt pads(STRsporsp); 553df930be7Sderaadt break; 554df930be7Sderaadt case NODE_LIST: 555df930be7Sderaadt pads(STRsemisp); 556df930be7Sderaadt break; 557df930be7Sderaadt } 558df930be7Sderaadt padd(t->t_dcdr); 559df930be7Sderaadt return; 560df930be7Sderaadt } 561df930be7Sderaadt if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 562df930be7Sderaadt pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); 563df930be7Sderaadt pads(t->t_dlef); 564df930be7Sderaadt } 565df930be7Sderaadt if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 566df930be7Sderaadt pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); 567df930be7Sderaadt if (t->t_dflg & F_STDERR) 568df930be7Sderaadt pads(STRand); 569df930be7Sderaadt pads(STRspace); 570df930be7Sderaadt pads(t->t_drit); 571df930be7Sderaadt } 572df930be7Sderaadt } 573df930be7Sderaadt 574df930be7Sderaadt static void 575e757c91eSderaadt pads(Char *cp) 576df930be7Sderaadt { 577e757c91eSderaadt int i; 578df930be7Sderaadt 579df930be7Sderaadt /* 580df930be7Sderaadt * Avoid the Quoted Space alias hack! Reported by: 581df930be7Sderaadt * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 582df930be7Sderaadt */ 583df930be7Sderaadt if (cp[0] == STRQNULL[0]) 584df930be7Sderaadt cp++; 585df930be7Sderaadt 586df930be7Sderaadt i = Strlen(cp); 587df930be7Sderaadt 588df930be7Sderaadt if (cmdlen >= PMAXLEN) 589df930be7Sderaadt return; 590df930be7Sderaadt if (cmdlen + i >= PMAXLEN) { 591ac8842f6Stedu (void) Strlcpy(cmdp, STRsp3dots, PMAXLEN - cmdlen); 592df930be7Sderaadt cmdlen = PMAXLEN; 593df930be7Sderaadt cmdp += 4; 594df930be7Sderaadt return; 595df930be7Sderaadt } 596ac8842f6Stedu (void) Strlcpy(cmdp, cp, PMAXLEN - cmdlen); 597df930be7Sderaadt cmdp += i; 598df930be7Sderaadt cmdlen += i; 599df930be7Sderaadt } 600df930be7Sderaadt 601df930be7Sderaadt /* 602df930be7Sderaadt * psavejob - temporarily save the current job on a one level stack 603df930be7Sderaadt * so another job can be created. Used for { } in exp6 604df930be7Sderaadt * and `` in globbing. 605df930be7Sderaadt */ 606df930be7Sderaadt void 607e757c91eSderaadt psavejob(void) 608df930be7Sderaadt { 609df930be7Sderaadt 610df930be7Sderaadt pholdjob = pcurrjob; 611df930be7Sderaadt pcurrjob = NULL; 612df930be7Sderaadt } 613df930be7Sderaadt 614df930be7Sderaadt /* 615df930be7Sderaadt * prestjob - opposite of psavejob. This may be missed if we are interrupted 616df930be7Sderaadt * somewhere, but pendjob cleans up anyway. 617df930be7Sderaadt */ 618df930be7Sderaadt void 619e757c91eSderaadt prestjob(void) 620df930be7Sderaadt { 621df930be7Sderaadt 622df930be7Sderaadt pcurrjob = pholdjob; 623df930be7Sderaadt pholdjob = NULL; 624df930be7Sderaadt } 625df930be7Sderaadt 626df930be7Sderaadt /* 627df930be7Sderaadt * pendjob - indicate that a job (set of commands) has been completed 628df930be7Sderaadt * or is about to begin. 629df930be7Sderaadt */ 630df930be7Sderaadt void 631e757c91eSderaadt pendjob(void) 632df930be7Sderaadt { 633e757c91eSderaadt struct process *pp, *tp; 634df930be7Sderaadt 635df930be7Sderaadt if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 636df930be7Sderaadt pp = pcurrjob; 637df930be7Sderaadt while (pp->p_pid != pp->p_jobid) 638df930be7Sderaadt pp = pp->p_friends; 639df930be7Sderaadt (void) fprintf(cshout, "[%d]", pp->p_index); 640df930be7Sderaadt tp = pp; 641df930be7Sderaadt do { 642df930be7Sderaadt (void) fprintf(cshout, " %d", pp->p_pid); 643df930be7Sderaadt pp = pp->p_friends; 644df930be7Sderaadt } while (pp != tp); 645df930be7Sderaadt (void) fputc('\n', cshout); 646df930be7Sderaadt } 647df930be7Sderaadt pholdjob = pcurrjob = 0; 648df930be7Sderaadt } 649df930be7Sderaadt 650df930be7Sderaadt /* 651df930be7Sderaadt * pprint - print a job 652df930be7Sderaadt */ 653df930be7Sderaadt static int 654e757c91eSderaadt pprint(struct process *pp, bool flag) 655df930be7Sderaadt { 656e757c91eSderaadt int status, reason; 657df930be7Sderaadt struct process *tp; 658df930be7Sderaadt int jobflags, pstatus; 659df930be7Sderaadt bool hadnl = 1; /* did we just have a newline */ 660df930be7Sderaadt 661df930be7Sderaadt (void) fpurge(cshout); 662df930be7Sderaadt 663df930be7Sderaadt while (pp->p_pid != pp->p_jobid) 664df930be7Sderaadt pp = pp->p_friends; 665df930be7Sderaadt if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 666df930be7Sderaadt pp->p_flags &= ~PPTIME; 667df930be7Sderaadt pp->p_flags |= PTIME; 668df930be7Sderaadt } 669df930be7Sderaadt tp = pp; 670df930be7Sderaadt status = reason = -1; 671df930be7Sderaadt jobflags = 0; 672df930be7Sderaadt do { 673df930be7Sderaadt jobflags |= pp->p_flags; 674df930be7Sderaadt pstatus = pp->p_flags & PALLSTATES; 675df930be7Sderaadt if (tp != pp && !hadnl && !(flag & FANCY) && 676df930be7Sderaadt ((pstatus == status && pp->p_reason == reason) || 677df930be7Sderaadt !(flag & REASON))) { 678df930be7Sderaadt (void) fputc(' ', cshout); 679df930be7Sderaadt hadnl = 0; 680df930be7Sderaadt } 681df930be7Sderaadt else { 682df930be7Sderaadt if (tp != pp && !hadnl) { 683df930be7Sderaadt (void) fputc('\n', cshout); 684df930be7Sderaadt hadnl = 1; 685df930be7Sderaadt } 686df930be7Sderaadt if (flag & NUMBER) { 687df930be7Sderaadt if (pp == tp) 688df930be7Sderaadt (void) fprintf(cshout, "[%d]%s %c ", pp->p_index, 689df930be7Sderaadt pp->p_index < 10 ? " " : "", 690df930be7Sderaadt pp == pcurrent ? '+' : 691df930be7Sderaadt (pp == pprevious ? '-' : ' ')); 692df930be7Sderaadt else 693df930be7Sderaadt (void) fprintf(cshout, " "); 694df930be7Sderaadt hadnl = 0; 695df930be7Sderaadt } 696df930be7Sderaadt if (flag & FANCY) { 697df930be7Sderaadt (void) fprintf(cshout, "%5d ", pp->p_pid); 698df930be7Sderaadt hadnl = 0; 699df930be7Sderaadt } 700df930be7Sderaadt if (flag & (REASON | AREASON)) { 70193079f38Sguenther int width = 0; 702df930be7Sderaadt if (flag & NAME) 70393079f38Sguenther width = -23; 704df930be7Sderaadt if (pstatus == status) 705df930be7Sderaadt if (pp->p_reason == reason) { 70693079f38Sguenther (void) fprintf(cshout, "%*s", width, ""); 707df930be7Sderaadt hadnl = 0; 708df930be7Sderaadt goto prcomd; 709df930be7Sderaadt } 710df930be7Sderaadt else 711df930be7Sderaadt reason = pp->p_reason; 712df930be7Sderaadt else { 713df930be7Sderaadt status = pstatus; 714df930be7Sderaadt reason = pp->p_reason; 715df930be7Sderaadt } 716df930be7Sderaadt switch (status) { 717df930be7Sderaadt 718df930be7Sderaadt case PRUNNING: 71993079f38Sguenther (void) fprintf(cshout, "%*s", width, "Running "); 720df930be7Sderaadt hadnl = 0; 721df930be7Sderaadt break; 722df930be7Sderaadt 723df930be7Sderaadt case PINTERRUPTED: 724df930be7Sderaadt case PSTOPPED: 725df930be7Sderaadt case PSIGNALED: 726df930be7Sderaadt /* 727df930be7Sderaadt * tell what happened to the background job 728df930be7Sderaadt * From: Michael Schroeder 729df930be7Sderaadt * <mlschroe@immd4.informatik.uni-erlangen.de> 730df930be7Sderaadt */ 731df930be7Sderaadt if ((flag & REASON) 732df930be7Sderaadt || ((flag & AREASON) 733df930be7Sderaadt && reason != SIGINT 734df930be7Sderaadt && (reason != SIGPIPE 735df930be7Sderaadt || (pp->p_flags & PPOU) == 0))) { 73693079f38Sguenther (void) fprintf(cshout, "%*s", width, 737df930be7Sderaadt sys_siglist[(unsigned char) 738df930be7Sderaadt pp->p_reason]); 739df930be7Sderaadt hadnl = 0; 740df930be7Sderaadt } 741df930be7Sderaadt break; 742df930be7Sderaadt 743df930be7Sderaadt case PNEXITED: 744df930be7Sderaadt case PAEXITED: 745df930be7Sderaadt if (flag & REASON) { 746df930be7Sderaadt if (pp->p_reason) 747df930be7Sderaadt (void) fprintf(cshout, "Exit %-18d", pp->p_reason); 748df930be7Sderaadt else 74993079f38Sguenther (void) fprintf(cshout, "%*s", width, "Done"); 750df930be7Sderaadt hadnl = 0; 751df930be7Sderaadt } 752df930be7Sderaadt break; 753df930be7Sderaadt 754df930be7Sderaadt default: 755df930be7Sderaadt (void) fprintf(csherr, "BUG: status=%-9o", status); 756df930be7Sderaadt } 757df930be7Sderaadt } 758df930be7Sderaadt } 759df930be7Sderaadt prcomd: 760df930be7Sderaadt if (flag & NAME) { 761df930be7Sderaadt (void) fprintf(cshout, "%s", vis_str(pp->p_command)); 762df930be7Sderaadt if (pp->p_flags & PPOU) 763df930be7Sderaadt (void) fprintf(cshout, " |"); 764df930be7Sderaadt if (pp->p_flags & PERR) 765df930be7Sderaadt (void) fputc('&', cshout); 766df930be7Sderaadt hadnl = 0; 767df930be7Sderaadt } 768df930be7Sderaadt if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) { 769df930be7Sderaadt (void) fprintf(cshout, " (core dumped)"); 770df930be7Sderaadt hadnl = 0; 771df930be7Sderaadt } 772df930be7Sderaadt if (tp == pp->p_friends) { 773df930be7Sderaadt if (flag & AMPERSAND) { 774df930be7Sderaadt (void) fprintf(cshout, " &"); 775df930be7Sderaadt hadnl = 0; 776df930be7Sderaadt } 777df930be7Sderaadt if (flag & JOBDIR && 778df930be7Sderaadt !eq(tp->p_cwd->di_name, dcwd->di_name)) { 779df930be7Sderaadt (void) fprintf(cshout, " (wd: "); 780df930be7Sderaadt dtildepr(value(STRhome), tp->p_cwd->di_name); 781df930be7Sderaadt (void) fputc(')', cshout); 782df930be7Sderaadt hadnl = 0; 783df930be7Sderaadt } 784df930be7Sderaadt } 785df930be7Sderaadt if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 786df930be7Sderaadt if (!hadnl) 787df930be7Sderaadt (void) fprintf(cshout, "\n\t"); 788df930be7Sderaadt prusage(&zru, &pp->p_rusage, &pp->p_etime, 789df930be7Sderaadt &pp->p_btime); 790df930be7Sderaadt hadnl = 1; 791df930be7Sderaadt } 792df930be7Sderaadt if (tp == pp->p_friends) { 793df930be7Sderaadt if (!hadnl) { 794df930be7Sderaadt (void) fputc('\n', cshout); 795df930be7Sderaadt hadnl = 1; 796df930be7Sderaadt } 797df930be7Sderaadt if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 798df930be7Sderaadt (void) fprintf(cshout, "(wd now: "); 799df930be7Sderaadt dtildepr(value(STRhome), dcwd->di_name); 800df930be7Sderaadt (void) fprintf(cshout, ")\n"); 801df930be7Sderaadt hadnl = 1; 802df930be7Sderaadt } 803df930be7Sderaadt } 804df930be7Sderaadt } while ((pp = pp->p_friends) != tp); 805df930be7Sderaadt if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 806df930be7Sderaadt if (jobflags & NUMBER) 807df930be7Sderaadt (void) fprintf(cshout, " "); 808df930be7Sderaadt ptprint(tp); 809df930be7Sderaadt hadnl = 1; 810df930be7Sderaadt } 811df930be7Sderaadt (void) fflush(cshout); 812df930be7Sderaadt return (jobflags); 813df930be7Sderaadt } 814df930be7Sderaadt 815df930be7Sderaadt static void 816e757c91eSderaadt ptprint(struct process *tp) 817df930be7Sderaadt { 818833a4d71Santon struct timespec tetime, diff; 819833a4d71Santon static struct timespec ztime; 820df930be7Sderaadt struct rusage ru; 821df930be7Sderaadt static struct rusage zru; 822e757c91eSderaadt struct process *pp = tp; 823df930be7Sderaadt 824df930be7Sderaadt ru = zru; 825df930be7Sderaadt tetime = ztime; 826df930be7Sderaadt do { 827df930be7Sderaadt ruadd(&ru, &pp->p_rusage); 828833a4d71Santon timespecsub(&pp->p_etime, &pp->p_btime, &diff); 829833a4d71Santon if (timespeccmp(&diff, &tetime, >)) 830df930be7Sderaadt tetime = diff; 831df930be7Sderaadt } while ((pp = pp->p_friends) != tp); 832df930be7Sderaadt prusage(&zru, &ru, &tetime, &ztime); 833df930be7Sderaadt } 834df930be7Sderaadt 835df930be7Sderaadt /* 836df930be7Sderaadt * dojobs - print all jobs 837df930be7Sderaadt */ 838df930be7Sderaadt void 839e757c91eSderaadt dojobs(Char **v, struct command *t) 840df930be7Sderaadt { 841e757c91eSderaadt struct process *pp; 842e757c91eSderaadt int flag = NUMBER | NAME | REASON; 843df930be7Sderaadt int i; 844df930be7Sderaadt 845df930be7Sderaadt if (chkstop) 846df930be7Sderaadt chkstop = 2; 847df930be7Sderaadt if (*++v) { 848df930be7Sderaadt if (v[1] || !eq(*v, STRml)) 849df930be7Sderaadt stderror(ERR_JOBS); 850df930be7Sderaadt flag |= FANCY | JOBDIR; 851df930be7Sderaadt } 852df930be7Sderaadt for (i = 1; i <= pmaxindex; i++) 853df930be7Sderaadt for (pp = proclist.p_next; pp; pp = pp->p_next) 854df930be7Sderaadt if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 855df930be7Sderaadt pp->p_flags &= ~PNEEDNOTE; 856df930be7Sderaadt if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 857df930be7Sderaadt pflush(pp); 858df930be7Sderaadt break; 859df930be7Sderaadt } 860df930be7Sderaadt } 861df930be7Sderaadt 862df930be7Sderaadt /* 863df930be7Sderaadt * dofg - builtin - put the job into the foreground 864df930be7Sderaadt */ 865df930be7Sderaadt void 866e757c91eSderaadt dofg(Char **v, struct command *t) 867df930be7Sderaadt { 868e757c91eSderaadt struct process *pp; 869df930be7Sderaadt 870df930be7Sderaadt okpcntl(); 871df930be7Sderaadt ++v; 872df930be7Sderaadt do { 873df930be7Sderaadt pp = pfind(*v); 874df930be7Sderaadt pstart(pp, 1); 875df930be7Sderaadt pjwait(pp); 876df930be7Sderaadt } while (*v && *++v); 877df930be7Sderaadt } 878df930be7Sderaadt 879df930be7Sderaadt /* 880df930be7Sderaadt * %... - builtin - put the job into the foreground 881df930be7Sderaadt */ 882df930be7Sderaadt void 883e757c91eSderaadt dofg1(Char **v, struct command *t) 884df930be7Sderaadt { 885e757c91eSderaadt struct process *pp; 886df930be7Sderaadt 887df930be7Sderaadt okpcntl(); 888df930be7Sderaadt pp = pfind(v[0]); 889df930be7Sderaadt pstart(pp, 1); 890df930be7Sderaadt pjwait(pp); 891df930be7Sderaadt } 892df930be7Sderaadt 893df930be7Sderaadt /* 894df930be7Sderaadt * dobg - builtin - put the job into the background 895df930be7Sderaadt */ 896df930be7Sderaadt void 897e757c91eSderaadt dobg(Char **v, struct command *t) 898df930be7Sderaadt { 899e757c91eSderaadt struct process *pp; 900df930be7Sderaadt 901df930be7Sderaadt okpcntl(); 902df930be7Sderaadt ++v; 903df930be7Sderaadt do { 904df930be7Sderaadt pp = pfind(*v); 905df930be7Sderaadt pstart(pp, 0); 906df930be7Sderaadt } while (*v && *++v); 907df930be7Sderaadt } 908df930be7Sderaadt 909df930be7Sderaadt /* 910df930be7Sderaadt * %... & - builtin - put the job into the background 911df930be7Sderaadt */ 912df930be7Sderaadt void 913e757c91eSderaadt dobg1(Char **v, struct command *t) 914df930be7Sderaadt { 915e757c91eSderaadt struct process *pp; 916df930be7Sderaadt 917df930be7Sderaadt pp = pfind(v[0]); 918df930be7Sderaadt pstart(pp, 0); 919df930be7Sderaadt } 920df930be7Sderaadt 921df930be7Sderaadt /* 922df930be7Sderaadt * dostop - builtin - stop the job 923df930be7Sderaadt */ 924df930be7Sderaadt void 925e757c91eSderaadt dostop(Char **v, struct command *t) 926df930be7Sderaadt { 927df930be7Sderaadt pkill(++v, SIGSTOP); 928df930be7Sderaadt } 929df930be7Sderaadt 930df930be7Sderaadt /* 931df930be7Sderaadt * dokill - builtin - superset of kill (1) 932df930be7Sderaadt */ 933df930be7Sderaadt void 934e757c91eSderaadt dokill(Char **v, struct command *t) 935df930be7Sderaadt { 936e757c91eSderaadt int signum = SIGTERM; 937a47b6461Sderaadt const char *errstr; 938e757c91eSderaadt char *name; 939df930be7Sderaadt 940df930be7Sderaadt v++; 941df930be7Sderaadt if (v[0] && v[0][0] == '-') { 942df930be7Sderaadt if (v[0][1] == 'l') { 943a7d49410Sderaadt if (v[1]) { 944a7d49410Sderaadt if (!Isdigit(v[1][0])) 945a7d49410Sderaadt stderror(ERR_NAME | ERR_BADSIG); 946a7d49410Sderaadt 947a47b6461Sderaadt signum = strtonum(short2str(v[1]), 0, NSIG-1, &errstr); 948a47b6461Sderaadt if (errstr) 949a7d49410Sderaadt stderror(ERR_NAME | ERR_BADSIG); 950a7d49410Sderaadt else if (signum == 0) 951a7d49410Sderaadt (void) fputc('0', cshout); /* 0's symbolic name is '0' */ 952a7d49410Sderaadt else 953a7d49410Sderaadt (void) fprintf(cshout, "%s ", sys_signame[signum]); 954a7d49410Sderaadt } else { 955df930be7Sderaadt for (signum = 1; signum < NSIG; signum++) { 956df930be7Sderaadt (void) fprintf(cshout, "%s ", sys_signame[signum]); 957df930be7Sderaadt if (signum == NSIG / 2) 958df930be7Sderaadt (void) fputc('\n', cshout); 959df930be7Sderaadt } 960a7d49410Sderaadt } 961df930be7Sderaadt (void) fputc('\n', cshout); 962df930be7Sderaadt return; 963df930be7Sderaadt } 964df930be7Sderaadt if (Isdigit(v[0][1])) { 965a47b6461Sderaadt signum = strtonum(short2str(v[0] + 1), 0, NSIG-1, &errstr); 966a47b6461Sderaadt if (errstr) 967df930be7Sderaadt stderror(ERR_NAME | ERR_BADSIG); 968df930be7Sderaadt } 969df930be7Sderaadt else { 970b0e79499Sderaadt if (v[0][1] == 's' && (Isspace(v[0][2]) || v[0][2] == '\0')) { 971a7d49410Sderaadt v++; 972b0e79499Sderaadt name = short2str(&v[0][0]); 973b0e79499Sderaadt } else { 974b0e79499Sderaadt name = short2str(&v[0][1]); 975b0e79499Sderaadt } 976df930be7Sderaadt 977a7d49410Sderaadt if (v[0] == NULL || v[1] == NULL) { 978a7d49410Sderaadt stderror(ERR_NAME | ERR_TOOFEW); 979a7d49410Sderaadt return; 980a7d49410Sderaadt } 981a7d49410Sderaadt 982df930be7Sderaadt for (signum = 1; signum < NSIG; signum++) 9839b4e984fSderaadt if (!strcasecmp(sys_signame[signum], name) || 984cbf92575Sderaadt (strlen(name) > 3 && !strncasecmp("SIG", name, 3) && 9859b4e984fSderaadt !strcasecmp(sys_signame[signum], name + 3))) 986df930be7Sderaadt break; 987df930be7Sderaadt 988df930be7Sderaadt if (signum == NSIG) { 989b0e79499Sderaadt if (name[0] == '0') 990a7d49410Sderaadt signum = 0; 991a7d49410Sderaadt else { 992a7d49410Sderaadt setname(vis_str(&v[0][0])); 993df930be7Sderaadt stderror(ERR_NAME | ERR_UNKSIG); 994df930be7Sderaadt } 995df930be7Sderaadt } 996a7d49410Sderaadt } 997df930be7Sderaadt v++; 998df930be7Sderaadt } 999df930be7Sderaadt pkill(v, signum); 1000df930be7Sderaadt } 1001df930be7Sderaadt 1002df930be7Sderaadt static void 1003e757c91eSderaadt pkill(Char **v, int signum) 1004df930be7Sderaadt { 1005e757c91eSderaadt struct process *pp, *np; 1006e757c91eSderaadt int jobflags = 0; 1007df930be7Sderaadt int pid, err1 = 0; 1008df930be7Sderaadt sigset_t sigset; 1009df930be7Sderaadt Char *cp; 1010df930be7Sderaadt 1011df930be7Sderaadt sigemptyset(&sigset); 1012df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 1013*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 1014df930be7Sderaadt if (setintr) 1015df930be7Sderaadt sigaddset(&sigset, SIGINT); 1016df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, NULL); 1017df930be7Sderaadt gflag = 0, tglob(v); 1018df930be7Sderaadt if (gflag) { 1019df930be7Sderaadt v = globall(v); 1020df930be7Sderaadt if (v == 0) 1021df930be7Sderaadt stderror(ERR_NAME | ERR_NOMATCH); 1022df930be7Sderaadt } 1023df930be7Sderaadt else { 1024df930be7Sderaadt v = gargv = saveblk(v); 1025df930be7Sderaadt trim(v); 1026df930be7Sderaadt } 1027df930be7Sderaadt 1028df930be7Sderaadt while (v && (cp = *v)) { 1029df930be7Sderaadt if (*cp == '%') { 1030df930be7Sderaadt np = pp = pfind(cp); 1031df930be7Sderaadt do 1032df930be7Sderaadt jobflags |= np->p_flags; 1033df930be7Sderaadt while ((np = np->p_friends) != pp); 1034df930be7Sderaadt switch (signum) { 1035df930be7Sderaadt 1036df930be7Sderaadt case SIGSTOP: 1037df930be7Sderaadt case SIGTSTP: 1038df930be7Sderaadt case SIGTTIN: 1039df930be7Sderaadt case SIGTTOU: 1040df930be7Sderaadt if ((jobflags & PRUNNING) == 0) { 1041df930be7Sderaadt (void) fprintf(csherr, "%s: Already suspended\n", 1042df930be7Sderaadt vis_str(cp)); 1043df930be7Sderaadt err1++; 1044df930be7Sderaadt goto cont; 1045df930be7Sderaadt } 1046df930be7Sderaadt break; 1047df930be7Sderaadt /* 1048df930be7Sderaadt * suspend a process, kill -CONT %, then type jobs; the shell 1049df930be7Sderaadt * says it is suspended, but it is running; thanks jaap.. 1050df930be7Sderaadt */ 1051df930be7Sderaadt case SIGCONT: 1052df930be7Sderaadt pstart(pp, 0); 1053df930be7Sderaadt goto cont; 1054df930be7Sderaadt } 10553aaa63ebSderaadt if (kill(-pp->p_jobid, signum) == -1) { 1056df930be7Sderaadt (void) fprintf(csherr, "%s: %s\n", vis_str(cp), 1057df930be7Sderaadt strerror(errno)); 1058df930be7Sderaadt err1++; 1059df930be7Sderaadt } 1060df930be7Sderaadt if (signum == SIGTERM || signum == SIGHUP) 1061df930be7Sderaadt (void) kill(-pp->p_jobid, SIGCONT); 1062df930be7Sderaadt } 1063df930be7Sderaadt else if (!(Isdigit(*cp) || *cp == '-')) 1064df930be7Sderaadt stderror(ERR_NAME | ERR_JOBARGS); 1065df930be7Sderaadt else { 106644d35ad9Smillert char *ep; 106744d35ad9Smillert char *pidnam = short2str(cp); 106844d35ad9Smillert 106944d35ad9Smillert pid = strtol(pidnam, &ep, 10); 107044d35ad9Smillert if (!*pidnam || *ep) { 107144d35ad9Smillert (void) fprintf(csherr, "%s: illegal process id\n", pidnam); 107244d35ad9Smillert err1++; 107344d35ad9Smillert goto cont; 107444d35ad9Smillert } 10753aaa63ebSderaadt if (kill((pid_t) pid, signum) == -1) { 1076df930be7Sderaadt (void) fprintf(csherr, "%d: %s\n", pid, strerror(errno)); 1077df930be7Sderaadt err1++; 1078df930be7Sderaadt goto cont; 1079df930be7Sderaadt } 1080df930be7Sderaadt if (signum == SIGTERM || signum == SIGHUP) 1081df930be7Sderaadt (void) kill((pid_t) pid, SIGCONT); 1082df930be7Sderaadt } 1083df930be7Sderaadt cont: 1084df930be7Sderaadt v++; 1085df930be7Sderaadt } 1086bcb7da30Smiko blkfree(gargv); 1087bcb7da30Smiko gargv = NULL; 1088df930be7Sderaadt sigprocmask(SIG_UNBLOCK, &sigset, NULL); 1089df930be7Sderaadt if (err1) 1090df930be7Sderaadt stderror(ERR_SILENT); 1091df930be7Sderaadt } 1092df930be7Sderaadt 1093df930be7Sderaadt /* 1094df930be7Sderaadt * pstart - start the job in foreground/background 1095df930be7Sderaadt */ 1096df930be7Sderaadt void 1097e757c91eSderaadt pstart(struct process *pp, int foregnd) 1098df930be7Sderaadt { 1099e757c91eSderaadt struct process *np; 1100df930be7Sderaadt sigset_t sigset, osigset; 1101df930be7Sderaadt long jobflags = 0; 1102df930be7Sderaadt 1103df930be7Sderaadt sigemptyset(&sigset); 1104df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 1105*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 1106df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 1107df930be7Sderaadt np = pp; 1108df930be7Sderaadt do { 1109df930be7Sderaadt jobflags |= np->p_flags; 1110df930be7Sderaadt if (np->p_flags & (PRUNNING | PSTOPPED)) { 1111df930be7Sderaadt np->p_flags |= PRUNNING; 1112df930be7Sderaadt np->p_flags &= ~PSTOPPED; 1113df930be7Sderaadt if (foregnd) 1114df930be7Sderaadt np->p_flags |= PFOREGND; 1115df930be7Sderaadt else 1116df930be7Sderaadt np->p_flags &= ~PFOREGND; 1117df930be7Sderaadt } 1118df930be7Sderaadt } while ((np = np->p_friends) != pp); 1119df930be7Sderaadt if (!foregnd) 1120df930be7Sderaadt pclrcurr(pp); 1121df930be7Sderaadt (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 1122df930be7Sderaadt if (foregnd) 1123df930be7Sderaadt (void) tcsetpgrp(FSHTTY, pp->p_jobid); 1124df930be7Sderaadt if (jobflags & PSTOPPED) 1125df930be7Sderaadt (void) kill(-pp->p_jobid, SIGCONT); 1126df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 1127df930be7Sderaadt } 1128df930be7Sderaadt 1129df930be7Sderaadt void 1130e757c91eSderaadt panystop(bool neednl) 1131df930be7Sderaadt { 1132e757c91eSderaadt struct process *pp; 1133df930be7Sderaadt 1134df930be7Sderaadt chkstop = 2; 1135df930be7Sderaadt for (pp = proclist.p_next; pp; pp = pp->p_next) 1136df930be7Sderaadt if (pp->p_flags & PSTOPPED) 1137df930be7Sderaadt stderror(ERR_STOPPED, neednl ? "\n" : ""); 1138df930be7Sderaadt } 1139df930be7Sderaadt 1140df930be7Sderaadt struct process * 1141e757c91eSderaadt pfind(Char *cp) 1142df930be7Sderaadt { 1143e757c91eSderaadt struct process *pp, *np; 1144df930be7Sderaadt 1145df930be7Sderaadt if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { 1146df930be7Sderaadt if (pcurrent == NULL) 1147df930be7Sderaadt stderror(ERR_NAME | ERR_JOBCUR); 1148df930be7Sderaadt return (pcurrent); 1149df930be7Sderaadt } 1150df930be7Sderaadt if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { 1151df930be7Sderaadt if (pprevious == NULL) 1152df930be7Sderaadt stderror(ERR_NAME | ERR_JOBPREV); 1153df930be7Sderaadt return (pprevious); 1154df930be7Sderaadt } 1155df930be7Sderaadt if (Isdigit(cp[1])) { 1156a47b6461Sderaadt const char *errstr; 1157a47b6461Sderaadt int idx = strtonum(short2str(cp + 1), 1, INT_MAX, &errstr); 1158df930be7Sderaadt 1159a47b6461Sderaadt if (errstr) { 1160a47b6461Sderaadt stderror(ERR_NAME | ERR_NOSUCHJOB); 1161a47b6461Sderaadt return (0); 1162a47b6461Sderaadt } 1163df930be7Sderaadt for (pp = proclist.p_next; pp; pp = pp->p_next) 1164df930be7Sderaadt if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 1165df930be7Sderaadt return (pp); 1166df930be7Sderaadt stderror(ERR_NAME | ERR_NOSUCHJOB); 1167a47b6461Sderaadt return (0); 1168df930be7Sderaadt } 1169df930be7Sderaadt np = NULL; 1170df930be7Sderaadt for (pp = proclist.p_next; pp; pp = pp->p_next) 1171df930be7Sderaadt if (pp->p_pid == pp->p_jobid) { 1172df930be7Sderaadt if (cp[1] == '?') { 1173e757c91eSderaadt Char *dp; 1174df930be7Sderaadt 1175df930be7Sderaadt for (dp = pp->p_command; *dp; dp++) { 1176df930be7Sderaadt if (*dp != cp[2]) 1177df930be7Sderaadt continue; 1178df930be7Sderaadt if (prefix(cp + 2, dp)) 1179df930be7Sderaadt goto match; 1180df930be7Sderaadt } 1181df930be7Sderaadt } 1182df930be7Sderaadt else if (prefix(cp + 1, pp->p_command)) { 1183df930be7Sderaadt match: 1184df930be7Sderaadt if (np) 1185df930be7Sderaadt stderror(ERR_NAME | ERR_AMBIG); 1186df930be7Sderaadt np = pp; 1187df930be7Sderaadt } 1188df930be7Sderaadt } 1189df930be7Sderaadt if (np) 1190df930be7Sderaadt return (np); 1191764064c4Smickey stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); 1192df930be7Sderaadt /* NOTREACHED */ 1193df930be7Sderaadt return (0); 1194df930be7Sderaadt } 1195df930be7Sderaadt 1196df930be7Sderaadt 1197df930be7Sderaadt /* 1198df930be7Sderaadt * pgetcurr - find most recent job that is not pp, preferably stopped 1199df930be7Sderaadt */ 1200df930be7Sderaadt static struct process * 1201e757c91eSderaadt pgetcurr(struct process *pp) 1202df930be7Sderaadt { 1203e757c91eSderaadt struct process *np; 1204e757c91eSderaadt struct process *xp = NULL; 1205df930be7Sderaadt 1206df930be7Sderaadt for (np = proclist.p_next; np; np = np->p_next) 1207df930be7Sderaadt if (np != pcurrent && np != pp && np->p_pid && 1208df930be7Sderaadt np->p_pid == np->p_jobid) { 1209df930be7Sderaadt if (np->p_flags & PSTOPPED) 1210df930be7Sderaadt return (np); 1211df930be7Sderaadt if (xp == NULL) 1212df930be7Sderaadt xp = np; 1213df930be7Sderaadt } 1214df930be7Sderaadt return (xp); 1215df930be7Sderaadt } 1216df930be7Sderaadt 1217df930be7Sderaadt /* 1218df930be7Sderaadt * donotify - flag the job so as to report termination asynchronously 1219df930be7Sderaadt */ 1220df930be7Sderaadt void 1221e757c91eSderaadt donotify(Char **v, struct command *t) 1222df930be7Sderaadt { 1223e757c91eSderaadt struct process *pp; 1224df930be7Sderaadt 1225df930be7Sderaadt pp = pfind(*++v); 1226df930be7Sderaadt pp->p_flags |= PNOTIFY; 1227df930be7Sderaadt } 1228df930be7Sderaadt 1229df930be7Sderaadt /* 1230df930be7Sderaadt * Do the fork and whatever should be done in the child side that 1231df930be7Sderaadt * should not be done if we are not forking at all (like for simple builtin's) 1232df930be7Sderaadt * Also do everything that needs any signals fiddled with in the parent side 1233df930be7Sderaadt * 1234df930be7Sderaadt * Wanttty tells whether process and/or tty pgrps are to be manipulated: 1235df930be7Sderaadt * -1: leave tty alone; inherit pgrp from parent 1236df930be7Sderaadt * 0: already have tty; manipulate process pgrps only 1237df930be7Sderaadt * 1: want to claim tty; manipulate process and tty pgrps 1238df930be7Sderaadt * It is usually just the value of tpgrp. 1239df930be7Sderaadt */ 1240df930be7Sderaadt 1241df930be7Sderaadt int 1242e757c91eSderaadt pfork(struct command *t, int wanttty) 1243df930be7Sderaadt { 1244e757c91eSderaadt int pid; 1245df930be7Sderaadt bool ignint = 0; 1246df930be7Sderaadt int pgrp; 1247df930be7Sderaadt sigset_t sigset, osigset; 1248df930be7Sderaadt 1249df930be7Sderaadt /* 1250df930be7Sderaadt * A child will be uninterruptible only under very special conditions. 1251df930be7Sderaadt * Remember that the semantics of '&' is implemented by disconnecting the 1252df930be7Sderaadt * process from the tty so signals do not need to ignored just for '&'. 1253df930be7Sderaadt * Thus signals are set to default action for children unless: we have had 1254df930be7Sderaadt * an "onintr -" (then specifically ignored) we are not playing with 1255df930be7Sderaadt * signals (inherit action) 1256df930be7Sderaadt */ 1257df930be7Sderaadt if (setintr) 1258df930be7Sderaadt ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 1259df930be7Sderaadt || (gointr && eq(gointr, STRminus)); 1260df930be7Sderaadt /* 1261df930be7Sderaadt * Check for maximum nesting of 16 processes to avoid Forking loops 1262df930be7Sderaadt */ 1263df930be7Sderaadt if (child == 16) 1264df930be7Sderaadt stderror(ERR_NESTING, 16); 1265df930be7Sderaadt /* 1266*324a3c8cSderaadt * Hold SIGCHLD/SIGHUP until we have the process installed in our table. 1267df930be7Sderaadt */ 1268df930be7Sderaadt sigemptyset(&sigset); 1269df930be7Sderaadt sigaddset(&sigset, SIGCHLD); 1270*324a3c8cSderaadt sigaddset(&sigset, SIGHUP); 1271df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 12723aaa63ebSderaadt while ((pid = fork()) == -1) 1273df930be7Sderaadt if (setintr == 0) 1274df930be7Sderaadt (void) sleep(FORKSLEEP); 1275df930be7Sderaadt else { 1276df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 1277df930be7Sderaadt stderror(ERR_NOPROC); 1278df930be7Sderaadt } 1279df930be7Sderaadt if (pid == 0) { 1280df930be7Sderaadt settimes(); 1281df930be7Sderaadt pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 1282df930be7Sderaadt pflushall(); 1283df930be7Sderaadt pcurrjob = NULL; 1284df930be7Sderaadt child++; 1285df930be7Sderaadt if (setintr) { 1286df930be7Sderaadt setintr = 0; /* until I think otherwise */ 1287df930be7Sderaadt /* 1288df930be7Sderaadt * Children just get blown away on SIGINT, SIGQUIT unless "onintr 1289df930be7Sderaadt * -" seen. 1290df930be7Sderaadt */ 1291df930be7Sderaadt (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 1292df930be7Sderaadt (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 1293df930be7Sderaadt if (wanttty >= 0) { 1294df930be7Sderaadt /* make stoppable */ 1295df930be7Sderaadt (void) signal(SIGTSTP, SIG_DFL); 1296df930be7Sderaadt (void) signal(SIGTTIN, SIG_DFL); 1297df930be7Sderaadt (void) signal(SIGTTOU, SIG_DFL); 1298df930be7Sderaadt } 1299df930be7Sderaadt (void) signal(SIGTERM, parterm); 1300df930be7Sderaadt } 1301df930be7Sderaadt else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 1302df930be7Sderaadt (void) signal(SIGINT, SIG_IGN); 1303df930be7Sderaadt (void) signal(SIGQUIT, SIG_IGN); 1304df930be7Sderaadt } 1305df930be7Sderaadt pgetty(wanttty, pgrp); 1306df930be7Sderaadt /* 1307df930be7Sderaadt * Nohup and nice apply only to NODE_COMMAND's but it would be nice 1308df930be7Sderaadt * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 1309df930be7Sderaadt * to know about nice/nohup/time 1310df930be7Sderaadt */ 1311df930be7Sderaadt if (t->t_dflg & F_NOHUP) 1312df930be7Sderaadt (void) signal(SIGHUP, SIG_IGN); 1313df930be7Sderaadt if (t->t_dflg & F_NICE) 1314df930be7Sderaadt (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 1315df930be7Sderaadt } 1316df930be7Sderaadt else { 1317df930be7Sderaadt if (wanttty >= 0) 1318df930be7Sderaadt (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 1319df930be7Sderaadt palloc(pid, t); 1320df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 1321df930be7Sderaadt } 1322df930be7Sderaadt 1323df930be7Sderaadt return (pid); 1324df930be7Sderaadt } 1325df930be7Sderaadt 1326df930be7Sderaadt static void 1327e757c91eSderaadt okpcntl(void) 1328df930be7Sderaadt { 1329df930be7Sderaadt if (tpgrp == -1) 1330df930be7Sderaadt stderror(ERR_JOBCONTROL); 1331df930be7Sderaadt if (tpgrp == 0) 1332df930be7Sderaadt stderror(ERR_JOBCTRLSUB); 1333df930be7Sderaadt } 1334df930be7Sderaadt 1335df930be7Sderaadt /* 1336df930be7Sderaadt * if we don't have vfork(), things can still go in the wrong order 1337df930be7Sderaadt * resulting in the famous 'Stopped (tty output)'. But some systems 1338df930be7Sderaadt * don't permit the setpgid() call, (these are more recent secure 1339df930be7Sderaadt * systems such as ibm's aix). Then we'd rather print an error message 1340df930be7Sderaadt * than hang the shell! 1341df930be7Sderaadt * I am open to suggestions how to fix that. 1342df930be7Sderaadt */ 1343df930be7Sderaadt void 1344e757c91eSderaadt pgetty(int wanttty, int pgrp) 1345df930be7Sderaadt { 1346df930be7Sderaadt sigset_t sigset, osigset; 1347df930be7Sderaadt 1348df930be7Sderaadt /* 1349df930be7Sderaadt * christos: I am blocking the tty signals till I've set things 1350df930be7Sderaadt * correctly.... 1351df930be7Sderaadt */ 1352df930be7Sderaadt if (wanttty > 0) { 1353df930be7Sderaadt sigemptyset(&sigset); 1354df930be7Sderaadt sigaddset(&sigset, SIGTSTP); 1355df930be7Sderaadt sigaddset(&sigset, SIGTTIN); 1356df930be7Sderaadt sigaddset(&sigset, SIGTTOU); 1357df930be7Sderaadt sigprocmask(SIG_BLOCK, &sigset, &osigset); 1358df930be7Sderaadt } 1359df930be7Sderaadt /* 1360df930be7Sderaadt * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 1361df930be7Sderaadt * Don't check for tpgrp >= 0 so even non-interactive shells give 1362df930be7Sderaadt * background jobs process groups Same for the comparison in the other part 1363df930be7Sderaadt * of the #ifdef 1364df930be7Sderaadt */ 1365df930be7Sderaadt if (wanttty >= 0) 1366df930be7Sderaadt if (setpgid(0, pgrp) == -1) { 1367df930be7Sderaadt (void) fprintf(csherr, "csh: setpgid error.\n"); 1368df930be7Sderaadt xexit(0); 1369df930be7Sderaadt } 1370df930be7Sderaadt 1371df930be7Sderaadt if (wanttty > 0) { 1372df930be7Sderaadt (void) tcsetpgrp(FSHTTY, pgrp); 1373df930be7Sderaadt sigprocmask(SIG_SETMASK, &osigset, NULL); 1374df930be7Sderaadt } 1375df930be7Sderaadt 1376df930be7Sderaadt if (tpgrp > 0) 1377df930be7Sderaadt tpgrp = 0; /* gave tty away */ 1378df930be7Sderaadt } 1379