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

Defined functions

dobg defined in line 760; used 2 times
dobg1 defined in line 776; used 2 times
dofg defined in line 725; used 2 times
dofg1 defined in line 744; used 2 times
dojobs defined in line 698; used 3 times
dokill defined in line 798; used 2 times
donotify defined in line 1009; used 2 times
dostop defined in line 788; used 2 times
dowait defined in line 264; used 2 times
okpcntl defined in line 1117; used 3 times
padd defined in line 421; used 6 times
pads defined in line 469; used 12 times
palloc defined in line 357; used 2 times
panystop defined in line 926; used 4 times
pchild defined in line 22; used 1 times
pclrcurr defined in line 333; used 3 times
pendjob defined in line 514; used 2 times
pfind defined in line 936; used 7 times
pflush defined in line 300; used 6 times
pflushall defined in line 286; used 1 times
pgetcurr defined in line 988; used 5 times
pjwait defined in line 206; used 3 times
pkill defined in line 836; used 2 times
pnote defined in line 156; used 1 times
pprint defined in line 536; used 5 times
prestjob defined in line 503; used 2 times
psavejob defined in line 492; used 2 times
pstart defined in line 896; used 4 times
ptprint defined in line 664; used 1 times
pwait defined in line 178; used 3 times

Defined variables

cmdlen defined in line 351; used 5 times
cmdp defined in line 352; used 6 times
command defined in line 350; used 2 times
frobby defined in line 14; used 7 times
sccsid defined in line 1; never used

Defined macros

BIGINDEX defined in line 13; used 1 times
Last modified: 1982-10-07
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2920
Valid CSS Valid XHTML 1.0 Strict