home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / jobs.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  16KB  |  765 lines

  1. /*
  2.  *
  3.  * jobs.c - job control
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made. 
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk. 
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22. #include <sys/errno.h>
  23.  
  24. /* != 0 means the handler is active */
  25.  
  26. static int handling = 0;
  27.  
  28. #ifdef INTHANDTYPE
  29. #define RETURN return 0
  30. #else
  31. #define RETURN return
  32. #endif
  33.  
  34. /* the signal handler */
  35.  
  36. HANDTYPE handler(sig,code) /**/
  37. int sig;int code;
  38. {
  39. long pid;
  40. int statusp;
  41. Job jn;
  42. struct process *pn;
  43. #ifdef HAS_RUSAGE
  44. struct rusage ru;
  45. #else
  46. long chlds,chldu;
  47. #endif
  48.  
  49. #ifdef RESETHANDNEEDED
  50.     signal(sig,handler);
  51. #endif
  52.     if (sig == SIGINT)
  53.         {
  54.         if (sigtrapped[SIGINT])
  55.             dotrap(SIGINT);
  56.         else
  57.             errflag = 1;
  58.         RETURN;
  59.         }
  60. #ifdef SIGWINCH
  61.     if (sig == SIGWINCH)
  62.         adjustwinsize();
  63. #endif
  64.     if (sig != SIGCHLD)
  65.         {
  66.         dotrap(sig);
  67.         if (sig == SIGALRM && !sigtrapped[SIGALRM])
  68.             {
  69.             zerr("timeout",NULL,0);
  70.             exit(1);
  71.             }
  72.         RETURN;
  73.         }
  74.     for (;;)
  75.         {
  76. #ifdef HAS_RUSAGE
  77.         pid = wait3((vptr) &statusp,WNOHANG|WUNTRACED,&ru);
  78. #else
  79. #ifndef WNOHANG
  80.         pid = wait(&statusp);
  81. #else
  82.         pid = wait3((vptr) &statusp,WNOHANG|WUNTRACED,NULL);
  83. #endif
  84.         chlds = shtms.tms_cstime;
  85.         chldu = shtms.tms_cutime;
  86.         times(&shtms);
  87. #endif
  88.         if (pid == -1)
  89.             {
  90.             if (errno != ECHILD)
  91.                 zerr("wait failed: %e",NULL,errno);
  92.             RETURN;
  93.             }
  94.         if (!pid)
  95.             RETURN;
  96.         findproc(pid,&jn,&pn);    /* find the process of this pid */
  97.         if (jn)
  98.             {
  99.             pn->statusp = statusp;
  100.             handling = 1;
  101. #ifdef HAS_RUSAGE
  102.             pn->ti.ru = ru;
  103. #else
  104.             pn->ti.st = shtms.tms_cstime-chlds;
  105.             pn->ti.ut = shtms.tms_cutime-chldu;
  106. #endif
  107.             pn->endtime = time(NULL);
  108.             updatestatus(jn);
  109.             handling = 0;
  110.             }
  111. #if 0
  112.         else if (WIFSTOPPED(statusp))
  113.             kill(pid,SIGKILL);    /* kill stopped untraced children */
  114. #endif
  115.         }
  116. }
  117.  
  118. /* change job table entry from stopped to running */
  119.  
  120. void makerunning(jn) /**/
  121. Job jn;
  122. {
  123. struct process *pn;
  124.  
  125.     jn->stat &= ~STAT_STOPPED;
  126.     for (pn = jn->procs; pn; pn = pn->next)
  127.         if (WIFSTOPPED(pn->statusp))
  128.             pn->statusp = SP_RUNNING;
  129. }
  130.  
  131. /* update status of job, possibly printing it */
  132.  
  133. void updatestatus(jn) /**/
  134. Job jn;
  135. {
  136. struct process *pn;
  137. int notrunning = 1,alldone = 1,val,job = jn-jobtab,somestopped = 0;
  138.  
  139.     for (pn = jn->procs; pn; pn = pn->next)
  140.         {
  141.         if (pn->statusp == SP_RUNNING)
  142.             notrunning = 0;
  143.         if (pn->statusp == SP_RUNNING || WIFSTOPPED(pn->statusp))
  144.             alldone = 0;
  145.         if (WIFSTOPPED(pn->statusp))
  146.             somestopped = 1;
  147.         if (!pn->next && jn)
  148.             val = (WIFSIGNALED(pn->statusp)) ?
  149.                 0200 | WTERMSIG(pn->statusp) : WEXITSTATUS(pn->statusp);
  150.         }
  151.     if (!notrunning)
  152.         return;
  153.     if (somestopped && (jn->stat & STAT_STOPPED))
  154.         return;
  155.     jn->stat |= (alldone) ? STAT_CHANGED|STAT_DONE :
  156.         STAT_CHANGED|STAT_STOPPED;
  157.     if (alldone && job == thisjob)
  158.         {
  159.         if (!ttyfrozen && !val) {
  160.             gettyinfo(&shttyinfo);
  161.             if (interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))
  162.                 sanetty(&shttyinfo);
  163. #ifdef TIOCSWINSZ
  164.             if (!(columns = shttyinfo.winsize.ws_col))
  165.                 columns = 80;
  166.             lines = shttyinfo.winsize.ws_row;
  167. #endif
  168.         } else
  169.             settyinfo(&shttyinfo);
  170.         lastval = val;
  171.         }
  172.     if ((jn->stat & (STAT_DONE|STAT_STOPPED)) == STAT_STOPPED) {
  173.         prevjob = curjob;
  174.         curjob = job;
  175.     }
  176.     if ((isset(NOTIFY) || job == thisjob) && jn->stat & STAT_LOCKED) {
  177.         printjob(jn,!!isset(LONGLISTJOBS));
  178.         if (zleactive) refresh();
  179.     }
  180.     if (sigtrapped[SIGCHLD] && job != thisjob)
  181.         dotrap(SIGCHLD);
  182. }
  183.  
  184. /* find process and job associated with pid */
  185.  
  186. void findproc(pid,jptr,pptr) /**/
  187. int pid;Job *jptr;struct process **pptr;
  188. {
  189. struct process *pn;
  190. int jn;
  191.  
  192.     for (jn = 1; jn != MAXJOB; jn++)
  193.         for (pn = jobtab[jn].procs; pn; pn = pn->next)
  194.             if (pn->pid == pid)
  195.                 {
  196.                 *pptr = pn;
  197.                 *jptr = jobtab+jn;
  198.                 return;
  199.                 }
  200.     *pptr = NULL;
  201.     *jptr = NULL;
  202. }
  203.  
  204. /*
  205.     lng = 0 means jobs 
  206.     lng = 1 means jobs -l
  207.     lng = 2 means jobs -p
  208. */
  209.  
  210. void printjob(jn,lng) /**/
  211. Job jn;int lng;
  212. {
  213. int job = jn-jobtab,len = 9,sig = -1,sflag = 0,llen,printed = 0;
  214. int conted = 0,lineleng = getlineleng(),skip = 0,doputnl = 0;
  215. struct process *pn;
  216.  
  217.     if (lng < 0)
  218.         {
  219.         conted = 1;
  220.         lng = 0;
  221.         }
  222.  
  223.     /* find length of longest signame, check to see if we
  224.         really need to print this job */
  225.  
  226.     for (pn = jn->procs; pn; pn = pn->next)
  227.         {
  228.         if (pn->statusp != SP_RUNNING)
  229.             if (WIFSIGNALED(pn->statusp))
  230.                 {
  231.                 sig = WTERMSIG(pn->statusp);
  232.                 llen = strlen(sigmsg[sig]);
  233.                 if (WCOREDUMPED(pn->statusp))
  234.                     llen += 14;
  235.                 if (llen > len)
  236.                     len = llen;
  237.                 if (sig != SIGINT && sig != SIGPIPE)
  238.                     sflag = 1;
  239.                 else if (sig == SIGINT)
  240.                     errflag = 1;
  241.                 if (job == thisjob && sig == SIGINT)
  242.                     doputnl = 1;
  243.                 }
  244.             else if (WIFSTOPPED(pn->statusp))
  245.                 {
  246.                 sig = WSTOPSIG(pn->statusp);
  247.                 if (strlen(sigmsg[sig]) > len)
  248.                     len = strlen(sigmsg[sig]);
  249.                 if (job == thisjob && sig == SIGTSTP)
  250.                     doputnl = 1;
  251.                 }
  252.             else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
  253.                     WEXITSTATUS(pn->statusp))
  254.                 sflag = 1;
  255.         }
  256.  
  257.     /* print if necessary */
  258.  
  259.     if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag ||
  260.             job != thisjob))
  261.         {
  262.         int len2,fline = 1;
  263.         struct process *qn;
  264.  
  265.         trashzle();
  266.         if (doputnl)
  267.             putc('\n',stderr);
  268.         for (pn = jn->procs; pn;)
  269.             {
  270.             len2 = ((job == thisjob) ? 5 : 10)+len; /* 2 spaces */
  271.             if (lng)
  272.                 qn = pn->next;
  273.             else for (qn = pn->next; qn; qn = qn->next)
  274.                 {
  275.                 if (qn->statusp != pn->statusp)
  276.                     break;
  277.                 if (strlen(qn->text)+len2+((qn->next) ? 3 : 0) > lineleng)
  278.                     break;
  279.                 len2 += strlen(qn->text)+2;
  280.                 }
  281.             if (job != thisjob)
  282.                 if (fline)
  283.                     fprintf(stderr,"[%d]  %c ",jn-jobtab,(job == curjob) ? '+' :
  284.                         (job == prevjob) ? '-' : ' ');
  285.                 else
  286.                     fprintf(stderr,(job > 9) ? "        " : "       ");
  287.             else
  288.                 fprintf(stderr,"zsh: ");
  289.             if (lng)
  290.                 if (lng == 1)
  291.                     fprintf(stderr,"%d ",pn->pid);
  292.                 else
  293.                     {
  294.                     int x = jn->gleader;
  295.  
  296.                     fprintf(stderr,"%d ",x);
  297.                     do skip++; while (x /= 10);
  298.                     skip++;
  299.                     lng = 0;
  300.                     }
  301.             else
  302.                 fprintf(stderr,"%*s",skip,"");
  303.             if (pn->statusp == SP_RUNNING)
  304.                 if (!conted)
  305.                     fprintf(stderr,"running%*s",len-7+2,"");
  306.                 else
  307.                     fprintf(stderr,"continued%*s",len-9+2,"");
  308.             else if (WIFEXITED(pn->statusp))
  309.                 if (WEXITSTATUS(pn->statusp))
  310.                     fprintf(stderr,"exit %-4d%*s",WEXITSTATUS(pn->statusp),
  311.                         len-9+2,"");
  312.                 else
  313.                     fprintf(stderr,"done%*s",len-4+2,"");
  314.             else if (WIFSTOPPED(pn->statusp))
  315.                 fprintf(stderr,"%-*s",len+2,sigmsg[WSTOPSIG(pn->statusp)]);
  316.             else if (WCOREDUMPED(pn->statusp))
  317.                 fprintf(stderr,"%s (core dumped)%*s",
  318.                     sigmsg[WTERMSIG(pn->statusp)],
  319.                     len-14+2-strlen(sigmsg[WTERMSIG(pn->statusp)]),"");
  320.             else
  321.                 fprintf(stderr,"%-*s",len+2,sigmsg[WTERMSIG(pn->statusp)]);
  322.             for (; pn != qn; pn = pn->next)
  323.                 fprintf(stderr,(pn->next) ? "%s | " : "%s",pn->text);
  324.             putc('\n',stderr);
  325.             fline = 0;
  326.             }
  327.         printed = 1;
  328.         }
  329.     else if (doputnl && interact)
  330.         putc('\n',stderr);
  331.     fflush(stderr);
  332.  
  333.     /* print "(pwd now: foo)" messages */
  334.  
  335.     if (interact && job==thisjob && strcmp(jn->pwd,pwd))
  336.         {
  337.         printf("(pwd now: ");
  338.         printdir(pwd);
  339.         printf(")\n");
  340.         fflush(stdout);
  341.         }
  342.  
  343.     /* delete job if done */
  344.  
  345.     if (jn->stat & STAT_DONE)
  346.         {
  347.         static struct job zero;
  348.         struct process *nx;
  349.         char *s;
  350.  
  351.         if ((jn->stat & STAT_TIMED) || (reporttime != -1 && report(jn))) {
  352.             dumptime(jn);
  353.             printed = 1;
  354.         }
  355.         for (pn = jn->procs; pn; pn = nx)
  356.             {
  357.             nx = pn->next;
  358.             free(pn);
  359.             }
  360.         free(jn->pwd);
  361.         if (jn->filelist)
  362.             {
  363.             while (s = getnode(jn->filelist))
  364.                 {
  365.                 unlink(s);
  366.                 free(s);
  367.                 }
  368.             free(jn->filelist);
  369.             }
  370.         *jn = zero;
  371.         if (job == curjob)
  372.             {
  373.             curjob = prevjob;
  374.             prevjob = job;
  375.             }
  376.         if (job == prevjob)
  377.             setprevjob();
  378.         }
  379.     else
  380.         jn->stat &= ~STAT_CHANGED;
  381. }
  382.  
  383. /* set the previous job to something reasonable */
  384.  
  385. void setprevjob() /**/
  386. {
  387. int t0;
  388.  
  389.     for (t0 = MAXJOB-1; t0; t0--)
  390.         if ((jobtab[t0].stat & STAT_INUSE) && (jobtab[t0].stat & STAT_STOPPED) &&
  391.                 t0 != curjob && t0 != thisjob)
  392.             break;
  393.     if (!t0)
  394.         for (t0 = MAXJOB-1; t0; t0--)
  395.             if ((jobtab[t0].stat & STAT_INUSE) && t0 != curjob && t0 != thisjob)
  396.                 break;
  397.     prevjob = (t0) ? t0 : -1;
  398. }
  399.  
  400. /* initialize a job table entry */
  401.  
  402. void initjob() /**/
  403. {
  404.     jobtab[thisjob].pwd = ztrdup(pwd);
  405.     jobtab[thisjob].stat = STAT_INUSE;
  406.     jobtab[thisjob].gleader = 0;
  407. }
  408.  
  409. /* add a process to the current job */
  410.  
  411. struct process *addproc(pid,text) /**/
  412. long pid;char *text;
  413. {
  414. struct process *process;
  415.  
  416.     if (!jobtab[thisjob].gleader) jobtab[thisjob].gleader = pid;
  417.     process = zcalloc(sizeof *process);
  418.     process->pid = pid;
  419.     if (text) strcpy(process->text,text);
  420.     else *process->text = '\0';
  421.     process->next = NULL;
  422.     process->statusp = SP_RUNNING;
  423.     process->bgtime = time(NULL);
  424.     if (jobtab[thisjob].procs) {
  425.         struct process *n;
  426.         for (n = jobtab[thisjob].procs; n->next; n = n->next);
  427.         process->next = NULL;
  428.         n->next = process;
  429.     } else jobtab[thisjob].procs = process;
  430.     return process;
  431. }
  432.  
  433. /* determine if it's all right to exec a command without
  434.     forking in last component of subshells; it's not ok if we have files
  435.     to delete */
  436.  
  437. int execok() /**/
  438. {
  439. Job jn;
  440.  
  441.     if (!exiting)
  442.         return 0;
  443.     for (jn = jobtab+1; jn != jobtab+MAXJOB; jn++)
  444.         if (jn->stat && jn->filelist)
  445.             return 0;
  446.     return 1;
  447.  
  448. }
  449.  
  450. void waitforpid(pid) /**/
  451. long pid;
  452. {
  453.     while (!errflag && (kill(pid,0) >= 0 || errno != ESRCH)) chldsuspend();
  454. }
  455.  
  456. /* wait for a job to finish */
  457.  
  458. void waitjob(job) /**/
  459. int job;
  460. {
  461. static struct job zero;
  462. Job jn;
  463.  
  464.     if (jobtab[job].procs)    /* if any forks were done */
  465.         {
  466.         jobtab[job].stat |= STAT_LOCKED;
  467.         if (jobtab[job].stat & STAT_CHANGED)
  468.             printjob(jobtab+job,!!isset(LONGLISTJOBS));
  469.         while (jobtab[job].stat &&
  470.                 !(jobtab[job].stat & (STAT_DONE|STAT_STOPPED)))
  471.             chldsuspend();
  472.         }
  473.     else    /* else do what printjob() usually does */
  474.         {
  475.         char *s;
  476.  
  477.         jn = jobtab+job;
  478.         free(jn->pwd);
  479.         if (jn->filelist)
  480.             {
  481.             while (s = getnode(jn->filelist))
  482.                 {
  483.                 unlink(s);
  484.                 free(s);
  485.                 }
  486.             free(jn->filelist);
  487.             }
  488.         *jn = zero;
  489.         }
  490. }
  491.  
  492. /* wait for running job to finish */
  493.  
  494. void waitjobs() /**/
  495. {
  496.     waitjob(thisjob);
  497.     thisjob = -1;
  498. }
  499.  
  500. /* clear job table when entering subshells */
  501.  
  502. void clearjobtab() /**/
  503. {
  504. static struct job zero;
  505. int t0;
  506.  
  507.     for (t0 = 1; t0 != MAXJOB; t0++)
  508.         jobtab[thisjob] = zero;
  509. }
  510.  
  511. /* get a free entry in the job table to use */
  512.  
  513. int getfreejob() /**/
  514. {
  515. int t0;
  516.  
  517.     for (t0 = 1; t0 != MAXJOB; t0++)
  518.         if (!jobtab[t0].stat) {
  519.             jobtab[t0].stat |= STAT_INUSE;
  520.             return t0;
  521.         }
  522.     zerr("job table full or recursion limit exceeded",NULL,0);
  523.     return -1;
  524. }
  525.  
  526. /* print pids for & */
  527.  
  528. void spawnjob() /**/
  529. {
  530. struct process *pn;
  531.  
  532.     if (!subsh)
  533.         {
  534.         if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED))
  535.             {
  536.             curjob = thisjob;
  537.             setprevjob();
  538.             }
  539.         else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
  540.             prevjob = thisjob;
  541.         if (interact && jobbing && jobtab[thisjob].procs)
  542.             {
  543.             fprintf(stderr,"[%d]",thisjob);
  544.             for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
  545.                 fprintf(stderr," %d",pn->pid);
  546.             fprintf(stderr,"\n");
  547.             fflush(stderr);
  548.             }
  549.         }
  550.     if (!jobtab[thisjob].procs)
  551.         {
  552.         char *s;
  553.         static struct job zero;
  554.         struct job *jn;
  555.  
  556.         jn = jobtab+thisjob;
  557.         free(jn->pwd);
  558.         if (jn->filelist)
  559.             {
  560.             while (s = getnode(jn->filelist))
  561.                 {
  562.                 unlink(s);
  563.                 free(s);
  564.                 }
  565.             free(jn->filelist);
  566.             }
  567.         *jn = zero;
  568.         }
  569.     else
  570.         jobtab[thisjob].stat |= STAT_LOCKED;
  571.     thisjob = -1;
  572. }
  573.  
  574. void fixsigs() /**/
  575. {
  576.     unblockchld();
  577. }
  578.  
  579. int report(j) /**/
  580. Job j;
  581. {
  582.     if (!j->procs) return 0;
  583. #ifdef HAS_RUSAGE
  584.     return (j->procs->ti.ru.ru_utime.tv_sec+j->procs->ti.ru.ru_stime.tv_sec)
  585.                  >= reporttime;
  586. #else
  587.     return (j->procs->ti.ut+j->procs->ti.st)/HZ >= reporttime;
  588. #endif
  589. }
  590.  
  591. void printtime(real,ti,desc) /**/
  592. time_t real;struct timeinfo *ti;char *desc;
  593. {
  594. char *s;
  595. #ifdef sun
  596. long ticks = 1;
  597. int pk = getpagesize()/1024;
  598. #else
  599. long sec;
  600. #endif
  601. #ifdef HAS_RUSAGE
  602. struct rusage *ru = &ti->ru;
  603. #endif
  604.  
  605.     if (!desc) desc = "";
  606. #ifdef HAS_RUSAGE
  607. #ifdef sun
  608.     ticks = (ru->ru_utime.tv_sec+ru->ru_stime.tv_sec)*HZ+
  609.               (ru->ru_utime.tv_usec+ru->ru_stime.tv_usec)*HZ/1000000;
  610.     if (!ticks) ticks = 1;
  611. #else
  612.     sec = ru->ru_utime.tv_sec + ru->ru_stime.tv_sec;
  613.     if (!sec) sec = 1;
  614. #endif
  615. #endif
  616.     for (s = timefmt; *s; s++)
  617.         if (*s == '%')
  618.             switch(s++,*s)
  619.                 {
  620.                 case 'E': fprintf(stderr,"%lds",real); break;
  621. #ifndef HAS_RUSAGE
  622.                 case 'U': fprintf(stderr,"%ld.%03lds",
  623.                     ti->ut/HZ,ti->ut*1000/60%1000); break;
  624.                 case 'S': fprintf(stderr,"%ld.%03lds",
  625.                     ti->st/HZ,ti->st*1000/60%1000); break;
  626.                 case 'P':
  627.                     if (real)
  628.                         fprintf(stderr,"%d%%",
  629.                             (int) (100*((ti->ut+ti->st)/HZ))/real);
  630.                     break;
  631. #else
  632.                 case 'U': fprintf(stderr,"%ld.%03lds",
  633.                     ru->ru_utime.tv_sec,ru->ru_utime.tv_usec/1000); break;
  634.                 case 'S': fprintf(stderr,"%ld.%03lds",
  635.                     ru->ru_stime.tv_sec,ru->ru_stime.tv_usec/1000); break;
  636.                 case 'P':
  637.                     if (real)
  638.                         fprintf(stderr,"%d%%",
  639.                             (int) (100*(ru->ru_utime.tv_sec+ru->ru_stime.tv_sec))
  640.                                 / real);
  641.                     break;
  642.                 case 'W': fprintf(stderr,"%ld",ru->ru_nswap); break;
  643. #ifdef sun
  644.                 case 'K': case 'D':
  645.                     fprintf(stderr,"%ld",ru->ru_idrss/ticks*pk); break;
  646.                 case 'M': fprintf(stderr,"%ld",ru->ru_maxrss*pk); break;
  647. #else
  648.                 case 'X': fprintf(stderr,"%ld",ru->ru_ixrss/sec); break;
  649.                 case 'D': fprintf(stderr,"%ld",
  650.                     (ru->ru_idrss+ru->ru_isrss)/sec); break;
  651.                 case 'K': fprintf(stderr,"%ld",
  652.                     (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss)/sec); break;
  653.                 case 'M': fprintf(stderr,"%ld",ru->ru_maxrss/1024); break;
  654. #endif
  655.                 case 'F': fprintf(stderr,"%ld",ru->ru_majflt); break;
  656.                 case 'R': fprintf(stderr,"%ld",ru->ru_minflt); break;
  657.                 case 'I': fprintf(stderr,"%ld",ru->ru_inblock); break;
  658.                 case 'O': fprintf(stderr,"%ld",ru->ru_oublock); break;
  659.                 case 'r': fprintf(stderr,"%ld",ru->ru_msgrcv); break;
  660.                 case 's': fprintf(stderr,"%ld",ru->ru_msgsnd); break;
  661.                 case 'k': fprintf(stderr,"%ld",ru->ru_nsignals); break;
  662.                 case 'w': fprintf(stderr,"%ld",ru->ru_nvcsw); break;
  663.                 case 'c': fprintf(stderr,"%ld",ru->ru_nivcsw); break;
  664. #endif
  665.                 case 'J': fprintf(stderr,"%s",desc); break;
  666.                 default: fprintf(stderr,"%%%c",*s); break;
  667.                 }
  668.         else
  669.             putc(*s,stderr);
  670.     putc('\n',stderr);
  671.     fflush(stderr);
  672. }
  673.  
  674. void dumptime(jn) /**/
  675. Job jn;
  676. {
  677. struct process *pn = jn->procs;
  678.  
  679.     if (!jn->procs)
  680.         return;
  681.     for (pn = jn->procs; pn; pn = pn->next)
  682.         printtime(pn->endtime-pn->bgtime,&pn->ti,pn->text);
  683. }
  684.  
  685. void shelltime() /**/
  686. {
  687. struct timeinfo ti;
  688. #ifdef HAS_RUSAGE
  689. struct rusage ru;
  690.  
  691.     getrusage(RUSAGE_SELF,&ru);
  692.     memcpy(&ti.ru,&ru,sizeof(ru));
  693.     printtime(time(NULL)-shtimer,&ti,"shell");
  694.  
  695.     getrusage(RUSAGE_CHILDREN,&ru);
  696.     memcpy(&ti.ru,&ru,sizeof(ru));
  697.     printtime(time(NULL)-shtimer,&ti,"children");
  698. #else
  699. struct tms buf;
  700.  
  701.     times(&buf);
  702.     ti.ut = buf.tms_utime;
  703.     ti.st = buf.tms_stime;
  704.     printtime(time(NULL)-shtimer,&ti,"shell");
  705.     ti.ut = buf.tms_cutime;
  706.     ti.st = buf.tms_cstime;
  707.     printtime(time(NULL)-shtimer,&ti,"children");
  708. #endif
  709. }
  710.  
  711. /* SIGHUP any jobs left running */
  712.  
  713. void killrunjobs() /**/
  714. {
  715. int t0,killed = 0;
  716.  
  717.     if (isset(NOHUP)) return;
  718.     for (t0 = 1; t0 != MAXJOB; t0++)
  719.         if (t0 != thisjob && (jobtab[t0].stat & STAT_LOCKED) &&
  720.                 !(jobtab[t0].stat & STAT_STOPPED)) {
  721.             if (killpg(jobtab[t0].gleader,SIGHUP) != -1) killed++;
  722.         }
  723.     if (killed) zerr("warning: %d jobs SIGHUPed",NULL,killed);
  724. }
  725.  
  726. /* check to see if user has jobs running/stopped */
  727.  
  728. void checkjobs() /**/
  729. {
  730. int t0;
  731.  
  732.     scanjobs();
  733.     for (t0 = 1; t0 != MAXJOB; t0++)
  734.         if (t0 != thisjob && jobtab[t0].stat & STAT_LOCKED)
  735.             break;
  736.     if (t0 != MAXJOB) {
  737.         if (jobtab[t0].stat & STAT_STOPPED) {
  738. #ifdef USE_SUSPENDED
  739.             zerr("you have suspended jobs.",NULL,0);
  740. #else
  741.             zerr("you have stopped jobs.",NULL,0);
  742. #endif
  743.         } else
  744.             zerr("you have running jobs.",NULL,0);
  745.         stopmsg = 1;
  746.     }
  747. }
  748.  
  749. /* send a signal to a job (simply involves kill if monitoring is on) */
  750.  
  751. int killjb(jn,sig) /**/
  752. Job jn;int sig;
  753. {
  754. struct process *pn;
  755. int err;
  756.  
  757.     if (jobbing)
  758.         return(killpg(jn->gleader,sig));
  759.     for (pn = jn->procs; pn; pn = pn->next)
  760.         if ((err = kill(pn->pid,sig)) == -1 && errno != ESRCH)
  761.             return -1;
  762.     return err;
  763. }
  764.  
  765.