openenvutils/commandshell/shell/src/jobs.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // jobs.c - job control
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "zsh.mdh"
       
    32 #include "jobs.pro"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #ifdef __WINSCW__
       
    36 #pragma warn_unusedarg off
       
    37 #pragma warn_possunwant off
       
    38 #endif//__WINSCW__
       
    39 #endif//__SYMBIAN32__
       
    40 
       
    41 #ifdef __SYMBIAN32__
       
    42 #include "dummy.h"
       
    43 #endif //__SYMBIAN32__
       
    44 
       
    45 /* the process group of the shell at startup (equal to mypgprp, except
       
    46    when we started without being process group leader */
       
    47 
       
    48 /**/
       
    49 mod_export pid_t origpgrp;
       
    50 
       
    51 /* the process group of the shell */
       
    52 
       
    53 /**/
       
    54 mod_export pid_t mypgrp;
       
    55  
       
    56 /* the job we are working on */
       
    57  
       
    58 /**/
       
    59 mod_export int thisjob;
       
    60 
       
    61 /* the current job (+) */
       
    62  
       
    63 /**/
       
    64 mod_export int curjob;
       
    65  
       
    66 /* the previous job (-) */
       
    67  
       
    68 /**/
       
    69 mod_export int prevjob;
       
    70  
       
    71 /* the job table */
       
    72  
       
    73 /**/
       
    74 mod_export struct job *jobtab;
       
    75 
       
    76 /* Size of the job table. */
       
    77 
       
    78 /**/
       
    79 mod_export int jobtabsize;
       
    80 
       
    81 /* The highest numbered job in the jobtable */
       
    82 
       
    83 /**/
       
    84 mod_export int maxjob;
       
    85 
       
    86 /* If we have entered a subshell, the original shell's job table. */
       
    87 static struct job *oldjobtab;
       
    88 
       
    89 /* The size of that. */
       
    90 static int oldmaxjob;
       
    91 
       
    92 /* shell timings */
       
    93  
       
    94 /**/
       
    95 #ifdef HAVE_GETRUSAGE
       
    96 /**/
       
    97 static struct rusage child_usage;
       
    98 /**/
       
    99 #else
       
   100 /**/
       
   101 static struct tms shtms;
       
   102 /**/
       
   103 #endif
       
   104  
       
   105 /* 1 if ttyctl -f has been executed */
       
   106  
       
   107 /**/
       
   108 int ttyfrozen;
       
   109 
       
   110 /* Previous values of errflag and breaks if the signal handler had to
       
   111  * change them. And a flag saying if it did that. */
       
   112 
       
   113 /**/
       
   114 int prev_errflag, prev_breaks, errbrk_saved;
       
   115 
       
   116 /**/
       
   117 int numpipestats, pipestats[MAX_PIPESTATS];
       
   118 
       
   119 /* Diff two timevals for elapsed-time computations */
       
   120 
       
   121 /**/
       
   122 static struct timeval *
       
   123 dtime(struct timeval *dt, struct timeval *t1, struct timeval *t2)
       
   124 {
       
   125     dt->tv_sec = t2->tv_sec - t1->tv_sec;
       
   126     dt->tv_usec = t2->tv_usec - t1->tv_usec;
       
   127     if (dt->tv_usec < 0) {
       
   128 	dt->tv_usec += 1000000.0;
       
   129 	dt->tv_sec -= 1.0;
       
   130     }
       
   131     return dt;
       
   132 }
       
   133 
       
   134 /* change job table entry from stopped to running */
       
   135 
       
   136 /**/
       
   137 void
       
   138 makerunning(Job jn)
       
   139 {
       
   140     Process pn;
       
   141 
       
   142     jn->stat &= ~STAT_STOPPED;
       
   143     for (pn = jn->procs; pn; pn = pn->next)
       
   144 #if 0
       
   145 	if (WIFSTOPPED(pn->status) && 
       
   146 	    (!(jn->stat & STAT_SUPERJOB) || pn->next))
       
   147 	    pn->status = SP_RUNNING;
       
   148 #endif
       
   149         if (WIFSTOPPED(pn->status))
       
   150 	    pn->status = SP_RUNNING;
       
   151 
       
   152     if (jn->stat & STAT_SUPERJOB)
       
   153 	makerunning(jobtab + jn->other);
       
   154 }
       
   155 
       
   156 /* Find process and job associated with pid.         *
       
   157  * Return 1 if search was successful, else return 0. */
       
   158 
       
   159 /**/
       
   160 int
       
   161 findproc(pid_t pid, Job *jptr, Process *pptr, int aux)
       
   162 {
       
   163     Process pn;
       
   164     int i;
       
   165 
       
   166     for (i = 1; i <= maxjob; i++)
       
   167     {
       
   168 	for (pn = aux ? jobtab[i].auxprocs : jobtab[i].procs;
       
   169 	     pn; pn = pn->next)
       
   170 	    if (pn->pid == pid) {
       
   171 		*pptr = pn;
       
   172 		*jptr = jobtab + i;
       
   173 		return 1;
       
   174 	    }
       
   175     }
       
   176 
       
   177     return 0;
       
   178 }
       
   179 
       
   180 /* Does the given job number have any processes? */
       
   181 
       
   182 /**/
       
   183 int
       
   184 hasprocs(int job)
       
   185 {
       
   186     Job jn = jobtab + job;
       
   187 
       
   188     return jn->procs || jn->auxprocs;
       
   189 }
       
   190 
       
   191 /* Find the super-job of a sub-job. */
       
   192 
       
   193 /**/
       
   194 static int
       
   195 super_job(int sub)
       
   196 {
       
   197     int i;
       
   198 
       
   199     for (i = 1; i <= maxjob; i++)
       
   200 	if ((jobtab[i].stat & STAT_SUPERJOB) &&
       
   201 	    jobtab[i].other == sub &&
       
   202 	    jobtab[i].gleader)
       
   203 	    return i;
       
   204     return 0;
       
   205 }
       
   206 
       
   207 /**/
       
   208 static int
       
   209 handle_sub(int job, int fg)
       
   210 {
       
   211     Job jn = jobtab + job, sj = jobtab + jn->other;
       
   212 
       
   213     if ((sj->stat & STAT_DONE) || (!sj->procs && !sj->auxprocs)) {
       
   214 	struct process *p;
       
   215 		    
       
   216 	for (p = sj->procs; p; p = p->next)
       
   217 	    if (WIFSIGNALED(p->status)) {
       
   218 		if (jn->gleader != mypgrp && jn->procs->next)
       
   219 		    killpg(jn->gleader, WTERMSIG(p->status));
       
   220 		else
       
   221 		    kill(jn->procs->pid, WTERMSIG(p->status));
       
   222 		kill(sj->other, SIGCONT);
       
   223 		kill(sj->other, WTERMSIG(p->status));
       
   224 		break;
       
   225 	    }
       
   226 	if (!p) {
       
   227 	    int cp;
       
   228 
       
   229 	    jn->stat &= ~STAT_SUPERJOB;
       
   230 	    jn->stat |= STAT_WASSUPER;
       
   231 
       
   232 	    if ((cp = ((WIFEXITED(jn->procs->status) ||
       
   233 			WIFSIGNALED(jn->procs->status)) &&
       
   234 		       killpg(jn->gleader, 0) == -1))) {
       
   235 		Process p;
       
   236 		for (p = jn->procs; p->next; p = p->next);
       
   237 		jn->gleader = p->pid;
       
   238 	    }
       
   239 	    /* This deleted the job too early if the parent
       
   240 	       shell waited for a command in a list that will
       
   241 	       be executed by the sub-shell (e.g.: if we have
       
   242 	       `ls|if true;then sleep 20;cat;fi' and ^Z the
       
   243 	       sleep, the rest will be executed by a sub-shell,
       
   244 	       but the parent shell gets notified for the
       
   245 	       sleep.
       
   246 	       deletejob(sj); */
       
   247 	    /* If this super-job contains only the sub-shell,
       
   248 	       we have to attach the tty to its process group
       
   249 	       now. */
       
   250 	    if ((fg || thisjob == job) &&
       
   251 		(!jn->procs->next || cp || jn->procs->pid != jn->gleader))
       
   252 		attachtty(jn->gleader);
       
   253 	    kill(sj->other, SIGCONT);
       
   254 	}
       
   255 	curjob = jn - jobtab;
       
   256     } else if (sj->stat & STAT_STOPPED) {
       
   257 	struct process *p;
       
   258 
       
   259 	jn->stat |= STAT_STOPPED;
       
   260 	for (p = jn->procs; p; p = p->next)
       
   261 	    if (p->status == SP_RUNNING ||
       
   262 		(!WIFEXITED(p->status) && !WIFSIGNALED(p->status)))
       
   263 		p->status = sj->procs->status;
       
   264 	curjob = jn - jobtab;
       
   265 	printjob(jn, !!isset(LONGLISTJOBS), 1);
       
   266 	return 1;
       
   267     }
       
   268     return 0;
       
   269 }
       
   270 
       
   271 
       
   272 /* Get the latest usage information */
       
   273 
       
   274 /**/
       
   275 void 
       
   276 get_usage(void)
       
   277 {
       
   278 #ifdef HAVE_GETRUSAGE
       
   279     getrusage(RUSAGE_CHILDREN, &child_usage);
       
   280 #else
       
   281     times(&shtms);
       
   282 #endif
       
   283 }
       
   284 
       
   285 
       
   286 #ifndef HAVE_GETRUSAGE
       
   287 /* Update status of process that we have just WAIT'ed for */
       
   288 
       
   289 /**/
       
   290 void
       
   291 update_process(Process pn, int status)
       
   292 {
       
   293     struct timezone dummy_tz;
       
   294     long childs, childu;
       
   295 
       
   296     childs = shtms.tms_cstime;
       
   297     childu = shtms.tms_cutime;
       
   298     /* get time-accounting info          */
       
   299     get_usage();
       
   300     gettimeofday(&pn->endtime, &dummy_tz);  /* record time process exited        */
       
   301 
       
   302     pn->status = status;                    /* save the status returned by WAIT  */
       
   303     pn->ti.st  = shtms.tms_cstime - childs; /* compute process system space time */
       
   304     pn->ti.ut  = shtms.tms_cutime - childu; /* compute process user space time   */
       
   305 }
       
   306 #endif
       
   307 
       
   308 /* Update status of job, possibly printing it */
       
   309 
       
   310 /**/
       
   311 void
       
   312 update_job(Job jn)
       
   313 {
       
   314     Process pn;
       
   315     int job;
       
   316     int val = 0, status = 0;
       
   317     int somestopped = 0, inforeground = 0;
       
   318 
       
   319     for (pn = jn->auxprocs; pn; pn = pn->next)
       
   320 	if (pn->status == SP_RUNNING)
       
   321 	    return;
       
   322 
       
   323     for (pn = jn->procs; pn; pn = pn->next) {
       
   324 	if (pn->status == SP_RUNNING)      /* some processes in this job are running       */
       
   325 	    return;                        /* so no need to update job table entry         */
       
   326 	if (WIFSTOPPED(pn->status))        /* some processes are stopped                   */
       
   327 	    somestopped = 1;               /* so job is not done, but entry needs updating */
       
   328 	if (!pn->next)                     /* last job in pipeline determines exit status  */
       
   329 	    val = (WIFSIGNALED(pn->status)) ? 0200 | WTERMSIG(pn->status) :
       
   330 		WEXITSTATUS(pn->status);
       
   331 	if (pn->pid == jn->gleader)        /* if this process is process group leader      */
       
   332 	    status = pn->status;
       
   333     }
       
   334 
       
   335     job = jn - jobtab;   /* compute job number */
       
   336 
       
   337     if (somestopped) {
       
   338 	if (jn->stty_in_env && !jn->ty) {
       
   339 	    jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
       
   340 	    gettyinfo(jn->ty);
       
   341 	}
       
   342 	if (jn->stat & STAT_STOPPED) {
       
   343 	    if (jn->stat & STAT_SUBJOB) {
       
   344 		/* If we have `cat foo|while read a; grep $a bar;done'
       
   345 		 * and have hit ^Z, the sub-job is stopped, but the
       
   346 		 * super-job may still be running, waiting to be stopped
       
   347 		 * or to exit. So we have to send it a SIGTSTP. */
       
   348 		int i;
       
   349 
       
   350 		if ((i = super_job(job)))
       
   351 		    killpg(jobtab[i].gleader, SIGTSTP);
       
   352 	    }
       
   353 	    return;
       
   354 	}
       
   355     }
       
   356     {                   /* job is done or stopped, remember return value */
       
   357 	lastval2 = val;
       
   358 	/* If last process was run in the current shell, keep old status
       
   359 	 * and let it handle its own traps, but always allow the test
       
   360 	 * for the pgrp.
       
   361 	 */
       
   362 	if (jn->stat & STAT_CURSH)
       
   363 	    inforeground = 1;
       
   364 	else if (job == thisjob) {
       
   365 	    lastval = val;
       
   366 	    inforeground = 2;
       
   367 	}
       
   368     }
       
   369 
       
   370     if (shout && shout != stderr && !ttyfrozen && !jn->stty_in_env &&
       
   371 	!zleactive && job == thisjob && !somestopped &&
       
   372 	!(jn->stat & STAT_NOSTTY)) 
       
   373 	gettyinfo(&shttyinfo);
       
   374 
       
   375     if (isset(MONITOR)) {
       
   376 	pid_t pgrp = gettygrp();           /* get process group of tty      */
       
   377 
       
   378 	/* is this job in the foreground of an interactive shell? */
       
   379 	if (mypgrp != pgrp && inforeground &&
       
   380 	    (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
       
   381 	    if (list_pipe) {
       
   382 		if (somestopped || (pgrp > 1 && kill(-pgrp, 0) == -1)) {
       
   383 		    attachtty(mypgrp);
       
   384 		    /* check window size and adjust if necessary */
       
   385 		    adjustwinsize(0);
       
   386 		} else {
       
   387 		    /*
       
   388 		     * Oh, dear, we're right in the middle of some confusion
       
   389 		     * of shell jobs on the righthand side of a pipeline, so
       
   390 		     * it's death to call attachtty() just yet.  Mark the
       
   391 		     * fact in the job, so that the attachtty() will be called
       
   392 		     * when the job is finally deleted.
       
   393 		     */
       
   394 		    jn->stat |= STAT_ATTACH;
       
   395 		}
       
   396 		/* If we have `foo|while true; (( x++ )); done', and hit
       
   397 		 * ^C, we have to stop the loop, too. */
       
   398 		if ((val & 0200) && inforeground == 1) {
       
   399 		    if (!errbrk_saved) {
       
   400 			errbrk_saved = 1;
       
   401 			prev_breaks = breaks;
       
   402 			prev_errflag = errflag;
       
   403 		    }
       
   404 		    breaks = loops;
       
   405 		    errflag = 1;
       
   406 		    inerrflush();
       
   407 		}
       
   408 	    } else {
       
   409 		attachtty(mypgrp);
       
   410 		/* check window size and adjust if necessary */
       
   411 		adjustwinsize(0);
       
   412 	    }
       
   413 	}
       
   414     } else if (list_pipe && (val & 0200) && inforeground == 1) {
       
   415 	if (!errbrk_saved) {
       
   416 	    errbrk_saved = 1;
       
   417 	    prev_breaks = breaks;
       
   418 	    prev_errflag = errflag;
       
   419 	}
       
   420 	breaks = loops;
       
   421 	errflag = 1;
       
   422 	inerrflush();
       
   423     }
       
   424     if (somestopped && jn->stat & STAT_SUPERJOB)
       
   425 	return;
       
   426     jn->stat |= (somestopped) ? STAT_CHANGED | STAT_STOPPED :
       
   427 	STAT_CHANGED | STAT_DONE;
       
   428     if (job == thisjob && (jn->stat & STAT_DONE)) {
       
   429 	int i;
       
   430 	Process p;
       
   431 
       
   432 	for (p = jn->procs, i = 0; p && i < MAX_PIPESTATS; p = p->next, i++)
       
   433 	    pipestats[i] = ((WIFSIGNALED(p->status)) ?
       
   434 			    0200 | WTERMSIG(p->status) :
       
   435 			    WEXITSTATUS(p->status));
       
   436 	if ((jn->stat & STAT_CURSH) && i < MAX_PIPESTATS)
       
   437 	    pipestats[i++] = lastval;
       
   438 	numpipestats = i;
       
   439     }
       
   440     if (!inforeground &&
       
   441 	(jn->stat & (STAT_SUBJOB | STAT_DONE)) == (STAT_SUBJOB | STAT_DONE)) {
       
   442 	int su;
       
   443 
       
   444 	if ((su = super_job(jn - jobtab)))
       
   445 	    handle_sub(su, 0);
       
   446     }
       
   447     if ((jn->stat & (STAT_DONE | STAT_STOPPED)) == STAT_STOPPED) {
       
   448 	prevjob = curjob;
       
   449 	curjob = job;
       
   450     }
       
   451     if ((isset(NOTIFY) || job == thisjob) && (jn->stat & STAT_LOCKED)) {
       
   452 	printjob(jn, !!isset(LONGLISTJOBS), 0);
       
   453 	if (zleactive)
       
   454 	    zrefresh();
       
   455     }
       
   456     if (sigtrapped[SIGCHLD] && job != thisjob)
       
   457 	dotrap(SIGCHLD);
       
   458 
       
   459     /* When MONITOR is set, the foreground process runs in a different *
       
   460      * process group from the shell, so the shell will not receive     *
       
   461      * terminal signals, therefore we we pretend that the shell got    *
       
   462      * the signal too.                                                 */
       
   463     if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) {
       
   464 	int sig = WTERMSIG(status);
       
   465 
       
   466 	if (sig == SIGINT || sig == SIGQUIT) {
       
   467 	    if (sigtrapped[sig]) {
       
   468 		dotrap(sig);
       
   469 		/* We keep the errflag as set or not by dotrap.
       
   470 		 * This is to fulfil the promise to carry on
       
   471 		 * with the jobs if trap returns zero.
       
   472 		 * Setting breaks = loops ensures a consistent return
       
   473 		 * status if inside a loop.  Maybe the code in loops
       
   474 		 * should be changed.
       
   475 		 */
       
   476 		if (errflag)
       
   477 		    breaks = loops;
       
   478 	    } else {
       
   479 		breaks = loops;
       
   480 		errflag = 1;
       
   481 	    }
       
   482 	}
       
   483     }
       
   484 }
       
   485 
       
   486 /* set the previous job to something reasonable */
       
   487 
       
   488 /**/
       
   489 static void
       
   490 setprevjob(void)
       
   491 {
       
   492     int i;
       
   493 
       
   494     for (i = maxjob; i; i--)
       
   495 	if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) &&
       
   496 	    !(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) {
       
   497 	    prevjob = i;
       
   498 	    return;
       
   499 	}
       
   500 
       
   501     for (i = maxjob; i; i--)
       
   502 	if ((jobtab[i].stat & STAT_INUSE) && !(jobtab[i].stat & STAT_SUBJOB) &&
       
   503 	    i != curjob && i != thisjob) {
       
   504 	    prevjob = i;
       
   505 	    return;
       
   506 	}
       
   507 
       
   508     prevjob = -1;
       
   509 }
       
   510 
       
   511 /**/
       
   512 #ifndef HAVE_GETRUSAGE
       
   513 static long clktck = 0;
       
   514 
       
   515 /**/
       
   516 static void
       
   517 set_clktck(void)
       
   518 {
       
   519 #ifdef _SC_CLK_TCK
       
   520     if (!clktck)
       
   521 	/* fetch clock ticks per second from *
       
   522 	 * sysconf only the first time       */
       
   523 	clktck = sysconf(_SC_CLK_TCK);
       
   524 #else
       
   525 # ifdef __NeXT__
       
   526     /* NeXTStep 3.3 defines CLK_TCK wrongly */
       
   527     clktck = 60;
       
   528 # else
       
   529 #  ifdef CLK_TCK
       
   530     clktck = CLK_TCK;
       
   531 #  else
       
   532 #   ifdef HZ
       
   533      clktck = HZ;
       
   534 #   else
       
   535      clktck = 60;
       
   536 #   endif
       
   537 #  endif
       
   538 # endif
       
   539 #endif
       
   540 }
       
   541 /**/
       
   542 #endif
       
   543 
       
   544 /**/
       
   545 static void
       
   546 printhhmmss(double secs)
       
   547 {
       
   548     int mins = (int) secs / 60;
       
   549     int hours = mins / 60;
       
   550 
       
   551     secs -= 60 * mins;
       
   552     mins -= 60 * hours;
       
   553     if (hours)
       
   554 	fprintf(stderr, "%d:%02d:%05.2f", hours, mins, secs);
       
   555     else if (mins)
       
   556 	fprintf(stderr,      "%d:%05.2f",        mins, secs);
       
   557     else
       
   558 	fprintf(stderr,           "%.3f",              secs);
       
   559 }
       
   560 
       
   561 static void
       
   562 printtime(struct timeval *real, child_times_t *ti, char *desc)
       
   563 {
       
   564     char *s;
       
   565     double elapsed_time, user_time, system_time;
       
   566 #ifdef HAVE_GETRUSAGE
       
   567     double total_time;
       
   568 #endif
       
   569     int percent;
       
   570 
       
   571     if (!desc)
       
   572 	desc = "";
       
   573 
       
   574     /* go ahead and compute these, since almost every TIMEFMT will have them */
       
   575     elapsed_time = real->tv_sec + real->tv_usec / 1000000.0;
       
   576 
       
   577 #ifdef HAVE_GETRUSAGE
       
   578     user_time = ti->ru_utime.tv_sec + ti->ru_utime.tv_usec / 1000000.0;
       
   579     system_time = ti->ru_stime.tv_sec + ti->ru_stime.tv_usec / 1000000.0;
       
   580     total_time = user_time + system_time;
       
   581     percent = 100.0 * total_time
       
   582 	/ (real->tv_sec + real->tv_usec / 1000000.0);
       
   583 #else
       
   584     set_clktck();
       
   585     user_time    = ti->ut / (double) clktck;
       
   586     system_time  = ti->st / (double) clktck;
       
   587     percent      =  100.0 * (ti->ut + ti->st)
       
   588 	/ (clktck * real->tv_sec + clktck * real->tv_usec / 1000000.0);
       
   589 #endif
       
   590 
       
   591     queue_signals();
       
   592     if (!(s = getsparam("TIMEFMT")))
       
   593 	s = DEFAULT_TIMEFMT;
       
   594 
       
   595     for (; *s; s++)
       
   596 	if (*s == '%')
       
   597 	    switch (*++s) {
       
   598 	    case 'E':
       
   599 		fprintf(stderr, "%4.2fs", elapsed_time);
       
   600 		break;
       
   601 	    case 'U':
       
   602 		fprintf(stderr, "%4.2fs", user_time);
       
   603 		break;
       
   604 	    case 'S':
       
   605 		fprintf(stderr, "%4.2fs", system_time);
       
   606 		break;
       
   607 	    case '*':
       
   608 		switch (*++s) {
       
   609 		case 'E':
       
   610 		    printhhmmss(elapsed_time);
       
   611 		    break;
       
   612 		case 'U':
       
   613 		    printhhmmss(user_time);
       
   614 		    break;
       
   615 		case 'S':
       
   616 		    printhhmmss(system_time);
       
   617 		    break;
       
   618 		default:
       
   619 		    fprintf(stderr, "%%*");
       
   620 		    s--;
       
   621 		    break;
       
   622 		}
       
   623 		break;
       
   624 	    case 'P':
       
   625 		fprintf(stderr, "%d%%", percent);
       
   626 		break;
       
   627 #ifdef HAVE_STRUCT_RUSAGE_RU_NSWAP
       
   628 	    case 'W':
       
   629 		fprintf(stderr, "%ld", ti->ru_nswap);
       
   630 		break;
       
   631 #endif
       
   632 #ifdef HAVE_STRUCT_RUSAGE_RU_IXRSS
       
   633 	    case 'X':
       
   634 		fprintf(stderr, "%ld", (long)(ti->ru_ixrss / total_time));
       
   635 		break;
       
   636 #endif
       
   637 #ifdef HAVE_STRUCT_RUSAGE_RU_IDRSS
       
   638 	    case 'D':
       
   639 		fprintf(stderr, "%ld",
       
   640 			(long) ((ti->ru_idrss
       
   641 #ifdef HAVE_STRUCT_RUSAGE_RU_ISRSS
       
   642 				 + ti->ru_isrss
       
   643 #endif
       
   644 				    ) / total_time));
       
   645 		break;
       
   646 #endif
       
   647 #if defined(HAVE_STRUCT_RUSAGE_RU_IDRSS) || \
       
   648     defined(HAVE_STRUCT_RUSAGE_RU_ISRSS) || \
       
   649     defined(HAVE_STRUCT_RUSAGE_RU_IXRSS)
       
   650 	    case 'K':
       
   651 		/* treat as D if X not available */
       
   652 		fprintf(stderr, "%ld",
       
   653 			(long) ((
       
   654 #ifdef HAVE_STRUCT_RUSAGE_RU_IXRSS
       
   655 				    ti->ru_ixrss
       
   656 #else
       
   657 				    0
       
   658 #endif
       
   659 #ifdef HAVE_STRUCT_RUSAGE_RU_IDRSS
       
   660 				    + ti->ru_idrss
       
   661 #endif
       
   662 #ifdef HAVE_STRUCT_RUSAGE_RU_ISRSS
       
   663 				    + ti->ru_isrss
       
   664 #endif
       
   665 				    ) / total_time));
       
   666 		break;
       
   667 #endif
       
   668 #ifdef HAVE_STRUCT_RUSAGE_RU_MAXRSS
       
   669 	    case 'M':
       
   670 		fprintf(stderr, "%ld", ti->ru_maxrss / 1024);
       
   671 		break;
       
   672 #endif
       
   673 #ifdef HAVE_STRUCT_RUSAGE_RU_MAJFLT
       
   674 	    case 'F':
       
   675 		fprintf(stderr, "%ld", ti->ru_majflt);
       
   676 		break;
       
   677 #endif
       
   678 #ifdef HAVE_STRUCT_RUSAGE_RU_MINFLT
       
   679 	    case 'R':
       
   680 		fprintf(stderr, "%ld", ti->ru_minflt);
       
   681 		break;
       
   682 #endif
       
   683 #ifdef HAVE_STRUCT_RUSAGE_RU_INBLOCK
       
   684 	    case 'I':
       
   685 		fprintf(stderr, "%ld", ti->ru_inblock);
       
   686 		break;
       
   687 #endif
       
   688 #ifdef HAVE_STRUCT_RUSAGE_RU_OUBLOCK
       
   689 	    case 'O':
       
   690 		fprintf(stderr, "%ld", ti->ru_oublock);
       
   691 		break;
       
   692 #endif
       
   693 #ifdef HAVE_STRUCT_RUSAGE_RU_MSGRCV
       
   694 	    case 'r':
       
   695 		fprintf(stderr, "%ld", ti->ru_msgrcv);
       
   696 		break;
       
   697 #endif
       
   698 #ifdef HAVE_STRUCT_RUSAGE_RU_MSGSND
       
   699 	    case 's':
       
   700 		fprintf(stderr, "%ld", ti->ru_msgsnd);
       
   701 		break;
       
   702 #endif
       
   703 #ifdef HAVE_STRUCT_RUSAGE_RU_NSIGNALS
       
   704 	    case 'k':
       
   705 		fprintf(stderr, "%ld", ti->ru_nsignals);
       
   706 		break;
       
   707 #endif
       
   708 #ifdef HAVE_STRUCT_RUSAGE_RU_NVCSW
       
   709 	    case 'w':
       
   710 		fprintf(stderr, "%ld", ti->ru_nvcsw);
       
   711 		break;
       
   712 #endif
       
   713 #ifdef HAVE_STRUCT_RUSAGE_RU_NIVCSW
       
   714 	    case 'c':
       
   715 		fprintf(stderr, "%ld", ti->ru_nivcsw);
       
   716 		break;
       
   717 #endif
       
   718 	    case 'J':
       
   719 		fprintf(stderr, "%s", desc);
       
   720 		break;
       
   721 	    case '%':
       
   722 		putc('%', stderr);
       
   723 		break;
       
   724 	    case '\0':
       
   725 		s--;
       
   726 		break;
       
   727 	    default:
       
   728 		fprintf(stderr, "%%%c", *s);
       
   729 		break;
       
   730 	} else
       
   731 	    putc(*s, stderr);
       
   732     unqueue_signals();
       
   733     putc('\n', stderr);
       
   734     fflush(stderr);
       
   735 }
       
   736 
       
   737 /**/
       
   738 static void
       
   739 dumptime(Job jn)
       
   740 {
       
   741     Process pn;
       
   742     struct timeval dtimeval;
       
   743 
       
   744     if (!jn->procs)
       
   745 	return;
       
   746     for (pn = jn->procs; pn; pn = pn->next)
       
   747 	printtime(dtime(&dtimeval, &pn->bgtime, &pn->endtime), &pn->ti,
       
   748 		  pn->text);
       
   749 }
       
   750 
       
   751 /* Check whether shell should report the amount of time consumed   *
       
   752  * by job.  This will be the case if we have preceded the command  *
       
   753  * with the keyword time, or if REPORTTIME is non-negative and the *
       
   754  * amount of time consumed by the job is greater than REPORTTIME   */
       
   755 
       
   756 /**/
       
   757 static int
       
   758 should_report_time(Job j)
       
   759 {
       
   760     struct value vbuf;
       
   761     Value v;
       
   762     char *s = "REPORTTIME";
       
   763     zlong reporttime;
       
   764 
       
   765     /* if the time keyword was used */
       
   766     if (j->stat & STAT_TIMED)
       
   767 	return 1;
       
   768 
       
   769     queue_signals();
       
   770     if (!(v = getvalue(&vbuf, &s, 0)) ||
       
   771 	(reporttime = getintvalue(v)) < 0) {
       
   772 	unqueue_signals();
       
   773 	return 0;
       
   774     }
       
   775     unqueue_signals();
       
   776     /* can this ever happen? */
       
   777     if (!j->procs)
       
   778 	return 0;
       
   779 
       
   780 #ifdef HAVE_GETRUSAGE
       
   781     reporttime -= j->procs->ti.ru_utime.tv_sec + j->procs->ti.ru_stime.tv_sec;
       
   782     if (j->procs->ti.ru_utime.tv_usec +
       
   783 	j->procs->ti.ru_stime.tv_usec >= 1000000)
       
   784 	reporttime--;
       
   785     return reporttime <= 0;
       
   786 #else
       
   787     set_clktck();
       
   788     return ((j->procs->ti.ut + j->procs->ti.st) / clktck >= reporttime);
       
   789 #endif
       
   790 }
       
   791 
       
   792 /* !(lng & 3) means jobs    *
       
   793  *  (lng & 1) means jobs -l *
       
   794  *  (lng & 2) means jobs -p
       
   795  *  (lng & 4) means jobs -d
       
   796  *
       
   797  * synch = 0 means asynchronous
       
   798  * synch = 1 means synchronous
       
   799  * synch = 2 means called synchronously from jobs
       
   800 */
       
   801 
       
   802 /**/
       
   803 void
       
   804 printjob(Job jn, int lng, int synch)
       
   805 {
       
   806     Process pn;
       
   807     int job, len = 9, sig, sflag = 0, llen;
       
   808     int conted = 0, lineleng = columns, skip = 0, doputnl = 0;
       
   809     FILE *fout = (synch == 2) ? stdout : shout;
       
   810 
       
   811     if (jn->stat & STAT_NOPRINT)
       
   812 	return;
       
   813 
       
   814     /*
       
   815      * Wow, what a hack.  Did I really write this? --- pws
       
   816      */
       
   817     if (jn < jobtab || jn >= jobtab + jobtabsize)
       
   818 	job = jn - oldjobtab;
       
   819     else
       
   820 	job = jn - jobtab;
       
   821 
       
   822     if (lng < 0) {
       
   823 	conted = 1;
       
   824 	lng = 0;
       
   825     }
       
   826 
       
   827 /* find length of longest signame, check to see */
       
   828 /* if we really need to print this job          */
       
   829 
       
   830     for (pn = jn->procs; pn; pn = pn->next) {
       
   831 	if (jn->stat & STAT_SUPERJOB &&
       
   832 	    jn->procs->status == SP_RUNNING && !pn->next)
       
   833 	    pn->status = SP_RUNNING;
       
   834 	if (pn->status != SP_RUNNING) {
       
   835 	    if (WIFSIGNALED(pn->status)) {
       
   836 		sig = WTERMSIG(pn->status);
       
   837 		llen = strlen(sigmsg(sig));
       
   838 		if (WCOREDUMP(pn->status))
       
   839 		    llen += 14;
       
   840 		if (llen > len)
       
   841 		    len = llen;
       
   842 		if (sig != SIGINT && sig != SIGPIPE)
       
   843 		    sflag = 1;
       
   844 		if (job == thisjob && sig == SIGINT)
       
   845 		    doputnl = 1;
       
   846 	    } else if (WIFSTOPPED(pn->status)) {
       
   847 		sig = WSTOPSIG(pn->status);
       
   848 		if ((int)strlen(sigmsg(sig)) > len)
       
   849 		    len = strlen(sigmsg(sig));
       
   850 		if (job == thisjob && sig == SIGTSTP)
       
   851 		    doputnl = 1;
       
   852 	    } else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
       
   853 		       WEXITSTATUS(pn->status))
       
   854 		sflag = 1;
       
   855 	}
       
   856     }
       
   857 
       
   858 /* print if necessary: ignore option state on explicit call to `jobs'. */
       
   859 
       
   860     if (synch == 2 || 
       
   861 	(interact && jobbing &&
       
   862 	 ((jn->stat & STAT_STOPPED) || sflag || job != thisjob))) {
       
   863 	int len2, fline = 1;
       
   864 	/* use special format for current job, except in `jobs' */
       
   865 	int thisfmt = job == thisjob && synch != 2;
       
   866 	Process qn;
       
   867 
       
   868 	if (!synch)
       
   869 	    trashzle();
       
   870 	if (doputnl && !synch)
       
   871 	    putc('\n', fout);
       
   872 	for (pn = jn->procs; pn;) {
       
   873 	    len2 = (thisfmt ? 5 : 10) + len;	/* 2 spaces */
       
   874 	    if (lng & 3)
       
   875 		qn = pn->next;
       
   876 	    else
       
   877 		for (qn = pn->next; qn; qn = qn->next) {
       
   878 		    if (qn->status != pn->status)
       
   879 			break;
       
   880 		    if ((int)strlen(qn->text) + len2 + ((qn->next) ? 3 : 0) > lineleng)
       
   881 			break;
       
   882 		    len2 += strlen(qn->text) + 2;
       
   883 		}
       
   884 	    if (!thisfmt) {
       
   885 		if (fline)
       
   886 		    fprintf(fout, "[%ld]  %c ",
       
   887 			    (long)job,
       
   888 			    (job == curjob) ? '+'
       
   889 			    : (job == prevjob) ? '-' : ' ');
       
   890 		else
       
   891 		    fprintf(fout, (job > 9) ? "        " : "       ");
       
   892 	    } else
       
   893 		fprintf(fout, "zsh: ");
       
   894 	    if (lng & 1)
       
   895 		fprintf(fout, "%ld ", (long) pn->pid);
       
   896 	    else if (lng & 2) {
       
   897 		pid_t x = jn->gleader;
       
   898 
       
   899 		fprintf(fout, "%ld ", (long) x);
       
   900 		do
       
   901 		    skip++;
       
   902 		while ((x /= 10));
       
   903 		skip++;
       
   904 		lng &= ~3;
       
   905 	    } else
       
   906 		fprintf(fout, "%*s", skip, "");
       
   907 	    if (pn->status == SP_RUNNING) {
       
   908 		if (!conted)
       
   909 		    fprintf(fout, "running%*s", len - 7 + 2, "");
       
   910 		else
       
   911 		    fprintf(fout, "continued%*s", len - 9 + 2, "");
       
   912 	    }
       
   913 	    else if (WIFEXITED(pn->status)) {
       
   914 		if (WEXITSTATUS(pn->status))
       
   915 		    fprintf(fout, "exit %-4d%*s", WEXITSTATUS(pn->status),
       
   916 			    len - 9 + 2, "");
       
   917 		else
       
   918 		    fprintf(fout, "done%*s", len - 4 + 2, "");
       
   919 	    } else if (WIFSTOPPED(pn->status))
       
   920 		fprintf(fout, "%-*s", len + 2, sigmsg(WSTOPSIG(pn->status)));
       
   921 	    else if (WCOREDUMP(pn->status))
       
   922 		fprintf(fout, "%s (core dumped)%*s",
       
   923 			sigmsg(WTERMSIG(pn->status)),
       
   924 			(int)(len - 14 + 2 - strlen(sigmsg(WTERMSIG(pn->status)))), "");
       
   925 	    else
       
   926 		fprintf(fout, "%-*s", len + 2, sigmsg(WTERMSIG(pn->status)));
       
   927 	    for (; pn != qn; pn = pn->next)
       
   928 		fprintf(fout, (pn->next) ? "%s | " : "%s", pn->text);
       
   929 	    putc('\n', fout);
       
   930 	    fline = 0;
       
   931 	}
       
   932 	fflush(fout);
       
   933     } else if (doputnl && interact && !synch) {
       
   934 	putc('\n', fout);
       
   935 	fflush(fout);
       
   936     }
       
   937 
       
   938 /* print "(pwd now: foo)" messages: with (lng & 4) we are printing
       
   939  * the directory where the job is running, otherwise the current directory
       
   940  */
       
   941 
       
   942     if ((lng & 4) || (interact && job == thisjob &&
       
   943 		      jn->pwd && strcmp(jn->pwd, pwd))) {
       
   944 	fprintf(shout, "(pwd %s: ", (lng & 4) ? "" : "now");
       
   945 	fprintdir(((lng & 4) && jn->pwd) ? jn->pwd : pwd, shout);
       
   946 	fprintf(shout, ")\n");
       
   947 	fflush(shout);
       
   948     }
       
   949 /* delete job if done */
       
   950 
       
   951     if (jn->stat & STAT_DONE) {
       
   952 	if (should_report_time(jn))
       
   953 	    dumptime(jn);
       
   954 	deletejob(jn);
       
   955 	if (job == curjob) {
       
   956 	    curjob = prevjob;
       
   957 	    prevjob = job;
       
   958 	}
       
   959 	if (job == prevjob)
       
   960 	    setprevjob();
       
   961     } else
       
   962 	jn->stat &= ~STAT_CHANGED;
       
   963 }
       
   964 
       
   965 /**/
       
   966 void
       
   967 deletefilelist(LinkList file_list)
       
   968 {
       
   969     char *s;
       
   970     if (file_list) {
       
   971 	while ((s = (char *)getlinknode(file_list))) {
       
   972 	    unlink(s);
       
   973 	    zsfree(s);
       
   974 	}
       
   975 	zfree(file_list, sizeof(struct linklist));
       
   976     }
       
   977 }
       
   978 
       
   979 /**/
       
   980 void
       
   981 freejob(Job jn, int deleting)
       
   982 {
       
   983     struct process *pn, *nx;
       
   984 
       
   985     pn = jn->procs;
       
   986     jn->procs = NULL;
       
   987     for (; pn; pn = nx) {
       
   988 	nx = pn->next;
       
   989 	zfree(pn, sizeof(struct process));
       
   990     }
       
   991 
       
   992     pn = jn->auxprocs;
       
   993     jn->auxprocs = NULL;
       
   994     for (; pn; pn = nx) {
       
   995 	nx = pn->next;
       
   996 	zfree(pn, sizeof(struct process));
       
   997     }
       
   998 
       
   999     if (jn->ty)
       
  1000 	zfree(jn->ty, sizeof(struct ttyinfo));
       
  1001     if (jn->pwd)
       
  1002 	zsfree(jn->pwd);
       
  1003     jn->pwd = NULL;
       
  1004     if (jn->stat & STAT_WASSUPER) {
       
  1005 	/* careful in case we shrink and move the job table */
       
  1006 	int job = jn - jobtab;
       
  1007 	if (deleting)
       
  1008 	    deletejob(jobtab + jn->other);
       
  1009 	else
       
  1010 	    freejob(jobtab + jn->other, 0);
       
  1011 	jn = jobtab + job;
       
  1012     }
       
  1013     jn->gleader = jn->other = 0;
       
  1014     jn->stat = jn->stty_in_env = 0;
       
  1015     jn->filelist = NULL;
       
  1016     jn->ty = NULL;
       
  1017 
       
  1018     /* Find the new highest job number. */
       
  1019     if (maxjob == jn - jobtab) {
       
  1020 	while (maxjob && !(jobtab[maxjob].stat & STAT_INUSE))
       
  1021 	    maxjob--;
       
  1022     }
       
  1023 }
       
  1024 
       
  1025 /*
       
  1026  * We are actually finished with this job, rather
       
  1027  * than freeing it to make space.
       
  1028  */
       
  1029 
       
  1030 /**/
       
  1031 void
       
  1032 deletejob(Job jn)
       
  1033 {
       
  1034     deletefilelist(jn->filelist);
       
  1035     if (jn->stat & STAT_ATTACH) {
       
  1036 	attachtty(mypgrp);
       
  1037 	adjustwinsize(0);
       
  1038     }
       
  1039 
       
  1040     freejob(jn, 1);
       
  1041 }
       
  1042 
       
  1043 /*
       
  1044  * Add a process to the current job.
       
  1045  * The third argument is 1 if we are adding a process which is not
       
  1046  * part of the main pipeline but an auxiliary process used for
       
  1047  * handling MULTIOS or process substitution.  We will wait for it
       
  1048  * but not display job information about it.
       
  1049  */
       
  1050 
       
  1051 /**/
       
  1052 void
       
  1053 addproc(pid_t pid, char *text, int aux, struct timeval *bgtime)
       
  1054 {
       
  1055     Process pn, *pnlist;
       
  1056 
       
  1057     DPUTS(thisjob == -1, "No valid job in addproc.");
       
  1058     pn = (Process) zshcalloc(sizeof *pn);
       
  1059     pn->pid = pid;
       
  1060     if (text)
       
  1061 	strcpy(pn->text, text);
       
  1062     else
       
  1063 	*pn->text = '\0';
       
  1064     pn->status = SP_RUNNING;
       
  1065     pn->next = NULL;
       
  1066 
       
  1067     if (!aux)
       
  1068     {
       
  1069 	pn->bgtime = *bgtime;
       
  1070 	/* if this is the first process we are adding to *
       
  1071 	 * the job, then it's the group leader.          */
       
  1072 	if (!jobtab[thisjob].gleader)
       
  1073 	    jobtab[thisjob].gleader = pid;
       
  1074 	/* attach this process to end of process list of current job */
       
  1075 	pnlist = &jobtab[thisjob].procs;
       
  1076     }
       
  1077     else
       
  1078 	pnlist = &jobtab[thisjob].auxprocs;
       
  1079 
       
  1080     if (*pnlist) {
       
  1081 	Process n;
       
  1082 
       
  1083 	for (n = *pnlist; n->next; n = n->next);
       
  1084 	n->next = pn;
       
  1085     } else {
       
  1086 	/* first process for this job */
       
  1087 	*pnlist = pn;
       
  1088     }
       
  1089     /* If the first process in the job finished before any others were *
       
  1090      * added, maybe STAT_DONE got set incorrectly.  This can happen if *
       
  1091      * a $(...) was waited for and the last existing job in the        *
       
  1092      * pipeline was already finished.  We need to be very careful that *
       
  1093      * there was no call to printjob() between then and now, else      *
       
  1094      * the job will already have been deleted from the table.          */
       
  1095     jobtab[thisjob].stat &= ~STAT_DONE;
       
  1096 }
       
  1097 
       
  1098 /* Check if we have files to delete.  We need to check this to see *
       
  1099  * if it's all right to exec a command without forking in the last *
       
  1100  * component of subshells or after the `-c' option.                */
       
  1101 
       
  1102 /**/
       
  1103 int
       
  1104 havefiles(void)
       
  1105 {
       
  1106     int i;
       
  1107 
       
  1108     for (i = 1; i <= maxjob; i++)
       
  1109 	if (jobtab[i].stat && jobtab[i].filelist)
       
  1110 	    return 1;
       
  1111     return 0;
       
  1112 
       
  1113 }
       
  1114 
       
  1115 /* wait for a particular process */
       
  1116 
       
  1117 /**/
       
  1118 void
       
  1119 waitforpid(pid_t pid)
       
  1120 {
       
  1121     int first = 1, q = queue_signal_level();
       
  1122 
       
  1123     /* child_block() around this loop in case #ifndef WNOHANG */
       
  1124     dont_queue_signals();
       
  1125     child_block();		/* unblocked in signal_suspend() */
       
  1126     while (!errflag && (kill(pid, 0) >= 0 || errno != ESRCH)) {
       
  1127 	if (first)
       
  1128 	    first = 0;
       
  1129 	else
       
  1130 	    kill(pid, SIGCONT);
       
  1131 
       
  1132 	signal_suspend(SIGCHLD, SIGINT);
       
  1133 	child_block();
       
  1134     }
       
  1135     child_unblock();
       
  1136     restore_queue_signals(q);
       
  1137 }
       
  1138 
       
  1139 /* wait for a job to finish */
       
  1140 
       
  1141 /**/
       
  1142 static void
       
  1143 zwaitjob(int job, int sig)
       
  1144 {
       
  1145     int q = queue_signal_level();
       
  1146     Job jn = jobtab + job;
       
  1147 
       
  1148     dont_queue_signals();
       
  1149     child_block();		 /* unblocked during signal_suspend() */
       
  1150     if (jn->procs || jn->auxprocs) { /* if any forks were done         */
       
  1151 	jn->stat |= STAT_LOCKED;
       
  1152 	if (jn->stat & STAT_CHANGED)
       
  1153 	    printjob(jn, !!isset(LONGLISTJOBS), 1);
       
  1154 	while (!errflag && jn->stat &&
       
  1155 	       !(jn->stat & STAT_DONE) &&
       
  1156 	       !(interact && (jn->stat & STAT_STOPPED))) {
       
  1157 	    signal_suspend(SIGCHLD, sig);
       
  1158 	    /* Commenting this out makes ^C-ing a job started by a function
       
  1159 	       stop the whole function again.  But I guess it will stop
       
  1160 	       something else from working properly, we have to find out
       
  1161 	       what this might be.  --oberon
       
  1162 
       
  1163 	    errflag = 0; */
       
  1164 	    if (subsh) {
       
  1165 		killjb(jn, SIGCONT);
       
  1166 		jn->stat &= ~STAT_STOPPED;
       
  1167 	    }
       
  1168 	    if (jn->stat & STAT_SUPERJOB)
       
  1169 		if (handle_sub(jn - jobtab, 1))
       
  1170 		    break;
       
  1171 	    child_block();
       
  1172 	}
       
  1173     } else {
       
  1174 	deletejob(jn);
       
  1175 	pipestats[0] = lastval;
       
  1176 	numpipestats = 1;
       
  1177     }
       
  1178     child_unblock();
       
  1179     restore_queue_signals(q);
       
  1180 }
       
  1181 
       
  1182 /* wait for running job to finish */
       
  1183 
       
  1184 /**/
       
  1185 void
       
  1186 waitjobs(void)
       
  1187 {
       
  1188     Job jn = jobtab + thisjob;
       
  1189     DPUTS(thisjob == -1, "No valid job in waitjobs.");
       
  1190 
       
  1191     if (jn->procs || jn->auxprocs)
       
  1192 	zwaitjob(thisjob, 0);
       
  1193     else {
       
  1194 	deletejob(jn);
       
  1195 	pipestats[0] = lastval;
       
  1196 	numpipestats = 1;
       
  1197     }
       
  1198     thisjob = -1;
       
  1199 }
       
  1200 
       
  1201 /* clear job table when entering subshells */
       
  1202 
       
  1203 /**/
       
  1204 mod_export void
       
  1205 clearjobtab(int monitor)
       
  1206 {
       
  1207     int i;
       
  1208 
       
  1209     for (i = 1; i <= maxjob; i++) {
       
  1210 	/*
       
  1211 	 * See if there is a jobtable worth saving.
       
  1212 	 * We never free the saved version; it only happens
       
  1213 	 * once for each subshell of a shell with job control,
       
  1214 	 * so doesn't create a leak.
       
  1215 	 */
       
  1216 	if (monitor && jobtab[i].stat)
       
  1217 	    oldmaxjob = i+1;
       
  1218 	else if (jobtab[i].stat & STAT_INUSE)
       
  1219 	    freejob(jobtab + i, 0);
       
  1220     }
       
  1221 
       
  1222     if (monitor && oldmaxjob) {
       
  1223 	int sz = oldmaxjob * sizeof(struct job);
       
  1224 	oldjobtab = (struct job *)zalloc(sz);
       
  1225 	memcpy(oldjobtab, jobtab, sz);
       
  1226 
       
  1227 	/* Don't report any job we're part of */
       
  1228 	if (thisjob != -1 && thisjob < oldmaxjob)
       
  1229 	    memset(oldjobtab+thisjob, 0, sizeof(struct job));
       
  1230     }
       
  1231 
       
  1232     memset(jobtab, 0, jobtabsize * sizeof(struct job)); /* zero out table */
       
  1233     maxjob = 0;
       
  1234 }
       
  1235 
       
  1236 static int initnewjob(int i)
       
  1237 {
       
  1238     jobtab[i].stat = STAT_INUSE;
       
  1239     if (jobtab[i].pwd) {
       
  1240 	zsfree(jobtab[i].pwd);
       
  1241 	jobtab[i].pwd = NULL;
       
  1242     }
       
  1243     jobtab[i].gleader = 0;
       
  1244 
       
  1245     if (i > maxjob)
       
  1246 	maxjob = i;
       
  1247 
       
  1248     return i;
       
  1249 }
       
  1250 
       
  1251 /* Get a free entry in the job table and initialize it. */
       
  1252 
       
  1253 /**/
       
  1254 int
       
  1255 initjob(void)
       
  1256 {
       
  1257     int i;
       
  1258 
       
  1259     for (i = 1; i <= maxjob; i++)
       
  1260 	if (!jobtab[i].stat)
       
  1261 	    return initnewjob(i);
       
  1262     if (maxjob + 1 < jobtabsize)
       
  1263 	return initnewjob(maxjob+1);
       
  1264 
       
  1265     if (expandjobtab())
       
  1266 	return initnewjob(i);
       
  1267 
       
  1268     zerr("job table full or recursion limit exceeded", NULL, 0);
       
  1269     return -1;
       
  1270 }
       
  1271 
       
  1272 /**/
       
  1273 void
       
  1274 setjobpwd(void)
       
  1275 {
       
  1276     int i;
       
  1277 
       
  1278     for (i = 1; i <= maxjob; i++)
       
  1279 	if (jobtab[i].stat && !jobtab[i].pwd)
       
  1280 	    jobtab[i].pwd = ztrdup(pwd);
       
  1281 }
       
  1282 
       
  1283 /* print pids for & */
       
  1284 
       
  1285 /**/
       
  1286 void
       
  1287 spawnjob(void)
       
  1288 {
       
  1289     Process pn;
       
  1290 
       
  1291     DPUTS(thisjob == -1, "No valid job in spawnjob.");
       
  1292     /* if we are not in a subshell */
       
  1293     if (!subsh) {
       
  1294 	if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED)) {
       
  1295 	    curjob = thisjob;
       
  1296 	    setprevjob();
       
  1297 	} else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
       
  1298 	    prevjob = thisjob;
       
  1299 	if (interact && jobbing && jobtab[thisjob].procs) {
       
  1300 	    fprintf(stderr, "[%d]", thisjob);
       
  1301 	    for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
       
  1302 		fprintf(stderr, " %ld", (long) pn->pid);
       
  1303 	    fprintf(stderr, "\n");
       
  1304 	    fflush(stderr);
       
  1305 	}
       
  1306     }
       
  1307     if (!hasprocs(thisjob))
       
  1308 	deletejob(jobtab + thisjob);
       
  1309     else
       
  1310 	jobtab[thisjob].stat |= STAT_LOCKED;
       
  1311     thisjob = -1;
       
  1312 }
       
  1313 
       
  1314 /**/
       
  1315 void
       
  1316 shelltime(void)
       
  1317 {
       
  1318     struct timezone dummy_tz;
       
  1319     struct timeval dtimeval, now;
       
  1320     child_times_t ti;
       
  1321 #ifndef HAVE_GETRUSAGE
       
  1322     struct tms buf;
       
  1323 #endif
       
  1324 
       
  1325     gettimeofday(&now, &dummy_tz);
       
  1326 
       
  1327 #ifdef HAVE_GETRUSAGE
       
  1328     getrusage(RUSAGE_SELF, &ti);
       
  1329 #else
       
  1330     times(&buf);
       
  1331 
       
  1332     ti.ut = buf.tms_utime;
       
  1333     ti.st = buf.tms_stime;
       
  1334 #endif
       
  1335     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
       
  1336 
       
  1337 #ifdef HAVE_GETRUSAGE
       
  1338     getrusage(RUSAGE_CHILDREN, &ti);
       
  1339 #else
       
  1340     ti.ut = buf.tms_cutime;
       
  1341     ti.st = buf.tms_cstime;
       
  1342 #endif
       
  1343     printtime(&dtimeval, &ti, "children");
       
  1344 
       
  1345 }
       
  1346 
       
  1347 /* see if jobs need printing */
       
  1348  
       
  1349 /**/
       
  1350 void
       
  1351 scanjobs(void)
       
  1352 {
       
  1353     int i;
       
  1354  
       
  1355     for (i = 1; i <= maxjob; i++)
       
  1356         if (jobtab[i].stat & STAT_CHANGED)
       
  1357             printjob(jobtab + i, 0, 1);
       
  1358 }
       
  1359 
       
  1360 /**** job control builtins ****/
       
  1361 
       
  1362 /* This simple function indicates whether or not s may represent      *
       
  1363  * a number.  It returns true iff s consists purely of digits and     *
       
  1364  * minuses.  Note that minus may appear more than once, and the empty *
       
  1365  * string will produce a `true' response.                             */
       
  1366 
       
  1367 /**/
       
  1368 static int
       
  1369 isanum(char *s)
       
  1370 {
       
  1371     while (*s == '-' || idigit(*s))
       
  1372 	s++;
       
  1373     return *s == '\0';
       
  1374 }
       
  1375 
       
  1376 /* Make sure we have a suitable current and previous job set. */
       
  1377 
       
  1378 /**/
       
  1379 static void
       
  1380 setcurjob(void)
       
  1381 {
       
  1382     if (curjob == thisjob ||
       
  1383 	(curjob != -1 && !(jobtab[curjob].stat & STAT_INUSE))) {
       
  1384 	curjob = prevjob;
       
  1385 	setprevjob();
       
  1386 	if (curjob == thisjob ||
       
  1387 	    (curjob != -1 && !((jobtab[curjob].stat & STAT_INUSE) &&
       
  1388 			       curjob != thisjob))) {
       
  1389 	    curjob = prevjob;
       
  1390 	    setprevjob();
       
  1391 	}
       
  1392     }
       
  1393 }
       
  1394 
       
  1395 /* Convert a job specifier ("%%", "%1", "%foo", "%?bar?", etc.) *
       
  1396  * to a job number.                                             */
       
  1397 
       
  1398 /**/
       
  1399 static int
       
  1400 getjob(char *s, char *prog)
       
  1401 {
       
  1402     int jobnum, returnval;
       
  1403 
       
  1404     /* if there is no %, treat as a name */
       
  1405     if (*s != '%')
       
  1406 	goto jump;
       
  1407     s++;
       
  1408     /* "%%", "%+" and "%" all represent the current job */
       
  1409     if (*s == '%' || *s == '+' || !*s) {
       
  1410 	if (curjob == -1) {
       
  1411 	    zwarnnam(prog, "no current job", NULL, 0);
       
  1412 	    returnval = -1;
       
  1413 	    goto done;
       
  1414 	}
       
  1415 	returnval = curjob;
       
  1416 	goto done;
       
  1417     }
       
  1418     /* "%-" represents the previous job */
       
  1419     if (*s == '-') {
       
  1420 	if (prevjob == -1) {
       
  1421 	    zwarnnam(prog, "no previous job", NULL, 0);
       
  1422 	    returnval = -1;
       
  1423 	    goto done;
       
  1424 	}
       
  1425 	returnval = prevjob;
       
  1426 	goto done;
       
  1427     }
       
  1428     /* a digit here means we have a job number */
       
  1429     if (idigit(*s)) {
       
  1430 	jobnum = atoi(s);
       
  1431 	if (jobnum && jobnum <= maxjob && jobtab[jobnum].stat &&
       
  1432 	    !(jobtab[jobnum].stat & STAT_SUBJOB) && jobnum != thisjob) {
       
  1433 	    returnval = jobnum;
       
  1434 	    goto done;
       
  1435 	}
       
  1436 	zwarnnam(prog, "%%%s: no such job", s, 0);
       
  1437 	returnval = -1;
       
  1438 	goto done;
       
  1439     }
       
  1440     /* "%?" introduces a search string */
       
  1441     if (*s == '?') {
       
  1442 	struct process *pn;
       
  1443 
       
  1444 	for (jobnum = maxjob; jobnum >= 0; jobnum--)
       
  1445 	    if (jobtab[jobnum].stat && !(jobtab[jobnum].stat & STAT_SUBJOB) &&
       
  1446 		jobnum != thisjob)
       
  1447 		for (pn = jobtab[jobnum].procs; pn; pn = pn->next)
       
  1448 		    if (strstr(pn->text, s + 1)) {
       
  1449 			returnval = jobnum;
       
  1450 			goto done;
       
  1451 		    }
       
  1452 	zwarnnam(prog, "job not found: %s", s, 0);
       
  1453 	returnval = -1;
       
  1454 	goto done;
       
  1455     }
       
  1456   jump:
       
  1457     /* anything else is a job name, specified as a string that begins the
       
  1458     job's command */
       
  1459     if ((jobnum = findjobnam(s)) != -1) {
       
  1460 	returnval = jobnum;
       
  1461 	goto done;
       
  1462     }
       
  1463     /* if we get here, it is because none of the above succeeded and went
       
  1464     to done */
       
  1465     zwarnnam(prog, "job not found: %s", s, 0);
       
  1466     returnval = -1;
       
  1467   done:
       
  1468     return returnval;
       
  1469 }
       
  1470 
       
  1471 /* For jobs -Z (which modifies the shell's name as seen in ps listings).  *
       
  1472  * hackzero is the start of the safely writable space, and hackspace is   *
       
  1473  * its length, excluding a final NUL terminator that will always be left. */
       
  1474 
       
  1475 static char *hackzero;
       
  1476 static int hackspace;
       
  1477 
       
  1478 
       
  1479 /* Initialise job handling. */
       
  1480 
       
  1481 /**/
       
  1482 void
       
  1483 init_jobs(char **argv, char **envp)
       
  1484 {
       
  1485     char *p, *q;
       
  1486     size_t init_bytes = MAXJOBS_ALLOC*sizeof(struct job);
       
  1487 
       
  1488     /*
       
  1489      * Initialise the job table.  If this fails, we're in trouble.
       
  1490      */
       
  1491     jobtab = (struct job *)zalloc(init_bytes);
       
  1492     if (!jobtab) {
       
  1493 	zerr("failed to allocate job table, aborting.", NULL, 0);
       
  1494 	exit(1);
       
  1495     }
       
  1496     jobtabsize = MAXJOBS_ALLOC;
       
  1497     memset(jobtab, 0, init_bytes);
       
  1498 
       
  1499     /*
       
  1500      * Initialise the jobs -Z system.  The technique is borrowed from
       
  1501      * perl: check through the argument and environment space, to see
       
  1502      * how many of the strings are in contiguous space.  This determines
       
  1503      * the value of hackspace.
       
  1504      */
       
  1505     hackzero = *argv;
       
  1506     p = strchr(hackzero, 0);
       
  1507     while(*++argv) {
       
  1508 	q = *argv;
       
  1509 	if(q != p+1)
       
  1510 	    goto done;
       
  1511 	p = strchr(q, 0);
       
  1512     }
       
  1513     for(; *envp; envp++) {
       
  1514 	q = *envp;
       
  1515 	if(q != p+1)
       
  1516 	    goto done;
       
  1517 	p = strchr(q, 0);
       
  1518     }
       
  1519     done:
       
  1520     hackspace = p - hackzero;
       
  1521 }
       
  1522 
       
  1523 
       
  1524 /*
       
  1525  * We have run out of space in the job table.
       
  1526  * Expand it by an additional MAXJOBS_ALLOC slots.
       
  1527  */
       
  1528 
       
  1529 /*
       
  1530  * An arbitrary limit on the absolute maximum size of the job table.
       
  1531  * This prevents us taking over the entire universe.
       
  1532  * Ought to be a multiple of MAXJOBS_ALLOC, but doesn't need to be.
       
  1533  */
       
  1534 #define MAX_MAXJOBS	1000
       
  1535 
       
  1536 /**/
       
  1537 int
       
  1538 expandjobtab(void)
       
  1539 {
       
  1540     int newsize = jobtabsize + MAXJOBS_ALLOC;
       
  1541     struct job *newjobtab;
       
  1542 
       
  1543     if (newsize > MAX_MAXJOBS)
       
  1544 	return 0;
       
  1545 
       
  1546     newjobtab = (struct job *)zrealloc(jobtab, newsize * sizeof(struct job));
       
  1547     if (!newjobtab)
       
  1548 	return 0;
       
  1549 
       
  1550     /*
       
  1551      * Clear the new section of the table; this is necessary for
       
  1552      * the jobs to appear unused.
       
  1553      */
       
  1554     memset(newjobtab + jobtabsize, 0, MAXJOBS_ALLOC * sizeof(struct job));
       
  1555 
       
  1556     jobtab = newjobtab;
       
  1557     jobtabsize = newsize;
       
  1558 
       
  1559     return 1;
       
  1560 }
       
  1561 
       
  1562 
       
  1563 /*
       
  1564  * See if we can reduce the job table.  We can if we go over
       
  1565  * a MAXJOBS_ALLOC boundary.  However, we leave a boundary,
       
  1566  * currently 20 jobs, so that we have a place for immediate
       
  1567  * expansion and don't play ping pong with the job table size.
       
  1568  */
       
  1569 
       
  1570 /**/
       
  1571 void
       
  1572 maybeshrinkjobtab(void)
       
  1573 {
       
  1574     int jobbound;
       
  1575 
       
  1576     queue_signals();
       
  1577     jobbound = maxjob + MAXJOBS_ALLOC - (maxjob % MAXJOBS_ALLOC);
       
  1578     if (jobbound < jobtabsize && jobbound > maxjob + 20) {
       
  1579 	struct job *newjobtab;
       
  1580 
       
  1581 	/* Hope this can't fail, but anyway... */
       
  1582 	newjobtab = (struct job *)zrealloc(jobtab,
       
  1583 					   jobbound*sizeof(struct job));
       
  1584 
       
  1585 	if (newjobtab) {
       
  1586 	    jobtab = newjobtab;
       
  1587 	    jobtabsize = jobbound;
       
  1588 	}
       
  1589     }
       
  1590     unqueue_signals();
       
  1591 }
       
  1592 
       
  1593 #ifndef __SYMBIAN32__
       
  1594 /* bg, disown, fg, jobs, wait: most of the job control commands are     *
       
  1595  * here.  They all take the same type of argument.  Exception: wait can *
       
  1596  * take a pid or a job specifier, whereas the others only work on jobs. */
       
  1597 
       
  1598 /**/
       
  1599 int
       
  1600 bin_fg(char *name, char **argv, Options ops, int func)
       
  1601 {
       
  1602     int job, lng, firstjob = -1, retval = 0, ofunc = func;
       
  1603 
       
  1604     if (OPT_ISSET(ops,'Z')) {
       
  1605 	int len;
       
  1606 
       
  1607 	if(isset(RESTRICTED)) {
       
  1608 	    zwarnnam(name, "-Z is restricted", NULL, 0);
       
  1609 	    return 1;
       
  1610 	}
       
  1611 	if(!argv[0] || argv[1]) {
       
  1612 	    zwarnnam(name, "-Z requires one argument", NULL, 0);
       
  1613 	    return 1;
       
  1614 	}
       
  1615 	queue_signals();
       
  1616 	unmetafy(*argv, &len);
       
  1617 	if(len > hackspace)
       
  1618 	    len = hackspace;
       
  1619 	memcpy(hackzero, *argv, len);
       
  1620 	memset(hackzero + len, 0, hackspace - len);
       
  1621 	unqueue_signals();
       
  1622 	return 0;
       
  1623     }
       
  1624 
       
  1625     lng = (OPT_ISSET(ops,'l')) ? 1 : (OPT_ISSET(ops,'p')) ? 2 : 0;
       
  1626     if (OPT_ISSET(ops,'d'))
       
  1627 	lng |= 4;
       
  1628     
       
  1629     if ((func == BIN_FG || func == BIN_BG) && !jobbing) {
       
  1630 	/* oops... maybe bg and fg should have been disabled? */
       
  1631 	zwarnnam(name, "no job control in this shell.", NULL, 0);
       
  1632 	return 1;
       
  1633     }
       
  1634 
       
  1635     queue_signals();
       
  1636     /* If necessary, update job table. */
       
  1637     if (unset(NOTIFY))
       
  1638 	scanjobs();
       
  1639 
       
  1640     if (func != BIN_JOBS || isset(MONITOR) || !oldmaxjob)
       
  1641 	setcurjob();
       
  1642 
       
  1643     if (func == BIN_JOBS)
       
  1644         /* If you immediately type "exit" after "jobs", this      *
       
  1645          * will prevent zexit from complaining about stopped jobs */
       
  1646 	stopmsg = 2;
       
  1647     if (!*argv) {
       
  1648 	/* This block handles all of the default cases (no arguments).  bg,
       
  1649 	fg and disown act on the current job, and jobs and wait act on all the
       
  1650 	jobs. */
       
  1651  	if (func == BIN_FG || func == BIN_BG || func == BIN_DISOWN) {
       
  1652 	    /* W.r.t. the above comment, we'd better have a current job at this
       
  1653 	    point or else. */
       
  1654 	    if (curjob == -1 || (jobtab[curjob].stat & STAT_NOPRINT)) {
       
  1655 		zwarnnam(name, "no current job", NULL, 0);
       
  1656 		unqueue_signals();
       
  1657 		return 1;
       
  1658 	    }
       
  1659 	    firstjob = curjob;
       
  1660 	} else if (func == BIN_JOBS) {
       
  1661 	    /* List jobs. */
       
  1662 	    struct job *jobptr;
       
  1663 	    int curmaxjob, ignorejob;
       
  1664 	    if (unset(MONITOR) && oldmaxjob) {
       
  1665 		jobptr = oldjobtab;
       
  1666 		curmaxjob = oldmaxjob ? oldmaxjob - 1 : 0;
       
  1667 		ignorejob = 0;
       
  1668 	    } else {
       
  1669 		jobptr = jobtab;
       
  1670 		curmaxjob = maxjob;
       
  1671 		ignorejob = thisjob;
       
  1672 	    }
       
  1673 	    for (job = 0; job <= curmaxjob; job++, jobptr++)
       
  1674 		if (job != ignorejob && jobptr->stat) {
       
  1675 		    if ((!OPT_ISSET(ops,'r') && !OPT_ISSET(ops,'s')) ||
       
  1676 			(OPT_ISSET(ops,'r') && OPT_ISSET(ops,'s')) ||
       
  1677 			(OPT_ISSET(ops,'r') && 
       
  1678 			 !(jobptr->stat & STAT_STOPPED)) ||
       
  1679 			(OPT_ISSET(ops,'s') && jobptr->stat & STAT_STOPPED))
       
  1680 			printjob(jobptr, lng, 2);
       
  1681 		}
       
  1682 	    unqueue_signals();
       
  1683 	    return 0;
       
  1684 	} else {   /* Must be BIN_WAIT, so wait for all jobs */
       
  1685 	    for (job = 0; job <= maxjob; job++)
       
  1686 		if (job != thisjob && jobtab[job].stat)
       
  1687 		    zwaitjob(job, SIGINT);
       
  1688 	    unqueue_signals();
       
  1689 	    return 0;
       
  1690 	}
       
  1691     }
       
  1692 
       
  1693     /* Defaults have been handled.  We now have an argument or two, or three...
       
  1694     In the default case for bg, fg and disown, the argument will be provided by
       
  1695     the above routine.  We now loop over the arguments. */
       
  1696     for (; (firstjob != -1) || *argv; (void)(*argv && argv++)) {
       
  1697 	int stopped, ocj = thisjob;
       
  1698 
       
  1699         func = ofunc;
       
  1700 
       
  1701 	if (func == BIN_WAIT && isanum(*argv)) {
       
  1702 	    /* wait can take a pid; the others can't. */
       
  1703 	    pid_t pid = (long)atoi(*argv);
       
  1704 	    Job j;
       
  1705 	    Process p;
       
  1706 
       
  1707 	    if (findproc(pid, &j, &p, 0))
       
  1708 		waitforpid(pid);
       
  1709 	    else
       
  1710 		zwarnnam(name, "pid %d is not a child of this shell", 0, pid);
       
  1711 	    retval = lastval2;
       
  1712 	    thisjob = ocj;
       
  1713 	    continue;
       
  1714 	}
       
  1715 	/* The only type of argument allowed now is a job spec.  Check it. */
       
  1716 	job = (*argv) ? getjob(*argv, name) : firstjob;
       
  1717 	firstjob = -1;
       
  1718 	if (job == -1) {
       
  1719 	    retval = 1;
       
  1720 	    break;
       
  1721 	}
       
  1722 	if (!(jobtab[job].stat & STAT_INUSE) ||
       
  1723 	    (jobtab[job].stat & STAT_NOPRINT)) {
       
  1724 	    zwarnnam(name, "no such job: %d", 0, job);
       
  1725 	    unqueue_signals();
       
  1726 	    return 1;
       
  1727 	}
       
  1728         /* If AUTO_CONTINUE is set (automatically make stopped jobs running
       
  1729          * on disown), we actually do a bg and then delete the job table entry. */
       
  1730 
       
  1731         if (isset(AUTOCONTINUE) && func == BIN_DISOWN &&
       
  1732             jobtab[job].stat & STAT_STOPPED)
       
  1733             func = BIN_BG;
       
  1734 
       
  1735 	/* We have a job number.  Now decide what to do with it. */
       
  1736 	switch (func) {
       
  1737 	case BIN_FG:
       
  1738 	case BIN_BG:
       
  1739 	case BIN_WAIT:
       
  1740 	    if (func == BIN_BG)
       
  1741 		jobtab[job].stat |= STAT_NOSTTY;
       
  1742 	    if ((stopped = (jobtab[job].stat & STAT_STOPPED)))
       
  1743 		makerunning(jobtab + job);
       
  1744 	    else if (func == BIN_BG) {
       
  1745 		/* Silly to bg a job already running. */
       
  1746 		zwarnnam(name, "job already in background", NULL, 0);
       
  1747 		thisjob = ocj;
       
  1748 		unqueue_signals();
       
  1749 		return 1;
       
  1750 	    }
       
  1751 	    /* It's time to shuffle the jobs around!  Reset the current job,
       
  1752 	    and pick a sensible secondary job. */
       
  1753 	    if (curjob == job) {
       
  1754 		curjob = prevjob;
       
  1755 		prevjob = (func == BIN_BG) ? -1 : job;
       
  1756 	    }
       
  1757 	    if (prevjob == job || prevjob == -1)
       
  1758 		setprevjob();
       
  1759 	    if (curjob == -1) {
       
  1760 		curjob = prevjob;
       
  1761 		setprevjob();
       
  1762 	    }
       
  1763 	    if (func != BIN_WAIT)
       
  1764 		/* for bg and fg -- show the job we are operating on */
       
  1765 		printjob(jobtab + job, (stopped) ? -1 : 0, 1);
       
  1766 	    if (func != BIN_BG) {		/* fg or wait */
       
  1767 		if (jobtab[job].pwd && strcmp(jobtab[job].pwd, pwd)) {
       
  1768 		    fprintf(shout, "(pwd : ");
       
  1769 		    fprintdir(jobtab[job].pwd, shout);
       
  1770 		    fprintf(shout, ")\n");
       
  1771 		}
       
  1772 		fflush(shout);
       
  1773 		if (func != BIN_WAIT) {		/* fg */
       
  1774 		    thisjob = job;
       
  1775 		    if ((jobtab[job].stat & STAT_SUPERJOB) &&
       
  1776 			((!jobtab[job].procs->next ||
       
  1777 			  (jobtab[job].stat & STAT_SUBLEADER) ||
       
  1778 			  killpg(jobtab[job].gleader, 0) == -1)) &&
       
  1779 			jobtab[jobtab[job].other].gleader)
       
  1780 			attachtty(jobtab[jobtab[job].other].gleader);
       
  1781 		    else
       
  1782 			attachtty(jobtab[job].gleader);
       
  1783 		}
       
  1784 	    }
       
  1785 	    if (stopped) {
       
  1786 		if (func != BIN_BG && jobtab[job].ty)
       
  1787 		    settyinfo(jobtab[job].ty);
       
  1788 		killjb(jobtab + job, SIGCONT);
       
  1789 	    }
       
  1790 	    if (func == BIN_WAIT)
       
  1791 		zwaitjob(job, SIGINT);
       
  1792 	    if (func != BIN_BG) {
       
  1793 		waitjobs();
       
  1794 		retval = lastval2;
       
  1795 	    } else if (ofunc == BIN_DISOWN)
       
  1796 	        deletejob(jobtab + job);
       
  1797 	    break;
       
  1798 	case BIN_JOBS:
       
  1799 	    printjob(job + jobtab, lng, 2);
       
  1800 	    break;
       
  1801 	case BIN_DISOWN:
       
  1802 	    if (jobtab[job].stat & STAT_STOPPED) {
       
  1803 		char buf[20], *pids = "";
       
  1804 
       
  1805 		if (jobtab[job].stat & STAT_SUPERJOB) {
       
  1806 		    Process pn;
       
  1807 
       
  1808 		    for (pn = jobtab[jobtab[job].other].procs; pn; pn = pn->next) {
       
  1809 			sprintf(buf, " -%d", pn->pid);
       
  1810 			pids = dyncat(pids, buf);
       
  1811 		    }
       
  1812 		    for (pn = jobtab[job].procs; pn->next; pn = pn->next) {
       
  1813 			sprintf(buf, " %d", pn->pid);
       
  1814 			pids = dyncat(pids, buf);
       
  1815 		    }
       
  1816 		    if (!jobtab[jobtab[job].other].procs && pn) {
       
  1817 			sprintf(buf, " %d", pn->pid);
       
  1818 			pids = dyncat(pids, buf);
       
  1819 		    }
       
  1820 		} else {
       
  1821 		    sprintf(buf, " -%d", jobtab[job].gleader);
       
  1822 		    pids = buf;
       
  1823 		}
       
  1824                 zwarnnam(name,
       
  1825 #ifdef USE_SUSPENDED
       
  1826                          "warning: job is suspended, use `kill -CONT%s' to resume",
       
  1827 #else
       
  1828                          "warning: job is stopped, use `kill -CONT%s' to resume",
       
  1829 #endif
       
  1830                          pids, 0);
       
  1831 	    }
       
  1832 	    deletejob(jobtab + job);
       
  1833 	    break;
       
  1834 	}
       
  1835 	thisjob = ocj;
       
  1836     }
       
  1837     unqueue_signals();
       
  1838     return retval;
       
  1839 }
       
  1840 #endif //__SYMBIAN32__
       
  1841 #if defined(SIGCHLD) && defined(SIGCLD)
       
  1842 #if SIGCHLD == SIGCLD
       
  1843 #define ALT_SIGS 1
       
  1844 #endif
       
  1845 #endif
       
  1846 #if defined(SIGPOLL) && defined(SIGIO)
       
  1847 #if SIGPOLL == SIGIO
       
  1848 #define ALT_SIGS 1
       
  1849 #endif
       
  1850 #endif
       
  1851 
       
  1852 #ifdef ALT_SIGS
       
  1853 const struct {
       
  1854     const char *name;
       
  1855     int num;
       
  1856 } alt_sigs[] = {
       
  1857 #if defined(SIGCHLD) && defined(SIGCLD)
       
  1858 #if SIGCHLD == SIGCLD
       
  1859     { "CLD", SIGCLD },
       
  1860 #endif
       
  1861 #endif
       
  1862 #if defined(SIGPOLL) && defined(SIGIO)
       
  1863 #if SIGPOLL == SIGIO
       
  1864     { "IO", SIGIO },
       
  1865 #endif
       
  1866 #endif
       
  1867     { NULL, 0 }
       
  1868 };
       
  1869 #endif
       
  1870 
       
  1871 #ifndef __SYMBIAN32__
       
  1872 /* kill: send a signal to a process.  The process(es) may be specified *
       
  1873  * by job specifier (see above) or pid.  A signal, defaulting to       *
       
  1874  * SIGTERM, may be specified by name or number, preceded by a dash.    */
       
  1875 
       
  1876 /**/
       
  1877 int
       
  1878 bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
       
  1879 {
       
  1880     int sig = SIGTERM;
       
  1881     int returnval = 0;
       
  1882 
       
  1883     /* check for, and interpret, a signal specifier */
       
  1884     if (*argv && **argv == '-') {
       
  1885 	if (idigit((*argv)[1]))
       
  1886 	    /* signal specified by number */
       
  1887 	    sig = atoi(*argv + 1);
       
  1888 	else if ((*argv)[1] != '-' || (*argv)[2]) {
       
  1889 	    char *signame = NULL;
       
  1890 
       
  1891 	    /* with argument "-l" display the list of signal names */
       
  1892 	    if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
       
  1893 		if (argv[1]) {
       
  1894 		    while (*++argv) {
       
  1895 			sig = zstrtol(*argv, &signame, 10);
       
  1896 			if (signame == *argv) {
       
  1897 			    for (sig = 1; sig <= SIGCOUNT; sig++)
       
  1898 				if (!cstrpcmp(sigs + sig, &signame))
       
  1899 				    break;
       
  1900 #ifdef ALT_SIGS
       
  1901 			    if (sig > SIGCOUNT) {
       
  1902 				int i;
       
  1903 
       
  1904 				for (i = 0; alt_sigs[i].name; i++)
       
  1905 				    if (!cstrpcmp(&alt_sigs[i].name, &signame))
       
  1906 				    {
       
  1907 					sig = alt_sigs[i].num;
       
  1908 					break;
       
  1909 				    }
       
  1910 			    }
       
  1911 #endif
       
  1912 			    if (sig > SIGCOUNT) {
       
  1913 				zwarnnam(nam, "unknown signal: SIG%s",
       
  1914 					 signame, 0);
       
  1915 				returnval++;
       
  1916 			    } else
       
  1917 				printf("%d\n", sig);
       
  1918 			} else {
       
  1919 			    if (*signame) {
       
  1920 				zwarnnam(nam, "unknown signal: SIG%s",
       
  1921 					 signame, 0);
       
  1922 				returnval++;
       
  1923 			    } else {
       
  1924 				if (WIFSIGNALED(sig))
       
  1925 				    sig = WTERMSIG(sig);
       
  1926 				else if (WIFSTOPPED(sig))
       
  1927 				    sig = WSTOPSIG(sig);
       
  1928 				if (1 <= sig && sig <= SIGCOUNT)
       
  1929 				    printf("%s\n", sigs[sig]);
       
  1930 				else
       
  1931 				    printf("%d\n", sig);
       
  1932 			    }
       
  1933 			}
       
  1934 		    }
       
  1935 		    return returnval;
       
  1936 		}
       
  1937 		printf("%s", sigs[1]);
       
  1938 		for (sig = 2; sig <= SIGCOUNT; sig++)
       
  1939 		    printf(" %s", sigs[sig]);
       
  1940 		putchar('\n');
       
  1941 		return 0;
       
  1942 	    }
       
  1943 
       
  1944     	    if ((*argv)[1] == 'n' && (*argv)[2] == '\0') {
       
  1945 	    	char *endp;
       
  1946 
       
  1947 	    	if (!*++argv) {
       
  1948 		    zwarnnam(nam, "-n: argument expected", NULL, 0);
       
  1949 		    return 1;
       
  1950 		}
       
  1951 		sig = zstrtol(*argv, &endp, 10);
       
  1952 		if (*endp) {
       
  1953 		    zwarnnam(nam, "invalid signal number", signame, 0);
       
  1954 		    return 1;
       
  1955 		}
       
  1956 	    } else {
       
  1957 		if (!((*argv)[1] == 's' && (*argv)[2] == '\0'))
       
  1958 		    signame = *argv + 1;
       
  1959 		else if (!(*++argv)) {
       
  1960 		    zwarnnam(nam, "-s: argument expected", NULL, 0);
       
  1961 		    return 1;
       
  1962 		} else
       
  1963 		    signame = *argv;
       
  1964 		makeuppercase(&signame);
       
  1965 		if (!strncmp(signame, "SIG", 3)) signame+=3;
       
  1966 
       
  1967 		/* check for signal matching specified name */
       
  1968 		for (sig = 1; sig <= SIGCOUNT; sig++)
       
  1969 		    if (!strcmp(*(sigs + sig), signame))
       
  1970 			break;
       
  1971 		if (*signame == '0' && !signame[1])
       
  1972 		    sig = 0;
       
  1973 #ifdef ALT_SIGS
       
  1974 		if (sig > SIGCOUNT) {
       
  1975 		    int i;
       
  1976 
       
  1977 		    for (i = 0; alt_sigs[i].name; i++)
       
  1978 			if (!strcmp(alt_sigs[i].name, signame))
       
  1979 			{
       
  1980 			    sig = alt_sigs[i].num;
       
  1981 			    break;
       
  1982 			}
       
  1983 		}
       
  1984 #endif
       
  1985 		if (sig > SIGCOUNT) {
       
  1986 		    zwarnnam(nam, "unknown signal: SIG%s", signame, 0);
       
  1987 		    zwarnnam(nam, "type kill -l for a List of signals", NULL, 0);
       
  1988 		    return 1;
       
  1989 		}
       
  1990 	    }
       
  1991 	}
       
  1992 	argv++;
       
  1993     }
       
  1994 
       
  1995     if (!*argv) {
       
  1996     	zwarnnam(nam, "not enough arguments", NULL, 0);
       
  1997 	return 1;
       
  1998     }
       
  1999 
       
  2000     queue_signals();
       
  2001     setcurjob();
       
  2002 
       
  2003     /* Remaining arguments specify processes.  Loop over them, and send the
       
  2004     signal (number sig) to each process. */
       
  2005     for (; *argv; argv++) {
       
  2006 	if (**argv == '%') {
       
  2007 	    /* job specifier introduced by '%' */
       
  2008 	    int p;
       
  2009 
       
  2010 	    if ((p = getjob(*argv, nam)) == -1) {
       
  2011 		returnval++;
       
  2012 		continue;
       
  2013 	    }
       
  2014 	    if (killjb(jobtab + p, sig) == -1) {
       
  2015 		zwarnnam("kill", "kill %s failed: %e", *argv, errno);
       
  2016 		returnval++;
       
  2017 		continue;
       
  2018 	    }
       
  2019 	    /* automatically update the job table if sending a SIGCONT to a
       
  2020 	    job, and send the job a SIGCONT if sending it a non-stopping
       
  2021 	    signal. */
       
  2022 	    if (jobtab[p].stat & STAT_STOPPED) {
       
  2023 		if (sig == SIGCONT)
       
  2024 		    jobtab[p].stat &= ~STAT_STOPPED;
       
  2025 		if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
       
  2026 		    && sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
       
  2027 		    killjb(jobtab + p, SIGCONT);
       
  2028 	    }
       
  2029 	} else if (!isanum(*argv)) {
       
  2030 	    zwarnnam("kill", "illegal pid: %s", *argv, 0);
       
  2031 	    returnval++;
       
  2032 	} else if (kill(atoi(*argv), sig) == -1) {
       
  2033 	    zwarnnam("kill", "kill %s failed: %e", *argv, errno);
       
  2034 	    returnval++;
       
  2035 	}
       
  2036     }
       
  2037     unqueue_signals();
       
  2038 
       
  2039     return returnval < 126 ? returnval : 1;
       
  2040 }
       
  2041 #endif //__SYMBIAN32__
       
  2042 /* Get a signal number from a string */
       
  2043 
       
  2044 /**/
       
  2045 mod_export int
       
  2046 getsignum(char *s)
       
  2047 {
       
  2048     int x, i;
       
  2049 
       
  2050     /* check for a signal specified by number */
       
  2051     x = atoi(s);
       
  2052     if (idigit(*s) && x >= 0 && x < VSIGCOUNT)
       
  2053 	return x;
       
  2054 
       
  2055     /* search for signal by name */
       
  2056     for (i = 0; i < VSIGCOUNT; i++)
       
  2057 	if (!strcmp(s, sigs[i]))
       
  2058 	    return i;
       
  2059 
       
  2060 #ifdef ALT_SIGS
       
  2061     for (i = 0; alt_sigs[i].name; i++)
       
  2062     {
       
  2063 	if (!strcmp(s, alt_sigs[i].name))
       
  2064 	    return alt_sigs[i].num;
       
  2065     }
       
  2066 #endif
       
  2067 
       
  2068     /* no matching signal */
       
  2069     return -1;
       
  2070 }
       
  2071 
       
  2072 /* Get the function node for a trap, taking care about alternative names */
       
  2073 /**/
       
  2074 HashNode
       
  2075 gettrapnode(int sig, int ignoredisable)
       
  2076 {
       
  2077     char fname[20];
       
  2078     HashNode hn;
       
  2079     HashNode (*getptr)(HashTable ht, char *name);
       
  2080 #ifdef ALT_SIGS
       
  2081     int i;
       
  2082 #endif
       
  2083     if (ignoredisable)
       
  2084 	getptr = shfunctab->getnode2;
       
  2085     else
       
  2086 	getptr = shfunctab->getnode;
       
  2087 
       
  2088     sprintf(fname, "TRAP%s", sigs[sig]);
       
  2089     if ((hn = getptr(shfunctab, fname)))
       
  2090 	return hn;
       
  2091 
       
  2092 #ifdef ALT_SIGS
       
  2093     for (i = 0; alt_sigs[i].name; i++) {
       
  2094 	if (alt_sigs[i].num == sig) {
       
  2095 	    sprintf(fname, "TRAP%s", alt_sigs[i].name);
       
  2096 	    if ((hn = getptr(shfunctab, fname)))
       
  2097 		return hn;
       
  2098 	}
       
  2099     }
       
  2100 #endif
       
  2101 
       
  2102     return NULL;
       
  2103 }
       
  2104 
       
  2105 /* Remove a TRAP function under any name for the signal */
       
  2106 
       
  2107 /**/
       
  2108 void
       
  2109 removetrapnode(int sig)
       
  2110 {
       
  2111     HashNode hn = gettrapnode(sig, 1);
       
  2112     if (hn) {
       
  2113 	shfunctab->removenode(shfunctab, hn->nam);
       
  2114 	shfunctab->freenode(hn);
       
  2115     }
       
  2116 }
       
  2117 
       
  2118 /* Suspend this shell */
       
  2119 
       
  2120 /**/
       
  2121 int
       
  2122 bin_suspend(char *name, UNUSED(char **argv), Options ops, UNUSED(int func))
       
  2123 {
       
  2124     /* won't suspend a login shell, unless forced */
       
  2125     if (islogin && !OPT_ISSET(ops,'f')) {
       
  2126 	zwarnnam(name, "can't suspend login shell", NULL, 0);
       
  2127 	return 1;
       
  2128     }
       
  2129     if (jobbing) {
       
  2130 	/* stop ignoring signals */
       
  2131 	signal_default(SIGTTIN);
       
  2132 	signal_default(SIGTSTP);
       
  2133 	signal_default(SIGTTOU);
       
  2134 
       
  2135 	/* Move ourselves back to the process group we came from */
       
  2136 	release_pgrp();
       
  2137     }
       
  2138 
       
  2139     /* suspend ourselves with a SIGTSTP */
       
  2140     killpg(origpgrp, SIGTSTP);
       
  2141 
       
  2142     if (jobbing) {
       
  2143 	acquire_pgrp();
       
  2144 	/* restore signal handling */
       
  2145 	signal_ignore(SIGTTOU);
       
  2146 	signal_ignore(SIGTSTP);
       
  2147 	signal_ignore(SIGTTIN);
       
  2148     }
       
  2149     return 0;
       
  2150 }
       
  2151 
       
  2152 /* find a job named s */
       
  2153 
       
  2154 /**/
       
  2155 int
       
  2156 findjobnam(char *s)
       
  2157 {
       
  2158     int jobnum;
       
  2159 
       
  2160     for (jobnum = maxjob; jobnum >= 0; jobnum--)
       
  2161 	if (!(jobtab[jobnum].stat & (STAT_SUBJOB | STAT_NOPRINT)) &&
       
  2162 	    jobtab[jobnum].stat && jobtab[jobnum].procs && jobnum != thisjob &&
       
  2163 	    jobtab[jobnum].procs->text && strpfx(s, jobtab[jobnum].procs->text))
       
  2164 	    return jobnum;
       
  2165     return -1;
       
  2166 }
       
  2167 
       
  2168 
       
  2169 /* make sure we are a process group leader by creating a new process
       
  2170    group if necessary */
       
  2171 
       
  2172 /**/
       
  2173 void
       
  2174 acquire_pgrp(void)
       
  2175 {
       
  2176     long ttpgrp;
       
  2177     sigset_t blockset, oldset;
       
  2178 
       
  2179     if ((mypgrp = GETPGRP()) > 0) {
       
  2180 	sigemptyset(&blockset);
       
  2181 	sigaddset(&blockset, SIGTTIN);
       
  2182 	sigaddset(&blockset, SIGTTOU);
       
  2183 	sigaddset(&blockset, SIGTSTP);
       
  2184 	oldset = signal_block(blockset);
       
  2185 	while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
       
  2186 	    mypgrp = GETPGRP();
       
  2187 	    if (mypgrp == mypid) {
       
  2188 		signal_setmask(oldset);
       
  2189 		attachtty(mypgrp); /* Might generate SIGT* */
       
  2190 		signal_block(blockset);
       
  2191 	    }
       
  2192 	    if (mypgrp == gettygrp())
       
  2193 		break;
       
  2194 	    signal_setmask(oldset);
       
  2195 	    read(0, NULL, 0); /* Might generate SIGT* */
       
  2196 	    signal_block(blockset);
       
  2197 	    mypgrp = GETPGRP();
       
  2198 	}
       
  2199 	if (mypgrp != mypid) {
       
  2200 	    if (setpgrp(0, 0) == 0) {
       
  2201 		mypgrp = mypid;
       
  2202 		attachtty(mypgrp);
       
  2203 	    } else
       
  2204 		opts[MONITOR] = 0;
       
  2205 	}
       
  2206 	signal_setmask(oldset);
       
  2207     } else
       
  2208 	opts[MONITOR] = 0;
       
  2209 }
       
  2210 
       
  2211 /* revert back to the process group we came from (before acquire_pgrp) */
       
  2212 
       
  2213 /**/
       
  2214 void
       
  2215 release_pgrp(void)
       
  2216 {
       
  2217     if (origpgrp != mypgrp) {
       
  2218 	attachtty(origpgrp);
       
  2219 	setpgrp(0, origpgrp);
       
  2220 	mypgrp = origpgrp;
       
  2221     }
       
  2222 }