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