xref: /titanic_41/usr/src/lib/libshell/common/sh/jobs.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  *  Job control for UNIX Shell
23  *
24  *   David Korn
25  *   AT&T Labs
26  *
27  *  Written October, 1982
28  *  Rewritten April, 1988
29  *  Revised January, 1992
30  */
31 
32 #include	"defs.h"
33 #include	<ctype.h>
34 #include	<wait.h>
35 #include	"io.h"
36 #include	"jobs.h"
37 #include	"history.h"
38 
39 #if !defined(WCONTINUED) || !defined(WIFCONTINUED)
40 #   undef  WCONTINUED
41 #   define WCONTINUED	0
42 #   undef  WIFCONTINUED
43 #   define WIFCONTINUED(wstat)	(0)
44 #endif
45 
46 #define	NJOB_SAVELIST	4
47 
48 /*
49  * temporary hack to get W* macros to work
50  */
51 #undef wait
52 #define wait    ______wait
53 /*
54  * This struct saves a link list of processes that have non-zero exit
55  * status, have had $! saved, but haven't been waited for
56  */
57 struct jobsave
58 {
59 	struct jobsave	*next;
60 	pid_t		pid;
61 	unsigned short	exitval;
62 };
63 
64 static struct jobsave *job_savelist;
65 static int njob_savelist;
66 static struct process *pwfg;
67 
68 static void init_savelist(void)
69 {
70 	register struct jobsave *jp;
71 	while(njob_savelist < NJOB_SAVELIST)
72 	{
73 		jp = newof(0,struct jobsave,1,0);
74 		jp->next = job_savelist;
75 		job_savelist = jp;
76 		njob_savelist++;
77 	}
78 }
79 
80 /*
81  * return next on link list of jobsave free list
82  */
83 static struct jobsave *jobsave_create(pid_t pid)
84 {
85 	register struct jobsave *jp = job_savelist;
86 	if(jp)
87 	{
88 		njob_savelist--;
89 		job_savelist = jp->next;
90 	}
91 	else
92 		jp = newof(0,struct jobsave,1,0);
93 	if(jp)
94 		jp->pid = pid;
95 	return(jp);
96 }
97 
98 struct back_save
99 {
100 	int		count;
101 	struct jobsave	*list;
102 };
103 
104 #define BYTE(n)		(((n)+CHAR_BIT-1)/CHAR_BIT)
105 #define MAXMSG	25
106 #define SH_STOPSIG	(SH_EXITSIG<<1)
107 
108 #ifdef VSUSP
109 #   ifndef CNSUSP
110 #	ifdef _POSIX_VDISABLE
111 #	   define CNSUSP	_POSIX_VDISABLE
112 #	else
113 #	   define CNSUSP	0
114 #	endif /* _POSIX_VDISABLE */
115 #   endif /* CNSUSP */
116 #   ifndef CSWTCH
117 #	ifdef CSUSP
118 #	    define CSWTCH	CSUSP
119 #	else
120 #	    define CSWTCH	('z'&037)
121 #	endif /* CSUSP */
122 #   endif /* CSWTCH */
123 #endif /* VSUSP */
124 
125 /* Process states */
126 #define P_EXITSAVE	01
127 #define P_STOPPED	02
128 #define P_NOTIFY	04
129 #define P_SIGNALLED	010
130 #define P_STTY		020
131 #define P_DONE		040
132 #define P_COREDUMP	0100
133 #define P_DISOWN	0200
134 #define P_FG		0400
135 
136 static int		job_chksave(pid_t);
137 static struct process	*job_bypid(pid_t);
138 static struct process	*job_byjid(int);
139 static char		*job_sigmsg(int);
140 static int		job_alloc(void);
141 static void		job_free(int);
142 static struct process	*job_unpost(struct process*,int);
143 static void		job_unlink(struct process*);
144 static void		job_prmsg(struct process*);
145 static struct process	*freelist;
146 static char		beenhere;
147 static char		possible;
148 static struct process	dummy;
149 static char		by_number;
150 static Sfio_t		*outfile;
151 static pid_t		lastpid;
152 static struct back_save	bck;
153 
154 
155 #ifdef JOBS
156     static void			job_set(struct process*);
157     static void			job_reset(struct process*);
158     static void			job_waitsafe(int);
159     static struct process	*job_byname(char*);
160     static struct process	*job_bystring(char*);
161     static struct termios	my_stty;  /* terminal state for shell */
162     static char			*job_string;
163 #else
164     extern const char		e_coredump[];
165 #endif /* JOBS */
166 
167 #ifdef SIGTSTP
168     static void		job_unstop(struct process*);
169     static void		job_fgrp(struct process*, int);
170 #   ifndef _lib_tcgetpgrp
171 #	ifdef TIOCGPGRP
172 	   static int _i_;
173 #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
174 #	endif /* TIOCGPGRP */
175 	int tcsetpgrp(int fd,pid_t pgrp)
176 	{
177 		int pgid = pgrp;
178 #		ifdef TIOCGPGRP
179 			return(ioctl(fd, TIOCSPGRP, &pgid));
180 #		else
181 			return(-1);
182 #		endif /* TIOCGPGRP */
183 	}
184 #   endif /* _lib_tcgetpgrp */
185 #else
186 #   define job_unstop(pw)
187 #   undef CNSUSP
188 #endif /* SIGTSTP */
189 
190 #ifndef OTTYDISC
191 #   undef NTTYDISC
192 #endif /* OTTYDISC */
193 
194 #ifdef JOBS
195 
196 typedef int (*Waitevent_f)(int,long,int);
197 
198 /*
199  * Reap one job
200  * When called with sig==0, it does a blocking wait
201  */
202 int job_reap(register int sig)
203 {
204 	register pid_t pid;
205 	register struct process *pw;
206 	struct process *px;
207 	register int flags;
208 	struct jobsave *jp;
209 	struct back_save *bp;
210 	int nochild=0, oerrno, wstat;
211 	Waitevent_f waitevent = sh.waitevent;
212 	static int wcontinued = WCONTINUED;
213 	if (vmbusy())
214 	{
215 		errormsg(SH_DICT,ERROR_warn(0),"vmbusy() inside job_reap() -- should not happen");
216 		if (getenv("_AST_KSH_VMBUSY_ABORT"))
217 			abort();
218 	}
219 #ifdef DEBUG
220 	if(sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d signal=%d\n",__LINE__,getpid(),job.in_critical,sig) <=0)
221 		write(2,"waitsafe\n",9);
222 	sfsync(sfstderr);
223 #endif /* DEBUG */
224 	job.savesig = 0;
225 	if(sig)
226 		flags = WNOHANG|WUNTRACED|wcontinued;
227 	else
228 		flags = WUNTRACED|wcontinued;
229 	sh.waitevent = 0;
230 	oerrno = errno;
231 	while(1)
232 	{
233 		if(!(flags&WNOHANG) && !sh.intrap && job.pwlist)
234 		{
235 			sh_onstate(SH_TTYWAIT);
236 			if(waitevent && (*waitevent)(-1,-1L,0))
237 				flags |= WNOHANG;
238 		}
239 		pid = waitpid((pid_t)-1,&wstat,flags);
240 		sh_offstate(SH_TTYWAIT);
241 
242 		/*
243 		 * some systems (linux 2.6) may return EINVAL
244 		 * when there are no continued children
245 		 */
246 
247 		if (pid<0 && errno==EINVAL && (flags&WCONTINUED))
248 			pid = waitpid((pid_t)-1,&wstat,flags&=~WCONTINUED);
249 		sh_sigcheck();
250 		if(sig && pid<0 && errno==EINTR)
251 			continue;
252 		if(pid<=0)
253 			break;
254 		flags |= WNOHANG;
255 		job.waitsafe++;
256 		jp = 0;
257 		lastpid = pid;
258 		if(!(pw=job_bypid(pid)))
259 		{
260 #ifdef DEBUG
261 			sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d unknown job pid=%d pw=%x\n",__LINE__,getpid(),job.in_critical,pid,pw);
262 #endif /* DEBUG */
263 			if (WIFCONTINUED(wstat) && wcontinued)
264 				continue;
265 			pw = &dummy;
266 			pw->p_exit = 0;
267 			pw->p_pgrp = 0;
268 			pw->p_exitmin = 0;
269 			if(job.toclear)
270 				job_clear();
271 			if(++bck.count > sh.lim.child_max)
272 				job_chksave(0);
273 			if(jp = jobsave_create(pid))
274 			{
275 				jp->next = bck.list;
276 				bck.list = jp;
277 				jp->exitval = 0;
278 			}
279 			pw->p_flag = 0;
280 			lastpid = pw->p_pid = pid;
281 			px = 0;
282 			if(jp && WIFSTOPPED(wstat))
283 			{
284 				jp->exitval = SH_STOPSIG;
285 				continue;
286 			}
287 		}
288 #ifdef SIGTSTP
289 		else
290 			px=job_byjid(pw->p_job);
291 		if(WIFSTOPPED(wstat))
292 		{
293 			if(px)
294 			{
295 				/* move to top of job list */
296 				job_unlink(px);
297 				px->p_nxtjob = job.pwlist;
298 				job.pwlist = px;
299 			}
300 			pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
301 			pw->p_exit = WSTOPSIG(wstat);
302 			if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
303 				sh_fault(pw->p_exit);
304 			continue;
305 		}
306 		else if (WIFCONTINUED(wstat) && wcontinued)
307 			pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED);
308 		else
309 #endif /* SIGTSTP */
310 		{
311 			/* check for coprocess completion */
312 			if(pid==sh.cpid)
313 			{
314 				sh_close(sh.coutpipe);
315 				sh_close(sh.cpipe[1]);
316 				sh.cpipe[1] = -1;
317 				sh.coutpipe = -1;
318 			}
319 			else if(sh.subshell)
320 				sh_subjobcheck(pid);
321 
322 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
323 			if (WIFSIGNALED(wstat))
324 			{
325 				pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
326 				if (WTERMCORE(wstat))
327 					pw->p_flag |= P_COREDUMP;
328 				pw->p_exit = WTERMSIG(wstat);
329 				/* if process in current jobs terminates from
330 				 * an interrupt, propogate to parent shell
331 				 */
332 				if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
333 				{
334 					pw->p_flag &= ~P_NOTIFY;
335 					sh_offstate(SH_STOPOK);
336 					sh_fault(SIGINT);
337 					sh_onstate(SH_STOPOK);
338 				}
339 			}
340 			else
341 			{
342 				pw->p_flag |= (P_DONE|P_NOTIFY);
343 				pw->p_exit =  pw->p_exitmin;
344 				if(WEXITSTATUS(wstat) > pw->p_exitmin)
345 					pw->p_exit = WEXITSTATUS(wstat);
346 			}
347 			if(pw->p_pgrp==0)
348 				pw->p_flag &= ~P_NOTIFY;
349 		}
350 		if(jp && pw== &dummy)
351 		{
352 			jp->exitval = pw->p_exit;
353 			if(pw->p_flag&P_SIGNALLED)
354 				jp->exitval |= SH_EXITSIG;
355 		}
356 #ifdef DEBUG
357 		sfprintf(sfstderr,"ksh: job line %4d: reap pid=%d critical=%d job %d with pid %d flags=%o complete with status=%x exit=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job,pid,pw->p_flag,wstat,pw->p_exit);
358 		sfsync(sfstderr);
359 #endif /* DEBUG*/
360 		/* only top-level process in job should have notify set */
361 		if(px && pw != px)
362 			pw->p_flag &= ~P_NOTIFY;
363 		if(pid==pw->p_fgrp && pid==tcgetpgrp(JOBTTY))
364 		{
365 			px = job_byjid((int)pw->p_job);
366 			for(; px && (px->p_flag&P_DONE); px=px->p_nxtproc);
367 			if(!px)
368 				tcsetpgrp(JOBTTY,job.mypid);
369 		}
370 		if(!sh.intrap && sh.st.trapcom[SIGCHLD] && pid>0 && (pwfg!=job_bypid(pid)))
371 		{
372 			sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
373 			sh.trapnote |= SH_SIGTRAP;
374 		}
375 	}
376 	if(errno==ECHILD)
377 	{
378 		errno = oerrno;
379 		nochild = 1;
380 	}
381 	sh.waitevent = waitevent;
382 	if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
383 	{
384 		outfile = sfstderr;
385 		job_list(pw,JOB_NFLAG|JOB_NLFLAG);
386 		job_unpost(pw,1);
387 		sfsync(sfstderr);
388 	}
389 	if(sig)
390 		signal(sig, job_waitsafe);
391 	return(nochild);
392 }
393 
394 /*
395  * This is the SIGCLD interrupt routine
396  */
397 static void job_waitsafe(int sig)
398 {
399 	if(job.in_critical || vmbusy())
400 	{
401 		job.savesig = sig;
402 		job.waitsafe++;
403 	}
404 	else
405 		job_reap(sig);
406 }
407 
408 /*
409  * initialize job control if possible
410  * if lflag is set the switching driver message will not print
411  */
412 void job_init(Shell_t *shp, int lflag)
413 {
414 	register int ntry=0;
415 	job.fd = JOBTTY;
416 	signal(SIGCHLD,job_waitsafe);
417 #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
418 	signal(SIGCLD,job_waitsafe);
419 #   endif
420 	if(njob_savelist < NJOB_SAVELIST)
421 		init_savelist();
422 	if(!sh_isoption(SH_INTERACTIVE))
423 		return;
424 	/* use new line discipline when available */
425 #ifdef NTTYDISC
426 #   ifdef FIOLOOKLD
427 	if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
428 #   else
429 	if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
430 #   endif /* FIOLOOKLD */
431 		return;
432 	if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
433 	{
434 		/* no job control when running with MPX */
435 #   if SHOPT_VSH
436 		sh_onoption(SH_VIRAW);
437 #   endif /* SHOPT_VSH */
438 		return;
439 	}
440 	if(job.linedisc==NTTYDISC)
441 		job.linedisc = -1;
442 #endif /* NTTYDISC */
443 
444 	job.mypgid = getpgrp();
445 	/* some systems have job control, but not initialized */
446 	if(job.mypgid<=0)
447         {
448 		/* Get a controlling terminal and set process group */
449 		/* This should have already been done by rlogin */
450                 register int fd;
451                 register char *ttynam;
452 #ifndef SIGTSTP
453                 setpgid(0,shp->pid);
454 #endif /*SIGTSTP */
455                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
456                         return;
457                 close(JOBTTY);
458                 if((fd = open(ttynam,O_RDWR)) <0)
459                         return;
460                 if(fd!=JOBTTY)
461                         sh_iorenumber(shp,fd,JOBTTY);
462                 job.mypgid = shp->pid;
463 #ifdef SIGTSTP
464                 tcsetpgrp(JOBTTY,shp->pid);
465                 setpgid(0,shp->pid);
466 #endif /* SIGTSTP */
467         }
468 #ifdef SIGTSTP
469 	if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
470 	{
471 		/* wait until we are in the foreground */
472 		while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
473 		{
474 			if(job.mytgid == -1)
475 				return;
476 			/* Stop this shell until continued */
477 			signal(SIGTTIN,SIG_DFL);
478 			kill(shp->pid,SIGTTIN);
479 			/* resumes here after continue tries again */
480 			if(ntry++ > IOMAXTRY)
481 			{
482 				errormsg(SH_DICT,0,e_no_start);
483 				return;
484 			}
485 		}
486 	}
487 #endif /* SIGTTIN */
488 
489 #ifdef NTTYDISC
490 	/* set the line discipline */
491 	if(job.linedisc>=0)
492 	{
493 		int linedisc = NTTYDISC;
494 #   ifdef FIOPUSHLD
495 		tty_get(JOBTTY,&my_stty);
496 		if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
497 			return;
498 		if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
499 		{
500 			ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
501 			return;
502 		}
503 		tty_set(JOBTTY,TCSANOW,&my_stty);
504 #   else
505 		if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
506 			return;
507 #   endif /* FIOPUSHLD */
508 		if(lflag==0)
509 			errormsg(SH_DICT,0,e_newtty);
510 		else
511 			job.linedisc = -1;
512 	}
513 #endif /* NTTYDISC */
514 	if(!possible)
515 		return;
516 
517 #ifdef SIGTSTP
518 	/* make sure that we are a process group leader */
519 	setpgid(0,shp->pid);
520 #   if defined(SA_NOCLDWAIT) && defined(_lib_sigflag)
521 	sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
522 #   endif /* SA_NOCLDWAIT */
523 	signal(SIGTTIN,SIG_IGN);
524 	signal(SIGTTOU,SIG_IGN);
525 	/* The shell now handles ^Z */
526 	signal(SIGTSTP,sh_fault);
527 	tcsetpgrp(JOBTTY,shp->pid);
528 #   ifdef CNSUSP
529 	/* set the switch character */
530 	tty_get(JOBTTY,&my_stty);
531 	job.suspend = (unsigned)my_stty.c_cc[VSUSP];
532 	if(job.suspend == (unsigned char)CNSUSP)
533 	{
534 		my_stty.c_cc[VSUSP] = CSWTCH;
535 		tty_set(JOBTTY,TCSAFLUSH,&my_stty);
536 	}
537 #   endif /* CNSUSP */
538 	sh_onoption(SH_MONITOR);
539 	job.jobcontrol++;
540 	job.mypid = shp->pid;
541 #endif /* SIGTSTP */
542 	return;
543 }
544 
545 
546 /*
547  * see if there are any stopped jobs
548  * restore tty driver and pgrp
549  */
550 int job_close(Shell_t* shp)
551 {
552 	register struct process *pw;
553 	register int count = 0, running = 0;
554 	if(possible && !job.jobcontrol)
555 		return(0);
556 	else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
557 		return(0);
558 	else if(getpid() != job.mypid)
559 		return(0);
560 	job_lock();
561 	if(!tty_check(0))
562 		beenhere++;
563 	for(pw=job.pwlist;pw;pw=pw->p_nxtjob)
564 	{
565 		if(!(pw->p_flag&P_STOPPED))
566 		{
567 			if(!(pw->p_flag&P_DONE))
568 				running++;
569 			continue;
570 		}
571 		if(beenhere)
572 			killpg(pw->p_pgrp,SIGTERM);
573 		count++;
574 	}
575 	if(beenhere++ == 0 && job.pwlist)
576 	{
577 		if(count)
578 		{
579 			errormsg(SH_DICT,0,e_terminate);
580 			return(-1);
581 		}
582 		else if(running && shp->login_sh)
583 		{
584 			errormsg(SH_DICT,0,e_jobsrunning);
585 			return(-1);
586 		}
587 	}
588 	job_unlock();
589 #   ifdef SIGTSTP
590 	if(possible && setpgid(0,job.mypgid)>=0)
591 		tcsetpgrp(job.fd,job.mypgid);
592 #   endif /* SIGTSTP */
593 #   ifdef NTTYDISC
594 	if(job.linedisc>=0)
595 	{
596 		/* restore old line discipline */
597 #	ifdef FIOPUSHLD
598 		tty_get(job.fd,&my_stty);
599 		if (ioctl(job.fd, FIOPOPLD, 0) < 0)
600 			return(0);
601 		if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
602 		{
603 			job.linedisc = NTTYDISC;
604 			ioctl(job.fd, FIOPUSHLD, &job.linedisc);
605 			return(0);
606 		}
607 		tty_set(job.fd,TCSAFLUSH,&my_stty);
608 #	else
609 		if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
610 			return(0);
611 #	endif /* FIOPUSHLD */
612 		errormsg(SH_DICT,0,e_oldtty);
613 	}
614 #   endif /* NTTYDISC */
615 #   ifdef CNSUSP
616 	if(possible && job.suspend==CNSUSP)
617 	{
618 		tty_get(job.fd,&my_stty);
619 		my_stty.c_cc[VSUSP] = CNSUSP;
620 		tty_set(job.fd,TCSAFLUSH,&my_stty);
621 	}
622 #   endif /* CNSUSP */
623 	job.jobcontrol = 0;
624 	return(0);
625 }
626 
627 static void job_set(register struct process *pw)
628 {
629 	/* save current terminal state */
630 	tty_get(job.fd,&my_stty);
631 	if(pw->p_flag&P_STTY)
632 	{
633 		/* restore terminal state for job */
634 		tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
635 	}
636 #ifdef SIGTSTP
637 	if((pw->p_flag&P_STOPPED) || tcgetpgrp(job.fd) == sh.pid)
638 		tcsetpgrp(job.fd,pw->p_fgrp);
639 	/* if job is stopped, resume it in the background */
640 	job_unstop(pw);
641 #endif	/* SIGTSTP */
642 }
643 
644 static void job_reset(register struct process *pw)
645 {
646 	/* save the terminal state for current job */
647 #ifdef SIGTSTP
648 	job_fgrp(pw,tcgetpgrp(job.fd));
649 	if(tcsetpgrp(job.fd,job.mypid) !=0)
650 		return;
651 #endif	/* SIGTSTP */
652 	/* force the following tty_get() to do a tcgetattr() unless fg */
653 	if(!(pw->p_flag&P_FG))
654 		tty_set(-1, 0, NIL(struct termios*));
655 	if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
656 	{
657 		if(tty_get(job.fd,&pw->p_stty) == 0)
658 			pw->p_flag |= P_STTY;
659 		/* restore terminal state for job */
660 		tty_set(job.fd,TCSAFLUSH,&my_stty);
661 	}
662 	beenhere = 0;
663 }
664 #endif /* JOBS */
665 
666 /*
667  * wait built-in command
668  */
669 
670 void job_bwait(char **jobs)
671 {
672 	register char *jp;
673 	register struct process *pw;
674 	register pid_t pid;
675 	if(*jobs==0)
676 		job_wait((pid_t)-1);
677 	else while(jp = *jobs++)
678 	{
679 #ifdef JOBS
680 		if(*jp == '%')
681 		{
682 			job_lock();
683 			pw = job_bystring(jp);
684 			job_unlock();
685 			if(pw)
686 				pid = pw->p_pid;
687 			else
688 				return;
689 		}
690 		else
691 #endif /* JOBS */
692 			pid = (int)strtol(jp, (char**)0, 10);
693 		job_wait(-pid);
694 	}
695 }
696 
697 #ifdef JOBS
698 /*
699  * execute function <fun> for each job
700  */
701 
702 int job_walk(Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[])
703 {
704 	register struct process *pw;
705 	register int r = 0;
706 	register char *jobid, **jobs=joblist;
707 	register struct process *px;
708 	job_string = 0;
709 	outfile = file;
710 	by_number = 0;
711 	job_lock();
712 	pw = job.pwlist;
713 	if(jobs==0)
714 	{
715 		/* do all jobs */
716 		for(;pw;pw=px)
717 		{
718 			px = pw->p_nxtjob;
719 			if(pw->p_env != sh.jobenv)
720 				continue;
721 			if((*fun)(pw,arg))
722 				r = 2;
723 		}
724 	}
725 	else if(*jobs==0)	/* current job */
726 	{
727 		/* skip over non-stop jobs */
728 		while(pw && (pw->p_env!=sh.jobenv || pw->p_pgrp==0))
729 			pw = pw->p_nxtjob;
730 		if((*fun)(pw,arg))
731 			r = 2;
732 	}
733 	else while(jobid = *jobs++)
734 	{
735 		job_string = jobid;
736 		if(*jobid==0)
737 			errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
738 		if(*jobid == '%')
739 			pw = job_bystring(jobid);
740 		else
741 		{
742 			int pid = (int)strtol(jobid, (char**)0, 10);
743 			if(pid<0)
744 				jobid++;
745 			while(isdigit(*jobid))
746 				jobid++;
747 			if(*jobid)
748 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,job_string);
749 			if(!(pw = job_bypid(pid)))
750 			{
751 				pw = &dummy;
752 				pw->p_pid = pid;
753 				pw->p_pgrp = pid;
754 			}
755 			by_number = 1;
756 		}
757 		if((*fun)(pw,arg))
758 			r = 2;
759 		by_number = 0;
760 	}
761 	job_unlock();
762 	return(r);
763 }
764 
765 /*
766  * send signal <sig> to background process group if not disowned
767  */
768 int job_terminate(register struct process *pw,register int sig)
769 {
770 	if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
771 		job_kill(pw,sig);
772 	return(0);
773 }
774 
775 /*
776  * list the given job
777  * flag JOB_LFLAG for long listing
778  * flag JOB_NFLAG for list only jobs marked for notification
779  * flag JOB_PFLAG for process id(s) only
780  */
781 
782 int job_list(struct process *pw,register int flag)
783 {
784 	register struct process *px = pw;
785 	register int  n;
786 	register const char *msg;
787 	register int msize;
788 	if(!pw || pw->p_job<=0)
789 		return(1);
790 	if(pw->p_env != sh.jobenv)
791 		return(0);
792 	if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
793 		return(0);
794 	if((flag&JOB_PFLAG))
795 	{
796 		sfprintf(outfile,"%d\n",px->p_pgrp?px->p_pgrp:px->p_pid);
797 		return(0);
798 	}
799 	if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
800 		return(0);
801 	job_lock();
802 	n = px->p_job;
803 	if(px==job.pwlist)
804 		msize = '+';
805 	else if(px==job.pwlist->p_nxtjob)
806 		msize = '-';
807 	else
808 		msize = ' ';
809 	if(flag&JOB_NLFLAG)
810 		sfputc(outfile,'\n');
811 	sfprintf(outfile,"[%d] %c ",n, msize);
812 	do
813 	{
814 		n = 0;
815 		if(flag&JOB_LFLAG)
816 			sfprintf(outfile,"%d\t",px->p_pid);
817 		if(px->p_flag&P_SIGNALLED)
818 			msg = job_sigmsg((int)(px->p_exit));
819 		else if(px->p_flag&P_NOTIFY)
820 		{
821 			msg = sh_translate(e_done);
822 			n = px->p_exit;
823 		}
824 		else
825 			msg = sh_translate(e_running);
826 		px->p_flag &= ~P_NOTIFY;
827 		sfputr(outfile,msg,-1);
828 		msize = strlen(msg);
829 		if(n)
830 		{
831 			sfprintf(outfile,"(%d)",(int)n);
832 			msize += (3+(n>10)+(n>100));
833 		}
834 		if(px->p_flag&P_COREDUMP)
835 		{
836 			msg = sh_translate(e_coredump);
837 			sfputr(outfile, msg, -1);
838 			msize += strlen(msg);
839 		}
840 		sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
841 		if(flag&JOB_LFLAG)
842 			px = px->p_nxtproc;
843 		else
844 		{
845 			while(px=px->p_nxtproc)
846 				px->p_flag &= ~P_NOTIFY;
847 			px = 0;
848 		}
849 		if(!px)
850 			hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
851 		else
852 			sfputr(outfile, e_nlspace, -1);
853 	}
854 	while(px);
855 	job_unlock();
856 	return(0);
857 }
858 
859 /*
860  * get the process group given the job number
861  * This routine returns the process group number or -1
862  */
863 static struct process *job_bystring(register char *ajob)
864 {
865 	register struct process *pw=job.pwlist;
866 	register int c;
867 	if(*ajob++ != '%' || !pw)
868 		return(NIL(struct process*));
869 	c = *ajob;
870 	if(isdigit(c))
871 		pw = job_byjid((int)strtol(ajob, (char**)0, 10));
872 	else if(c=='+' || c=='%')
873 		;
874 	else if(c=='-')
875 	{
876 		if(pw)
877 			pw = job.pwlist->p_nxtjob;
878 	}
879 	else
880 		pw = job_byname(ajob);
881 	if(pw && pw->p_flag)
882 		return(pw);
883 	return(NIL(struct process*));
884 }
885 
886 /*
887  * Kill a job or process
888  */
889 
890 int job_kill(register struct process *pw,register int sig)
891 {
892 	register pid_t pid;
893 	register int r;
894 	const char *msg;
895 #ifdef SIGTSTP
896 	int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
897 #else
898 #	define stopsig	1
899 #endif	/* SIGTSTP */
900 	job_lock();
901 	errno = ECHILD;
902 	if(pw==0)
903 		goto error;
904 	pid = pw->p_pid;
905 	if(by_number)
906 	{
907 		if(pid==0 && job.jobcontrol)
908 			r = job_walk(outfile, job_kill,sig, (char**)0);
909 #ifdef SIGTSTP
910 		if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
911 		{
912 			/* can't stop login shell */
913 			errno = EPERM;
914 			r = -1;
915 		}
916 		else
917 		{
918 			if(pid>=0)
919 			{
920 				if((r = kill(pid,sig))>=0 && !stopsig)
921 				{
922 					if(pw->p_flag&P_STOPPED)
923 						pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
924 					if(sig)
925 						kill(pid,SIGCONT);
926 				}
927 			}
928 			else
929 			{
930 				if((r = killpg(-pid,sig))>=0 && !stopsig)
931 				{
932 					job_unstop(job_bypid(pw->p_pid));
933 					if(sig)
934 						killpg(-pid,SIGCONT);
935 				}
936 			}
937 		}
938 #else
939 		if(pid>=0)
940 			r = kill(pid,sig);
941 		else
942 			r = killpg(-pid,sig);
943 #endif	/* SIGTSTP */
944 	}
945 	else
946 	{
947 		if(pid = pw->p_pgrp)
948 		{
949 			r = killpg(pid,sig);
950 #ifdef SIGTSTP
951 			if(r>=0 && (sig==SIGHUP||sig==SIGTERM || sig==SIGCONT))
952 				job_unstop(pw);
953 #endif	/* SIGTSTP */
954 			if(r>=0)
955 				sh_delay(.05);
956 		}
957 		while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0)
958 		{
959 #ifdef SIGTSTP
960 			if(sig==SIGHUP || sig==SIGTERM)
961 				kill(pw->p_pid,SIGCONT);
962 #endif	/* SIGTSTP */
963 			pw = pw->p_nxtproc;
964 		}
965 	}
966 	if(r<0 && job_string)
967 	{
968 	error:
969 		if(pw && by_number)
970 			msg = sh_translate(e_no_proc);
971 		else
972 			msg = sh_translate(e_no_job);
973 		if(errno == EPERM)
974 			msg = sh_translate(e_access);
975 		sfprintf(sfstderr,"kill: %s: %s\n",job_string, msg);
976 		r = 2;
977 	}
978 	sh_delay(.001);
979 	job_unlock();
980 	return(r);
981 }
982 
983 /*
984  * Get process structure from first letters of jobname
985  *
986  */
987 
988 static struct process *job_byname(char *name)
989 {
990 	register struct process *pw = job.pwlist;
991 	register struct process *pz = 0;
992 	register int *flag = 0;
993 	register char *cp = name;
994 	int offset;
995 	if(!sh.hist_ptr)
996 		return(NIL(struct process*));
997 	if(*cp=='?')
998 		cp++,flag= &offset;
999 	for(;pw;pw=pw->p_nxtjob)
1000 	{
1001 		if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
1002 		{
1003 			if(pz)
1004 				errormsg(SH_DICT,ERROR_exit(1),e_jobusage,name-1);
1005 			pz = pw;
1006 		}
1007 	}
1008 	return(pz);
1009 }
1010 
1011 #else
1012 #   define job_set(x)
1013 #   define job_reset(x)
1014 #endif /* JOBS */
1015 
1016 
1017 
1018 /*
1019  * Initialize the process posting array
1020  */
1021 
1022 void	job_clear(void)
1023 {
1024 	register struct process *pw, *px;
1025 	register struct process *pwnext;
1026 	register int j = BYTE(sh.lim.child_max);
1027 	register struct jobsave *jp,*jpnext;
1028 	job_lock();
1029 	for(pw=job.pwlist; pw; pw=pwnext)
1030 	{
1031 		pwnext = pw->p_nxtjob;
1032 		while(px=pw)
1033 		{
1034 			pw = pw->p_nxtproc;
1035 			free((void*)px);
1036 		}
1037 	}
1038 	for(jp=bck.list; jp;jp=jpnext)
1039 	{
1040 		jpnext = jp->next;
1041 		free((void*)jp);
1042 	}
1043 	bck.list = 0;
1044 	if(njob_savelist < NJOB_SAVELIST)
1045 		init_savelist();
1046 	job.pwlist = NIL(struct process*);
1047 	job.numpost=0;
1048 	job.waitall = 0;
1049 	job.curpgid = 0;
1050 	job.toclear = 0;
1051 	if(!job.freejobs)
1052 		job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
1053 	while(j >=0)
1054 		job.freejobs[j--]  = 0;
1055 	job_unlock();
1056 }
1057 
1058 /*
1059  * put the process <pid> on the process list and return the job number
1060  * if non-zero, <join> is the process id of the job to join
1061  */
1062 
1063 int job_post(pid_t pid, pid_t join)
1064 {
1065 	register struct process *pw;
1066 	register History_t *hp = sh.hist_ptr;
1067 	int val;
1068 	sh.jobenv = sh.curenv;
1069 	if(njob_savelist < NJOB_SAVELIST)
1070 		init_savelist();
1071 	if(job.toclear)
1072 	{
1073 		job_clear();
1074 		return(0);
1075 	}
1076 	job_lock();
1077 	if(pw = job_bypid(pid))
1078 		job_unpost(pw,0);
1079 	if(join && (pw=job_bypid(join)))
1080 	{
1081 		/* if job to join is not first move it to front */
1082 		if((pw=job_byjid(pw->p_job)) != job.pwlist)
1083 		{
1084 			job_unlink(pw);
1085 			pw->p_nxtjob = job.pwlist;
1086 			job.pwlist = pw;
1087 		}
1088 	}
1089 	if(pw=freelist)
1090 		freelist = pw->p_nxtjob;
1091 	else
1092 		pw = new_of(struct process,0);
1093 	job.numpost++;
1094 	if(join && job.pwlist)
1095 	{
1096 		/* join existing current job */
1097 		pw->p_nxtjob = job.pwlist->p_nxtjob;
1098 		pw->p_nxtproc = job.pwlist;
1099 		pw->p_job = job.pwlist->p_job;
1100 	}
1101 	else
1102 	{
1103 		/* create a new job */
1104 		while((pw->p_job = job_alloc()) < 0)
1105 			job_wait((pid_t)1);
1106 		pw->p_nxtjob = job.pwlist;
1107 		pw->p_nxtproc = 0;
1108 	}
1109 	job.pwlist = pw;
1110 	pw->p_env = sh.curenv;
1111 	pw->p_pid = pid;
1112 	pw->p_flag = P_EXITSAVE;
1113 	pw->p_exitmin = sh.xargexit;
1114 	pw->p_exit = 0;
1115 	if(sh_isstate(SH_MONITOR))
1116 	{
1117 		if(killpg(job.curpgid,0)<0 && errno==ESRCH)
1118 			job.curpgid = pid;
1119 		pw->p_fgrp = job.curpgid;
1120 	}
1121 	else
1122 		pw->p_fgrp = 0;
1123 	pw->p_pgrp = pw->p_fgrp;
1124 #ifdef DEBUG
1125 	sfprintf(sfstderr,"ksh: job line %4d: post pid=%d critical=%d job=%d pid=%d pgid=%d savesig=%d join=%d\n",__LINE__,getpid(),job.in_critical,pw->p_job,
1126 		pw->p_pid,pw->p_pgrp,job.savesig,join);
1127 	sfsync(sfstderr);
1128 #endif /* DEBUG */
1129 #ifdef JOBS
1130 	if(hp && !sh_isstate(SH_PROFILE))
1131 		pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
1132 	else
1133 		pw->p_name = -1;
1134 #endif /* JOBS */
1135 	if ((val = job_chksave(pid)) >= 0)
1136 	{
1137 		pw->p_exit = val;
1138 		if(pw->p_exit==SH_STOPSIG)
1139 		{
1140 			pw->p_flag |= (P_SIGNALLED|P_STOPPED);
1141 			pw->p_exit = 0;
1142 		}
1143 		else
1144 			pw->p_flag |= (P_DONE|P_NOTIFY);
1145 	}
1146 	lastpid = 0;
1147 	job_unlock();
1148 	return(pw->p_job);
1149 }
1150 
1151 /*
1152  * Returns a process structure give a process id
1153  */
1154 
1155 static struct process *job_bypid(pid_t pid)
1156 {
1157 	register struct process  *pw, *px;
1158 	for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
1159 		for(px=pw; px; px=px->p_nxtproc)
1160 		{
1161 			if(px->p_pid==pid)
1162 				return(px);
1163 		}
1164 	return(NIL(struct process*));
1165 }
1166 
1167 /*
1168  * return a pointer to a job given the job id
1169  */
1170 
1171 static struct process *job_byjid(int jobid)
1172 {
1173 	register struct process *pw;
1174 	for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
1175 	{
1176 		if(pw->p_job==jobid)
1177 			break;
1178 	}
1179 	return(pw);
1180 }
1181 
1182 /*
1183  * print a signal message
1184  */
1185 static void job_prmsg(register struct process *pw)
1186 {
1187 	if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
1188 	{
1189 		register const char *msg, *dump;
1190 		msg = job_sigmsg((int)(pw->p_exit));
1191 		msg = sh_translate(msg);
1192 		if(pw->p_flag&P_COREDUMP)
1193 			dump =  sh_translate(e_coredump);
1194 		else
1195 			dump = "";
1196 		if(sh_isstate(SH_INTERACTIVE))
1197 			sfprintf(sfstderr,"%s%s\n",msg,dump);
1198 		else
1199 			errormsg(SH_DICT,2,"%d: %s%s",pw->p_pid,msg,dump);
1200 	}
1201 }
1202 
1203 /*
1204  * Wait for process pid to complete
1205  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
1206  * pid=0 to unpost all done processes
1207  * pid=1 to wait for at least one process to complete
1208  * pid=-1 to wait for all runing processes
1209  */
1210 
1211 int	job_wait(register pid_t pid)
1212 {
1213 	register struct process *pw=0,*px;
1214 	register int	jobid = 0;
1215 	int		nochild = 1;
1216 	char		intr = 0;
1217 	if(pid <= 0)
1218 	{
1219 		if(pid==0)
1220 			goto done;
1221 		pid = -pid;
1222 		intr = 1;
1223 	}
1224 	job_lock();
1225 	if(pid > 1)
1226 	{
1227 		if(pid==sh.spid)
1228 			sh.spid = 0;
1229 		if(!(pw=job_bypid(pid)))
1230 		{
1231 			/* check to see whether job status has been saved */
1232 			if((sh.exitval = job_chksave(pid)) < 0)
1233 				sh.exitval = ERROR_NOENT;
1234 			exitset();
1235 			job_unlock();
1236 			return(nochild);
1237 		}
1238 		else if(intr && pw->p_env!=sh.curenv)
1239 		{
1240 			sh.exitval = ERROR_NOENT;
1241 			job_unlock();
1242 			return(nochild);
1243 		}
1244 		jobid = pw->p_job;
1245 		if(!intr)
1246 			pw->p_flag &= ~P_EXITSAVE;
1247 		if(pw->p_pgrp && job.parent!= (pid_t)-1)
1248 			job_set(job_byjid(jobid));
1249 	}
1250 	pwfg = pw;
1251 #ifdef DEBUG
1252 	sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d job=%d pid=%d\n",__LINE__,getpid(),job.in_critical,jobid,pid);
1253 	if(pw)
1254 		sfprintf(sfstderr,"ksh: job line %4d: wait pid=%d critical=%d flags=%o\n",__LINE__,getpid(),job.in_critical,pw->p_flag);
1255 #endif /* DEBUG*/
1256 	errno = 0;
1257 	if(sh.coutpipe>=0 && sh.cpid==lastpid)
1258 	{
1259 		sh_close(sh.coutpipe);
1260 		sh_close(sh.cpipe[1]);
1261 		sh.cpipe[1] = sh.coutpipe = -1;
1262 	}
1263 	while(1)
1264 	{
1265 		if(job.waitsafe)
1266 		{
1267 			for(px=job.pwlist;px; px = px->p_nxtjob)
1268 			{
1269 				if(px!=pw && (px->p_flag&P_NOTIFY))
1270 				{
1271 					if(sh_isoption(SH_NOTIFY))
1272 					{
1273 						outfile = sfstderr;
1274 						job_list(px,JOB_NFLAG|JOB_NLFLAG);
1275 						sfsync(sfstderr);
1276 					}
1277 					else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
1278 					{
1279 						job_prmsg(px);
1280 						px->p_flag &= ~P_NOTIFY;
1281 					}
1282 				}
1283 			}
1284 		}
1285 		if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
1286 		{
1287 #ifdef SIGTSTP
1288 			if(pw->p_flag&P_STOPPED)
1289 			{
1290 				pw->p_flag |= P_EXITSAVE;
1291 				if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
1292 				{
1293 					if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
1294 						break;
1295 
1296 					killpg(pw->p_pgrp,SIGCONT);
1297 				}
1298 				else /* ignore stop when non-interactive */
1299 					pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
1300 			}
1301 			else
1302 #endif /* SIGTSTP */
1303 			{
1304 				if(pw->p_flag&P_SIGNALLED)
1305 				{
1306 					pw->p_flag &= ~P_NOTIFY;
1307 					job_prmsg(pw);
1308 				}
1309 				else if(pw->p_flag&P_DONE)
1310 					pw->p_flag &= ~P_NOTIFY;
1311 				if(pw->p_job==jobid)
1312 				{
1313 					px = job_byjid(jobid);
1314 					/* last process in job */
1315 					if(sh_isoption(SH_PIPEFAIL))
1316 					{
1317 						/* last non-zero exit */
1318 						for(;px;px=px->p_nxtproc)
1319 						{
1320 							if(px->p_exit)
1321 								break;
1322 						}
1323 						if(!px)
1324 							px = pw;
1325 					}
1326 					else if(px!=pw)
1327 						px = 0;
1328 					if(px)
1329 					{
1330 						sh.exitval=px->p_exit;
1331 						if(px->p_flag&P_SIGNALLED)
1332 							sh.exitval |= SH_EXITSIG;
1333 						if(intr)
1334 							px->p_flag &= ~P_EXITSAVE;
1335 					}
1336 				}
1337 				if(!job.waitall)
1338 				{
1339 					if(!sh_isoption(SH_PIPEFAIL))
1340 						job_unpost(pw,1);
1341 					break;
1342 				}
1343 				else if(!(px=job_unpost(pw,1)))
1344 					break;
1345 				pw = px;
1346 				continue;
1347 			}
1348 		}
1349 		sfsync(sfstderr);
1350 		job.waitsafe = 0;
1351 		nochild = job_reap(job.savesig);
1352 		if(job.waitsafe)
1353 			continue;
1354 		if(nochild)
1355 			break;
1356 		if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
1357 			sh_timetraps();
1358 		if((intr && sh.trapnote) || (pid==1 && !intr))
1359 			break;
1360 	}
1361 	pwfg = 0;
1362 	job_unlock();
1363 	if(pid==1)
1364 		return(nochild);
1365 	exitset();
1366 	if(pw->p_pgrp)
1367 	{
1368 		job_reset(pw);
1369 		/* propogate keyboard interrupts to parent */
1370 		if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
1371 			sh_fault(SIGINT);
1372 #ifdef SIGTSTP
1373 		else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
1374 		{
1375 			job.parent = 0;
1376 			sh_fault(SIGTSTP);
1377 		}
1378 #endif /* SIGTSTP */
1379 	}
1380 	else
1381 	{
1382 		if(pw->p_pid == tcgetpgrp(JOBTTY))
1383 		{
1384 			if(pw->p_pgrp==0)
1385 				pw->p_pgrp = pw->p_pid;
1386 			job_reset(pw);
1387 		}
1388 		tty_set(-1, 0, NIL(struct termios*));
1389 	}
1390 done:
1391 	if(!job.waitall && sh_isoption(SH_PIPEFAIL))
1392 		return(nochild);
1393 	if(!sh.intrap)
1394 	{
1395 		job_lock();
1396 		for(pw=job.pwlist; pw; pw=px)
1397 		{
1398 			px = pw->p_nxtjob;
1399 			job_unpost(pw,0);
1400 		}
1401 		job_unlock();
1402 	}
1403 	return(nochild);
1404 }
1405 
1406 /*
1407  * move job to foreground if bgflag == 'f'
1408  * move job to background if bgflag == 'b'
1409  * disown job if bgflag == 'd'
1410  */
1411 
1412 int job_switch(register struct process *pw,int bgflag)
1413 {
1414 	register const char *msg;
1415 	job_lock();
1416 	if(!pw || !(pw=job_byjid((int)pw->p_job)))
1417 	{
1418 		job_unlock();
1419 		return(1);
1420 	}
1421 	if(bgflag=='d')
1422 	{
1423 		for(; pw; pw=pw->p_nxtproc)
1424 			pw->p_flag |= P_DISOWN;
1425 		job_unlock();
1426 		return(0);
1427 	}
1428 #ifdef SIGTSTP
1429 	if(bgflag=='b')
1430 	{
1431 		sfprintf(outfile,"[%d]\t",(int)pw->p_job);
1432 		sh.bckpid = pw->p_pid;
1433 		msg = "&";
1434 	}
1435 	else
1436 	{
1437 		job_unlink(pw);
1438 		pw->p_nxtjob = job.pwlist;
1439 		job.pwlist = pw;
1440 		msg = "";
1441 	}
1442 	hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
1443 	sfputr(outfile,msg,'\n');
1444 	sfsync(outfile);
1445 	if(bgflag=='f')
1446 	{
1447 		if(!(pw=job_unpost(pw,1)))
1448 		{
1449 			job_unlock();
1450 			return(1);
1451 		}
1452 		job.waitall = 1;
1453 		pw->p_flag |= P_FG;
1454 		job_wait(pw->p_pid);
1455 		job.waitall = 0;
1456 	}
1457 	else if(pw->p_flag&P_STOPPED)
1458 		job_unstop(pw);
1459 #endif /* SIGTSTP */
1460 	job_unlock();
1461 	return(0);
1462 }
1463 
1464 
1465 #ifdef SIGTSTP
1466 /*
1467  * Set the foreground group associated with a job
1468  */
1469 
1470 static void job_fgrp(register struct process *pw, int newgrp)
1471 {
1472 	for(; pw; pw=pw->p_nxtproc)
1473 		pw->p_fgrp = newgrp;
1474 }
1475 
1476 /*
1477  * turn off STOP state of a process group and send CONT signals
1478  */
1479 
1480 static void job_unstop(register struct process *px)
1481 {
1482 	register struct process *pw;
1483 	register int num = 0;
1484 	for(pw=px ;pw ;pw=pw->p_nxtproc)
1485 	{
1486 		if(pw->p_flag&P_STOPPED)
1487 		{
1488 			num++;
1489 			pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
1490 		}
1491 	}
1492 	if(num!=0)
1493 	{
1494 		if(px->p_fgrp != px->p_pgrp)
1495 			killpg(px->p_fgrp,SIGCONT);
1496 		killpg(px->p_pgrp,SIGCONT);
1497 	}
1498 }
1499 #endif	/* SIGTSTP */
1500 
1501 /*
1502  * remove a job from table
1503  * If all the processes have not completed, unpost first non-completed  process
1504  * Otherwise the job is removed and job_unpost returns NULL.
1505  * pwlist is reset if the first job is removed
1506  * if <notify> is non-zero, then jobs with pending notifications are unposted
1507  */
1508 
1509 static struct process *job_unpost(register struct process *pwtop,int notify)
1510 {
1511 	register struct process *pw;
1512 	/* make sure all processes are done */
1513 #ifdef DEBUG
1514 	sfprintf(sfstderr,"ksh: job line %4d: drop pid=%d critical=%d pid=%d env=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_pid,pwtop->p_env);
1515 	sfsync(sfstderr);
1516 #endif /* DEBUG */
1517 	pwtop = pw = job_byjid((int)pwtop->p_job);
1518 	for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)||pw->p_env); pw=pw->p_nxtproc);
1519 	if(pw)
1520 		return(pw);
1521 	/* all processes complete, unpost job */
1522 	job_unlink(pwtop);
1523 	for(pw=pwtop; pw; pw=pw->p_nxtproc)
1524 	{
1525 		/* save the exit status for background jobs */
1526 		if((pw->p_flag&P_EXITSAVE) ||  pw->p_pid==sh.spid)
1527 		{
1528 			struct jobsave *jp;
1529 			/* save status for future wait */
1530 			if(bck.count++ > sh.lim.child_max)
1531 				job_chksave(0);
1532 			if(jp = jobsave_create(pw->p_pid))
1533 			{
1534 				jp->next = bck.list;
1535 				bck.list = jp;
1536 				jp->exitval = pw->p_exit;
1537 				if(pw->p_flag&P_SIGNALLED)
1538 					jp->exitval |= SH_EXITSIG;
1539 			}
1540 			pw->p_flag &= ~P_EXITSAVE;
1541 		}
1542 		pw->p_flag &= ~P_DONE;
1543 		job.numpost--;
1544 		pw->p_nxtjob = freelist;
1545 		freelist = pw;
1546 	}
1547 #ifdef DEBUG
1548 	sfprintf(sfstderr,"ksh: job line %4d: free pid=%d critical=%d job=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_job);
1549 	sfsync(sfstderr);
1550 #endif /* DEBUG */
1551 	job_free((int)pwtop->p_job);
1552 	return((struct process*)0);
1553 }
1554 
1555 /*
1556  * unlink a job form the job list
1557  */
1558 static void job_unlink(register struct process *pw)
1559 {
1560 	register struct process *px;
1561 	if(pw==job.pwlist)
1562 	{
1563 		job.pwlist = pw->p_nxtjob;
1564 		job.curpgid = 0;
1565 		return;
1566 	}
1567 	for(px=job.pwlist;px;px=px->p_nxtjob)
1568 		if(px->p_nxtjob == pw)
1569 		{
1570 			px->p_nxtjob = pw->p_nxtjob;
1571 			return;
1572 		}
1573 }
1574 
1575 /*
1576  * get an unused job number
1577  * freejobs is a bit vector, 0 is unused
1578  */
1579 
1580 static int job_alloc(void)
1581 {
1582 	register int j=0;
1583 	register unsigned mask = 1;
1584 	register unsigned char *freeword;
1585 	register int jmax = BYTE(sh.lim.child_max);
1586 	/* skip to first word with a free slot */
1587 	for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
1588 	if(j >= jmax)
1589 	{
1590 		register struct process *pw;
1591 		for(j=1; j < sh.lim.child_max; j++)
1592 		{
1593 			if((pw=job_byjid(j))&& !job_unpost(pw,0))
1594 				break;
1595 		}
1596 		j /= CHAR_BIT;
1597 		if(j >= jmax)
1598 			return(-1);
1599 	}
1600 	freeword = &job.freejobs[j];
1601 	j *= CHAR_BIT;
1602 	for(j++;mask&(*freeword);j++,mask <<=1);
1603 	*freeword  |= mask;
1604 	return(j);
1605 }
1606 
1607 /*
1608  * return a job number
1609  */
1610 
1611 static void job_free(register int n)
1612 {
1613 	register int j = (--n)/CHAR_BIT;
1614 	register unsigned mask;
1615 	n -= j*CHAR_BIT;
1616 	mask = 1 << n;
1617 	job.freejobs[j]  &= ~mask;
1618 }
1619 
1620 static char *job_sigmsg(int sig)
1621 {
1622 	static char signo[40];
1623 #ifdef apollo
1624 	/*
1625 	 * This code handles the formatting for the apollo specific signal
1626 	 * SIGAPOLLO.
1627 	 */
1628 	extern char *apollo_error(void);
1629 
1630 	if ( sig == SIGAPOLLO )
1631 		return( apollo_error() );
1632 #endif /* apollo */
1633 	if(sig<sh.sigmax && sh.sigmsg[sig])
1634 		return(sh.sigmsg[sig]);
1635 #if defined(SIGRTMIN) && defined(SIGRTMAX)
1636 	if(sig>=sh.sigruntime[SH_SIGRTMIN] && sig<=sh.sigruntime[SH_SIGRTMAX])
1637 	{
1638 		static char sigrt[20];
1639 		if(sig>sh.sigruntime[SH_SIGRTMIN]+(sh.sigruntime[SH_SIGRTMAX]-sig<=sh.sigruntime[SH_SIGRTMIN])/2)
1640 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMAX-%d",sh.sigruntime[SH_SIGRTMAX]-sig);
1641 		else
1642 			sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-sh.sigruntime[SH_SIGRTMIN]);
1643 		return(sigrt);
1644 	}
1645 #endif
1646 	sfsprintf(signo,sizeof(signo),sh_translate(e_signo),sig);
1647 	return(signo);
1648 }
1649 
1650 /*
1651  * see whether exit status has been saved and delete it
1652  * if pid==0, then oldest saved process is deleted
1653  * If pid is not found a -1 is returned.
1654  */
1655 static int job_chksave(register pid_t pid)
1656 {
1657 	register struct jobsave *jp = bck.list, *jpold=0;
1658 	register int r= -1;
1659 	while(jp)
1660 	{
1661 		if(jp->pid==pid)
1662 			break;
1663 		if(pid==0 && !jp->next)
1664 			break;
1665 		jpold = jp;
1666 		jp = jp->next;
1667 	}
1668 	if(jp)
1669 	{
1670 		r = 0;
1671 		if(pid)
1672 			r = jp->exitval;
1673 		if(jpold)
1674 			jpold->next = jp->next;
1675 		else
1676 			bck.list = jp->next;
1677 		bck.count--;
1678 		if(njob_savelist < NJOB_SAVELIST)
1679 		{
1680 			njob_savelist++;
1681 			jp->next = job_savelist;
1682 			job_savelist = jp;
1683 		}
1684 		else
1685 			free((void*)jp);
1686 	}
1687 	return(r);
1688 }
1689 
1690 void *job_subsave(void)
1691 {
1692 	struct back_save *bp = new_of(struct back_save,0);
1693 	job_lock();
1694 	*bp = bck;
1695 	bck.count = 0;
1696 	bck.list = 0;
1697 	job_unlock();
1698 	return((void*)bp);
1699 }
1700 
1701 void job_subrestore(void* ptr)
1702 {
1703 	register struct jobsave *jp;
1704 	register struct back_save *bp = (struct back_save*)ptr;
1705 	register struct process *pw, *px, *pwnext;
1706 	struct jobsave *jpnext;
1707 	job_lock();
1708 	for(jp=bck.list; jp; jp=jpnext)
1709 	{
1710 		jpnext = jp->next;
1711 		if(jp->pid==sh.spid)
1712 		{
1713 			jp->next = bp->list;
1714 			bp->list = jp;
1715 		}
1716 		else
1717 			job_chksave(jp->pid);
1718 	}
1719 	for(pw=job.pwlist; pw; pw=pwnext)
1720 	{
1721 		pwnext = pw->p_nxtjob;
1722 		if(pw->p_env != sh.curenv)
1723 			continue;
1724 		for(px=pw; px; px=px->p_nxtproc)
1725 			px->p_flag |= P_DONE;
1726 		job_unpost(pw,0);
1727 	}
1728 
1729 	/*
1730 	 * queue up old lists for disposal by job_reap()
1731 	 */
1732 
1733 	bck = *bp;
1734 	free((void*)bp);
1735 	job_unlock();
1736 }
1737 
1738 int sh_waitsafe(void)
1739 {
1740 	return(job.waitsafe);
1741 }
1742 
1743 void job_fork(pid_t parent)
1744 {
1745 #ifdef DEBUG
1746 	sfprintf(sfstderr,"ksh: job line %4d: fork pid=%d critical=%d parent=%d\n",__LINE__,getpid(),job.in_critical,parent);
1747 #endif /* DEBUG */
1748 	switch (parent)
1749 	{
1750 	case -1:
1751 		job_lock();
1752 		break;
1753 	case 0:
1754 		job_unlock();
1755 		job.waitsafe = 0;
1756 		job.in_critical = 0;
1757 		break;
1758 	default:
1759 		job_unlock();
1760 		break;
1761 	}
1762 }
1763