|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley Software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char *sccsid = "@(#)sh.proc.c 5.10 (Berkeley) 5/19/88"; ! 9: #endif ! 10: ! 11: #include "sh.h" ! 12: #include "sh.dir.h" ! 13: #include "sh.proc.h" ! 14: #include <sys/wait.h> ! 15: #include <sys/ioctl.h> ! 16: ! 17: /* ! 18: * C Shell - functions that manage processes, handling hanging, termination ! 19: */ ! 20: ! 21: #define BIGINDEX 9 /* largest desirable job index */ ! 22: ! 23: /* ! 24: * pchild - called at interrupt level by the SIGCHLD signal ! 25: * indicating that at least one child has terminated or stopped ! 26: * thus at least one wait system call will definitely return a ! 27: * childs status. Top level routines (like pwait) must be sure ! 28: * to mask interrupts when playing with the proclist data structures! ! 29: */ ! 30: pchild() ! 31: { ! 32: register struct process *pp; ! 33: register struct process *fp; ! 34: register int pid; ! 35: union wait w; ! 36: int jobflags; ! 37: struct rusage ru; ! 38: extern int insource; ! 39: ! 40: loop: ! 41: pid = wait3(&w, (setintr && (intty || insource) ? WNOHANG|WUNTRACED:WNOHANG), &ru); ! 42: if (pid <= 0) { ! 43: if (errno == EINTR) { ! 44: errno = 0; ! 45: goto loop; ! 46: } ! 47: pnoprocesses = pid == -1; ! 48: return; ! 49: } ! 50: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) ! 51: if (pid == pp->p_pid) ! 52: goto found; ! 53: goto loop; ! 54: found: ! 55: if (pid == atoi(value("child"))) ! 56: unsetv("child"); ! 57: pp->p_flags &= ~(PRUNNING|PSTOPPED|PREPORTED); ! 58: if (WIFSTOPPED(w)) { ! 59: pp->p_flags |= PSTOPPED; ! 60: pp->p_reason = w.w_stopsig; ! 61: } else { ! 62: if (pp->p_flags & (PTIME|PPTIME) || adrof("time")) ! 63: (void) gettimeofday(&pp->p_etime, (struct timezone *)0); ! 64: pp->p_rusage = ru; ! 65: if (WIFSIGNALED(w)) { ! 66: if (w.w_termsig == SIGINT) ! 67: pp->p_flags |= PINTERRUPTED; ! 68: else ! 69: pp->p_flags |= PSIGNALED; ! 70: if (w.w_coredump) ! 71: pp->p_flags |= PDUMPED; ! 72: pp->p_reason = w.w_termsig; ! 73: } else { ! 74: pp->p_reason = w.w_retcode; ! 75: if (pp->p_reason != 0) ! 76: pp->p_flags |= PAEXITED; ! 77: else ! 78: pp->p_flags |= PNEXITED; ! 79: } ! 80: } ! 81: jobflags = 0; ! 82: fp = pp; ! 83: do { ! 84: if ((fp->p_flags & (PPTIME|PRUNNING|PSTOPPED)) == 0 && ! 85: !child && adrof("time") && ! 86: fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >= ! 87: atoi(value("time"))) ! 88: fp->p_flags |= PTIME; ! 89: jobflags |= fp->p_flags; ! 90: } while ((fp = fp->p_friends) != pp); ! 91: pp->p_flags &= ~PFOREGND; ! 92: if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { ! 93: pp->p_flags &= ~PPTIME; ! 94: pp->p_flags |= PTIME; ! 95: } ! 96: if ((jobflags & (PRUNNING|PREPORTED)) == 0) { ! 97: fp = pp; ! 98: do { ! 99: if (fp->p_flags&PSTOPPED) ! 100: fp->p_flags |= PREPORTED; ! 101: } while((fp = fp->p_friends) != pp); ! 102: while(fp->p_pid != fp->p_jobid) ! 103: fp = fp->p_friends; ! 104: if (jobflags&PSTOPPED) { ! 105: if (pcurrent && pcurrent != fp) ! 106: pprevious = pcurrent; ! 107: pcurrent = fp; ! 108: } else ! 109: pclrcurr(fp); ! 110: if (jobflags&PFOREGND) { ! 111: if (jobflags & (PSIGNALED|PSTOPPED|PPTIME) || ! 112: #ifdef IIASA ! 113: jobflags & PAEXITED || ! 114: #endif ! 115: !eq(dcwd->di_name, fp->p_cwd->di_name)) { ! 116: ; /* print in pjwait */ ! 117: } ! 118: /* ! 119: else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) ! 120: ptprint(fp); ! 121: */ ! 122: } else { ! 123: if (jobflags&PNOTIFY || adrof("notify")) { ! 124: printf("\215\n"); ! 125: (void) pprint(pp, NUMBER|NAME|REASON); ! 126: if ((jobflags&PSTOPPED) == 0) ! 127: pflush(pp); ! 128: } else { ! 129: fp->p_flags |= PNEEDNOTE; ! 130: neednote++; ! 131: } ! 132: } ! 133: } ! 134: goto loop; ! 135: } ! 136: ! 137: pnote() ! 138: { ! 139: register struct process *pp; ! 140: int flags; ! 141: long omask; ! 142: ! 143: neednote = 0; ! 144: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) { ! 145: if (pp->p_flags & PNEEDNOTE) { ! 146: omask = sigblock(sigmask(SIGCHLD)); ! 147: pp->p_flags &= ~PNEEDNOTE; ! 148: flags = pprint(pp, NUMBER|NAME|REASON); ! 149: if ((flags&(PRUNNING|PSTOPPED)) == 0) ! 150: pflush(pp); ! 151: (void) sigsetmask(omask); ! 152: } ! 153: } ! 154: } ! 155: ! 156: /* ! 157: * pwait - wait for current job to terminate, maintaining integrity ! 158: * of current and previous job indicators. ! 159: */ ! 160: pwait() ! 161: { ! 162: register struct process *fp, *pp; ! 163: long omask; ! 164: ! 165: /* ! 166: * Here's where dead procs get flushed. ! 167: */ ! 168: omask = sigblock(sigmask(SIGCHLD)); ! 169: for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next) ! 170: if (pp->p_pid == 0) { ! 171: fp->p_next = pp->p_next; ! 172: xfree(pp->p_command); ! 173: if (pp->p_cwd && --pp->p_cwd->di_count == 0) ! 174: if (pp->p_cwd->di_next == 0) ! 175: dfree(pp->p_cwd); ! 176: xfree((char *)pp); ! 177: pp = fp; ! 178: } ! 179: (void) sigsetmask(omask); ! 180: pjwait(pcurrjob); ! 181: } ! 182: ! 183: /* ! 184: * pjwait - wait for a job to finish or become stopped ! 185: * It is assumed to be in the foreground state (PFOREGND) ! 186: */ ! 187: pjwait(pp) ! 188: register struct process *pp; ! 189: { ! 190: register struct process *fp; ! 191: int jobflags, reason; ! 192: long omask; ! 193: ! 194: while (pp->p_pid != pp->p_jobid) ! 195: pp = pp->p_friends; ! 196: fp = pp; ! 197: do { ! 198: if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING) ! 199: printf("BUG: waiting for background job!\n"); ! 200: } while ((fp = fp->p_friends) != pp); ! 201: /* ! 202: * Now keep pausing as long as we are not interrupted (SIGINT), ! 203: * and the target process, or any of its friends, are running ! 204: */ ! 205: fp = pp; ! 206: omask = sigblock(sigmask(SIGCHLD)); ! 207: for (;;) { ! 208: jobflags = 0; ! 209: do ! 210: jobflags |= fp->p_flags; ! 211: while ((fp = (fp->p_friends)) != pp); ! 212: if ((jobflags & PRUNNING) == 0) ! 213: break; ! 214: sigpause(sigblock(0L) &~ sigmask(SIGCHLD)); ! 215: } ! 216: (void) sigsetmask(omask); ! 217: if (tpgrp > 0) /* get tty back */ ! 218: (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp); ! 219: if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) || ! 220: !eq(dcwd->di_name, fp->p_cwd->di_name)) { ! 221: if (jobflags&PSTOPPED) ! 222: printf("\n"); ! 223: (void) pprint(pp, AREASON|SHELLDIR); ! 224: } ! 225: if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr && ! 226: (!gointr || !eq(gointr, "-"))) { ! 227: if ((jobflags & PSTOPPED) == 0) ! 228: pflush(pp); ! 229: pintr1(0); ! 230: /*NOTREACHED*/ ! 231: } ! 232: reason = 0; ! 233: fp = pp; ! 234: do { ! 235: if (fp->p_reason) ! 236: reason = fp->p_flags & (PSIGNALED|PINTERRUPTED) ? ! 237: fp->p_reason | QUOTE : fp->p_reason; ! 238: } while ((fp = fp->p_friends) != pp); ! 239: set("status", putn(reason)); ! 240: if (reason && exiterr) ! 241: exitstat(); ! 242: pflush(pp); ! 243: } ! 244: ! 245: /* ! 246: * dowait - wait for all processes to finish ! 247: */ ! 248: dowait() ! 249: { ! 250: register struct process *pp; ! 251: long omask; ! 252: ! 253: pjobs++; ! 254: omask = sigblock(sigmask(SIGCHLD)); ! 255: loop: ! 256: for (pp = proclist.p_next; pp; pp = pp->p_next) ! 257: if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ ! 258: pp->p_flags&PRUNNING) { ! 259: sigpause(0L); ! 260: goto loop; ! 261: } ! 262: (void) sigsetmask(omask); ! 263: pjobs = 0; ! 264: } ! 265: ! 266: /* ! 267: * pflushall - flush all jobs from list (e.g. at fork()) ! 268: */ ! 269: pflushall() ! 270: { ! 271: register struct process *pp; ! 272: ! 273: for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) ! 274: if (pp->p_pid) ! 275: pflush(pp); ! 276: } ! 277: ! 278: /* ! 279: * pflush - flag all process structures in the same job as the ! 280: * the argument process for deletion. The actual free of the ! 281: * space is not done here since pflush is called at interrupt level. ! 282: */ ! 283: pflush(pp) ! 284: register struct process *pp; ! 285: { ! 286: register struct process *np; ! 287: register int index; ! 288: ! 289: if (pp->p_pid == 0) { ! 290: printf("BUG: process flushed twice"); ! 291: return; ! 292: } ! 293: while (pp->p_pid != pp->p_jobid) ! 294: pp = pp->p_friends; ! 295: pclrcurr(pp); ! 296: if (pp == pcurrjob) ! 297: pcurrjob = 0; ! 298: index = pp->p_index; ! 299: np = pp; ! 300: do { ! 301: np->p_index = np->p_pid = 0; ! 302: np->p_flags &= ~PNEEDNOTE; ! 303: } while ((np = np->p_friends) != pp); ! 304: if (index == pmaxindex) { ! 305: for (np = proclist.p_next, index = 0; np; np = np->p_next) ! 306: if (np->p_index > index) ! 307: index = np->p_index; ! 308: pmaxindex = index; ! 309: } ! 310: } ! 311: ! 312: /* ! 313: * pclrcurr - make sure the given job is not the current or previous job; ! 314: * pp MUST be the job leader ! 315: */ ! 316: pclrcurr(pp) ! 317: register struct process *pp; ! 318: { ! 319: ! 320: if (pp == pcurrent) ! 321: if (pprevious != PNULL) { ! 322: pcurrent = pprevious; ! 323: pprevious = pgetcurr(pp); ! 324: } else { ! 325: pcurrent = pgetcurr(pp); ! 326: pprevious = pgetcurr(pp); ! 327: } ! 328: else if (pp == pprevious) ! 329: pprevious = pgetcurr(pp); ! 330: } ! 331: ! 332: /* +4 here is 1 for '\0', 1 ea for << >& >> */ ! 333: char command[PMAXLEN+4]; ! 334: int cmdlen; ! 335: char *cmdp; ! 336: /* ! 337: * palloc - allocate a process structure and fill it up. ! 338: * an important assumption is made that the process is running. ! 339: */ ! 340: palloc(pid, t) ! 341: int pid; ! 342: register struct command *t; ! 343: { ! 344: register struct process *pp; ! 345: int i; ! 346: ! 347: pp = (struct process *)calloc(1, sizeof(struct process)); ! 348: pp->p_pid = pid; ! 349: pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND; ! 350: if (t->t_dflg & FTIME) ! 351: pp->p_flags |= PPTIME; ! 352: cmdp = command; ! 353: cmdlen = 0; ! 354: padd(t); ! 355: *cmdp++ = 0; ! 356: if (t->t_dflg & FPOU) { ! 357: pp->p_flags |= PPOU; ! 358: if (t->t_dflg & FDIAG) ! 359: pp->p_flags |= PDIAG; ! 360: } ! 361: pp->p_command = savestr(command); ! 362: if (pcurrjob) { ! 363: struct process *fp; ! 364: /* careful here with interrupt level */ ! 365: pp->p_cwd = 0; ! 366: pp->p_index = pcurrjob->p_index; ! 367: pp->p_friends = pcurrjob; ! 368: pp->p_jobid = pcurrjob->p_pid; ! 369: for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) ! 370: ; ! 371: fp->p_friends = pp; ! 372: } else { ! 373: pcurrjob = pp; ! 374: pp->p_jobid = pid; ! 375: pp->p_friends = pp; ! 376: pp->p_cwd = dcwd; ! 377: dcwd->di_count++; ! 378: if (pmaxindex < BIGINDEX) ! 379: pp->p_index = ++pmaxindex; ! 380: else { ! 381: struct process *np; ! 382: ! 383: for (i = 1; ; i++) { ! 384: for (np = proclist.p_next; np; np = np->p_next) ! 385: if (np->p_index == i) ! 386: goto tryagain; ! 387: pp->p_index = i; ! 388: if (i > pmaxindex) ! 389: pmaxindex = i; ! 390: break; ! 391: tryagain:; ! 392: } ! 393: } ! 394: if (pcurrent == PNULL) ! 395: pcurrent = pp; ! 396: else if (pprevious == PNULL) ! 397: pprevious = pp; ! 398: } ! 399: pp->p_next = proclist.p_next; ! 400: proclist.p_next = pp; ! 401: (void) gettimeofday(&pp->p_btime, (struct timezone *)0); ! 402: } ! 403: ! 404: padd(t) ! 405: register struct command *t; ! 406: { ! 407: char **argp; ! 408: ! 409: if (t == 0) ! 410: return; ! 411: switch (t->t_dtyp) { ! 412: ! 413: case TPAR: ! 414: pads("( "); ! 415: padd(t->t_dspr); ! 416: pads(" )"); ! 417: break; ! 418: ! 419: case TCOM: ! 420: for (argp = t->t_dcom; *argp; argp++) { ! 421: pads(*argp); ! 422: if (argp[1]) ! 423: pads(" "); ! 424: } ! 425: break; ! 426: ! 427: case TOR: ! 428: case TAND: ! 429: case TFIL: ! 430: case TLST: ! 431: padd(t->t_dcar); ! 432: switch (t->t_dtyp) { ! 433: case TOR: ! 434: pads(" || "); ! 435: break; ! 436: case TAND: ! 437: pads(" && "); ! 438: break; ! 439: case TFIL: ! 440: pads(" | "); ! 441: break; ! 442: case TLST: ! 443: pads("; "); ! 444: break; ! 445: } ! 446: padd(t->t_dcdr); ! 447: return; ! 448: } ! 449: if ((t->t_dflg & FPIN) == 0 && t->t_dlef) { ! 450: pads((t->t_dflg & FHERE) ? " << " : " < "); ! 451: pads(t->t_dlef); ! 452: } ! 453: if ((t->t_dflg & FPOU) == 0 && t->t_drit) { ! 454: pads((t->t_dflg & FCAT) ? " >>" : " >"); ! 455: if (t->t_dflg & FDIAG) ! 456: pads("&"); ! 457: pads(" "); ! 458: pads(t->t_drit); ! 459: } ! 460: } ! 461: ! 462: pads(cp) ! 463: char *cp; ! 464: { ! 465: register int i = strlen(cp); ! 466: ! 467: if (cmdlen >= PMAXLEN) ! 468: return; ! 469: if (cmdlen + i >= PMAXLEN) { ! 470: (void) strcpy(cmdp, " ..."); ! 471: cmdlen = PMAXLEN; ! 472: cmdp += 4; ! 473: return; ! 474: } ! 475: (void) strcpy(cmdp, cp); ! 476: cmdp += i; ! 477: cmdlen += i; ! 478: } ! 479: ! 480: /* ! 481: * psavejob - temporarily save the current job on a one level stack ! 482: * so another job can be created. Used for { } in exp6 ! 483: * and `` in globbing. ! 484: */ ! 485: psavejob() ! 486: { ! 487: ! 488: pholdjob = pcurrjob; ! 489: pcurrjob = PNULL; ! 490: } ! 491: ! 492: /* ! 493: * prestjob - opposite of psavejob. This may be missed if we are interrupted ! 494: * somewhere, but pendjob cleans up anyway. ! 495: */ ! 496: prestjob() ! 497: { ! 498: ! 499: pcurrjob = pholdjob; ! 500: pholdjob = PNULL; ! 501: } ! 502: ! 503: /* ! 504: * pendjob - indicate that a job (set of commands) has been completed ! 505: * or is about to begin. ! 506: */ ! 507: pendjob() ! 508: { ! 509: register struct process *pp, *tp; ! 510: ! 511: if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) { ! 512: pp = pcurrjob; ! 513: while (pp->p_pid != pp->p_jobid) ! 514: pp = pp->p_friends; ! 515: printf("[%d]", pp->p_index); ! 516: tp = pp; ! 517: do { ! 518: printf(" %d", pp->p_pid); ! 519: pp = pp->p_friends; ! 520: } while (pp != tp); ! 521: printf("\n"); ! 522: } ! 523: pholdjob = pcurrjob = 0; ! 524: } ! 525: ! 526: /* ! 527: * pprint - print a job ! 528: */ ! 529: pprint(pp, flag) ! 530: register struct process *pp; ! 531: { ! 532: register status, reason; ! 533: struct process *tp; ! 534: extern char *linp, linbuf[]; ! 535: int jobflags, pstatus; ! 536: char *format; ! 537: ! 538: while (pp->p_pid != pp->p_jobid) ! 539: pp = pp->p_friends; ! 540: if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { ! 541: pp->p_flags &= ~PPTIME; ! 542: pp->p_flags |= PTIME; ! 543: } ! 544: tp = pp; ! 545: status = reason = -1; ! 546: jobflags = 0; ! 547: do { ! 548: jobflags |= pp->p_flags; ! 549: pstatus = pp->p_flags & PALLSTATES; ! 550: if (tp != pp && linp != linbuf && !(flag&FANCY) && ! 551: (pstatus == status && pp->p_reason == reason || ! 552: !(flag&REASON))) ! 553: printf(" "); ! 554: else { ! 555: if (tp != pp && linp != linbuf) ! 556: printf("\n"); ! 557: if(flag&NUMBER) ! 558: if (pp == tp) ! 559: printf("[%d]%s %c ", pp->p_index, ! 560: pp->p_index < 10 ? " " : "", ! 561: pp==pcurrent ? '+' : ! 562: (pp == pprevious ? '-' : ' ')); ! 563: else ! 564: printf(" "); ! 565: if (flag&FANCY) ! 566: printf("%5d ", pp->p_pid); ! 567: if (flag&(REASON|AREASON)) { ! 568: if (flag&NAME) ! 569: format = "%-23s"; ! 570: else ! 571: format = "%s"; ! 572: if (pstatus == status) ! 573: if (pp->p_reason == reason) { ! 574: printf(format, ""); ! 575: goto prcomd; ! 576: } else ! 577: reason = pp->p_reason; ! 578: else { ! 579: status = pstatus; ! 580: reason = pp->p_reason; ! 581: } ! 582: switch (status) { ! 583: ! 584: case PRUNNING: ! 585: printf(format, "Running "); ! 586: break; ! 587: ! 588: case PINTERRUPTED: ! 589: case PSTOPPED: ! 590: case PSIGNALED: ! 591: if ((flag&(REASON|AREASON)) ! 592: && reason != SIGINT ! 593: && reason != SIGPIPE) ! 594: printf(format, mesg[pp->p_reason].pname); ! 595: break; ! 596: ! 597: case PNEXITED: ! 598: case PAEXITED: ! 599: if (flag & REASON) ! 600: if (pp->p_reason) ! 601: printf("Exit %-16d", pp->p_reason); ! 602: else ! 603: printf(format, "Done"); ! 604: break; ! 605: ! 606: default: ! 607: printf("BUG: status=%-9o", status); ! 608: } ! 609: } ! 610: } ! 611: prcomd: ! 612: if (flag&NAME) { ! 613: printf("%s", pp->p_command); ! 614: if (pp->p_flags & PPOU) ! 615: printf(" |"); ! 616: if (pp->p_flags & PDIAG) ! 617: printf("&"); ! 618: } ! 619: if (flag&(REASON|AREASON) && pp->p_flags&PDUMPED) ! 620: printf(" (core dumped)"); ! 621: if (tp == pp->p_friends) { ! 622: if (flag&ERSAND) ! 623: printf(" &"); ! 624: if (flag&JOBDIR && ! 625: !eq(tp->p_cwd->di_name, dcwd->di_name)) { ! 626: printf(" (wd: "); ! 627: dtildepr(value("home"), tp->p_cwd->di_name); ! 628: printf(")"); ! 629: } ! 630: } ! 631: if (pp->p_flags&PPTIME && !(status&(PSTOPPED|PRUNNING))) { ! 632: if (linp != linbuf) ! 633: printf("\n\t"); ! 634: { static struct rusage zru; ! 635: prusage(&zru, &pp->p_rusage, &pp->p_etime, ! 636: &pp->p_btime); ! 637: } ! 638: } ! 639: if (tp == pp->p_friends) { ! 640: if (linp != linbuf) ! 641: printf("\n"); ! 642: if (flag&SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { ! 643: printf("(wd now: "); ! 644: dtildepr(value("home"), dcwd->di_name); ! 645: printf(")\n"); ! 646: } ! 647: } ! 648: } while ((pp = pp->p_friends) != tp); ! 649: if (jobflags&PTIME && (jobflags&(PSTOPPED|PRUNNING)) == 0) { ! 650: if (jobflags & NUMBER) ! 651: printf(" "); ! 652: ptprint(tp); ! 653: } ! 654: return (jobflags); ! 655: } ! 656: ! 657: ptprint(tp) ! 658: register struct process *tp; ! 659: { ! 660: struct timeval tetime, diff; ! 661: static struct timeval ztime; ! 662: struct rusage ru; ! 663: static struct rusage zru; ! 664: register struct process *pp = tp; ! 665: ! 666: ru = zru; ! 667: tetime = ztime; ! 668: do { ! 669: ruadd(&ru, &pp->p_rusage); ! 670: tvsub(&diff, &pp->p_etime, &pp->p_btime); ! 671: if (timercmp(&diff, &tetime, >)) ! 672: tetime = diff; ! 673: } while ((pp = pp->p_friends) != tp); ! 674: prusage(&zru, &ru, &tetime, &ztime); ! 675: } ! 676: ! 677: /* ! 678: * dojobs - print all jobs ! 679: */ ! 680: dojobs(v) ! 681: char **v; ! 682: { ! 683: register struct process *pp; ! 684: register int flag = NUMBER|NAME|REASON; ! 685: int i; ! 686: ! 687: if (chkstop) ! 688: chkstop = 2; ! 689: if (*++v) { ! 690: if (v[1] || !eq(*v, "-l")) ! 691: error("Usage: jobs [ -l ]"); ! 692: flag |= FANCY|JOBDIR; ! 693: } ! 694: for (i = 1; i <= pmaxindex; i++) ! 695: for (pp = proclist.p_next; pp; pp = pp->p_next) ! 696: if (pp->p_index == i && pp->p_pid == pp->p_jobid) { ! 697: pp->p_flags &= ~PNEEDNOTE; ! 698: if (!(pprint(pp, flag) & (PRUNNING|PSTOPPED))) ! 699: pflush(pp); ! 700: break; ! 701: } ! 702: } ! 703: ! 704: /* ! 705: * dofg - builtin - put the job into the foreground ! 706: */ ! 707: dofg(v) ! 708: char **v; ! 709: { ! 710: register struct process *pp; ! 711: ! 712: okpcntl(); ! 713: ++v; ! 714: do { ! 715: pp = pfind(*v); ! 716: pstart(pp, 1); ! 717: pjwait(pp); ! 718: } while (*v && *++v); ! 719: } ! 720: ! 721: /* ! 722: * %... - builtin - put the job into the foreground ! 723: */ ! 724: dofg1(v) ! 725: char **v; ! 726: { ! 727: register struct process *pp; ! 728: ! 729: okpcntl(); ! 730: pp = pfind(v[0]); ! 731: pstart(pp, 1); ! 732: pjwait(pp); ! 733: } ! 734: ! 735: /* ! 736: * dobg - builtin - put the job into the background ! 737: */ ! 738: dobg(v) ! 739: char **v; ! 740: { ! 741: register struct process *pp; ! 742: ! 743: okpcntl(); ! 744: ++v; ! 745: do { ! 746: pp = pfind(*v); ! 747: pstart(pp, 0); ! 748: } while (*v && *++v); ! 749: } ! 750: ! 751: /* ! 752: * %... & - builtin - put the job into the background ! 753: */ ! 754: dobg1(v) ! 755: char **v; ! 756: { ! 757: register struct process *pp; ! 758: ! 759: pp = pfind(v[0]); ! 760: pstart(pp, 0); ! 761: } ! 762: ! 763: /* ! 764: * dostop - builtin - stop the job ! 765: */ ! 766: dostop(v) ! 767: char **v; ! 768: { ! 769: ! 770: pkill(++v, SIGSTOP); ! 771: } ! 772: ! 773: /* ! 774: * dokill - builtin - superset of kill (1) ! 775: */ ! 776: dokill(v) ! 777: char **v; ! 778: { ! 779: register int signum; ! 780: register char *name; ! 781: ! 782: v++; ! 783: if (v[0] && v[0][0] == '-') { ! 784: if (v[0][1] == 'l') { ! 785: for (signum = 1; signum <= NSIG; signum++) { ! 786: if (name = mesg[signum].iname) ! 787: printf("%s ", name); ! 788: if (signum == 16) ! 789: cshputchar('\n'); ! 790: } ! 791: cshputchar('\n'); ! 792: return; ! 793: } ! 794: if (digit(v[0][1])) { ! 795: signum = atoi(v[0]+1); ! 796: if (signum < 0 || signum > NSIG) ! 797: bferr("Bad signal number"); ! 798: } else { ! 799: name = &v[0][1]; ! 800: for (signum = 1; signum <= NSIG; signum++) ! 801: if (mesg[signum].iname && ! 802: eq(name, mesg[signum].iname)) ! 803: goto gotsig; ! 804: setname(name); ! 805: bferr("Unknown signal; kill -l lists signals"); ! 806: } ! 807: gotsig: ! 808: v++; ! 809: } else ! 810: signum = SIGTERM; ! 811: pkill(v, signum); ! 812: } ! 813: ! 814: pkill(v, signum) ! 815: char **v; ! 816: int signum; ! 817: { ! 818: register struct process *pp, *np; ! 819: register int jobflags = 0; ! 820: int pid, err = 0; ! 821: long omask; ! 822: char *cp; ! 823: extern char *sys_errlist[]; ! 824: ! 825: omask = sigmask(SIGCHLD); ! 826: if (setintr) ! 827: omask |= sigmask(SIGINT); ! 828: omask = sigblock(omask) & ~omask; ! 829: while (*v) { ! 830: cp = globone(*v); ! 831: if (*cp == '%') { ! 832: np = pp = pfind(cp); ! 833: do ! 834: jobflags |= np->p_flags; ! 835: while ((np = np->p_friends) != pp); ! 836: switch (signum) { ! 837: ! 838: case SIGSTOP: ! 839: case SIGTSTP: ! 840: case SIGTTIN: ! 841: case SIGTTOU: ! 842: if ((jobflags & PRUNNING) == 0) { ! 843: printf("%s: Already suspended\n", cp); ! 844: err++; ! 845: goto cont; ! 846: } ! 847: } ! 848: if (killpg(pp->p_jobid, signum) < 0) { ! 849: printf("%s: ", cp); ! 850: printf("%s\n", sys_errlist[errno]); ! 851: err++; ! 852: } ! 853: if (signum == SIGTERM || signum == SIGHUP) ! 854: (void) killpg(pp->p_jobid, SIGCONT); ! 855: } else if (!(digit(*cp) || *cp == '-')) ! 856: bferr("Arguments should be jobs or process id's"); ! 857: else { ! 858: pid = atoi(cp); ! 859: if (kill(pid, signum) < 0) { ! 860: printf("%d: ", pid); ! 861: printf("%s\n", sys_errlist[errno]); ! 862: err++; ! 863: goto cont; ! 864: } ! 865: if (signum == SIGTERM || signum == SIGHUP) ! 866: (void) kill(pid, SIGCONT); ! 867: } ! 868: cont: ! 869: xfree(cp); ! 870: v++; ! 871: } ! 872: (void) sigsetmask(omask); ! 873: if (err) ! 874: error(NOSTR); ! 875: } ! 876: ! 877: /* ! 878: * pstart - start the job in foreground/background ! 879: */ ! 880: pstart(pp, foregnd) ! 881: register struct process *pp; ! 882: int foregnd; ! 883: { ! 884: register struct process *np; ! 885: int jobflags = 0; ! 886: long omask; ! 887: ! 888: omask = sigblock(sigmask(SIGCHLD)); ! 889: np = pp; ! 890: do { ! 891: jobflags |= np->p_flags; ! 892: if (np->p_flags&(PRUNNING|PSTOPPED)) { ! 893: np->p_flags |= PRUNNING; ! 894: np->p_flags &= ~PSTOPPED; ! 895: if (foregnd) ! 896: np->p_flags |= PFOREGND; ! 897: else ! 898: np->p_flags &= ~PFOREGND; ! 899: } ! 900: } while((np = np->p_friends) != pp); ! 901: if (!foregnd) ! 902: pclrcurr(pp); ! 903: (void) pprint(pp, foregnd ? NAME|JOBDIR : NUMBER|NAME|AMPERSAND); ! 904: if (foregnd) ! 905: (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pp->p_jobid); ! 906: if (jobflags&PSTOPPED) ! 907: (void) killpg(pp->p_jobid, SIGCONT); ! 908: (void) sigsetmask(omask); ! 909: } ! 910: ! 911: panystop(neednl) ! 912: { ! 913: register struct process *pp; ! 914: ! 915: chkstop = 2; ! 916: for (pp = proclist.p_next; pp; pp = pp->p_next) ! 917: if (pp->p_flags & PSTOPPED) ! 918: error("\nThere are suspended jobs" + 1 - neednl); ! 919: } ! 920: ! 921: struct process * ! 922: pfind(cp) ! 923: char *cp; ! 924: { ! 925: register struct process *pp, *np; ! 926: ! 927: if (cp == 0 || cp[1] == 0 || eq(cp, "%%") || eq(cp, "%+")) { ! 928: if (pcurrent == PNULL) ! 929: bferr("No current job"); ! 930: return (pcurrent); ! 931: } ! 932: if (eq(cp, "%-") || eq(cp, "%#")) { ! 933: if (pprevious == PNULL) ! 934: bferr("No previous job"); ! 935: return (pprevious); ! 936: } ! 937: if (digit(cp[1])) { ! 938: int index = atoi(cp+1); ! 939: for (pp = proclist.p_next; pp; pp = pp->p_next) ! 940: if (pp->p_index == index && pp->p_pid == pp->p_jobid) ! 941: return (pp); ! 942: bferr("No such job"); ! 943: } ! 944: np = PNULL; ! 945: for (pp = proclist.p_next; pp; pp = pp->p_next) ! 946: if (pp->p_pid == pp->p_jobid) { ! 947: if (cp[1] == '?') { ! 948: register char *dp; ! 949: for (dp = pp->p_command; *dp; dp++) { ! 950: if (*dp != cp[2]) ! 951: continue; ! 952: if (prefix(cp+2, dp)) ! 953: goto match; ! 954: } ! 955: } else if (prefix(cp+1, pp->p_command)) { ! 956: match: ! 957: if (np) ! 958: bferr("Ambiguous"); ! 959: np = pp; ! 960: } ! 961: } ! 962: if (np) ! 963: return (np); ! 964: if (cp[1] == '?') ! 965: bferr("No job matches pattern"); ! 966: else ! 967: bferr("No such job"); ! 968: /*NOTREACHED*/ ! 969: } ! 970: ! 971: /* ! 972: * pgetcurr - find most recent job that is not pp, preferably stopped ! 973: */ ! 974: struct process * ! 975: pgetcurr(pp) ! 976: register struct process *pp; ! 977: { ! 978: register struct process *np; ! 979: register struct process *xp = PNULL; ! 980: ! 981: for (np = proclist.p_next; np; np = np->p_next) ! 982: if (np != pcurrent && np != pp && np->p_pid && ! 983: np->p_pid == np->p_jobid) { ! 984: if (np->p_flags & PSTOPPED) ! 985: return (np); ! 986: if (xp == PNULL) ! 987: xp = np; ! 988: } ! 989: return (xp); ! 990: } ! 991: ! 992: /* ! 993: * donotify - flag the job so as to report termination asynchronously ! 994: */ ! 995: donotify(v) ! 996: char **v; ! 997: { ! 998: register struct process *pp; ! 999: ! 1000: pp = pfind(*++v); ! 1001: pp->p_flags |= PNOTIFY; ! 1002: } ! 1003: ! 1004: /* ! 1005: * Do the fork and whatever should be done in the child side that ! 1006: * should not be done if we are not forking at all (like for simple builtin's) ! 1007: * Also do everything that needs any signals fiddled with in the parent side ! 1008: * ! 1009: * Wanttty tells whether process and/or tty pgrps are to be manipulated: ! 1010: * -1: leave tty alone; inherit pgrp from parent ! 1011: * 0: already have tty; manipulate process pgrps only ! 1012: * 1: want to claim tty; manipulate process and tty pgrps ! 1013: * It is usually just the value of tpgrp. ! 1014: */ ! 1015: pfork(t, wanttty) ! 1016: struct command *t; /* command we are forking for */ ! 1017: int wanttty; ! 1018: { ! 1019: register int pid; ! 1020: bool ignint = 0; ! 1021: int pgrp; ! 1022: long omask; ! 1023: ! 1024: /* ! 1025: * A child will be uninterruptible only under very special ! 1026: * conditions. Remember that the semantics of '&' is ! 1027: * implemented by disconnecting the process from the tty so ! 1028: * signals do not need to ignored just for '&'. ! 1029: * Thus signals are set to default action for children unless: ! 1030: * we have had an "onintr -" (then specifically ignored) ! 1031: * we are not playing with signals (inherit action) ! 1032: */ ! 1033: if (setintr) ! 1034: ignint = (tpgrp == -1 && (t->t_dflg&FINT)) ! 1035: || (gointr && eq(gointr, "-")); ! 1036: /* ! 1037: * Hold SIGCHLD until we have the process installed in our table. ! 1038: */ ! 1039: omask = sigblock(sigmask(SIGCHLD)); ! 1040: while ((pid = fork()) < 0) ! 1041: if (setintr == 0) ! 1042: sleep(FORKSLEEP); ! 1043: else { ! 1044: (void) sigsetmask(omask); ! 1045: error("No more processes"); ! 1046: } ! 1047: if (pid == 0) { ! 1048: settimes(); ! 1049: pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); ! 1050: pflushall(); ! 1051: pcurrjob = PNULL; ! 1052: child++; ! 1053: if (setintr) { ! 1054: setintr = 0; /* until I think otherwise */ ! 1055: /* ! 1056: * Children just get blown away on SIGINT, SIGQUIT ! 1057: * unless "onintr -" seen. ! 1058: */ ! 1059: (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); ! 1060: (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); ! 1061: if (wanttty >= 0) { ! 1062: /* make stoppable */ ! 1063: (void) signal(SIGTSTP, SIG_DFL); ! 1064: (void) signal(SIGTTIN, SIG_DFL); ! 1065: (void) signal(SIGTTOU, SIG_DFL); ! 1066: } ! 1067: (void) signal(SIGTERM, parterm); ! 1068: } else if (tpgrp == -1 && (t->t_dflg&FINT)) { ! 1069: (void) signal(SIGINT, SIG_IGN); ! 1070: (void) signal(SIGQUIT, SIG_IGN); ! 1071: } ! 1072: if (wanttty > 0) ! 1073: (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&pgrp); ! 1074: if (wanttty >= 0 && tpgrp >= 0) ! 1075: (void) setpgrp(0, pgrp); ! 1076: if (tpgrp > 0) ! 1077: tpgrp = 0; /* gave tty away */ ! 1078: /* ! 1079: * Nohup and nice apply only to TCOM's but it would be ! 1080: * nice (?!?) if you could say "nohup (foo;bar)" ! 1081: * Then the parser would have to know about nice/nohup/time ! 1082: */ ! 1083: if (t->t_dflg & FNOHUP) ! 1084: (void) signal(SIGHUP, SIG_IGN); ! 1085: if (t->t_dflg & FNICE) ! 1086: (void) setpriority(PRIO_PROCESS, 0, t->t_nice); ! 1087: } else { ! 1088: palloc(pid, t); ! 1089: (void) sigsetmask(omask); ! 1090: } ! 1091: ! 1092: return (pid); ! 1093: } ! 1094: ! 1095: okpcntl() ! 1096: { ! 1097: ! 1098: if (tpgrp == -1) ! 1099: error("No job control in this shell"); ! 1100: if (tpgrp == 0) ! 1101: error("No job control in subshells"); ! 1102: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.