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

Defined functions

dobg defined in line 738; used 2 times
dobg1 defined in line 754; used 2 times
dofg defined in line 707; used 2 times
dofg1 defined in line 724; used 2 times
dojobs defined in line 680; used 3 times
dokill defined in line 776; used 2 times
donotify defined in line 994; used 2 times
dostop defined in line 766; used 2 times
dowait defined in line 248; used 2 times
okpcntl defined in line 1094; used 3 times
padd defined in line 404; used 4 times
pads defined in line 462; used 14 times
palloc defined in line 340; used 2 times
panystop defined in line 910; used 4 times
pchild defined in line 31; used 1 times
pclrcurr defined in line 316; used 3 times
pendjob defined in line 507; used 2 times
pfind defined in line 920; used 7 times
pflush defined in line 283; used 6 times
pflushall defined in line 269; used 1 times
pgetcurr defined in line 973; used 5 times
pjwait defined in line 187; used 3 times
pkill defined in line 814; used 2 times
pnote defined in line 137; used 1 times
pprint defined in line 529; used 5 times
prestjob defined in line 496; used 2 times
psavejob defined in line 485; used 2 times
pstart defined in line 879; used 4 times
ptprint defined in line 657; used 1 times
pwait defined in line 160; used 3 times

Defined variables

cmdlen defined in line 334; used 5 times
cmdp defined in line 335; used 6 times
command defined in line 333; used 2 times
sccsid defined in line 8; never used

Defined macros

BIGINDEX defined in line 22; used 1 times
Last modified: 1996-03-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7078
Valid CSS Valid XHTML 1.0 Strict