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