1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.proc.c,v 3.1 1991/07/05 02:00:43 christos Exp $ */ 2: /* 3: * sh.proc.c: Job manipulations 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: sh.proc.c,v 3.1 1991/07/05 02:00:43 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #include "ed.h" 45: 46: /* 47: * a little complicated #include <sys/wait.h>! :-( 48: */ 49: #if SVID > 0 50: # ifdef hpux 51: # ifndef __hpux 52: # include "tc.wait.h" /* 6.5 broke <sys/wait.h> */ 53: # else 54: # ifndef POSIX 55: # define _BSD 56: # endif 57: # ifndef _CLASSIC_POSIX_TYPES 58: # define _CLASSIC_POSIX_TYPES 59: # endif 60: # include <sys/wait.h> /* 7.0 fixed it again */ 61: # endif /* __hpux */ 62: # else /* hpux */ 63: # if defined(OREO) || defined(IRIS4D) || defined(POSIX) 64: # include <sys/wait.h> 65: # else /* OREO || IRIS4D || POSIX */ 66: # include "tc.wait.h" 67: # endif /* OREO || IRIS4D || POSIX */ 68: # endif /* hpux */ 69: #else /* SVID == 0 */ 70: # include <sys/wait.h> 71: #endif /* SVID == 0 */ 72: 73: #if !defined(NSIG) && defined(SIGMAX) 74: # define NSIG (SIGMAX+1) 75: #endif /* !NSIG && SIGMAX */ 76: 77: #ifdef aiws 78: # undef HZ 79: # define HZ 16 80: #endif /* aiws */ 81: 82: #ifndef HZ 83: # define HZ 100 /* for division into seconds */ 84: #endif 85: 86: #ifndef WTERMSIG 87: # define WTERMSIG(w) (((union wait *) &(w))->w_termsig) 88: # define BSDWAIT 89: #endif /* !WTERMSIG */ 90: #ifndef WEXITSTATUS 91: # define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) 92: #endif /* !WEXITSTATUS */ 93: #ifndef WSTOPSIG 94: # define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) 95: #endif /* WSTOPSIG */ 96: 97: #ifndef WCOREDUMP 98: # ifdef BSDWAIT 99: # define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) 100: # else /* !BSDWAIT */ 101: # define WCOREDUMP(w) ((w) & 0200) 102: # endif /* !BSDWAIT */ 103: #endif /* !WCOREDUMP */ 104: 105: /* 106: * C Shell - functions that manage processes, handling hanging, termination 107: */ 108: 109: #define BIGINDEX 9 /* largest desirable job index */ 110: 111: #ifdef BSDTIMES 112: # if defined(sun) || defined(hp9000) 113: static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, 114: 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}; 115: 116: # else /* !sun && !hp9000 */ 117: # ifdef masscomp 118: /* 119: * Initialization of this structure under RTU 4.1A & RTU 5.0 is problematic 120: * because the first two elements are unions of a time_t and a struct timeval. 121: * So we'll just have to trust the loader to do the "right thing", DAS DEC-90. 122: */ 123: static struct rusage zru; 124: # else /* masscomp */ 125: static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 126: 0, 0, 0, 0, 0, 0}; 127: # endif /* masscomp */ 128: # endif /* !sun && !hp9000 */ 129: #else /* ! BSDTIMES */ 130: # ifdef _SEQUENT_ 131: static struct pro_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, 132: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 133: # else /* !_SEQUENT_ */ 134: static struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; 135: # endif /* !_SEQUENT_ */ 136: #endif /* !BSDTIMES */ 137: 138: #ifndef RUSAGE_CHILDREN 139: # define RUSAGE_CHILDREN -1 140: #endif 141: 142: static void pflushall __P((void)); 143: static void pflush __P((struct process *)); 144: static void pclrcurr __P((struct process *)); 145: static void padd __P((struct command *)); 146: static int pprint __P((struct process *, int)); 147: static void ptprint __P((struct process *)); 148: static void pads __P((Char *)); 149: static void pkill __P((Char **v, int)); 150: static struct process *pgetcurr __P((struct process *)); 151: static void okpcntl __P((void)); 152: 153: /* 154: * pchild - called at interrupt level by the SIGCHLD signal 155: * indicating that at least one child has terminated or stopped 156: * thus at least one wait system call will definitely return a 157: * childs status. Top level routines (like pwait) must be sure 158: * to mask interrupts when playing with the proclist data structures! 159: */ 160: sigret_t 161: /*ARGSUSED*/ 162: pchild(snum) 163: int snum; 164: { 165: register struct process *pp; 166: register struct process *fp; 167: register int pid; 168: extern int insource; 169: #ifdef BSDWAIT 170: union wait w; 171: #else /* !BSDWAIT */ 172: int w; 173: #endif /* !BSDWAIT */ 174: int jobflags; 175: #ifdef BSDTIMES 176: struct rusage ru; 177: #else /* !BSDTIMES */ 178: # ifdef _SEQUENT_ 179: struct pro_stats ru; 180: struct pro_stats cpst1, cpst2; 181: tmval_t tv; 182: # else /* !_SEQUENT_ */ 183: struct tms proctimes; 184: 185: if (!timesdone) { 186: timesdone++; 187: (void) times(&shtimes); 188: } 189: # endif /* _SEQUENT_ */ 190: #endif /* BSDTIMES */ 191: 192: #ifdef JOBDEBUG 193: xprintf("pchild()\n"); 194: #endif /* JOBDEBUG */ 195: 196: /* Christos on where the signal(SIGCHLD, pchild) shoud be: 197: * 198: * I think that it should go *after* the wait, unlike most signal handlers. 199: * 200: * In release two (for which I have manuals), it says that wait will remove 201: * the first child from the queue of dead children. 202: * All the rest of the children that die while in the signal handler of the 203: * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish 204: * the signal handler, and there are items in the queue, the process will 205: * receive another SIGC(H)LD before signal returns. BTW this is from the 206: * manual page on comp-sim... Maybe it is not applicable to the hp's, but 207: * I read on the news in comp.unix.wizards or comp.unix.questions yesterday 208: * that another person was claiming the the signal() call should be after 209: * the wait(). 210: */ 211: 212: loop: 213: errno = 0; /* reset, just in case */ 214: #ifdef JOBDEBUG 215: xprintf("Waiting...\n"); 216: flush(); 217: #endif 218: #ifdef BSDJOBS 219: # ifdef BSDTIMES 220: /* both a wait3 and rusage */ 221: # ifndef BSDWAIT 222: pid = wait3(&w, 223: (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 224: # else /* BSDWAIT */ 225: pid = wait3(&w.w_status, 226: (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); 227: # endif /* BSDWAIT */ 228: # else /* !BSDTIMES */ 229: # ifdef _SEQUENT_ 230: (void) get_pro_stats(&tv, PS_SELF, 0, &cpst1); 231: pid = waitpid(-1, &w, 232: (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 233: (void) get_pro_stats(&tv, PS_SELF, 0, &cpst2); 234: pr_stat_sub(&cpst2, &cpst1, &ru); 235: # else /* !_SEQUENT_ */ 236: # ifndef POSIX 237: /* we have a wait3, but no rusage stuff */ 238: pid = wait3(&w.w_status, 239: (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); 240: # else /* POSIX */ 241: pid = waitpid(-1, &w, 242: (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); 243: # endif /* POSIX */ 244: # endif /* !_SEQUENT_ */ 245: # endif /* !BSDTIMES */ 246: #else /* !BSDJOBS */ 247: # ifdef BSDTIMES 248: /* both a wait3 and rusage */ 249: # ifdef hpux 250: pid = wait3(&w.w_status, WNOHANG, 0); 251: # else /* !hpux */ 252: pid = wait3(&w.w_status, WNOHANG, &ru); 253: # endif /* !hpux */ 254: # else /* !BSDTIMES */ 255: # if SVID < 3 256: /* no wait3, therefore no rusage */ 257: /* on Sys V, this may hang. I hope it's not going to be a problem */ 258: pid = ourwait(&w.w_status); 259: # else /* SVID >= 3 */ 260: /* 261: * XXX: for greater than 3 we should use waitpid(). 262: * but then again, SVR4 falls into the POSIX/BSDJOBS category. 263: */ 264: pid = wait(&w.w_status); 265: # endif /* SVID >= 3 */ 266: # endif /* BSDTIMES */ 267: #endif /* BSDJOBS */ 268: 269: #ifdef JOBDEBUG 270: { 271: char buffer[100]; 272: xsprintf(buffer, "pid %d, retval %x termsig %x retcode %x\n", 273: pid, w, WTERMSIG(w), WEXITSTATUS(w)); 274: xprintf(buffer); 275: flush(); 276: } 277: #endif /* JOBDEBUG */ 278: 279: if (pid <= 0) { 280: #ifdef JOBDEBUG 281: xprintf("errno == %d\n", errno); 282: #endif 283: if (errno == EINTR) { 284: errno = 0; 285: goto loop; 286: } 287: pnoprocesses = pid == -1; 288: #ifndef SIGVOID 289: return (0); 290: #else /* !SIGVOID */ 291: return; 292: #endif /* SIGVOID */ 293: } 294: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 295: if (pid == pp->p_pid) 296: goto found; 297: #ifndef BSDJOBS 298: /* this should never have happened */ 299: stderror(ERR_SYNC, pid); 300: xexit(0); 301: #else /* BSDJOBS */ 302: goto loop; 303: #endif /* BSDJOBS */ 304: found: 305: if (pid == atoi(short2str(value(STRchild)))) 306: unsetv(STRchild); 307: pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); 308: if (WIFSTOPPED(w)) { 309: pp->p_flags |= PSTOPPED; 310: pp->p_reason = WSTOPSIG(w); 311: } 312: else { 313: if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) 314: #ifndef BSDTIMES 315: # ifdef _SEQUENT_ 316: (void) get_pro_stats(&pp->p_etime, PS_SELF, NULL, NULL); 317: # else /* !_SEQUENT_ */ 318: pp->p_etime = times(&proctimes); 319: # endif /* !_SEQUENT_ */ 320: #else /* BSDTIMES */ 321: (void) gettimeofday(&pp->p_etime, NULL); 322: #endif /* BSDTIMES */ 323: 324: 325: #if defined(BSDTIMES) || defined(_SEQUENT_) 326: pp->p_rusage = ru; 327: #else /* !BSDTIMES && !_SEQUENT_ */ 328: (void) times(&proctimes); 329: pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; 330: pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; 331: shtimes = proctimes; 332: #endif /* !BSDTIMES && !_SEQUENT_ */ 333: if (WIFSIGNALED(w)) { 334: if (WTERMSIG(w) == SIGINT) 335: pp->p_flags |= PINTERRUPTED; 336: else 337: pp->p_flags |= PSIGNALED; 338: if (WCOREDUMP(w)) 339: pp->p_flags |= PDUMPED; 340: pp->p_reason = WTERMSIG(w); 341: } 342: else { 343: pp->p_reason = WEXITSTATUS(w); 344: if (pp->p_reason != 0) 345: pp->p_flags |= PAEXITED; 346: else 347: pp->p_flags |= PNEXITED; 348: } 349: } 350: jobflags = 0; 351: fp = pp; 352: do { 353: if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && 354: !child && adrof(STRtime) && 355: #ifdef BSDTIMES 356: fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec 357: #else /* !BSDTIMES */ 358: # ifdef _SEQUENT_ 359: fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec 360: # else /* !_SEQUENT_ */ 361: # ifndef POSIX 362: (fp->p_utime + fp->p_stime) / HZ 363: # else /* POSIX */ 364: (fp->p_utime + fp->p_stime) / CLK_TCK 365: # endif /* POSIX */ 366: # endif /* !_SEQUENT_ */ 367: #endif /* !BSDTIMES */ 368: >= atoi(short2str(value(STRtime)))) 369: fp->p_flags |= PTIME; 370: jobflags |= fp->p_flags; 371: } while ((fp = fp->p_friends) != pp); 372: pp->p_flags &= ~PFOREGND; 373: if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 374: pp->p_flags &= ~PPTIME; 375: pp->p_flags |= PTIME; 376: } 377: if ((jobflags & (PRUNNING | PREPORTED)) == 0) { 378: fp = pp; 379: do { 380: if (fp->p_flags & PSTOPPED) 381: fp->p_flags |= PREPORTED; 382: } while ((fp = fp->p_friends) != pp); 383: while (fp->p_pid != fp->p_jobid) 384: fp = fp->p_friends; 385: if (jobflags & PSTOPPED) { 386: if (pcurrent && pcurrent != fp) 387: pprevious = pcurrent; 388: pcurrent = fp; 389: } 390: else 391: pclrcurr(fp); 392: if (jobflags & PFOREGND) { 393: if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || 394: #ifdef IIASA 395: jobflags & PAEXITED || 396: #endif /* IIASA */ 397: !eq(dcwd->di_name, fp->p_cwd->di_name)) { 398: ; /* print in pjwait */ 399: } 400: /* PWP: print a newline after ^C */ 401: else if (jobflags & PINTERRUPTED) 402: #ifdef SHORT_STRINGS 403: xputchar('\r' | QUOTE), xputchar('\n'); 404: #else /* !SHORT_STRINGS */ 405: xprintf("\215\n"); /* \215 is a quoted ^M */ 406: #endif /* !SHORT_STRINGS */ 407: #ifdef notdef 408: else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) 409: ptprint(fp); 410: #endif 411: } 412: else { 413: if (jobflags & PNOTIFY || adrof(STRnotify)) { 414: #ifdef SHORT_STRINGS 415: xputchar('\r' | QUOTE), xputchar('\n'); 416: #else /* !SHORT_STRINGS */ 417: xprintf("\215\n"); /* \215 is a quoted ^M */ 418: #endif /* !SHORT_STRINGS */ 419: (void) pprint(pp, NUMBER | NAME | REASON); 420: if ((jobflags & PSTOPPED) == 0) 421: pflush(pp); 422: { 423: extern Char GettingInput; 424: 425: if (GettingInput) { 426: errno = 0; 427: (void) Rawmode(); 428: ClearLines(); 429: ClearDisp(); 430: Refresh(); 431: } 432: } 433: } 434: else { 435: fp->p_flags |= PNEEDNOTE; 436: neednote++; 437: } 438: } 439: } 440: #ifdef BSDJOBS 441: goto loop; 442: #endif /* BSDJOBS */ 443: } 444: 445: void 446: pnote() 447: { 448: register struct process *pp; 449: int flags; 450: #ifdef BSDSIGS 451: sigmask_t omask; 452: #endif /* BSDSIGS */ 453: 454: neednote = 0; 455: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) { 456: if (pp->p_flags & PNEEDNOTE) { 457: #ifdef BSDSIGS 458: omask = sigblock(sigmask(SIGCHLD)); 459: #else /* !BSDSIGS */ 460: (void) sighold(SIGCHLD); 461: #endif /* !BSDSIGS */ 462: pp->p_flags &= ~PNEEDNOTE; 463: flags = pprint(pp, NUMBER | NAME | REASON); 464: if ((flags & (PRUNNING | PSTOPPED)) == 0) 465: pflush(pp); 466: #ifdef BSDSIGS 467: (void) sigsetmask(omask); 468: #else /* !BSDSIGS */ 469: (void) sigrelse(SIGCHLD); 470: #endif /* !BSDSIGS */ 471: } 472: } 473: } 474: 475: /* 476: * pwait - wait for current job to terminate, maintaining integrity 477: * of current and previous job indicators. 478: */ 479: void 480: pwait() 481: { 482: register struct process *fp, *pp; 483: #ifdef BSDSIGS 484: sigmask_t omask; 485: #endif /* BSDSIGS */ 486: 487: /* 488: * Here's where dead procs get flushed. 489: */ 490: #ifdef BSDSIGS 491: omask = sigblock(sigmask(SIGCHLD)); 492: #else /* !BSDSIGS */ 493: (void) sighold(SIGCHLD); 494: #endif /* !BSDSIGS */ 495: for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next) 496: if (pp->p_pid == 0) { 497: fp->p_next = pp->p_next; 498: xfree((ptr_t) pp->p_command); 499: if (pp->p_cwd && --pp->p_cwd->di_count == 0) 500: if (pp->p_cwd->di_next == 0) 501: dfree(pp->p_cwd); 502: xfree((ptr_t) pp); 503: pp = fp; 504: } 505: #ifdef BSDSIGS 506: (void) sigsetmask(omask); 507: #else /* !BSDSIGS */ 508: (void) sigrelse(SIGCHLD); 509: # ifdef notdef 510: if (setintr) 511: sigignore(SIGINT); 512: # endif 513: #endif /* !BSDSIGS */ 514: pjwait(pcurrjob); 515: } 516: 517: 518: /* 519: * pjwait - wait for a job to finish or become stopped 520: * It is assumed to be in the foreground state (PFOREGND) 521: */ 522: void 523: pjwait(pp) 524: register struct process *pp; 525: { 526: register struct process *fp; 527: int jobflags, reason; 528: #ifdef BSDSIGS 529: sigmask_t omask; 530: #endif /* BSDSIGS */ 531: 532: while (pp->p_pid != pp->p_jobid) 533: pp = pp->p_friends; 534: fp = pp; 535: 536: do { 537: if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) 538: xprintf("BUG: waiting for background job!\n"); 539: } while ((fp = fp->p_friends) != pp); 540: /* 541: * Now keep pausing as long as we are not interrupted (SIGINT), and the 542: * target process, or any of its friends, are running 543: */ 544: fp = pp; 545: #ifdef BSDSIGS 546: omask = sigblock(sigmask(SIGCHLD)); 547: #endif /* BSDSIGS */ 548: for (;;) { 549: #ifndef BSDSIGS 550: (void) sighold(SIGCHLD); 551: #endif /* !BSDSIGS */ 552: jobflags = 0; 553: do 554: jobflags |= fp->p_flags; 555: while ((fp = (fp->p_friends)) != pp); 556: if ((jobflags & PRUNNING) == 0) 557: break; 558: #ifdef JOBDEBUG 559: xprintf("starting to sigpause for SIGCHLD on %d\n", fp->p_pid); 560: #endif /* JOBDEBUG */ 561: #ifdef BSDSIGS 562: /* sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */ 563: (void) sigpause(omask & ~sigmask(SIGCHLD)); 564: #else /* !BSDSIGS */ 565: (void) sigpause(SIGCHLD); 566: #endif /* !BSDSIGS */ 567: } 568: #ifdef BSDSIGS 569: (void) sigsetmask(omask); 570: #else /* !BSDSIGS */ 571: (void) sigrelse(SIGCHLD); 572: #endif /* !BSDSIGS */ 573: #ifdef BSDJOBS 574: if (tpgrp > 0) /* get tty back */ 575: (void) tcsetpgrp(FSHTTY, tpgrp); 576: #endif /* BSDJOBS */ 577: if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || 578: !eq(dcwd->di_name, fp->p_cwd->di_name)) { 579: if (jobflags & PSTOPPED) { 580: xprintf("\n"); 581: if (adrof(STRl_jobs)) { 582: Char *jobcommand[3]; 583: 584: jobcommand[0] = STRjobs; 585: if (eq(value(STRl_jobs), STRlong)) 586: jobcommand[1] = STRml; 587: else 588: jobcommand[1] = NULL; 589: jobcommand[2] = NULL; 590: 591: dojobs(jobcommand); 592: (void) pprint(pp, SHELLDIR); 593: } 594: else 595: (void) pprint(pp, AREASON | SHELLDIR); 596: } 597: else 598: (void) pprint(pp, AREASON | SHELLDIR); 599: } 600: if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && 601: (!gointr || !eq(gointr, STRminus))) { 602: if ((jobflags & PSTOPPED) == 0) 603: pflush(pp); 604: pintr1(0); 605: /* NOTREACHED */ 606: } 607: reason = 0; 608: fp = pp; 609: do { 610: if (fp->p_reason) 611: reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? 612: fp->p_reason | META : fp->p_reason; 613: } while ((fp = fp->p_friends) != pp); 614: if ((reason != 0) && (adrof(STRprintexitvalue))) /* PWP */ 615: xprintf("Exit %d\n", reason); 616: set(STRstatus, putn(reason)); 617: if (reason && exiterr) 618: exitstat(); 619: pflush(pp); 620: /* cwd_cmd(); *//* (PWP) this is what pre_cmd is for! */ 621: } 622: 623: /* 624: * dowait - wait for all processes to finish 625: */ 626: void 627: dowait() 628: { 629: register struct process *pp; 630: #ifdef BSDSIGS 631: sigmask_t omask; 632: #endif /* BSDSIGS */ 633: 634: pjobs++; 635: #ifdef BSDSIGS 636: omask = sigblock(sigmask(SIGCHLD)); 637: loop: 638: #else /* !BSDSIGS */ 639: if (setintr) 640: (void) sigrelse(SIGINT); 641: loop: 642: (void) sighold(SIGCHLD); 643: #endif /* !BSDSIGS */ 644: for (pp = proclist.p_next; pp; pp = pp->p_next) 645: if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ 646: pp->p_flags & PRUNNING) { 647: #ifdef BSDSIGS 648: (void) sigpause((sigmask_t) 0); 649: #else /* !BSDSIGS */ 650: (void) sigpause(SIGCHLD); 651: #endif /* !BSDSIGS */ 652: goto loop; 653: } 654: #ifdef BSDSIGS 655: (void) sigsetmask(omask); 656: #else /* !BSDSIGS */ 657: (void) sigrelse(SIGCHLD); 658: #endif /* !BSDSIGS */ 659: pjobs = 0; 660: } 661: 662: /* 663: * pflushall - flush all jobs from list (e.g. at fork()) 664: */ 665: static void 666: pflushall() 667: { 668: register struct process *pp; 669: 670: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) 671: if (pp->p_pid) 672: pflush(pp); 673: } 674: 675: /* 676: * pflush - flag all process structures in the same job as the 677: * the argument process for deletion. The actual free of the 678: * space is not done here since pflush is called at interrupt level. 679: */ 680: static void 681: pflush(pp) 682: register struct process *pp; 683: { 684: register struct process *np; 685: register int idx; 686: 687: if (pp->p_pid == 0) { 688: xprintf("BUG: process flushed twice"); 689: return; 690: } 691: while (pp->p_pid != pp->p_jobid) 692: pp = pp->p_friends; 693: pclrcurr(pp); 694: if (pp == pcurrjob) 695: pcurrjob = 0; 696: idx = pp->p_index; 697: np = pp; 698: do { 699: np->p_index = np->p_pid = 0; 700: np->p_flags &= ~PNEEDNOTE; 701: } while ((np = np->p_friends) != pp); 702: if (idx == pmaxindex) { 703: for (np = proclist.p_next, idx = 0; np; np = np->p_next) 704: if (np->p_index > idx) 705: idx = np->p_index; 706: pmaxindex = idx; 707: } 708: } 709: 710: /* 711: * pclrcurr - make sure the given job is not the current or previous job; 712: * pp MUST be the job leader 713: */ 714: static void 715: pclrcurr(pp) 716: register struct process *pp; 717: { 718: if (pp == pcurrent) 719: if (pprevious != PNULL) { 720: pcurrent = pprevious; 721: pprevious = pgetcurr(pp); 722: } 723: else { 724: pcurrent = pgetcurr(pp); 725: pprevious = pgetcurr(pp); 726: } 727: else if (pp == pprevious) 728: pprevious = pgetcurr(pp); 729: } 730: 731: /* +4 here is 1 for '\0', 1 ea for << >& >> */ 732: static Char command[PMAXLEN + 4]; 733: static int cmdlen; 734: static Char *cmdp; 735: 736: /* 737: * palloc - allocate a process structure and fill it up. 738: * an important assumption is made that the process is running. 739: */ 740: void 741: palloc(pid, t) 742: int pid; 743: register struct command *t; 744: { 745: register struct process *pp; 746: int i; 747: 748: pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); 749: pp->p_pid = pid; 750: pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; 751: if (t->t_dflg & F_TIME) 752: pp->p_flags |= PPTIME; 753: cmdp = command; 754: cmdlen = 0; 755: padd(t); 756: *cmdp++ = 0; 757: if (t->t_dflg & F_PIPEOUT) { 758: pp->p_flags |= PPOU; 759: if (t->t_dflg & F_STDERR) 760: pp->p_flags |= PDIAG; 761: } 762: pp->p_command = Strsave(command); 763: if (pcurrjob) { 764: struct process *fp; 765: 766: /* careful here with interrupt level */ 767: pp->p_cwd = 0; 768: pp->p_index = pcurrjob->p_index; 769: pp->p_friends = pcurrjob; 770: pp->p_jobid = pcurrjob->p_pid; 771: for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends); 772: fp->p_friends = pp; 773: } 774: else { 775: pcurrjob = pp; 776: pp->p_jobid = pid; 777: pp->p_friends = pp; 778: pp->p_cwd = dcwd; 779: dcwd->di_count++; 780: if (pmaxindex < BIGINDEX) 781: pp->p_index = ++pmaxindex; 782: else { 783: struct process *np; 784: 785: for (i = 1;; i++) { 786: for (np = proclist.p_next; np; np = np->p_next) 787: if (np->p_index == i) 788: goto tryagain; 789: pp->p_index = i; 790: if (i > pmaxindex) 791: pmaxindex = i; 792: break; 793: tryagain:; 794: } 795: } 796: if (pcurrent == PNULL) 797: pcurrent = pp; 798: else if (pprevious == PNULL) 799: pprevious = pp; 800: } 801: pp->p_next = proclist.p_next; 802: proclist.p_next = pp; 803: #ifdef BSDTIMES 804: (void) gettimeofday(&pp->p_btime, NULL); 805: #else /* !BSDTIMES */ 806: # ifdef _SEQUENT_ 807: (void) get_pro_stats(&pp->p_btime, PS_SELF, NULL, NULL); 808: # else /* !_SEQUENT_ */ 809: { 810: struct tms tmptimes; 811: 812: pp->p_btime = times(&tmptimes); 813: } 814: # endif /* !_SEQUENT_ */ 815: #endif /* !BSDTIMES */ 816: } 817: 818: static void 819: padd(t) 820: register struct command *t; 821: { 822: Char **argp; 823: 824: if (t == 0) 825: return; 826: switch (t->t_dtyp) { 827: 828: case NODE_PAREN: 829: pads(STRL_parensp); 830: padd(t->t_dspr); 831: pads(STRspRparen); 832: break; 833: 834: case NODE_COMMAND: 835: for (argp = t->t_dcom; *argp; argp++) { 836: pads(*argp); 837: if (argp[1]) 838: pads(STRspace); 839: } 840: break; 841: 842: case NODE_OR: 843: case NODE_AND: 844: case NODE_PIPE: 845: case NODE_LIST: 846: padd(t->t_dcar); 847: switch (t->t_dtyp) { 848: case NODE_OR: 849: pads(STRsP2sp); 850: break; 851: case NODE_AND: 852: pads(STRspand2sp); 853: break; 854: case NODE_PIPE: 855: pads(STRsPsp); 856: break; 857: case NODE_LIST: 858: pads(STRsmsp); 859: break; 860: } 861: padd(t->t_dcdr); 862: return; 863: } 864: if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { 865: pads((t->t_dflg & F_READ) ? STRspL_arrow2sp : STRspLarrowsp); 866: pads(t->t_dlef); 867: } 868: if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { 869: pads((t->t_dflg & F_APPEND) ? STRspR_arrow2 : STRspRarrow); 870: if (t->t_dflg & F_STDERR) 871: pads(STRand); 872: pads(STRspace); 873: pads(t->t_drit); 874: } 875: } 876: 877: static void 878: pads(cp) 879: Char *cp; 880: { 881: register int i; 882: 883: /* 884: * Avoid the Quoted Space alias hack! Reported by: 885: * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) 886: */ 887: if (cp[0] == STRQNULL[0]) 888: cp++; 889: 890: i = Strlen(cp); 891: 892: if (cmdlen >= PMAXLEN) 893: return; 894: if (cmdlen + i >= PMAXLEN) { 895: (void) Strcpy(cmdp, STRsp3dots); 896: cmdlen = PMAXLEN; 897: cmdp += 4; 898: return; 899: } 900: (void) Strcpy(cmdp, cp); 901: cmdp += i; 902: cmdlen += i; 903: } 904: 905: /* 906: * psavejob - temporarily save the current job on a one level stack 907: * so another job can be created. Used for { } in exp6 908: * and `` in globbing. 909: */ 910: void 911: psavejob() 912: { 913: pholdjob = pcurrjob; 914: pcurrjob = PNULL; 915: } 916: 917: /* 918: * prestjob - opposite of psavejob. This may be missed if we are interrupted 919: * somewhere, but pendjob cleans up anyway. 920: */ 921: void 922: prestjob() 923: { 924: pcurrjob = pholdjob; 925: pholdjob = PNULL; 926: } 927: 928: /* 929: * pendjob - indicate that a job (set of commands) has been completed 930: * or is about to begin. 931: */ 932: void 933: pendjob() 934: { 935: register struct process *pp, *tp; 936: 937: if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { 938: pp = pcurrjob; 939: while (pp->p_pid != pp->p_jobid) 940: pp = pp->p_friends; 941: xprintf("[%d]", pp->p_index); 942: tp = pp; 943: do { 944: xprintf(" %d", pp->p_pid); 945: pp = pp->p_friends; 946: } while (pp != tp); 947: xprintf("\n"); 948: } 949: pholdjob = pcurrjob = 0; 950: } 951: 952: /* 953: * pprint - print a job 954: */ 955: static int 956: pprint(pp, flag) 957: register struct process *pp; 958: bool flag; 959: { 960: register status, reason; 961: struct process *tp; 962: extern char *linp, linbuf[]; 963: int jobflags, pstatus; 964: char *format; 965: 966: while (pp->p_pid != pp->p_jobid) 967: pp = pp->p_friends; 968: if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { 969: pp->p_flags &= ~PPTIME; 970: pp->p_flags |= PTIME; 971: } 972: tp = pp; 973: status = reason = -1; 974: jobflags = 0; 975: do { 976: jobflags |= pp->p_flags; 977: pstatus = pp->p_flags & PALLSTATES; 978: if (tp != pp && linp != linbuf && !(flag & FANCY) && 979: (pstatus == status && pp->p_reason == reason || 980: !(flag & REASON))) 981: xprintf(" "); 982: else { 983: if (tp != pp && linp != linbuf) 984: xprintf("\n"); 985: if (flag & NUMBER) 986: if (pp == tp) 987: xprintf("[%d]%s %c ", pp->p_index, 988: pp->p_index < 10 ? " " : "", 989: pp == pcurrent ? '+' : 990: (pp == pprevious ? '-' : ' ')); 991: else 992: xprintf(" "); 993: if (flag & FANCY) { 994: #ifdef TCF 995: extern char *sitename(); 996: 997: #endif /* TCF */ 998: xprintf("%5d ", pp->p_pid); 999: #ifdef TCF 1000: xprintf("%11s ", sitename(pp->p_pid)); 1001: #endif /* TCF */ 1002: } 1003: if (flag & (REASON | AREASON)) { 1004: if (flag & NAME) 1005: #ifdef SUSPENDED 1006: format = "%-23s"; 1007: #else /* !SUSPENDED */ 1008: format = "%-21s"; 1009: #endif /* !SUSPENDED */ 1010: else 1011: format = "%s"; 1012: if (pstatus == status) 1013: if (pp->p_reason == reason) { 1014: xprintf(format, ""); 1015: goto prcomd; 1016: } 1017: else 1018: reason = pp->p_reason; 1019: else { 1020: status = pstatus; 1021: reason = pp->p_reason; 1022: } 1023: switch (status) { 1024: 1025: case PRUNNING: 1026: xprintf(format, "Running "); 1027: break; 1028: 1029: case PINTERRUPTED: 1030: case PSTOPPED: 1031: case PSIGNALED: 1032: /* 1033: * tell what happened to the background job 1034: * From: Michael Schroeder 1035: * <mlschroe@immd4.informatik.uni-erlangen.de> 1036: */ 1037: if ((flag & REASON) 1038: || ((flag & AREASON) 1039: && reason != SIGINT 1040: && (reason != SIGPIPE 1041: || (pp->p_flags & PPOU) == 0))) 1042: xprintf(format, mesg[pp->p_reason].pname); 1043: else 1044: reason = -1; 1045: break; 1046: 1047: case PNEXITED: 1048: case PAEXITED: 1049: if (flag & REASON) 1050: if (pp->p_reason) 1051: #ifdef SUSPENDED 1052: xprintf("Exit %-18d", pp->p_reason); 1053: #else /* SUSPENDED */ 1054: xprintf("Exit %-16d", pp->p_reason); 1055: #endif /* SUSPENDED */ 1056: else 1057: xprintf(format, "Done"); 1058: break; 1059: 1060: default: 1061: xprintf("BUG: status=%-9o", status); 1062: } 1063: } 1064: } 1065: prcomd: 1066: if (flag & NAME) { 1067: xprintf("%s", short2str(pp->p_command)); 1068: if (pp->p_flags & PPOU) 1069: xprintf(" |"); 1070: if (pp->p_flags & PDIAG) 1071: xprintf("&"); 1072: } 1073: if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) 1074: xprintf(" (core dumped)"); 1075: if (tp == pp->p_friends) { 1076: if (flag & AMPERSAND) 1077: xprintf(" &"); 1078: if (flag & JOBDIR && 1079: !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1080: xprintf(" (wd: "); 1081: dtildepr(value(STRhome), tp->p_cwd->di_name); 1082: xprintf(")"); 1083: } 1084: } 1085: if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { 1086: if (linp != linbuf) 1087: xprintf("\n\t"); 1088: #if defined(BSDTIMES) || defined(_SEQUENT_) 1089: prusage(&zru, &pp->p_rusage, &pp->p_etime, 1090: &pp->p_btime); 1091: #else /* !BSDTIMES && !SEQUENT */ 1092: lru.tms_utime = pp->p_utime; 1093: lru.tms_stime = pp->p_stime; 1094: lru.tms_cutime = 0; 1095: lru.tms_cstime = 0; 1096: prusage(&zru, &lru, pp->p_etime, 1097: pp->p_btime); 1098: #endif /* !BSDTIMES && !SEQUENT */ 1099: 1100: } 1101: if (tp == pp->p_friends) { 1102: if (linp != linbuf) 1103: xprintf("\n"); 1104: if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { 1105: xprintf("(wd now: "); 1106: dtildepr(value(STRhome), dcwd->di_name); 1107: xprintf(")\n"); 1108: } 1109: } 1110: } while ((pp = pp->p_friends) != tp); 1111: if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { 1112: if (jobflags & NUMBER) 1113: xprintf(" "); 1114: ptprint(tp); 1115: } 1116: return (jobflags); 1117: } 1118: 1119: static void 1120: ptprint(tp) 1121: register struct process *tp; 1122: { 1123: #ifdef BSDTIMES 1124: struct timeval tetime, diff; 1125: static struct timeval ztime; 1126: struct rusage ru; 1127: static struct rusage zru; 1128: register struct process *pp = tp; 1129: 1130: ru = zru; 1131: tetime = ztime; 1132: do { 1133: ruadd(&ru, &pp->p_rusage); 1134: tvsub(&diff, &pp->p_etime, &pp->p_btime); 1135: if (timercmp(&diff, &tetime, >)) 1136: tetime = diff; 1137: } while ((pp = pp->p_friends) != tp); 1138: prusage(&zru, &ru, &tetime, &ztime); 1139: #else /* !BSDTIMES */ 1140: # ifdef _SEQUENT_ 1141: # define timercmp(tvp, uvp, cmp) \ 1142: ((tvp)->tv_sec cmp (uvp)->tv_sec || \ 1143: (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) 1144: tmval_t tetime, diff; 1145: static tmval_t ztime; 1146: struct pro_stats ru; 1147: static struct pro_stats zru; 1148: register struct process *pp = tp; 1149: 1150: ru = zru; 1151: tetime = ztime; 1152: do { 1153: ruadd(&ru, &pp->p_rusage); 1154: tvsub(&diff, &pp->p_etime, &pp->p_btime); 1155: if (timercmp(&diff, &tetime, >)) 1156: tetime = diff; 1157: } while ((pp = pp->p_friends) != tp); 1158: prusage(&zru, &ru, &tetime, &ztime); 1159: # else /* !_SEQUENT_ */ 1160: # ifndef POSIX 1161: static time_t ztime = 0; 1162: static time_t zu_time = 0; 1163: static time_t zs_time = 0; 1164: time_t tetime, diff; 1165: time_t u_time, s_time; 1166: 1167: # else /* POSIX */ 1168: static clock_t ztime = 0; 1169: static clock_t zu_time = 0; 1170: static clock_t zs_time = 0; 1171: clock_t tetime, diff; 1172: clock_t u_time, s_time; 1173: 1174: # endif /* POSIX */ 1175: struct tms zts, rts; 1176: register struct process *pp = tp; 1177: 1178: u_time = zu_time; 1179: s_time = zs_time; 1180: tetime = ztime; 1181: do { 1182: u_time += pp->p_utime; 1183: s_time += pp->p_stime; 1184: diff = pp->p_etime - pp->p_btime; 1185: if (diff > tetime) 1186: tetime = diff; 1187: } while ((pp = pp->p_friends) != tp); 1188: zts.tms_utime = zu_time; 1189: zts.tms_stime = zs_time; 1190: zts.tms_cutime = 0; 1191: zts.tms_cstime = 0; 1192: rts.tms_utime = u_time; 1193: rts.tms_stime = s_time; 1194: rts.tms_cutime = 0; 1195: rts.tms_cstime = 0; 1196: prusage(&zts, &rts, tetime, ztime); 1197: # endif /* !_SEQUENT_ */ 1198: #endif /* !BSDTIMES */ 1199: } 1200: 1201: /* 1202: * dojobs - print all jobs 1203: */ 1204: void 1205: dojobs(v) 1206: Char **v; 1207: { 1208: register struct process *pp; 1209: register int flag = NUMBER | NAME | REASON; 1210: int i; 1211: 1212: if (chkstop) 1213: chkstop = 2; 1214: if (*++v) { 1215: if (v[1] || !eq(*v, STRml)) 1216: stderror(ERR_JOBS); 1217: flag |= FANCY | JOBDIR; 1218: } 1219: for (i = 1; i <= pmaxindex; i++) 1220: for (pp = proclist.p_next; pp; pp = pp->p_next) 1221: if (pp->p_index == i && pp->p_pid == pp->p_jobid) { 1222: pp->p_flags &= ~PNEEDNOTE; 1223: if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) 1224: pflush(pp); 1225: break; 1226: } 1227: } 1228: 1229: /* 1230: * dofg - builtin - put the job into the foreground 1231: */ 1232: void 1233: dofg(v) 1234: Char **v; 1235: { 1236: register struct process *pp; 1237: 1238: okpcntl(); 1239: ++v; 1240: do { 1241: pp = pfind(*v); 1242: pstart(pp, 1); 1243: #ifndef BSDSIGS 1244: # ifdef notdef 1245: if (setintr) 1246: sigignore(SIGINT); 1247: # endif 1248: #endif /* !BSDSIGS */ 1249: pjwait(pp); 1250: } while (*v && *++v); 1251: } 1252: 1253: /* 1254: * %... - builtin - put the job into the foreground 1255: */ 1256: void 1257: dofg1(v) 1258: Char **v; 1259: { 1260: register struct process *pp; 1261: 1262: okpcntl(); 1263: pp = pfind(v[0]); 1264: pstart(pp, 1); 1265: #ifndef BSDSIGS 1266: # ifdef notdef 1267: if (setintr) 1268: sigignore(SIGINT); 1269: # endif 1270: #endif /* !BSDSIGS */ 1271: pjwait(pp); 1272: } 1273: 1274: /* 1275: * dobg - builtin - put the job into the background 1276: */ 1277: void 1278: dobg(v) 1279: Char **v; 1280: { 1281: register struct process *pp; 1282: 1283: okpcntl(); 1284: ++v; 1285: do { 1286: pp = pfind(*v); 1287: pstart(pp, 0); 1288: } while (*v && *++v); 1289: } 1290: 1291: /* 1292: * %... & - builtin - put the job into the background 1293: */ 1294: void 1295: dobg1(v) 1296: Char **v; 1297: { 1298: register struct process *pp; 1299: 1300: pp = pfind(v[0]); 1301: pstart(pp, 0); 1302: } 1303: 1304: /* 1305: * dostop - builtin - stop the job 1306: */ 1307: void 1308: dostop(v) 1309: Char **v; 1310: { 1311: #ifdef BSDJOBS 1312: pkill(++v, SIGSTOP); 1313: #endif /* BSDJOBS */ 1314: } 1315: 1316: /* 1317: * dokill - builtin - superset of kill (1) 1318: */ 1319: void 1320: dokill(v) 1321: Char **v; 1322: { 1323: register int signum, len = 0; 1324: register char *name; 1325: extern int T_Cols; 1326: 1327: v++; 1328: if (v[0] && v[0][0] == '-') { 1329: if (v[0][1] == 'l') { 1330: for (signum = 1; signum <= NSIG; signum++) { 1331: if ((name = mesg[signum].iname) != NULL) { 1332: len += strlen(name) + 1; 1333: if (len >= T_Cols - 1) { 1334: xprintf("\n"); 1335: len = strlen(name) + 1; 1336: } 1337: xprintf("%s ", name); 1338: } 1339: } 1340: xprintf("\n"); 1341: return; 1342: } 1343: if (Isdigit(v[0][1])) { 1344: signum = atoi(short2str(v[0] + 1)); 1345: if (signum < 0 || signum > NSIG) 1346: stderror(ERR_NAME | ERR_BADSIG); 1347: } 1348: else { 1349: for (signum = 1; signum <= NSIG; signum++) 1350: if (mesg[signum].iname && 1351: eq(&v[0][1], str2short(mesg[signum].iname))) 1352: goto gotsig; 1353: setname(short2str(&v[0][1])); 1354: stderror(ERR_NAME | ERR_UNKSIG); 1355: } 1356: gotsig: 1357: v++; 1358: } 1359: else 1360: signum = SIGTERM; 1361: pkill(v, signum); 1362: } 1363: 1364: static void 1365: pkill(v, signum) 1366: Char **v; 1367: int signum; 1368: { 1369: register struct process *pp, *np; 1370: register int jobflags = 0; 1371: int pid, err1 = 0; 1372: #ifdef BSDSIGS 1373: sigmask_t omask; 1374: #endif /* BSDSIGS */ 1375: Char *cp; 1376: 1377: #ifdef BSDSIGS 1378: omask = sigmask(SIGCHLD); 1379: if (setintr) 1380: omask |= sigmask(SIGINT); 1381: omask = sigblock(omask) & ~omask; 1382: #else /* !BSDSIGS */ 1383: if (setintr) 1384: (void) sighold(SIGINT); 1385: (void) sighold(SIGCHLD); 1386: #endif /* !BSDSIGS */ 1387: gflag = 0, tglob(v); 1388: if (gflag) { 1389: v = globall(v); 1390: if (v == 0) 1391: stderror(ERR_NAME | ERR_NOMATCH); 1392: } 1393: else { 1394: v = gargv = saveblk(v); 1395: trim(v); 1396: } 1397: 1398: while (v && (cp = *v)) { 1399: if (*cp == '%') { 1400: np = pp = pfind(cp); 1401: do 1402: jobflags |= np->p_flags; 1403: while ((np = np->p_friends) != pp); 1404: #ifdef BSDJOBS 1405: switch (signum) { 1406: 1407: case SIGSTOP: 1408: case SIGTSTP: 1409: case SIGTTIN: 1410: case SIGTTOU: 1411: if ((jobflags & PRUNNING) == 0) { 1412: # ifdef SUSPENDED 1413: xprintf("%s: Already suspended\n", 1414: short2str(cp)); 1415: # else /* !SUSPENDED */ 1416: xprintf("%s: Already stopped\n", 1417: short2str(cp)); 1418: # endif /* !SUSPENDED */ 1419: err1++; 1420: goto cont; 1421: } 1422: break; 1423: /* 1424: * suspend a process, kill -CONT %, then type jobs; the shell 1425: * says it is suspended, but it is running; thanks jaap.. 1426: */ 1427: case SIGCONT: 1428: pstart(pp, 0); 1429: goto cont; 1430: } 1431: #endif /* BSDJOBS */ 1432: if (killpg((pid_t) pp->p_jobid, signum) < 0) { 1433: xprintf("%s: %s\n", short2str(cp), strerror(errno)); 1434: err1++; 1435: } 1436: #ifdef BSDJOBS 1437: if (signum == SIGTERM || signum == SIGHUP) 1438: (void) killpg((pid_t) pp->p_jobid, SIGCONT); 1439: #endif /* BSDJOBS */ 1440: } 1441: else if (!(Isdigit(*cp) || *cp == '-')) 1442: stderror(ERR_NAME | ERR_JOBARGS); 1443: else { 1444: pid = atoi(short2str(cp)); 1445: if (kill((pid_t) pid, signum) < 0) { 1446: xprintf("%d: %s\n", pid, strerror(errno)); 1447: err1++; 1448: goto cont; 1449: } 1450: #ifdef BSDJOBS 1451: if (signum == SIGTERM || signum == SIGHUP) 1452: (void) kill((pid_t) pid, SIGCONT); 1453: #endif /* BSDJOBS */ 1454: } 1455: cont: 1456: v++; 1457: } 1458: if (gargv) 1459: blkfree(gargv), gargv = 0; 1460: #ifdef BSDSIGS 1461: (void) sigsetmask(omask); 1462: #else /* !BSDSIGS */ 1463: (void) sigrelse(SIGCHLD); 1464: if (setintr) 1465: (void) sigrelse(SIGINT); 1466: #endif /* !BSDSIGS */ 1467: if (err1) 1468: stderror(ERR_SILENT); 1469: } 1470: 1471: /* 1472: * pstart - start the job in foreground/background 1473: */ 1474: void 1475: pstart(pp, foregnd) 1476: register struct process *pp; 1477: int foregnd; 1478: { 1479: register struct process *np; 1480: #ifdef BSDSIGS 1481: sigmask_t omask; 1482: #endif /* BSDSIGS */ 1483: long jobflags = 0; 1484: 1485: #ifdef BSDSIGS 1486: omask = sigblock(sigmask(SIGCHLD)); 1487: #else /* !BSDSIGS */ 1488: (void) sighold(SIGCHLD); 1489: #endif 1490: np = pp; 1491: do { 1492: jobflags |= np->p_flags; 1493: if (np->p_flags & (PRUNNING | PSTOPPED)) { 1494: np->p_flags |= PRUNNING; 1495: np->p_flags &= ~PSTOPPED; 1496: if (foregnd) 1497: np->p_flags |= PFOREGND; 1498: else 1499: np->p_flags &= ~PFOREGND; 1500: } 1501: } while ((np = np->p_friends) != pp); 1502: if (!foregnd) 1503: pclrcurr(pp); 1504: (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); 1505: #ifdef BSDJOBS 1506: if (foregnd) 1507: (void) tcsetpgrp(FSHTTY, pp->p_jobid); 1508: if (jobflags & PSTOPPED) 1509: (void) killpg((pid_t) pp->p_jobid, SIGCONT); 1510: #endif /* BSDJOBS */ 1511: #ifdef BSDSIGS 1512: (void) sigsetmask(omask); 1513: #else /* !BSDSIGS */ 1514: (void) sigrelse(SIGCHLD); 1515: #endif /* !BSDSIGS */ 1516: } 1517: 1518: void 1519: panystop(neednl) 1520: bool neednl; 1521: { 1522: register struct process *pp; 1523: 1524: chkstop = 2; 1525: for (pp = proclist.p_next; pp; pp = pp->p_next) 1526: if (pp->p_flags & PSTOPPED) 1527: stderror(ERR_STOPPED, neednl ? "\n" : ""); 1528: } 1529: 1530: struct process * 1531: pfind(cp) 1532: Char *cp; 1533: { 1534: register struct process *pp, *np; 1535: 1536: if (cp == 0 || cp[1] == 0 || eq(cp, STRc_2) || eq(cp, STRc_plus)) { 1537: if (pcurrent == PNULL) 1538: stderror(ERR_NAME | ERR_JOBCUR); 1539: return (pcurrent); 1540: } 1541: if (eq(cp, STRc_minus) || eq(cp, STRc_hash)) { 1542: if (pprevious == PNULL) 1543: stderror(ERR_NAME | ERR_JOBPREV); 1544: return (pprevious); 1545: } 1546: if (Isdigit(cp[1])) { 1547: int idx = atoi(short2str(cp + 1)); 1548: 1549: for (pp = proclist.p_next; pp; pp = pp->p_next) 1550: if (pp->p_index == idx && pp->p_pid == pp->p_jobid) 1551: return (pp); 1552: stderror(ERR_NAME | ERR_NOSUCHJOB); 1553: } 1554: np = PNULL; 1555: for (pp = proclist.p_next; pp; pp = pp->p_next) 1556: if (pp->p_pid == pp->p_jobid) { 1557: if (cp[1] == '?') { 1558: register Char *dp; 1559: 1560: for (dp = pp->p_command; *dp; dp++) { 1561: if (*dp != cp[2]) 1562: continue; 1563: if (prefix(cp + 2, dp)) 1564: goto match; 1565: } 1566: } 1567: else if (prefix(cp + 1, pp->p_command)) { 1568: match: 1569: if (np) 1570: stderror(ERR_NAME | ERR_AMBIG); 1571: np = pp; 1572: } 1573: } 1574: if (np) 1575: return (np); 1576: stderror(ERR_NAME | cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB); 1577: /* NOTREACHED */ 1578: return (0); 1579: } 1580: 1581: 1582: /* 1583: * pgetcurr - find most recent job that is not pp, preferably stopped 1584: */ 1585: static struct process * 1586: pgetcurr(pp) 1587: register struct process *pp; 1588: { 1589: register struct process *np; 1590: register struct process *xp = PNULL; 1591: 1592: for (np = proclist.p_next; np; np = np->p_next) 1593: if (np != pcurrent && np != pp && np->p_pid && 1594: np->p_pid == np->p_jobid) { 1595: if (np->p_flags & PSTOPPED) 1596: return (np); 1597: if (xp == PNULL) 1598: xp = np; 1599: } 1600: return (xp); 1601: } 1602: 1603: /* 1604: * donotify - flag the job so as to report termination asynchronously 1605: */ 1606: void 1607: donotify(v) 1608: Char **v; 1609: { 1610: register struct process *pp; 1611: 1612: pp = pfind(*++v); 1613: pp->p_flags |= PNOTIFY; 1614: } 1615: 1616: /* 1617: * Do the fork and whatever should be done in the child side that 1618: * should not be done if we are not forking at all (like for simple builtin's) 1619: * Also do everything that needs any signals fiddled with in the parent side 1620: * 1621: * Wanttty tells whether process and/or tty pgrps are to be manipulated: 1622: * -1: leave tty alone; inherit pgrp from parent 1623: * 0: already have tty; manipulate process pgrps only 1624: * 1: want to claim tty; manipulate process and tty pgrps 1625: * It is usually just the value of tpgrp. 1626: */ 1627: 1628: int 1629: pfork(t, wanttty) 1630: struct command *t; /* command we are forking for */ 1631: int wanttty; 1632: { 1633: register int pid; 1634: bool ignint = 0; 1635: int pgrp; 1636: #ifdef BSDSIGS 1637: sigmask_t omask; 1638: #endif /* BSDSIGS */ 1639: #if SIGSYNCH 1640: sigvec_t osv; 1641: static sigvec_t nsv = {synch_handler, ~0, 0}; 1642: #endif /* SIGSYNCH */ 1643: 1644: /* 1645: * A child will be uninterruptible only under very special conditions. 1646: * Remember that the semantics of '&' is implemented by disconnecting the 1647: * process from the tty so signals do not need to ignored just for '&'. 1648: * Thus signals are set to default action for children unless: we have had 1649: * an "onintr -" (then specifically ignored) we are not playing with 1650: * signals (inherit action) 1651: */ 1652: if (setintr) 1653: ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) 1654: || (gointr && eq(gointr, STRminus)); 1655: /* 1656: * Check for maximum nesting of 16 processes to avoid Forking loops 1657: */ 1658: if (child == 16) 1659: stderror(ERR_NESTING, 16); 1660: /* 1661: * Hold SIGCHLD until we have the process installed in our table. 1662: */ 1663: #ifdef SIGSYNCH 1664: if (mysigvec(SIGSYNCH, &nsv, &osv)) 1665: stderror(ERR_SYSTEM, "pfork: sigvec set", strerror(errno)); 1666: #endif /* SIGSYNCH */ 1667: #ifdef BSDSIGS 1668: omask = sigblock(sigmask(SIGCHLD)); 1669: #else /* !BSDSIGS */ 1670: (void) sighold(SIGCHLD); 1671: #endif /* !BSDSIGS */ 1672: while ((pid = fork()) < 0) 1673: if (setintr == 0) 1674: (void) sleep(FORKSLEEP); 1675: else { 1676: #ifdef BSDSIGS 1677: (void) sigsetmask(omask); 1678: #else /* !BSDSIGS */ 1679: (void) sigrelse(SIGINT); 1680: (void) sigrelse(SIGCHLD); 1681: #endif /* !BSDSIGS */ 1682: stderror(ERR_NOPROC); 1683: } 1684: if (pid == 0) { 1685: settimes(); 1686: pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); 1687: pflushall(); 1688: pcurrjob = PNULL; 1689: #if !defined(BSDTIMES) && !defined(_SEQUENT_) 1690: timesdone = 0; 1691: #endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ 1692: child++; 1693: if (setintr) { 1694: setintr = 0; /* until I think otherwise */ 1695: #ifndef BSDSIGS 1696: (void) sigrelse(SIGCHLD); 1697: #endif /* !BSDSIGS */ 1698: /* 1699: * Children just get blown away on SIGINT, SIGQUIT unless "onintr 1700: * -" seen. 1701: */ 1702: (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); 1703: (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); 1704: #ifdef BSDJOBS 1705: if (wanttty >= 0) { 1706: /* make stoppable */ 1707: (void) signal(SIGTSTP, SIG_DFL); 1708: (void) signal(SIGTTIN, SIG_DFL); 1709: (void) signal(SIGTTOU, SIG_DFL); 1710: } 1711: #endif /* BSDJOBS */ 1712: (void) signal(SIGTERM, parterm); 1713: } 1714: else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { 1715: (void) signal(SIGINT, SIG_IGN); 1716: (void) signal(SIGQUIT, SIG_IGN); 1717: } 1718: #ifdef OREO 1719: sigignore(SIGIO); /* ignore SIGIO in child too */ 1720: #endif /* OREO */ 1721: 1722: pgetty(wanttty, pgrp); 1723: /* 1724: * Nohup and nice apply only to NODE_COMMAND's but it would be nice 1725: * (?!?) if you could say "nohup (foo;bar)" Then the parser would have 1726: * to know about nice/nohup/time 1727: */ 1728: if (t->t_dflg & F_NOHUP) 1729: (void) signal(SIGHUP, SIG_IGN); 1730: if (t->t_dflg & F_NICE) 1731: #ifdef BSDNICE 1732: (void) setpriority(PRIO_PROCESS, 0, t->t_nice); 1733: #else /* !BSDNICE */ 1734: (void) nice(t->t_nice); 1735: #endif /* !BSDNICE */ 1736: #ifdef F_VER 1737: if (t->t_dflg & F_VER) { 1738: Setenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); 1739: dohash(); 1740: } 1741: #endif /* F_VER */ 1742: #ifdef SIGSYNCH 1743: /* rfw 8/89 now parent can continue */ 1744: if (kill(getppid(), SIGSYNCH)) 1745: stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); 1746: #endif /* SIGSYNCH */ 1747: 1748: } 1749: else { 1750: #ifdef POSIXJOBS 1751: if (wanttty >= 0) 1752: (void) setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); 1753: #endif /* POSIXJOBS */ 1754: palloc(pid, t); 1755: #ifdef SIGSYNCH 1756: /* 1757: * rfw 8/89 Wait for child to own terminal. Solves half of ugly 1758: * synchronization problem. With this change, we know that the only 1759: * reason setpgrp to a previous process in a pipeline can fail is that 1760: * the previous process has already exited. Without this hack, he may 1761: * either have exited or not yet started to run. Two uglies become 1762: * one. 1763: */ 1764: sigpause(omask & ~SYNCHMASK); 1765: if (mysigvec(SIGSYNCH, &osv, NULL)) 1766: stderror(ERR_SYSTEM, "pfork parent: sigvec restore", 1767: strerror(errno)); 1768: #endif /* SIGSYNCH */ 1769: 1770: #ifdef BSDSIGS 1771: (void) sigsetmask(omask); 1772: #else /* !BSDSIGS */ 1773: (void) sigrelse(SIGCHLD); 1774: #endif /* !BSDSIGS */ 1775: } 1776: return (pid); 1777: } 1778: 1779: static void 1780: okpcntl() 1781: { 1782: if (tpgrp == -1) 1783: stderror(ERR_JOBCONTROL); 1784: if (tpgrp == 0) 1785: stderror(ERR_JOBCTRLSUB); 1786: } 1787: 1788: /* 1789: * if we don't have vfork(), things can still go in the wrong order 1790: * resulting in the famous 'Stopped (tty output)'. But some systems 1791: * don't permit the setpgid() call, (these are more recent secure 1792: * systems such as ibm's aix), when they do. Then we'd rather print 1793: * an error message than hang the shell! 1794: * I am open to suggestions how to fix that. 1795: */ 1796: void 1797: pgetty(wanttty, pgrp) 1798: int wanttty, pgrp; 1799: { 1800: #ifdef BSDJOBS 1801: # if defined(BSDSIGS) && defined(POSIXJOBS) 1802: sigmask_t omask = 0; 1803: # endif /* BSDSIGS && POSIXJOBS */ 1804: 1805: # ifdef JOBDEBUG 1806: xprintf("wanttty %d\n", wanttty); 1807: # endif 1808: 1809: # ifdef POSIXJOBS 1810: /* 1811: * christos: I am blocking the tty signals till I've set things 1812: * correctly.... 1813: */ 1814: if (wanttty > 0) 1815: # ifdef BSDSIGS 1816: omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); 1817: # else /* !BSDSIGS */ 1818: { 1819: (void) sighold(SIGTSTP); 1820: (void) sighold(SIGTTIN); 1821: (void) sighold(SIGTTOU); 1822: } 1823: # endif /* !BSDSIGS */ 1824: 1825: /* 1826: * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 1827: * Don't check for tpgrp >= 0 so even non-interactive shells give 1828: * background jobs process groups Same for the comparison in the other part 1829: * of the #ifdef 1830: */ 1831: if (wanttty >= 0) 1832: if (setpgid(0, pgrp) == -1) { 1833: xprintf("tcsh: setpgid error.\n"); 1834: xexit(0); 1835: } 1836: # endif /* POSIXJOBS */ 1837: 1838: if (wanttty > 0) 1839: (void) tcsetpgrp(FSHTTY, pgrp); 1840: 1841: # ifndef POSIXJOBS 1842: if (wanttty >= 0) 1843: if (setpgid(0, pgrp) == -1) { 1844: xprintf("tcsh: setpgid error.\n"); 1845: xexit(0); 1846: } 1847: # else /* POSIXJOBS */ 1848: if (wanttty > 0) 1849: # ifdef BSDSIGS 1850: (void) sigsetmask(omask); 1851: # else /* BSDSIGS */ 1852: { 1853: (void) sigrelse(SIGTSTP); 1854: (void) sigrelse(SIGTTIN); 1855: (void) sigrelse(SIGTTOU); 1856: } 1857: # endif /* !BSDSIGS */ 1858: # endif /* POSIXJOBS */ 1859: 1860: if (tpgrp > 0) 1861: tpgrp = 0; /* gave tty away */ 1862: #endif /* BSDJOBS */ 1863: }