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