# 2.11BSD#431 - /usr/src/bin/csh/sh.proc.c

##### Functions

    dobg              X
    dobg1             X
    dofg              X
    dofg1             X
    dojobs            X
    dokill            X
    donotify          X
    dostop            X
    dowait            X
    okpcntl           X
    padd              X
    pads              X
    palloc            X
    panystop          X
    pchild            X
    pclrcurr          X
    pendjob           X
    pfind             X
    pflush            X
    pflushall         X
    pfork             X
    pgetcurr          X
    pjwait            X
    pkill             X
    pnote             X
    pprint            X
    prestjob          X
    psavejob          X
    pstart            X
    ptprint           X
    pwait             X

##### Variables

    cmdlen            X
    cmdp              X
    command           X

##### Macros

    BIGINDEX          X

       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

- in /usr/src/bin/csh/sh.init.c line 18, 93

dobg1 defined in line 754; used 2 times

- in /usr/src/bin/csh/sh.func.c line 24-27(2)

dofg defined in line 707; used 2 times

- in /usr/src/bin/csh/sh.init.c line 30, 113

dofg1 defined in line 724; used 2 times

- in /usr/src/bin/csh/sh.func.c line 24-26(2)

dojobs defined in line 680; used 3 times

- in /usr/src/bin/csh/sh.c line 638
- in /usr/src/bin/csh/sh.init.c line 37, 125

dokill defined in line 776; used 2 times

- in /usr/src/bin/csh/sh.init.c line 38, 126

donotify defined in line 994; used 2 times

- in /usr/src/bin/csh/sh.init.c line 49, 137

dostop defined in line 766; used 2 times

- in /usr/src/bin/csh/sh.init.c line 58, 150

dowait defined in line 248; used 2 times

- in /usr/src/bin/csh/sh.init.c line 67, 162

okpcntl defined in line 1094; used 3 times

- in line 712, 729, 743

padd defined in line 404; used 4 times

- in line 354, 415, 431, 446

pads defined in line 462; used 14 times

- in line 414-423(4), 434-443(4), 450-458(6)

palloc defined in line 340; used 2 times

- in line 1087
- in /usr/src/bin/csh/sh.sem.c line 165

panystop defined in line 910; used 4 times

- in /usr/src/bin/csh/sh.func.c line 189, 202, 326
- in /usr/src/bin/csh/sh.lex.c line 1158

pchild defined in line 31; used 1 times

- in /usr/src/bin/csh/sh.h line 431

pclrcurr defined in line 316; used 3 times

- in line 109, 295, 901

pendjob defined in line 507; used 2 times

- in /usr/src/bin/csh/sh.c line 685
- in /usr/src/bin/csh/sh.sem.c line 283

pfind defined in line 920; used 7 times

- in line 715, 730, 746, 759, 831, 999
- in /usr/src/bin/csh/sh.proc.h line 84

pflush defined in line 283; used 6 times

- in line 127, 150, 228, 242, 275, 699

pflushall defined in line 269; used 1 times

- in line 1049

pfork defined in line 1014; used 3 times

- in /usr/src/bin/csh/sh.exp.c line 410
- in /usr/src/bin/csh/sh.glob.c line 648
- in /usr/src/bin/csh/sh.sem.c line 119

pgetcurr defined in line 973; used 5 times

- in line 323-329(4)
- in /usr/src/bin/csh/sh.proc.h line 82

pjwait defined in line 187; used 3 times

- in line 180, 717, 732

pkill defined in line 814; used 2 times

- in line 770, 811

pnote defined in line 137; used 1 times

- in /usr/src/bin/csh/sh.c line 730

pprint defined in line 529; used 5 times

- in line 125, 148, 223, 698, 902

prestjob defined in line 496; used 2 times

- in /usr/src/bin/csh/sh.exp.c line 416
- in /usr/src/bin/csh/sh.glob.c line 725

psavejob defined in line 485; used 2 times

- in /usr/src/bin/csh/sh.exp.c line 409
- in /usr/src/bin/csh/sh.glob.c line 641

pstart defined in line 879; used 4 times

- in line 716, 731, 747, 760

ptprint defined in line 657; used 1 times

- in line 652

pwait defined in line 160; used 3 times

- in /usr/src/bin/csh/sh.exp.c line 415
- in /usr/src/bin/csh/sh.glob.c line 724
- in /usr/src/bin/csh/sh.sem.c line 226

#### Defined variables

cmdlen defined in line 334; used 5 times

- in line 353, 467-471(3), 477

cmdp defined in line 335; used 6 times

- in line 352-355(2), 470-476(4)

command defined in line 333; used 2 times

- in line 352, 361

sccsid defined in line 8; never used

#### Defined macros

BIGINDEX defined in line 22; used 1 times

- in line 378

Last modified: 1996-03-21 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3344 |