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