xref: /original-bsd/local/toolchest/ksh/sh/jobs.c (revision e59fb703)
1 /*
2 
3  *      Copyright (c) 1984, 1985, 1986 AT&T
4  *      All Rights Reserved
5 
6  *      THIS IS UNPUBLISHED PROPRIETARY SOURCE
7  *      CODE OF AT&T.
8  *      The copyright notice above does not
9  *      evidence any actual or intended
10  *      publication of such source code.
11 
12  */
13 /* @(#)jobs.c	1.1 */
14 
15 /*
16  *  Job control for UNIX Shell
17  *
18  *   David Korn
19  *   AT&T Bell Laboratories
20  *   Room 5D-112
21  *   Murray Hill, N. J. 07974
22  *   Tel. x7975
23  *
24  *  Written October, 1982
25  */
26 
27 
28 #include	<errno.h>
29 
30 #ifdef BSD
31 # ifdef BSD_4_2
32 #include	<sys/wait.h>
33 # else
34 #include	<wait.h>
35 # endif /* BSD_4_2 */
36 #endif	/* BSD */
37 
38 #ifdef SXT
39 #define		SIGSTOP	20
40 #define		SIGSTIN	21
41 #include	<sys/types.h>
42 #include	<sys/tty.h>
43 #include	<sys/sxt.h>
44 #include	<sys/stat.h>
45 #endif	/* SXT */
46 
47 #include	"defs.h"
48 #include	"flags.h"
49 #include	"shtype.h"
50 #include	"jobs.h"
51 #include	"brkincr.h"
52 #include	"io.h"
53 #include	"history.h"
54 
55 #ifdef SXT
56 #undef input
57 static status_update();
58 static int open_chan();
59 static int fd_chan = -1;
60 static char tinybuf;
61 #endif	/* SXT */
62 
63 #define LOBYTE	0377
64 #define MAXMSG	25
65 
66 void	await();
67 void	postclr();
68 
69 extern void	fault();
70 extern long	hist_list();
71 extern long	hist_position();
72 extern char	*itos();
73 extern char	*malloc();
74 extern void	failed();
75 extern void	free();
76 extern void	p_str();
77 extern void	p_prp();
78 extern void	p_num();
79 extern void	p_sub();
80 extern void	p_nchr();
81 extern void	p_flush();
82 extern void	p_setout();
83 
84 static int	set_ttygrp();
85 static int	set_job();
86 static int	reset_ttygrp();
87 static struct process *next_proc();
88 static struct process *jobbyname();
89 static struct process *job_bynum();
90 static struct process *job_bypid();
91 static struct process *job_post();
92 static struct process *unpost();
93 static struct process *pgrp_jobs();
94 static int get_job();
95 static int match_jobname();
96 static int unstop();
97 static void free_job();
98 static void pw_unlink();
99 static struct process *freelist;
100 #define	numrun	jobstat.p_numrun	/* number of running jobs */
101 #define	numpost	jobstat.p_numpost	/* number of posted jobs */
102 #define	pwlist	jobstat.p_pwlist
103 #define freejobs jobstat.p_freejobs	/* free job numbers */
104 static long pr_jobname();
105 
106 #ifdef FIOLOOKLD
107 #define version8	1
108 extern int tty_ld, ntty_ld;
109 #define OTTYDISC	tty_ld
110 #define NTTYDISC	ntty_ld
111 #endif	/* FIOLOOKLD */
112 
113 
114 static int savepgrp;
115 static int savetgrp;
116 static BOOL old_driver;
117 static BOOL beenhere;
118 
119 #ifdef BSD
120 static struct sgttyb my_stty;		/* terminal state for shell */
121 #else
122 static struct termio my_stty;		/* terminal state for shell */
123 #endif	/* BSD */
124 
125 #ifdef BSD
126 /*
127  * initialize job control
128  * if lflag is set the switching driver message will not print
129  */
130 
131 int init_jobs(lflag)
132 {
133 	int ldisc;
134 	register int ntry = 0;
135 	register int pid;
136 	jobstat.mypid = pid = getpid();
137 	savepgrp = getpgrp(pid);
138 # ifdef version8
139 	if((ldisc = ioctl (2, FIOLOOKLD, 0)) <0)
140 # else
141 	if(ioctl(2,TIOCGETD,&ldisc) !=0)
142 # endif /* version8 */
143 		return(-1);
144 	if(ldisc!=NTTYDISC && ldisc!=OTTYDISC)
145 	{
146 		/* no job control when running with MPX */
147 # ifdef VSH
148 		on_option(VIRAW);
149 # endif /* VSH */
150 		return(-1);
151 	}
152 retry:
153 	signal(SIGTTOU,SIG_IGN);
154 	if(ioctl(2,TIOCGPGRP,&savetgrp) !=0)
155 	{
156 		fputs(j_not_tty,output);
157 		return(-1);
158 	}
159 	/* This shell must be in foreground to change state */
160 	if(savetgrp != savepgrp)
161 	{
162 		signal(SIGTTOU,SIG_DFL);
163 		kill(pid,SIGTTOU);
164 		/* wait for continue and try again */
165 		if(ntry++ > 100)
166 		{
167 			fputs(j_no_start,output);
168 			return(-1);
169 		}
170 		goto retry;
171 	}
172 	if(ldisc == OTTYDISC)
173 	{
174 		ldisc = NTTYDISC;
175 # ifdef version8
176 		ioctl(2,TIOCGETP,&my_stty);
177 		if (ioctl(2, FIOPOPLD, 0) < 0)
178 			return(-1);
179 		if (ioctl(2, FIOPUSHLD, &ldisc, 0) < 0)
180 		{
181 			ldisc = OTTYDISC;
182 			 ioctl(2, FIOPUSHLD, &ldisc, 0);
183 			return(-1);
184 		}
185 		ioctl(2,TIOCSETN,&my_stty);
186 # else
187 		if(ioctl(2,TIOCSETD,&ldisc) !=0)
188 			return(-1);
189 # endif /* version8 */
190 		if(lflag==0)
191 		{
192 			fputs(j_newtty,output);
193 			old_driver++;
194 		}
195 	}
196 	on_option(MONITOR);
197 	signal(SIGCHLD,fault);
198 	signal(SIGTSTP,SIG_IGN);
199 	signal(SIGTTIN,SIG_IGN);
200 	setpgrp(pid,pid);
201 	set_ttygrp(pid);
202 	return(0);
203 }
204 
205 
206 /*
207  * see if there are any stopped jobs
208  * restore tty driver and pgrp
209  */
210 
211 int close_jobs()
212 {
213 	register struct process *pw = pwlist;
214 	register int count = 0;
215 	int ldisc;
216 	if((states&MONITOR)==0)
217 		return(0);
218 	for(;pw;pw=pw->p_next)
219 	{
220 		if((pw->p_flag&P_STOPPED)==0)
221 			continue;
222 		if(beenhere)
223 			killpg(pw->p_pgrp,SIGTERM);
224 		count++;
225 	}
226 	if(beenhere++ == 0 && pwlist)
227 	{
228 		if(count)
229 		{
230 			fputs(j_terminate,output);
231 			return(-1);
232 		}
233 		else if(login_sh)
234 		{
235 			fputs(j_running,output);
236 			return(-1);
237 		}
238 	}
239 	set_ttygrp(savepgrp);
240 	if(old_driver)
241 	{
242 		/* restore old line discipline */
243 		ldisc = OTTYDISC;
244 # ifdef version8
245 		ioctl(2,TIOCGETP,&my_stty);
246 		if (ioctl(2, FIOPOPLD, 0) < 0)
247 			return(0);
248 		if (ioctl(2, FIOPUSHLD, &ldisc, 0) < 0)
249 		{
250 			ldisc = NTTYDISC;
251 			ioctl(2, FIOPUSHLD, &ldisc, 0);
252 			return(0);
253 		}
254 		ioctl(2,TIOCSETN,&my_stty);
255 # else
256 		if(ioctl(2,TIOCSETD,&ldisc) !=0)
257 			return(0);
258 # endif /* version8 */
259 		fputs(j_oldtty,output);
260 	}
261 	return(0);
262 }
263 
264 /*
265  * Set the ttygroup id to pid
266  */
267 
268 static int set_ttygrp(pid)
269 {
270 	if(ioctl(2,TIOCSPGRP,&pid) !=0)
271 		return(-1);
272 	return(0);
273 }
274 
275 /*
276  * Set the ttygroup id to a previously running job
277  */
278 #else
279 # ifdef SXT
280 static char sxt[] = "/dev/sxt/000";
281 static struct sxtblock status1,status2;
282 
283 int init_jobs(lflag)
284 {
285 	register int pid;
286 	register int dev;
287 	struct stat statbuf;
288 	jobstat.mypid = pid = getpid();
289 	savepgrp = getpgrp(pid);
290 	if(ioctl(2,SXTIOCSTAT,&status2) < 0)
291 		return(-1);
292 	if(ioctl(2,TCGETA,&my_stty) < 0)
293 		return(-1);
294 	if(fstat(2,&statbuf) < 0)
295 		return(-1);
296 	dev = statbuf.st_rdev&0xff;
297 	/* must be channel 0 */
298 	if(dev&07)
299 		return(-1);
300 	dev >>= 3;
301 	sxt[10] = '0' + (dev%10);
302 	sxt[9] = '0' + dev/10;
303 	my_stty.c_cc[VSWTCH] = CSWTCH;
304 	if(ioctl(2,TCSETAF,&my_stty) < 0)
305 		return(-1);
306 	setpgrp(pid,pid);
307 	jobstat.maxjob = MAXPCHAN;
308 	on_option(MONITOR);
309 	return(0);
310 }
311 #endif	/* SXT */
312 
313 int close_jobs()
314 {
315 	register struct process *pw = pwlist;
316 	register int count = 0;
317 	if((states&MONITOR)==0)
318 		return(0);
319 # ifdef SXT
320 	for(;pw;pw=pw->p_next)
321 	{
322 		if((pw->p_flag&P_STOPPED)==0)
323 			continue;
324 		if(beenhere)
325 			kill(-pw->p_pgrp,SIGTERM);
326 		count++;
327 	}
328 # endif /* SXT */
329 	if(beenhere++ == 0 && pwlist && login_sh)
330 # ifdef SXT
331 	{
332 		if(count)
333 		{
334 			fputs(j_terminate,output);
335 			return(-1);
336 		}
337 		if(login_sh || jobstat.maxjob)
338 # endif /* SXT */
339 		{
340 			fputs(j_running,output);
341 			return(-1);
342 		}
343 # ifdef SXT
344 	}
345 	if(jobstat.maxjob)
346 		kill_all();
347 # endif /* SXT */
348 	return(0);
349 }
350 
351 #endif	/* BSD */
352 
353 static int set_job(pw)
354 register struct process *pw;
355 {
356 	/* save current terminal state */
357 #ifdef BSD
358 	ioctl(2,TIOCGETP,&my_stty);
359 #else
360 	ioctl(2,TCGETA,&my_stty);
361 #endif	/* BSD */
362 #ifdef SXT
363 	/* make sure child has opened channel */
364 	if(jobstat.pipe[0] > 0)
365 	{
366 		read(jobstat.pipe[0],&tinybuf,1);
367 		close(jobstat.pipe[0]);
368 		jobstat.pipe[0] = 0;
369 	}
370 	if(pw->p_job < jobstat.maxjob)
371 		if(ioctl(2,SXTIOCSWTCH,pw->p_job)!=0)
372 		{
373 			return(-1);
374 		}
375 #endif	/* SXT */
376 	if(pw->p_flag&P_STTY)
377 	{
378 		/* restore terminal state for job */
379 #ifdef BSD
380 		ioctl(2,TIOCSETN,&pw->p_stty);
381 #else
382 		ioctl(2,TCSETAF,&pw->p_stty);
383 #endif	/* BSD */
384 	}
385 #ifdef BSD
386 	if(ioctl(2,TIOCSPGRP,&pw->p_pgrp) !=0)
387 		return(-1);
388 #endif	/* BSD */
389 	return(0);
390 }
391 
392 static int	reset_ttygrp(pw,flag)
393 register struct process *pw;
394 {
395 	/* save the terminal state for current job */
396 #ifdef BSD
397 	if(ioctl(2,TIOCSPGRP,&jobstat.mypid) !=0)
398 	{
399 		return(-1);
400 	}
401 #endif	/* BSD */
402 #ifdef SXT
403 	if(pw && pw->p_job < jobstat.maxjob)
404 	{
405 		/* save the state of terminated process */
406 		if(flag==0 && fd_chan>=0)
407 		{
408 			if(ioctl(fd_chan,TCGETA,&pw->p_stty)==0)
409 			{
410 				my_stty = pw->p_stty;
411 				/* for timing problem */
412 				ioctl(fd_chan,TCSETAW,&my_stty);
413 			}
414 		}
415 		close(fd_chan);
416 		fd_chan = -1;
417 		/* grab control in channel 0 */
418 		ioctl(2,TCSETAW,&my_stty);
419 		if(ioctl(2,SXTIOCSWTCH,0)!=0)
420 		{
421 			return(-1);
422 		}
423 		if(flag==0)
424 			ioctl(2,TCSETAW,&my_stty);
425 		beenhere = 0;
426 		return(0);
427 	}
428 #endif	/* SXT */
429 	if(pw && flag)
430 	{
431 #ifdef BSD
432 		if(ioctl(2,TIOCGETP,&pw->p_stty) == 0)
433 #else
434 		if(ioctl(2,TCGETA,&pw->p_stty) == 0)
435 #endif	/* BSD */
436 			pw->p_flag |= P_STTY;
437 		/* restore terminal state for job */
438 #ifdef BSD
439 		ioctl(2,TIOCSETN,&my_stty);
440 #else
441 		ioctl(2,TCSETAF,&my_stty);
442 #endif	/* BSD */
443 	}
444 	beenhere = 0;
445 	return(0);
446 }
447 
448 #if BSD || SXT
449 
450 /*
451  * move job to foreground if bgflag == 0
452  * move job to background if bgflag != 0
453  */
454 
455 switch_jobs(ajob,bgflag)
456 register char *ajob;
457 {
458 	register struct process *pw=NULL;
459 	register int pgrp;
460 # ifdef SXT
461 	if(jobstat.maxjob==0)
462 		return(NULL);
463 # endif /* SXT */
464 	if(*ajob)
465 		pw = pgrp_jobs(ajob);
466 	else if(pwlist)
467 		pw = job_bynum((int)pwlist->p_job);
468 	if(pw)
469 	{
470 		if(bgflag)
471 		{
472 			pgrp = pw->p_pgrp;
473 			if(pw->p_flag&P_STOPPED)
474 			{
475 				p_sub((int)pw->p_job,'\t');
476 				pr_jobname(pw,'&',0L);
477 				fputs(j_amp,output);
478 				unstop(pgrp);
479 			}
480 		}
481 		else
482 		{
483 			pw_unlink(pw);
484 			pw->p_next = pwlist;
485 			pwlist = pw;
486 			pr_jobname(pw,'&',0L);
487 			newline();
488 			await(pw->p_pid,3);
489 		}
490 	}
491 	return(pw!=NULL);
492 }
493 
494 /*
495  * list the current jobs
496  * flag L_FLAG for long listing
497  * flag N_FLAG for list only jobs marked for notification
498  */
499 #endif	/* BSD */
500 
501 list_jobs(flag)
502 int flag;
503 {
504 	register struct process *pw;
505 	register struct process *px;
506 	register int m;
507 	register struct process *py;
508 	int  n;
509 	long offset;
510 	int jobm = 0;
511 	register char *msg;
512 	int msize;
513 	if(pwlist==NULL)
514 		return;
515 	await(0,2);
516 	p_setout(standout);
517 	/* get job number corresponding to '-' */
518 	if(pw=pgrp_jobs("%-"))
519 		jobm = pw->p_job;
520 	for(pw=pwlist;pw;pw=py)
521 	{
522 		py = pw->p_next;
523 		if(pw->p_flag&P_PIPEJOB)
524 			continue;
525 		if((flag&N_FLAG) && (pw->p_flag&P_NOTIFY)==0)
526 			continue;
527 		n = pw->p_job;
528 		p_sub(n,' ');
529 		m = ' ';
530 		if(pw->p_job==pwlist->p_job)
531 			m = '+';
532 		else if(pw->p_job==jobm)
533 		{
534 			m = '-';
535 			jobm = 0;
536 		}
537 		putc(m,output);
538 		putc(' ',output);
539 		offset = 0;
540 		if(flag&L_FLAG)
541 			px = next_proc(pwlist,(int)pw->p_job);
542 		else
543 			px = pw;
544 		do
545 		{
546 			unsigned xitval = 0;
547 			if(flag&L_FLAG)
548 				p_num(px->p_pid,'\t');
549 			if(px->p_sig&0177)
550 				msg = sysmsg[px->p_sig&0177];
551 			else if(px->p_flag&P_NOTIFY)
552 			{
553 				msg = j_Done;
554 				xitval = px->p_sig>>8;
555 			}
556 			else
557 				msg = j_Running;
558 			fputs(msg,output);
559 			msize = strlen(msg);
560 			if(xitval)
561 			{
562 				putc('(',output);
563 				p_num((int)xitval,')');
564 				msize += (3+(xitval>10)+(xitval>100));
565 			}
566 			if(px->p_flag&P_COREDUMP)
567 			{
568 				fputs(j_coredump,output);
569 				msize += strlen(j_coredump);
570 			}
571 			p_nchr(SP,MAXMSG-msize);
572 			if(flag&L_FLAG)
573 				px = next_proc(px->p_next,(int)pw->p_job);
574 			else
575 				px = NULL;
576 			offset = pr_jobname(pw,(px?'|':0),offset);
577 			if(flag&L_FLAG)
578 			{
579 				if(px)
580 					fputs(j_space,output);
581 				else if(pw->p_pid == cpid)
582 					fputs(j_cpid,output);
583 			}
584 		}
585 		while(px);
586 		if(pw->p_flag&P_STOPPED)
587 			pw->p_flag &= ~P_NOTIFY;
588 		else if(pw->p_flag&P_NOTIFY)
589 		{
590 			unpost(pw);
591 			if(jobm && (px=pgrp_jobs("%-")))
592 				jobm = px->p_job;
593 		}
594 	}
595 }
596 
597 /*
598  * return the pointer of next process with given job number after slot px
599  */
600 
601 static struct process * next_proc(pw,job)
602 register struct process *pw;
603 register int job;
604 {
605 	for(;pw;pw=pw->p_next)
606 	{
607 		if(pw->p_job == job)
608 			return(pw);
609 	}
610 	return(NULL);
611 }
612 
613 /*
614  * print the command
615  * Stop the output if character <ch> encountered
616  */
617 
618 static long pr_jobname(pw,ch,offset)
619 register struct process *pw;
620 register long offset;
621 int ch;
622 {
623 	if(fc_fix)
624 	{
625 		offset = hist_list(pw->p_name+offset,ch,";");
626 		offset -= pw->p_name;
627 	}
628 	return(++offset);
629 }
630 
631 /*
632  * get the process group given the job number
633  * This routine returns the process group number or -1
634  */
635 
636 static struct process *pgrp_jobs(ajob)
637 register char *ajob;
638 {
639 	register struct process *pw;
640 	register int c;
641 	if(*ajob++ != '%' || pwlist==NULL)
642 		return(NULL);
643 	c = *ajob;
644 	if(isdigit(c))
645 		pw = job_bynum(atoi(ajob));
646 	else if(c=='+' || c=='%')
647 		pw = job_bynum((int)pwlist->p_job);
648 	else if(c=='-')
649 	{
650 		/* find the second jobnumber on the list */
651 		for(pw=pwlist->p_next;pw && pw->p_job==pwlist->p_job;pw=pw->p_next);
652 		if(pw==NULL)
653 			return(pw);
654 		pw = job_bynum((int)pw->p_job);
655 	}
656 	else
657 		pw = jobbyname(ajob);
658 	if(pw && pw->p_flag)
659 		return(pw);
660 	return(NULL);
661 }
662 
663 /*
664  * send a hang-up signal to each of the jobs
665  */
666 int kill_all()
667 {
668 	register struct process *pw = pwlist;
669 	for(;pw;pw=pw->p_next)
670 	{
671 		if(pw->p_pgrp == pw->p_pid)
672 		{
673 #ifdef BSD
674 			unstop(pw->p_pgrp);
675 			killpg(pw->p_pgrp,SIGHUP);
676 #else
677 			kill(-pw->p_pgrp,SIGHUP);
678 #endif	/* BSD */
679 		}
680 	}
681 }
682 
683 /*
684  * Kill a job or process
685  */
686 
687 int job_kill(job,sig)
688 register char *job;
689 int sig;
690 {
691 	register char *rjob = job;
692 	register struct process *pw;
693 	register int pid;
694 	register int r;
695 	char *msg;
696 	if(*rjob == '%')
697 	{
698 		if(pw=pgrp_jobs(rjob))
699 		{
700 #ifdef BSD
701 			r = unstop(pw->p_pgrp);
702 			if(sig!=SIGCONT || r < 0)
703 				r = killpg(pw->p_pgrp,sig);
704 #else
705 			pid = pw->p_pgrp;
706 			if(states&MONITOR)
707 				pid = -pid;
708 			r = kill(pid,sig);
709 #endif	/* BSD */
710 		}
711 		else
712 		{
713 			r = -1;
714 			errno = ESRCH;
715 		}
716 	}
717 	else
718 	{
719 		pid = atoi(rjob);
720 		if(pid==0 && *rjob != '0')
721 			failed(bkill,kill_usage);
722 #ifdef BSD
723 		if(sig==SIGSTOP && pid==jobstat.mypid && ppid==1)
724 		{
725 		/* can't stop login shell */
726 			errno = EPERM;
727 			r = -1;
728 		}
729 		else
730 		{
731 			if((pw=job_bypid(pid)) && (pw->p_flag&P_STOPPED))
732 			{
733 				pw->p_flag &= ~P_STOPPED;
734 				numrun++;
735 				kill(pid,SIGCONT);
736 			}
737 			r = kill(pid,sig);
738 		}
739 #else
740 		r = kill(pid,sig);
741 #endif	/* BSD */
742 	}
743 	if(r<0)
744 	{
745 		p_setout(stderr);
746 		fputs(j_kill,output);
747 		if(*rjob == '%')
748 			msg = j_no_job;
749 		else
750 			msg = j_no_proc;
751 		p_str(rjob,':');
752 		if(errno == EPERM)
753 			msg = j_perm;
754 		p_str(msg,NL);
755 		r = 1;
756 	}
757 	return(r);
758 }
759 
760 /*
761  * Get process structure from job number
762  */
763 
764 static struct process *job_bynum(num)
765 register int num;
766 {
767 	register struct process *pw = pwlist;
768 	for(;pw;pw=pw->p_next)
769 	{
770 		if((pw->p_flag&(P_PIPEJOB|P_WAITED)) == P_PIPEJOB)
771 			continue;
772 		if(pw->p_job == num)
773 			return(pw);
774 	}
775 	return(NULL);
776 }
777 
778 /*
779  * Get process structure from first letters of jobname
780  *
781  */
782 
783 static struct process *jobbyname(name)
784 char *name;
785 {
786 	register struct process *pw = pwlist;
787 	register struct fixcmd *fp = fc_fix;
788 	if(fp==NULL)
789 		return(NULL);
790 	for(;pw;pw=pw->p_next)
791 	{
792 		if((pw->p_flag&(P_PIPEJOB|P_WAITED)) == P_PIPEJOB)
793 			continue;
794 		if(match_jobname(fp->fixfd,pw,name))
795 			goto retrn;
796 	}
797 	pw = NULL;
798 retrn:
799 	return(pw);
800 }
801 
802 
803 /*
804  * match the name to the command starting with given name
805  */
806 
807 static int	match_jobname(fdi,pw,name)
808 FILE *fdi;
809 register struct process *pw;
810 char *name;
811 {
812 	register int c;
813 	register char *sp;
814 	if(fdi && pw->p_name>0)
815 	{
816 		fseek(fdi,pw->p_name,0);
817 		for(sp=name;*sp;sp++)
818 		{
819 			c = getc(fdi);
820 			if(c != *sp)
821 				return(0);
822 		}
823 		return(1);
824 	}
825 	return(0);
826 }
827 
828 
829 
830 /*
831  * Initialize the process posting array
832  */
833 
834 void	postclr()
835 {
836 	register struct process *pw = pwlist;
837 	register struct process *px;
838 	register int j = JBYTES;
839 	for(;pw;pw=px)
840 	{
841 		px = pw->p_next;
842 		free((char*)pw);
843 	}
844 	pwlist = NULL;
845 	numpost=0;
846 	numrun = 0;
847 	while(--j >=0)
848 		freejobs[j]  = 0;
849 }
850 
851 /*
852  * put the process <pcsid> on the process list and return the job number
853  * turn on the specified flag bits.
854  */
855 
856 int post(pid,flag)
857 int pid;
858 {
859 	register struct process *pw;
860 	if(pw=job_post(pid))
861 	{
862 		pw->p_flag |= flag;
863 		return(pw->p_job);
864 	}
865 	return(-1);
866 }
867 
868 /*
869  * internal version of post, this routine returns a process structure
870  */
871 
872 static struct process *job_post(pcsid)
873 int 	pcsid;
874 {
875 	register struct process  *pw = pwlist;
876 	register struct process  *px=NULL;
877 	register struct fixcmd *fp = fc_fix;
878 	if(pcsid)
879 	{
880 		for(;pw;pw=pw->p_next)
881 		{
882 			if(pw->p_pid==pcsid)
883 				return(pw);
884 			if(pw->p_pgrp == jobstat.cur_pgrp)
885 				px = pw;
886 		}
887 		if(pw=freelist)
888 			freelist = pw->p_next;
889 		else if((pw=(struct process*)malloc(sizeof(struct process)))==NULL)
890 			error(nospace);
891 		numrun++;
892 		numpost++;
893 		if(px)
894 		{
895 			pw->p_next = px->p_next;
896 			px->p_next = pw;
897 			pw->p_job = px->p_job;
898 		}
899 		else
900 		{
901 			/* put at front of list */
902 			pw->p_next = pwlist;
903 			pw->p_job = get_job();
904 			pwlist = pw;
905 		}
906 		pw->p_pid = pcsid;
907 		pw->p_flag = P_RUNNING;
908 		pw->p_pgrp = jobstat.cur_pgrp;
909 		if(fp!=NULL)
910 			pw->p_name=hist_position(fp->fixind-1);
911 		else
912 			pw->p_name = -1;
913 		pw->p_sig = 0;
914 		if(numpost >= MAXJ-1)
915 			await(0,0);
916 		return(pw);
917 	}
918 	return(NULL);
919 }
920 
921 /*
922  * get job number given the process id
923  */
924 
925 static struct process *job_bypid(pid)
926 register int pid;
927 {
928 	register struct process *pw;
929 	if(pid==0)
930 		return(NULL);
931 	for(pw=pwlist;pw;pw=pw->p_next)
932 	if(pw->p_pid == pid)
933 			break;
934 	return(pw);
935 }
936 
937 /*
938  * Wait for process i to complete
939  * flag=1 when wait builtin invoked so that it can be interrupted
940  * flag=2 to check for waiting processes and return
941  * flag=3 to resume job in foreground
942  * i=0 to wait for any process
943  * i=-1 to wait for all runing processes
944  */
945 
946 void	await(i, flag)
947 register int 	i;
948 int 	flag;
949 {
950 	int 	rc=0;
951 	int 	w;
952 	int my_job = -1;
953 #ifdef BSD
954 	union wait wstat;
955 #endif	/* BSD */
956 	register struct process *pw = NULL;
957 	struct process *px;
958 	if(i!= -1 && i)
959 	{
960 		if(flag)
961 		{
962 			pw = job_bypid(i);
963 			if(flag==3 && pw)
964 				flag = 0;
965 		}
966 		else
967 			pw = job_post(i);
968 		if(flag)
969 		{
970 			if(pw==0 || (pw->p_flag&P_STOPPED))
971 			return;
972 		}
973 		my_job = pw->p_job;
974 	}
975 	if(flag==0 && (states&MONITOR) && pw)
976 	{
977 		set_job(pw);
978 		/* if job is stopped, resume it in the background */
979 #if BSD || SXT
980 		if(pw->p_flag&P_STOPPED)
981 			unstop(pw->p_pgrp);
982 # ifdef SXT
983 		if(pw->p_job < jobstat.maxjob)
984 			open_chan(pw->p_job);
985 # endif /* SXT */
986 #endif	/* BSD */
987 	}
988 	p_flush();
989 	while(numrun>0)
990 	{
991 		register int 	p;
992 		register int 	sig;
993 		register int 	w_hi;
994 #ifdef BSD
995 		if(is_option(MONITOR) || flag==2)
996 		{
997 		retry:
998 			errno = 0;
999 			sig = sighold(SIGCHLD);
1000 			trapnote &= ~SIGJOBS;
1001 			p=wait3(&wstat,WNOHANG|WUNTRACED,0);
1002 			errno = 0;
1003 			if(p==0 && flag!=2)
1004 			{
1005 # ifdef BSD_4_2
1006 				sigpause(sig&~(1<<(SIGCHLD-1)));
1007 # else
1008 				sigpause(SIGCHLD);
1009 # endif /* BSD_4_2 */
1010 				if(errno==EINTR && flag==1 && (trapnote&SIGJOBS)==0)
1011 					break;
1012 				goto retry;
1013 			}
1014 			trapnote &= ~SIGJOBS;
1015 			sigrelse(SIGCHLD);
1016 			if(p==0 || p== -1)
1017 				return;
1018 			w = wstat.w_status;
1019 			pw = job_bypid(p);
1020 			if(pw->p_job == my_job && (states&MONITOR))
1021 			{
1022 				register int ssig = wstat.w_S.w_Stopsig;
1023 				if(WIFSTOPPED(wstat) && (ssig==SIGTTIN||ssig==SIGTTOU))
1024 				{
1025 					/* job stopped before it got terminal */
1026 					killpg(pw->p_pgrp,SIGCONT);
1027 					continue;
1028 				}
1029 				if(p==i)
1030 					reset_ttygrp(pw,w&LOBYTE);
1031 			}
1032 		}
1033 		else
1034 #endif	/* BSD */
1035 		{
1036 #ifndef BSD
1037 # ifdef SXT
1038 			if(jobstat.maxjob >0)
1039 			{
1040 				/* check for job status change */
1041 				status1 = status2;
1042 				status2.input = status2.output = 0;
1043 				if(ioctl(2,SXTIOCSTAT,&status2)!=0)
1044 				{
1045 					jobstat.maxjob = 0;
1046 				}
1047 				else if(status1.input != status2.input)
1048 				{
1049 					status_update(status2.input,status1.input,SIGSTIN);
1050 				}
1051 				else if(status1.output != status2.output)
1052 				{
1053 					status_update(status2.output,status1.output,SIGSTOP);
1054 				}
1055 			}
1056 # endif /* SXT */
1057 			/* enable fault handler to see if there are any pending jobs */
1058 			if((trapnote&SIGJOBS)==0)
1059 				signal(SIGCLD,fault);
1060 			if(flag==2 && (trapnote&SIGJOBS)==0)
1061 				return;
1062 # ifdef SXT
1063 			if(my_job>=0 && (trapnote&SIGJOBS)==0 && jobstat.maxjob)
1064 			{
1065 				errno = 0;
1066 		        	p = ioctl(2, SXTIOCWF, 0);
1067 				if(p==0)
1068 					/* job stopped */
1069 				{
1070        		         		ioctl(2, SXTIOCBLK, my_job);
1071 					if(fd_chan>=0)
1072 					{
1073 						if(ioctl(fd_chan,TCFLSH,2)!=0)
1074 						{
1075 							;
1076 						}
1077 					}
1078 					pw->p_flag |= (P_NOTIFY|P_STOPPED);
1079 					pw->p_sig = SIGSTOP;
1080 					reset_ttygrp(pw,1);
1081 					break;
1082 				}
1083 			}
1084 # endif /* SXT */
1085 #endif	/* BSD */
1086 			trapnote &= ~ SIGJOBS;
1087 			p=wait(&w);
1088 			if(p== -1)
1089 			{
1090 				if(errno==ECHILD)
1091 				{
1092 					postclr();
1093 					return;
1094 				}
1095 				else if(errno==EINTR)
1096 				{
1097 					if(trapnote&SIGJOBS)
1098 						continue;
1099 					if(flag)
1100 						break;
1101 				}
1102 				continue;
1103 			}
1104 			trapnote &= ~ SIGJOBS;
1105 			pw = job_bypid(p);
1106 #ifdef SXT
1107 			pw->p_flag &= ~P_STOPPED;
1108 #endif	/* SXT */
1109 			/* restore original tty state if jobs aborted */
1110 			if(p == i && (states&MONITOR))
1111 				reset_ttygrp(pw,w&LOBYTE);
1112 		}
1113 		if(pw)
1114 		{
1115 			numrun--;
1116 			pw->p_flag |= P_NOTIFY;
1117 #ifdef BSD
1118 			if((states&MONITOR) && WIFSTOPPED(wstat))
1119 				pw->p_flag |= P_STOPPED;
1120 			else
1121 #endif	/* BSD */
1122 			{
1123 				if(p==cpid)
1124 				{
1125 					cpid = 0;
1126 					cpipe[1] = NULL;
1127 				}
1128 				if(p==i || (states&MONITOR)==0)
1129 				{
1130 					if(px=unpost(pw))
1131 					{
1132 						if(i)
1133 						{
1134 							if(p==i && (states&MONITOR))
1135 								set_job(px);
1136 							i = px->p_pid;
1137 						}
1138 						continue;
1139 					}
1140 				}
1141 			}
1142 		}
1143 		sig = w&0177;
1144 		if(states&MONITOR)
1145 		{
1146 #ifdef BSD
1147 			if(WIFSTOPPED(wstat))
1148 			{
1149 				if(pw)
1150 					pw->p_sig = wstat.w_S.w_Stopsig;
1151 				if(p == i)
1152 					break;
1153 				continue;
1154 			}
1155 			else if(p!=i)
1156 #else
1157 			if(p!=i)
1158 #endif	/* BSD */
1159 			{
1160 				if(pw)
1161 					pw->p_sig = w;
1162 				if(w&HIGHBIT)
1163 					pw->p_flag |= P_COREDUMP;
1164 				continue;
1165 			}
1166 			/* this is needed since child not in same process group */
1167 			else if(sig==SIGINT || sig==SIGQUIT || sig==SIGHUP)
1168 				fault(sig);
1169 		}
1170 		w_hi = (w>>8)&LOBYTE;
1171 		if(sig)
1172 		{
1173 			if(sig == 0177	/* ptrace! return */)
1174 			{
1175 				fputs(ptrace,output);
1176 				sig = w_hi;
1177 			}
1178 			if(sig!=SIGINT && sig!=SIGPIPE)
1179 			{
1180 				if(i!=p || (states&PROMPT)==0)
1181 					p_prp(itos(p),SP);
1182 				fputs(sysmsg[sig],output);
1183 				if(w&HIGHBIT)
1184 					fputs(coredump,output);
1185 			}
1186 			newline();
1187 		}
1188 		if(p == i)
1189 		{
1190 			rc = (sig ? sig|SIGFAIL : w_hi);
1191 			break;
1192 		}
1193 		if(i == 0)
1194 			break;
1195 	}
1196 	if(flag>=2)
1197 		return;
1198 	exitval=rc;
1199 	exitset();
1200 }
1201 
1202 #if BSD || SXT
1203 /*
1204  * turn off STOP state of a process group
1205  */
1206 
1207 static int unstop(grp)
1208 register int grp;
1209 {
1210 	register struct process *pw;
1211 	register int num = numrun;
1212 	for(pw=pwlist;pw;pw=pw->p_next)
1213 	{
1214 		if(pw->p_pgrp != grp)
1215 			continue;
1216 		if(pw->p_flag&P_STOPPED)
1217 		{
1218 			num++;
1219 			pw->p_flag &= ~P_STOPPED;
1220 			pw->p_sig = 0;
1221 # ifdef SXT
1222 			break;
1223 # endif /* SXT */
1224 		}
1225 	}
1226 	if(num!=numrun)
1227 	{
1228 		p_flush();
1229 #ifdef BSD
1230 		numrun = num;
1231 		return(killpg(grp,SIGCONT));
1232 #endif
1233 	}
1234 	return(-1);
1235 }
1236 #endif	/* BSD */
1237 
1238 /*
1239  * remove a process group from table
1240  * If all the processes have not completed then unpost returns
1241  * the structure pointer  of an unfinished process.
1242  * Otherwise NULL is returned.
1243  */
1244 
1245 static struct process *unpost(pwtop)
1246 struct process *pwtop;
1247 {
1248 	register struct process *pw;
1249 	register struct process *px=NULL;
1250 	register int job = pwtop->p_job;
1251 	register struct process *py;
1252 	/* look for unfinished processes */
1253 	for(pw=pwlist;pw;pw=pw->p_next)
1254 	{
1255 		if(pw->p_job != job)
1256 			continue;
1257 		if((pw->p_flag&P_NOTIFY)==0)
1258 			px = pw;
1259 	}
1260 	if(px)
1261 	{
1262 		px->p_flag &= ~P_PIPEJOB;
1263 		px->p_flag |= P_WAITED;
1264 		return(px);
1265 	}
1266 	/* all processes complete, unpost job */
1267 	for(pw=pwlist;pw;pw=py)
1268 	{
1269 		py = pw->p_next;
1270 		if(pw->p_job != job)
1271 		{
1272 			px = pw;
1273 			continue;
1274 		}
1275 		numpost--;
1276 		if(px==NULL)
1277 			pwlist = py;
1278 		else
1279 			px->p_next = py;
1280 		pw->p_next = freelist;
1281 		freelist = pw;
1282 	}
1283 	free_job((int)pwtop->p_job);
1284 	return(NULL);
1285 }
1286 
1287 /*
1288  * unlink a process form the process list
1289  */
1290 
1291 static void pw_unlink(pw)
1292 register struct process *pw;
1293 {
1294 	register struct process *px;
1295 	if(pw==pwlist)
1296 	{
1297 		pwlist = pw->p_next;
1298 		return;
1299 	}
1300 	for(px=pwlist;px;px=px->p_next)
1301 		if(px->p_next == pw)
1302 		{
1303 			px->p_next = pw->p_next;
1304 			return;
1305 		}
1306 }
1307 
1308 /*
1309  * get an unused job number
1310  * freejobs is a bit vector, 0 is unused
1311  */
1312 
1313 static int get_job()
1314 {
1315 	register int j=0;
1316 	register unsigned mask = 1;
1317 	register unsigned char *freeword;
1318 	/* skip to first word with a free slot */
1319 	while(freejobs[j] == 0xff)
1320 		j++;
1321 	freeword = &freejobs[j];
1322 	j *= 8;
1323 	for(j++;mask&(*freeword);j++,mask <<=1);
1324 	*freeword  |=mask;
1325 	return(j);
1326 }
1327 
1328 /*
1329  * return a job number
1330  */
1331 
1332 static void free_job(n)
1333 register int n;
1334 {
1335 	register int j = (--n)/8;
1336 	register unsigned mask;
1337 	n -= j*8;
1338 	mask = 1 << n;
1339 	freejobs[j]  &= ~mask;
1340 }
1341 
1342 #ifdef SXT
1343 /*
1344  * open up the input streams for a new channel
1345  */
1346 
1347 static char *open_mode[3] = {"r","w","w+"};
1348 j_new_chan()
1349 {
1350 	register FILE* fd;
1351 	register int i;
1352 	sxt[11] = '0' + jobstat.cur_job;
1353 	close(jobstat.pipe[0]);
1354 	fd = fopen(sxt,"r+");
1355 	if(ioctl(fileno(fd),TCSETA,&my_stty)<0 || fd==NULL)
1356 	{
1357 		close(jobstat.pipe[1]);
1358 		return(0);
1359 	}
1360 	for(i=0;i<3;i++)
1361 	{
1362 		if(isatty(i))
1363 		{
1364 			fclose(file_fd(i));
1365 			fdopen(dup(fileno(fd)),open_mode[i]);
1366 		}
1367 	}
1368 	fclose(fd);
1369 	write(jobstat.pipe[1],nullstr,1);
1370 	close(jobstat.pipe[1]);
1371 	return(1);
1372 }
1373 
1374 int next_job()
1375 {
1376 	register int i = get_job();
1377 	free_job(i);
1378 	return(i);
1379 }
1380 
1381 static status_update(mask2,mask1,sigval)
1382 {
1383 	register int i,j;
1384 	register struct process *pw;
1385 	for(i = 1; i < MAXPCHAN; i++)
1386 	{
1387 		j = 1<<i;
1388 		if((mask1&j)==0 && (mask2&j))
1389 		{
1390 			if(pw = job_bynum(i))
1391 				pw->p_sig = sigval;
1392 		}
1393 		else if((mask2&j)==0 && (mask1&j))
1394 		{
1395 			if(pw = job_bynum(i))
1396 				pw->p_sig = 0;
1397 		}
1398 	}
1399 }
1400 
1401 static int open_chan(j)
1402 {
1403 	sxt[11] = '0' + j;
1404 	if(fd_chan>=0)
1405 	{
1406 		return;
1407 	}
1408 	fd_chan = open(sxt,2);
1409 }
1410 #endif	/* SXT */
1411 
1412