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&AMPERSAND)
 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: }

Defined functions

dobg defined in line 735; used 2 times
dobg1 defined in line 751; used 2 times
dofg defined in line 704; used 2 times
dofg1 defined in line 721; used 2 times
dojobs defined in line 677; used 3 times
dokill defined in line 773; used 2 times
donotify defined in line 990; used 2 times
dostop defined in line 763; used 2 times
dowait defined in line 245; used 2 times
okpcntl defined in line 1089; used 3 times
padd defined in line 401; used 4 times
pads defined in line 459; used 14 times
palloc defined in line 337; used 2 times
panystop defined in line 906; used 4 times
pchild defined in line 30; used 1 times
pclrcurr defined in line 313; used 3 times
pendjob defined in line 504; used 2 times
pfind defined in line 916; used 7 times
pflush defined in line 280; used 6 times
pflushall defined in line 266; used 1 times
pgetcurr defined in line 969; used 5 times
pjwait defined in line 185; used 3 times
pkill defined in line 811; used 2 times
pnote defined in line 136; used 1 times
pprint defined in line 526; used 5 times
prestjob defined in line 493; used 2 times
psavejob defined in line 482; used 2 times
pstart defined in line 876; used 4 times
ptprint defined in line 654; used 1 times
pwait defined in line 158; used 3 times

Defined variables

cmdlen defined in line 331; used 5 times
cmdp defined in line 332; used 6 times
command defined in line 330; used 2 times
sccsid defined in line 8; never used

Defined macros

BIGINDEX defined in line 21; used 1 times
Last modified: 1986-05-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2898
Valid CSS Valid XHTML 1.0 Strict