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