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