Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / jobs.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: jobs.c /main/4 1996/10/04 15:50:46 drk $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
29 *                    AT&T BELL LABORATORIES                    *
30 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
31 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
32 *                                                              *
33 *                Copyright (c) 1995 AT&T Corp.                 *
34 *              Unpublished & Not for Publication               *
35 *                     All Rights Reserved                      *
36 *                                                              *
37 *       The copyright notice above does not evidence any       *
38 *      actual or intended publication of such source code      *
39 *                                                              *
40 *               This software was created by the               *
41 *           Advanced Software Technology Department            *
42 *                    AT&T Bell Laboratories                    *
43 *                                                              *
44 *               For further information contact                *
45 *                    {research,attmail}!dgk                    *
46 *                                                              *
47 ***************************************************************/
48
49 /* : : generated by proto : : */
50
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__      "C"
55 #else
56 #define __MANGLE__
57 #endif
58 #define __STDARG__
59 #define __PROTO__(x)    x
60 #define __OTORP__(x)
61 #define __PARAM__(n,o)  n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
64 #define const
65 #endif
66 #define signed
67 #define void            int
68 #define volatile
69 #define __V_            char
70 #else
71 #define __V_            void
72 #endif
73 #else
74 #define __PROTO__(x)    ()
75 #define __OTORP__(x)    x
76 #define __PARAM__(n,o)  o
77 #define __MANGLE__
78 #define __V_            char
79 #define const
80 #define signed
81 #define void            int
82 #define volatile
83 #endif
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__      ...
86 #else
87 #define __VARARG__
88 #endif
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a)       va_start(p,a)
91 #else
92 #define __VA_START__(p,a)       va_start(p)
93 #endif
94 #endif
95 #include        "defs.h"
96 #include        <ctype.h>
97 #include        <wait.h>
98 #include        "io.h"
99 #include        "jobs.h"
100 #include        "history.h"
101
102 /*
103  * temporary hack to get W* macros to work
104  */
105 #undef wait
106 #define wait    ______wait
107 /*
108  * This struct saves a link list of processes that have non-zero exit
109  * status, have had $! saved, but haven't been waited for
110  */
111 struct jobsave
112 {
113         struct jobsave  *next;
114         pid_t           pid;
115         unsigned short  exitval;
116         int             env;
117 };
118
119
120 #define BYTE(n)         (1+ (n)/CHAR_BIT)
121 #define MAXMSG  25
122
123 #ifdef VSUSP
124 #   ifndef CNSUSP
125 #       ifdef _POSIX_VDISABLE
126 #          define CNSUSP        _POSIX_VDISABLE
127 #       else
128 #          define CNSUSP        0
129 #       endif /* _POSIX_VDISABLE */
130 #   endif /* CNSUSP */
131 #   ifndef CSWTCH
132 #       ifdef CSUSP
133 #           define CSWTCH       CSUSP
134 #       else
135 #           define CSWTCH       ('z'&037)
136 #       endif /* CSUSP */
137 #   endif /* CSWTCH */
138 #endif /* VSUSP */
139
140 /* Process states */
141 #define P_EXITSAVE      01
142 #define P_STOPPED       02
143 #define P_NOTIFY        04
144 #define P_SIGNALLED     010
145 #define P_STTY          020
146 #define P_DONE          040
147 #define P_COREDUMP      0100
148 #define P_DISOWN        0200
149
150 static struct process   *job_bypid __PROTO__((pid_t));
151 static struct process   *job_byjid __PROTO__((int));
152 static char             *job_sigmsg __PROTO__((int));
153 static int              job_alloc __PROTO__((void));
154 static void             job_free __PROTO__((int));
155 static struct process   *job_unpost __PROTO__((struct process*,int));
156 static void             job_unlink __PROTO__((struct process*));
157 static void             job_prmsg __PROTO__((struct process*));
158 static struct process   *freelist;
159 static char             beenhere;
160 static char             possible;
161 static int              savesig;
162 static struct process   dummy;
163 static int              bck_count;
164 static struct jobsave   *bck_list;
165 static char             by_number;
166 static Sfio_t           *outfile;
167
168 #ifdef JOBS
169     static void                 job_set __PROTO__((struct process*));
170     static void                 job_reset __PROTO__((struct process*));
171     static void                 job_waitsafe __PROTO__((int));
172     static struct process       *job_byname __PROTO__((char*));
173     static struct process       *job_bystring __PROTO__((char*));
174     static struct termios       my_stty;  /* terminal state for shell */
175     static char                 *job_string;
176 #else
177     extern __MANGLE__ const char                e_coredump[];
178 #endif /* JOBS */
179
180 #ifdef SIGTSTP
181     static void         job_unstop __PROTO__((struct process*));
182     static void         job_fgrp __PROTO__((struct process*, int));
183 #   ifndef _lib_tcgetpgrp
184 #       ifdef TIOCGPGRP
185            static int _i_;
186 #          define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)    
187 #       endif /* TIOCGPGRP */
188         int tcsetpgrp __PARAM__((int fd,pid_t pgrp), (fd, pgrp)) __OTORP__(int fd;pid_t pgrp;){
189                 int pgid = pgrp;
190 #               ifdef TIOCGPGRP
191                         return(ioctl(fd, TIOCSPGRP, &pgid));    
192 #               else
193                         return(-1);
194 #               endif /* TIOCGPGRP */
195         }
196 #   endif /* _lib_tcgetpgrp */
197 #else
198 #   define job_unstop(pw)
199 #   undef CNSUSP
200 #endif /* SIGTSTP */
201
202 #ifndef OTTYDISC
203 #   undef NTTYDISC
204 #endif /* OTTYDISC */
205
206
207 #ifdef JOBS
208
209 /*
210  * This is the SIGCLD interrupt routine
211  * When called with sig==0, it does a blocking wait
212  */
213 static void job_waitsafe __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
214         register pid_t pid;
215         register struct process *pw;
216         register int flags;
217         struct process dummy;
218         struct jobsave *jp;
219         int wstat;
220 #ifdef DEBUG
221         if(sfprintf(sfstderr,"%ld: signal %d critical=%d\n",(long)getpid(),sig,job.in_critical) <=0)
222                 write(2,"waitsafe\n",9);
223         sfsync(sfstderr);
224 #endif /* DEBUG */
225         if(job.in_critical && sig)
226         {
227                 savesig = sig;
228                 return;
229         }
230         savesig = 0;
231         if(sig)
232                 flags = WNOHANG|WUNTRACED;
233         else
234                 flags = WUNTRACED;
235         while(1)
236         {
237                 if(!(flags&WNOHANG))
238                 {
239                         if(sh_waitevent(-1))
240                                 flags |= WNOHANG;
241                 }
242                 pid = waitpid((pid_t)-1,&wstat,flags);
243                 if(sig && pid<0 && errno==EINTR)
244                         continue;
245                 if(pid<=0)
246                         break;
247                 flags |= WNOHANG;
248                 job.waitsafe++;
249                 if(!(pw=job_bypid(pid)))
250                 {
251 #ifdef DEBUG
252                         sfprintf(sfstderr,"%ld: unknown job pid=%ld pw=%p\n",(long)getpid(),(long)pid,pw);
253 #endif /* DEBUG */
254                         if(WIFSTOPPED(wstat))
255                                 continue;
256                         pw = &dummy;
257                         if(bck_count++ > sh.lim.child_max)
258                                 job_chksave(0);
259                         jp = new_of(struct jobsave,0);
260                         jp->next = bck_list;
261                         bck_list = jp;
262                         pw->p_pid = jp->pid = pid;
263                         pw->p_flag = 0;
264                         jp->exitval = 0;
265                         jp->env = sh.curenv;
266                 }
267 #ifdef SIGTSTP
268                 if(WIFSTOPPED(wstat))
269                 {
270                         /* move to top of job list */
271                         struct process *px=job_byjid(pw->p_job);
272                         job_unlink(px);
273                         px->p_nxtjob = job.pwlist;
274                         job.pwlist = px;
275                         pw->p_exit = WSTOPSIG(wstat);
276                         pw->p_flag |= (P_NOTIFY|P_SIGNALLED|P_STOPPED);
277                         if(pw->p_pgrp && pw->p_pgrp==job.curpgid && sh_isstate(SH_STOPOK))
278                                 sh_fault(pw->p_exit); 
279                         continue;
280                 }
281                 else
282 #endif /* SIGTSTP */
283                 {
284                         /* check for coprocess completion */
285                         if(pid==sh.cpid)
286                         {
287                                 sh_close(sh.coutpipe);
288                                 sh_close(sh.cpipe[1]);
289                                 sh.cpipe[1] = -1;
290                                 sh.coutpipe = -1;
291                         }
292                         if (WIFSIGNALED(wstat))
293                         {
294                                 pw->p_flag &= ~P_STOPPED;
295                                 pw->p_flag |= (P_DONE|P_NOTIFY|P_SIGNALLED);
296                                 if (WTERMCORE(wstat))
297                                         pw->p_flag |= P_COREDUMP;
298                                 pw->p_exit = WTERMSIG(wstat);
299                                 /* if process in current jobs terminates from
300                                  * an interrupt, propogate to parent shell
301                                  */
302                                 if(pw->p_pgrp && pw->p_pgrp==job.curpgid && pw->p_exit==SIGINT && sh_isstate(SH_STOPOK))
303                                 {
304                                         pw->p_flag &= ~P_NOTIFY;
305                                         sh_offstate(SH_STOPOK);
306                                         sh_fault(SIGINT); 
307                                         sh_onstate(SH_STOPOK);
308                                 }
309                         }
310                         else
311                         {
312                                 pw->p_flag |= (P_DONE|P_NOTIFY);
313                                 pw->p_exit = WEXITSTATUS(wstat);
314                         }
315                         if(pw->p_pgrp==0)
316                                 pw->p_flag &= ~P_NOTIFY;
317                 }
318                 if(pw == &dummy)
319                 {
320                         jp->exitval = pw->p_exit;
321                         if(pw->p_flag&P_SIGNALLED)
322                                 jp->exitval |= SH_EXITSIG;
323                 }
324 #ifdef DEBUG
325                 sfprintf(sfstderr,"%ld: job %d with pid %ld flags=%o complete with status=%x exit=%d\n",(long)getpid(),pw->p_job,(long)pid,pw->p_flag,wstat,pw->p_exit);
326                 sfsync(sfstderr);
327 #endif /* DEBUG*/
328         }
329         if(sh.st.trapcom[SIGCHLD])
330         {
331                 sh.sigflag[SIGCHLD] |= SH_SIGTRAP;
332                 sh.trapnote |= SH_SIGTRAP;
333         }
334         if(sh_isoption(SH_NOTIFY) && sh_isstate(SH_TTYWAIT))
335         {
336                 outfile = sfstderr;
337                 job_list(pw,JOB_NFLAG|JOB_NLFLAG);
338                 job_unpost(pw,1);
339                 sfsync(sfstderr);
340         }
341         if(sig)
342                 signal(sig, job_waitsafe);
343 }
344
345 /*
346  * initialize job control if possible
347  * if lflag is set the switching driver message will not print
348  */
349 void job_init __PARAM__((int lflag), (lflag)) __OTORP__(int lflag;){
350         register int ntry=0;
351
352         job.fd = JOBTTY;
353         signal(SIGCHLD,job_waitsafe);
354 #   if defined(SIGCLD) && (SIGCLD!=SIGCHLD)
355         signal(SIGCLD,job_waitsafe);
356 #   endif
357         if(!sh_isoption(SH_INTERACTIVE))
358                 return;
359         /* use new line discipline when available */
360 #ifdef NTTYDISC
361 #   ifdef FIOLOOKLD
362         if((job.linedisc = ioctl(JOBTTY, FIOLOOKLD, 0)) <0)
363 #   else
364         if(ioctl(JOBTTY,TIOCGETD,&job.linedisc) !=0)
365 #   endif /* FIOLOOKLD */
366                 return;
367         if(job.linedisc!=NTTYDISC && job.linedisc!=OTTYDISC)
368         {
369                 /* no job control when running with MPX */
370 #   ifdef SHOPT_VSH
371                 sh_onoption(SH_VIRAW);
372 #   endif /* SHOPT_VSH */
373                 return;
374         }
375         if(job.linedisc==NTTYDISC)
376                 job.linedisc = -1;
377 #endif /* NTTYDISC */
378
379         job.mypgid = getpgrp();
380         /* some systems have job control, but not initialized */
381         if(job.mypgid<=0)
382         {
383                 /* Get a controlling terminal and set process group */
384                 /* This should have already been done by rlogin */
385                 register int fd;
386                 register char *ttynam;
387 #ifndef SIGTSTP
388                 setpgid(0,sh.pid);
389 #endif /*SIGTSTP */
390                 if(job.mypgid<0 || !(ttynam=ttyname(JOBTTY)))
391                         return;
392                 close(JOBTTY);
393                 if((fd = open(ttynam,O_RDWR)) <0)
394                         return;
395                 if(fd!=JOBTTY)
396                         sh_iorenumber(fd,JOBTTY);
397                 job.mypgid = sh.pid;
398 #ifdef SIGTSTP
399                 tcsetpgrp(JOBTTY,sh.pid);
400                 setpgid(0,sh.pid);
401 #endif /* SIGTSTP */
402         }
403 #ifdef SIGTSTP
404         if(possible = (setpgid(0,job.mypgid)>=0) || errno==EPERM)
405         {
406                 /* wait until we are in the foreground */
407                 while((job.mytgid=tcgetpgrp(JOBTTY)) != job.mypgid)
408                 {
409                         if(job.mytgid == -1)
410                                 return;
411                         /* Stop this shell until continued */
412                         signal(SIGTTIN,SIG_DFL);
413                         kill(sh.pid,SIGTTIN);
414                         /* resumes here after continue tries again */
415                         if(ntry++ > IOMAXTRY)
416                         {
417                                 error(0,e_no_start);
418                                 return;
419                         }
420                 }
421         }
422 #endif /* SIGTTIN */
423
424 #ifdef NTTYDISC
425         /* set the line discipline */
426         if(job.linedisc>=0)
427         {
428                 int linedisc = NTTYDISC;
429 #   ifdef FIOPUSHLD
430                 tty_get(JOBTTY,&my_stty);
431                 if (ioctl(JOBTTY, FIOPOPLD, 0) < 0)
432                         return;
433                 if (ioctl(JOBTTY, FIOPUSHLD, &linedisc) < 0)
434                 {
435                         ioctl(JOBTTY, FIOPUSHLD, &job.linedisc);
436                         return;
437                 }
438                 tty_set(JOBTTY,TCSANOW,&my_stty);
439 #   else
440                 if(ioctl(JOBTTY,TIOCSETD,&linedisc) !=0)
441                         return;
442 #   endif /* FIOPUSHLD */
443                 if(lflag==0)
444                         error(0,e_newtty);
445                 else
446                         job.linedisc = -1;
447         }
448 #endif /* NTTYDISC */
449         if(!possible)
450                 return;
451
452 #ifdef SIGTSTP
453         /* make sure that we are a process group leader */
454         setpgid(0,sh.pid);
455 #   if defined(SA_NOCLDWAIT) && defined(_lib_sigflag)
456         sigflag(SIGCHLD, SA_NOCLDSTOP|SA_NOCLDWAIT, 0);
457 #   endif /* SA_NOCLDWAIT */
458         signal(SIGTTIN,SIG_IGN);
459         signal(SIGTTOU,SIG_IGN);
460         /* The shell now handles ^Z */
461         signal(SIGTSTP,sh_fault);
462         tcsetpgrp(JOBTTY,sh.pid);
463 #   ifdef CNSUSP
464         /* set the switch character */
465         tty_get(JOBTTY,&my_stty);
466         job.suspend = (unsigned)my_stty.c_cc[VSUSP];
467         if(job.suspend == (unsigned char)CNSUSP)
468         {
469                 my_stty.c_cc[VSUSP] = CSWTCH;
470                 tty_set(JOBTTY,TCSAFLUSH,&my_stty);
471         }
472 #   endif /* CNSUSP */
473         sh_onoption(SH_MONITOR);
474         job.jobcontrol++;
475 #endif /* SIGTSTP */
476         return;
477 }
478
479
480 /*
481  * see if there are any stopped jobs
482  * restore tty driver and pgrp
483  */
484 int job_close __PARAM__((void), ()){
485         register struct process *pw = job.pwlist;
486         register int count = 0, running = 0;
487         if(possible && !job.jobcontrol)
488                 return(0);
489         else if(!possible && (!sh_isstate(SH_MONITOR) || sh_isstate(SH_FORKED)))
490                 return(0);
491         if(!tty_check(0))
492                 beenhere++;
493         for(;pw;pw=pw->p_nxtjob)
494         {
495                 if(!(pw->p_flag&P_STOPPED))
496                 {
497                         if(!(pw->p_flag&P_DONE))
498                                 running++;
499                         continue;
500                 }
501                 if(beenhere)
502                         killpg(pw->p_pgrp,SIGTERM);
503                 count++;
504         }
505         if(beenhere++ == 0 && job.pwlist)
506         {
507                 if(count)
508                 {
509                         error(0,e_terminate);
510                         return(-1);
511                 }
512                 else if(running && sh.login_sh)
513                 {
514                         error(0,e_jobsrunning);
515                         return(-1);
516                 }
517         }
518 #   ifdef SIGTSTP
519         if(possible && setpgid(0,job.mypgid)>=0)
520                 tcsetpgrp(job.fd,job.mypgid);
521 #   endif /* SIGTSTP */
522 #   ifdef NTTYDISC
523         if(job.linedisc>=0)
524         {
525                 /* restore old line discipline */
526 #       ifdef FIOPUSHLD
527                 tty_get(job.fd,&my_stty);
528                 if (ioctl(job.fd, FIOPOPLD, 0) < 0)
529                         return(0);
530                 if (ioctl(job.fd, FIOPUSHLD, &job.linedisc) < 0)
531                 {
532                         job.linedisc = NTTYDISC;
533                         ioctl(job.fd, FIOPUSHLD, &job.linedisc);
534                         return(0);
535                 }
536                 tty_set(job.fd,TCSAFLUSH,&my_stty);
537 #       else
538                 if(ioctl(job.fd,TIOCSETD,&job.linedisc) !=0)
539                         return(0);
540 #       endif /* FIOPUSHLD */
541                 error(0,e_oldtty);
542         }
543 #   endif /* NTTYDISC */
544 #   ifdef CNSUSP
545         if(possible && job.suspend==CNSUSP)
546         {
547                 tty_get(job.fd,&my_stty);
548                 my_stty.c_cc[VSUSP] = CNSUSP;
549                 tty_set(job.fd,TCSAFLUSH,&my_stty);
550         }
551 #   endif /* CNSUSP */
552         job.jobcontrol = 0;
553         return(0);
554 }
555
556 static void job_set __PARAM__((register struct process *pw), (pw)) __OTORP__(register struct process *pw;){
557         /* save current terminal state */
558         tty_get(job.fd,&my_stty);
559         if(pw->p_flag&P_STTY)
560         {
561                 /* restore terminal state for job */
562                 tty_set(job.fd,TCSAFLUSH,&pw->p_stty);
563         }
564 #ifdef SIGTSTP
565         tcsetpgrp(job.fd,pw->p_fgrp);
566         /* if job is stopped, resume it in the background */
567         job_unstop(pw);
568 #endif  /* SIGTSTP */
569 }
570
571 static void job_reset __PARAM__((register struct process *pw), (pw)) __OTORP__(register struct process *pw;){
572         /* save the terminal state for current job */
573 #ifdef SIGTSTP
574         job_fgrp(pw,tcgetpgrp(job.fd));
575         if(tcsetpgrp(job.fd,sh.pid) !=0)
576                 return;
577 #endif  /* SIGTSTP */
578         /* force the following tty_get() to do a tcgetattr() */
579         tty_set(-1, 0, NIL(struct termios*));
580         if(pw && (pw->p_flag&P_SIGNALLED) && pw->p_exit!=SIGHUP)
581         {
582                 if(tty_get(job.fd,&pw->p_stty) == 0)
583                         pw->p_flag |= P_STTY;
584                 /* restore terminal state for job */
585                 tty_set(job.fd,TCSAFLUSH,&my_stty);
586         }
587         beenhere = 0;
588 }
589 #endif /* JOBS */
590
591 /*
592  * wait built-in command
593  */
594
595 void job_bwait __PARAM__((char **jobs), (jobs)) __OTORP__(char **jobs;){
596         register char *job;
597         register struct process *pw;
598         register pid_t pid;
599         if(*jobs==0)
600                 job_wait((pid_t)-1);
601         else while(job = *jobs++)
602         {
603 #ifdef JOBS
604                 if(*job == '%')
605                 {
606                         if(pw = job_bystring(job))
607                                 pid = pw->p_pid;
608                         else
609                                 return;
610                 }
611                 else
612 #endif /* JOBS */
613                         pid = atoi(job);
614                 job_wait(-pid);
615         }
616 }
617
618 #ifdef JOBS
619 /*
620  * execute function <fun> for each job
621  */
622
623 int job_walk __PARAM__((Sfio_t *file,int (*fun)(struct process*,int),int arg,char *joblist[]), (file, fun, arg, joblist)) __OTORP__(Sfio_t *file;int (*fun)();int arg;char *joblist[];){
624         register struct process *pw = job.pwlist;
625         register int r = 0;
626         register char *jobid, **jobs=joblist;
627         register struct process *px;
628         job_string = 0;
629         outfile = file;
630         by_number = 0;
631         if(jobs==0)
632         {
633                 /* do all jobs */
634                 for(;pw;pw=px)
635                 {
636                         px = pw->p_nxtjob;
637                         if((*fun)(pw,arg))
638                                 r = 2;
639                 }
640         }
641         else if(*jobs==0)       /* current job */
642         {
643                 /* skip over non-stop jobs */
644                 while(pw && pw->p_pgrp==0)
645                         pw = pw->p_nxtjob;
646                 if((*fun)(pw,arg))
647                         r = 2;
648         }
649         else while(jobid = *jobs++)
650         {
651                 job_string = jobid;
652                 if(*jobid==0)
653                         error(ERROR_exit(1),e_jobusage,job_string);
654                 if(*jobid == '%')
655                         pw = job_bystring(jobid);
656                 else
657                 {
658                         int pid = atoi(jobid);
659                         if(pid<0)
660                                 jobid++;
661                         while(isdigit(*jobid))
662                                 jobid++;
663                         if(*jobid)
664                                 error(ERROR_exit(1),e_jobusage,job_string);
665                         if(!(pw = job_bypid(pid)))
666                         {
667                                 pw = &dummy;
668                                 pw->p_pid = pid;
669                                 pw->p_pgrp = pid;
670                         }
671                         by_number = 1;
672                 }
673                 if((*fun)(pw,arg))
674                         r = 2;
675                 by_number = 0;
676         }
677         return(r);
678 }
679
680 /*
681  * send signal <sig> to background process group if not disowned
682  */
683 int job_terminate __PARAM__((register struct process *pw,register int sig), (pw, sig)) __OTORP__(register struct process *pw;register int sig;){
684         if(pw->p_pgrp && !(pw->p_flag&P_DISOWN))
685                 job_kill(pw,sig);
686         return(0);
687 }
688
689 /*
690  * list the given job
691  * flag JOB_LFLAG for long listing
692  * flag JOB_NFLAG for list only jobs marked for notification
693  * flag JOB_PFLAG for process id(s) only
694  */
695
696 int job_list __PARAM__((struct process *pw,register int flag), (pw, flag)) __OTORP__(struct process *pw;register int flag;){
697         register struct process *px = pw;
698         register int  n;
699         register const char *msg;
700         register int msize;
701         if(!pw || pw->p_job<=0)
702                 return(1);
703         if(pw->p_env != sh.jobenv)
704                 return(0);
705         if((flag&JOB_NFLAG) && (!(px->p_flag&P_NOTIFY)||px->p_pgrp==0))
706                 return(0);
707         if((flag&JOB_PFLAG))
708         {
709                 sfprintf(outfile,"%ld\n",(long)px->p_pgrp);
710                 return(0);
711         }
712         if((px->p_flag&P_DONE) && job.waitall && !(flag&JOB_LFLAG))
713                 return(0);
714         n = px->p_job;
715         if(px==job.pwlist)
716                 msize = '+';
717         else if(px==job.pwlist->p_nxtjob)
718                 msize = '-';
719         else
720                 msize = ' ';
721         if(flag&JOB_NLFLAG)
722                 sfputc(outfile,'\n');
723         sfprintf(outfile,"[%d] %c ",n, msize);
724         do
725         {
726                 n = 0;
727                 if(flag&JOB_LFLAG)
728                         sfprintf(outfile,"%ld\t",(long)px->p_pid);
729                 if(px->p_flag&P_SIGNALLED)
730                         msg = job_sigmsg((int)(px->p_exit));
731                 else if(px->p_flag&P_NOTIFY)
732                 {
733                         msg = e_done;
734                         n = px->p_exit;
735                 }
736                 else
737                         msg = e_running;
738                 px->p_flag &= ~P_NOTIFY;
739                 msg = ERROR_translate(msg,1);
740                 sfputr(outfile,msg,-1);
741                 msize = strlen(msg);
742                 if(n)
743                 {
744                         sfprintf(outfile,"(%d)",(int)n);
745                         msize += (3+(n>10)+(n>100));
746                 }
747                 if(px->p_flag&P_COREDUMP)
748                 {
749                         msg = ERROR_translate(e_coredump,1);
750                         sfputr(outfile, msg, -1);
751                         msize += strlen(msg);
752                 }
753                 sfnputc(outfile,' ',MAXMSG>msize?MAXMSG-msize:1);
754                 if(flag&JOB_LFLAG)
755                         px = px->p_nxtproc;
756                 else
757                         px = 0;
758                 if(!px)
759                         hist_list(sh.hist_ptr,outfile,pw->p_name,0,";");
760                 else
761                         sfputr(outfile, e_nlspace, -1);
762         }
763         while(px);
764         return(0);
765 }
766
767 /*
768  * get the process group given the job number
769  * This routine returns the process group number or -1
770  */
771 static struct process *job_bystring __PARAM__((register char *ajob), (ajob)) __OTORP__(register char *ajob;){
772         register struct process *pw=job.pwlist;
773         register int c;
774         if(*ajob++ != '%' || !pw)
775                 return(NIL(struct process*));
776         c = *ajob;
777         if(isdigit(c))
778                 pw = job_byjid(atoi(ajob));
779         else if(c=='+' || c=='%')
780                 ;
781         else if(c=='-')
782         {
783                 if(pw)
784                         pw = job.pwlist->p_nxtjob;
785         }
786         else
787                 pw = job_byname(ajob);
788         if(pw && pw->p_flag)
789                 return(pw);
790         return(NIL(struct process*));
791 }
792
793 /*
794  * Kill a job or process
795  */
796
797 int job_kill __PARAM__((register struct process *pw,register int sig), (pw, sig)) __OTORP__(register struct process *pw;register int sig;){
798         register pid_t pid;
799         register int r;
800         const char *msg;
801 #ifdef SIGTSTP
802         int stopsig = (sig==SIGSTOP||sig==SIGTSTP||sig==SIGTTIN||sig==SIGTTOU);
803 #else
804 #       define stopsig  1
805 #endif  /* SIGTSTP */
806         errno = 0;
807         if(pw==0)
808                 goto error;
809         pid = pw->p_pid;
810         if(by_number)
811         {
812                 if(pid==0 && job.jobcontrol)
813                         r = job_walk(outfile, job_kill,sig, (char**)0);
814 #ifdef SIGTSTP
815                 if(sig==SIGSTOP && pid==sh.pid && sh.ppid==1)
816                 {
817                         /* can't stop login shell */
818                         errno = EPERM;
819                         r = -1;
820                 }
821                 else
822                 {
823                         if(pid>=0)
824                         {
825                                 if((r = kill(pid,sig))>=0 && !stopsig)
826                                 {
827                                         if(pw->p_flag&P_STOPPED)
828                                                 pw->p_flag &= ~(P_STOPPED|P_SIGNALLED);
829                                         kill(pid,SIGCONT);
830                                 }
831                         }
832                         else
833                         {
834                                 if((r = killpg(-pid,sig))>=0 && !stopsig)
835                                 {
836                                         job_unstop(job_bypid(pw->p_pid));
837                                         killpg(-pid,SIGCONT);
838                                 }
839                         }
840                 }
841 #else
842                 if(pid>=0)
843                         r = kill(pid,sig);
844                 else
845                         r = killpg(-pid,sig);
846 #endif  /* SIGTSTP */
847         }
848         else
849         {
850                 if(pid = pw->p_pgrp)
851                 {
852                         if((r = killpg(pid,sig))>=0 && (sig==SIGHUP||sig==SIGTERM))
853                                 job_unstop(pw);
854                         if(r>=0)
855                                 sh_delay(.05);
856                 }
857                 while(pw && pw->p_pgrp==0 && (r=kill(pw->p_pid,sig))>=0) 
858                 {
859 #ifdef SIGTSTP
860                         if(sig==SIGHUP || sig==SIGTERM)
861                                 kill(pw->p_pid,SIGCONT);
862 #endif  /* SIGTSTP */
863                         pw = pw->p_nxtproc;
864                 }
865         }
866         if(r<0 && job_string)
867         {
868         error:
869                 if(pw && by_number)
870                         msg = e_no_proc;
871                 else
872                         msg = e_no_job;
873                 if(errno == EPERM)
874                         msg = e_access;
875                 sfprintf(sfstderr,"kill: %s: %s\n",job_string, ERROR_translate(msg,1));
876                 r = 2;
877         }
878         return(r);
879 }
880
881 /*
882  * Get process structure from first letters of jobname
883  *
884  */
885
886 static struct process *job_byname __PARAM__((char *name), (name)) __OTORP__(char *name;){
887         register struct process *pw = job.pwlist;
888         register struct process *pz = 0;
889         register int *flag = 0;
890         register char *cp = name;
891         int offset;
892         if(!sh.hist_ptr)
893                 return(NIL(struct process*));
894         if(*cp=='?')
895                 cp++,flag= &offset;
896         for(;pw;pw=pw->p_nxtjob)
897         {
898                 if(hist_match(sh.hist_ptr,pw->p_name,cp,flag)>=0)
899                 {
900                         if(pz)
901                                 error(ERROR_exit(1),e_jobusage,name-1);
902                         pz = pw;
903                 }
904         }
905         return(pz);
906 }
907
908 #else
909 #   define job_set(x)
910 #   define job_reset(x)
911 #endif /* JOBS */
912
913
914
915 /*
916  * Initialize the process posting array
917  */
918
919 void    job_clear __PARAM__((void), ()){
920         register struct process *pw, *px;
921         register struct process *pwnext;
922         register int j = BYTE(sh.lim.child_max);
923         register struct jobsave *jp;
924         for(pw=job.pwlist; pw; pw=pwnext)
925         {
926                 pwnext = pw->p_nxtjob;
927                 while(px=pw)
928                 {
929                         pw = pw->p_nxtproc;
930                         free((char*)px);
931                 }
932         }
933         for(jp=bck_list; jp;)
934         {
935                 px = (struct process*)jp;
936                 jp = jp->next;
937                 free((char*)px);
938         }
939         bck_list = 0;
940         job.pwlist = NIL(struct process*);
941         job.numpost=0;
942         job.waitall = 0;
943         job.curpgid = 0;
944         job.toclear = 0;
945         if(!job.freejobs)
946                 job.freejobs = (unsigned char*)malloc((unsigned)(j+1));
947         while(j >=0)
948                 job.freejobs[j--]  = 0;
949 }
950
951 /*
952  * put the process <pid> on the process list and return the job number
953  * if non-zero, <join> is the process id of the job to join
954  */
955
956 int job_post __PARAM__((pid_t pid, pid_t join), (pid, join)) __OTORP__(pid_t pid; pid_t join;){
957         register struct process *pw;
958         register History_t *hp = sh.hist_ptr;
959         sh.jobenv = sh.curenv;
960         if(job.toclear)
961         {
962                 job_clear();
963                 return(0);
964         }
965         if(join && (pw=job_bypid(join)))
966         {
967                 /* if job to join is not first move it to front */
968                 if((pw=job_byjid(pw->p_job)) != job.pwlist)
969                 {
970                         job_unlink(pw);
971                         pw->p_nxtjob = job.pwlist;
972                         job.pwlist = pw;
973                 }
974         }
975         if(pw=freelist)
976                 freelist = pw->p_nxtjob;
977         else
978                 pw = new_of(struct process,0);
979         job.numpost++;
980         if(join && job.pwlist)
981         {
982                 /* join existing current job */
983                 pw->p_nxtjob = job.pwlist->p_nxtjob;
984                 pw->p_nxtproc = job.pwlist;
985                 pw->p_job = job.pwlist->p_job;
986         }
987         else
988         {
989                 /* create a new job */
990                 pw->p_nxtjob = job.pwlist;
991                 while((pw->p_job = job_alloc()) < 0)
992                         job_wait((pid_t)1);
993                 pw->p_nxtproc = 0;
994         }
995         job.pwlist = pw;
996         pw->p_env = sh.curenv;
997         pw->p_pid = pid;
998         pw->p_flag = P_EXITSAVE;
999         if(sh_isstate(SH_MONITOR))
1000                 pw->p_fgrp = job.curpgid;
1001         else
1002                 pw->p_fgrp = 0;
1003         pw->p_pgrp = pw->p_fgrp;
1004 #ifdef DEBUG
1005         sfprintf(sfstderr,"%ld: posting %d pid=%ld pgid=%ld savesig=%d join=%ld\n",
1006                  (long)getpid(),pw->p_job,(long)pw->p_pid,(long)pw->p_pgrp,savesig,(long)join);
1007         sfsync(sfstderr);
1008 #endif /* DEBUG */
1009 #ifdef JOBS
1010         if(hp && !sh_isstate(SH_PROFILE))
1011                 pw->p_name=hist_tell(sh.hist_ptr,(int)hp->histind-1);
1012         else
1013                 pw->p_name = -1;
1014 #endif /* JOBS */
1015         job.in_critical=0;
1016         if(savesig)
1017                 job_waitsafe(savesig);
1018         return(pw->p_job);
1019 }
1020
1021 /*
1022  * Returns a process structure give a process id
1023  */
1024
1025 static struct process *job_bypid __PARAM__((pid_t pid), (pid)) __OTORP__(pid_t pid;){
1026         register struct process  *pw, *px;
1027         for(pw=job.pwlist; pw; pw=pw->p_nxtjob)
1028                 for(px=pw; px; px=px->p_nxtproc)
1029                 {
1030                         if(px->p_pid==pid)
1031                                 return(px);
1032                 }
1033         return(NIL(struct process*));
1034 }
1035
1036 /*
1037  * return a pointer to a job given the job id
1038  */
1039
1040 static struct process *job_byjid __PARAM__((int jobid), (jobid)) __OTORP__(int jobid;){
1041         register struct process *pw;
1042         for(pw=job.pwlist;pw; pw = pw->p_nxtjob)
1043         {
1044                 if(pw->p_job==jobid)
1045                         break;
1046         }
1047         return(pw);
1048 }
1049
1050 /*
1051  * print a signal message
1052  */
1053 static void job_prmsg __PARAM__((register struct process *pw), (pw)) __OTORP__(register struct process *pw;){
1054         if(pw->p_exit!=SIGINT && pw->p_exit!=SIGPIPE)
1055         {
1056                 register const char *msg, *dump;
1057                 msg = job_sigmsg((int)(pw->p_exit));
1058                 msg = ERROR_translate(msg,1);
1059                 if(pw->p_flag&P_COREDUMP)
1060                         dump =  ERROR_translate(e_coredump,1);
1061                 else
1062                         dump = "";
1063                 if(sh_isstate(SH_INTERACTIVE))
1064                         sfprintf(sfstderr,"%s%s\n",msg,dump);
1065                 else
1066                         error(2,"%d: %s%s",pw->p_pid,msg,dump);
1067         }
1068 }
1069
1070 /*
1071  * Wait for process pid to complete
1072  * If pid < -1, then wait can be interrupted, -pid is waited for (wait builtin)
1073  * pid=0 to unpost all done processes
1074  * pid=1 to wait for at least one process to complete
1075  * pid=-1 to wait for all runing processes
1076  */
1077
1078 void    job_wait __PARAM__((register pid_t pid), (pid)) __OTORP__(register pid_t pid;){
1079         register struct process *pw=0,*px;
1080         register int    jobid = 0;
1081         char            intr = 0;
1082         if(pid <= 0)
1083         {
1084                 if(pid==0)
1085                         goto done;
1086                 pid = -pid;
1087                 intr = 1;
1088         }
1089         job.in_critical = 1;
1090         if(pid > 1)
1091         {
1092                 if(!(pw=job_bypid(pid)))
1093                 {
1094                         /* check to see whether job status has been saved */
1095                         if((sh.exitval = job_chksave(pid)) < 0)
1096                                 sh.exitval = ERROR_NOENT;
1097                         exitset();
1098                         job.in_critical = 0;
1099                         if(savesig)
1100                                 job_waitsafe(savesig);
1101                         return;
1102                 }
1103                 else if(intr && pw->p_env!=sh.curenv)
1104                 {
1105                         sh.exitval = ERROR_NOENT;
1106                         return;
1107                 }
1108                 jobid = pw->p_job;
1109                 if(!intr)
1110                         pw->p_flag &= ~P_EXITSAVE;
1111                 if(pw->p_pgrp && job.parent!= (pid_t)-1)
1112                         job_set(job_byjid(jobid));
1113         }
1114 #ifdef DEBUG
1115         sfprintf(sfstderr,"%ld: job_wait job=%d pid=%ld\n",(long)getpid(),jobid,(long)pid);
1116         if(pw)
1117                 sfprintf(sfstderr,"%ld: job_wait flags=%o\n",(long)getpid(),pw->p_flag);
1118 #endif /* DEBUG*/
1119         while(1)
1120         {
1121                 job.in_critical = 1;
1122                 if(job.waitsafe)
1123                 {
1124                         for(px=job.pwlist;px; px = px->p_nxtjob)
1125                         {
1126                                 if(px!=pw && (px->p_flag&P_NOTIFY))
1127                                 {
1128                                         if(sh_isoption(SH_NOTIFY))
1129                                         {
1130                                                 outfile = sfstderr;
1131                                                 job_list(px,JOB_NFLAG|JOB_NLFLAG);
1132                                                 sfsync(sfstderr);
1133                                         }
1134                                         else if(!sh_isoption(SH_INTERACTIVE) && (px->p_flag&P_SIGNALLED))
1135                                         {
1136                                                 job_prmsg(px);
1137                                                 px->p_flag &= ~P_NOTIFY;
1138                                         }
1139                                 }
1140                         }
1141                 }
1142                 if(pw && (pw->p_flag&(P_DONE|P_STOPPED)))
1143                 {
1144 #ifdef SIGTSTP
1145                         if(pw->p_flag&P_STOPPED)
1146                         {
1147                                 pw->p_flag |= P_EXITSAVE;
1148                                 if(sh_isoption(SH_INTERACTIVE) && !sh_isstate(SH_FORKED))
1149                                 {
1150                                         if( pw->p_exit!=SIGTTIN && pw->p_exit!=SIGTTOU)
1151                                                 break;
1152
1153                                         killpg(pw->p_pgrp,SIGCONT);
1154                                 }
1155                                 else /* ignore stop when non-interactive */
1156                                         pw->p_flag &= ~(P_NOTIFY|P_SIGNALLED|P_STOPPED|P_EXITSAVE);
1157                         }
1158                         else
1159 #endif /* SIGTSTP */
1160                         {
1161                                 if(pw->p_flag&P_SIGNALLED)
1162                                 {
1163                                         pw->p_flag &= ~P_NOTIFY;
1164                                         job_prmsg(pw);
1165                                 }
1166                                 else if(pw->p_flag&P_DONE)
1167                                         pw->p_flag &= ~P_NOTIFY;
1168                                 if(pw == job_byjid(jobid))
1169                                 {
1170                                         /* last process in job */
1171                                         sh.exitval = pw->p_exit;
1172                                         if(pw->p_flag&P_SIGNALLED)
1173                                                 sh.exitval |= SH_EXITSIG;
1174                                         if(intr)
1175                                                 pw->p_flag &= ~P_EXITSAVE;
1176                                 }
1177                                 if(!(px=job_unpost(pw,1)) || !job.waitall) 
1178                                         break;
1179                                 pw = px;
1180                                 continue;
1181                         }
1182                 }
1183                 sfsync(sfstderr);
1184                 job.in_critical = !savesig;
1185                 job.waitsafe = 0;
1186                 job_waitsafe(savesig);
1187                 if(job.waitsafe)
1188                         continue;
1189                 if(errno==ECHILD)
1190                         break;
1191                 if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
1192                         sh_timetraps();
1193                 if((intr && sh.trapnote) || (pid==1 && !intr))
1194                         break;
1195         }
1196         job.in_critical = 0;
1197         if(savesig)
1198                 job_waitsafe(savesig);
1199         if(pid==1)
1200                 return;
1201         exitset();
1202         if(pw->p_pgrp)
1203         {
1204                 job_reset(pw);
1205                 /* propogate keyboard interrupts to parent */
1206                 if((pw->p_flag&P_SIGNALLED) && pw->p_exit==SIGINT && !(sh.sigflag[SIGINT]&SH_SIGOFF))
1207                         sh_fault(SIGINT); 
1208 #ifdef SIGTSTP
1209                 else if((pw->p_flag&P_STOPPED) && pw->p_exit==SIGTSTP)
1210                 {
1211                         job.parent = 0;
1212                         sh_fault(SIGTSTP); 
1213                 }
1214 #endif /* SIGTSTP */
1215         }
1216 done:
1217         if(!sh.intrap)
1218         {
1219                 for(pw=job.pwlist; pw; pw=px)
1220                 {
1221                         px = pw->p_nxtjob;
1222                         job_unpost(pw,0);
1223                 }
1224         }
1225 }
1226
1227 /*
1228  * move job to foreground if bgflag == 'f'
1229  * move job to background if bgflag == 'b'
1230  * disown job if bgflag == 'd'
1231  */
1232
1233 job_switch __PARAM__((register struct process *pw,int bgflag), (pw, bgflag)) __OTORP__(register struct process *pw;int bgflag;){
1234         register const char *msg;
1235         if(!pw || !(pw=job_byjid((int)pw->p_job)))
1236                 return(1);
1237         if(bgflag=='d')
1238         {
1239                 for(; pw; pw=pw->p_nxtproc)
1240                         pw->p_flag |= P_DISOWN;
1241                 return(0);
1242         }
1243 #ifdef SIGTSTP
1244         if(bgflag=='b')
1245         {
1246                 sfprintf(outfile,"[%d]\t",(int)pw->p_job);
1247                 msg = "&";
1248         }
1249         else
1250         {
1251                 job_unlink(pw);
1252                 pw->p_nxtjob = job.pwlist;
1253                 job.pwlist = pw;
1254                 msg = "";
1255         }
1256         hist_list(sh.hist_ptr,outfile,pw->p_name,'&',";");
1257         sfputr(outfile,msg,'\n');
1258         sfsync(outfile);
1259         if(bgflag=='f')
1260         {
1261                 if(!(pw=job_unpost(pw,1)))
1262                         return(1);
1263                 job.waitall = 1;
1264                 job_wait(pw->p_pid);
1265                 job.waitall = 0;
1266         }
1267         else if(pw->p_flag&P_STOPPED)
1268                 job_unstop(pw);
1269 #endif /* SIGTSTP */
1270         return(0);
1271 }
1272
1273
1274 #ifdef SIGTSTP
1275 /*
1276  * Set the foreground group associated with a job
1277  */
1278
1279 static void job_fgrp __PARAM__((register struct process *pw, int newgrp), (pw, newgrp)) __OTORP__(register struct process *pw; int newgrp;){
1280         for(; pw; pw=pw->p_nxtproc)
1281                 pw->p_fgrp = newgrp;
1282 }
1283
1284 /*
1285  * turn off STOP state of a process group and send CONT signals
1286  */
1287
1288 static void job_unstop __PARAM__((register struct process *px), (px)) __OTORP__(register struct process *px;){
1289         register struct process *pw;
1290         register int num = 0;
1291         for(pw=px ;pw ;pw=pw->p_nxtproc)
1292         {
1293                 if(pw->p_flag&P_STOPPED)
1294                 {
1295                         num++;
1296                         pw->p_flag &= ~(P_STOPPED|P_SIGNALLED|P_NOTIFY);
1297                 }
1298         }
1299         if(num!=0)
1300         {
1301                 if(px->p_fgrp != px->p_pgrp)
1302                         killpg(px->p_fgrp,SIGCONT);
1303                 killpg(px->p_pgrp,SIGCONT);
1304         }
1305 }
1306 #endif  /* SIGTSTP */
1307
1308 /*
1309  * remove a job from table
1310  * If all the processes have not completed, unpost first non-completed  process
1311  * Otherwise the job is removed and job_unpost returns NULL.
1312  * pwlist is reset if the first job is removed
1313  * if <notify> is non-zero, then jobs with pending notifications are unposted
1314  */
1315
1316 static struct process *job_unpost __PARAM__((register struct process *pwtop,int notify), (pwtop, notify)) __OTORP__(register struct process *pwtop;int notify;){
1317         register struct process *pw;
1318         /* make sure all processes are done */
1319 #ifdef DEBUG
1320         sfprintf(sfstderr,"%ld: unpost pid=%ld\n",(long)getpid(),(long)pwtop->p_pid);
1321         sfsync(sfstderr);
1322 #endif /* DEBUG */
1323         pwtop = pw = job_byjid((int)pwtop->p_job);
1324         for(; pw && (pw->p_flag&P_DONE)&&(notify||!(pw->p_flag&P_NOTIFY)); pw=pw->p_nxtproc);
1325         if(pw)
1326                 return(pw);
1327         /* all processes complete, unpost job */
1328         job_unlink(pwtop);
1329         for(pw=pwtop; pw; pw=pw->p_nxtproc)
1330         {
1331                 /* save the exit status for background jobs */
1332                 if(pw->p_flag&P_EXITSAVE)
1333                 {
1334                         struct jobsave *jp;
1335                         /* save status for future wait */
1336                         if(bck_count++ > sh.lim.child_max)
1337                                 job_chksave(0);
1338                         jp = new_of(struct jobsave,0);
1339                         jp->next = bck_list;
1340                         bck_list = jp;
1341                         jp->pid = pw->p_pid;
1342                         jp->env = sh.curenv;
1343                         jp->exitval = pw->p_exit;
1344                         if(pw->p_flag&P_SIGNALLED)
1345                                 jp->exitval |= SH_EXITSIG;
1346                         pw->p_flag &= ~P_EXITSAVE;
1347                 }
1348                 pw->p_flag &= ~P_DONE;
1349                 job.numpost--;
1350                 pw->p_nxtjob = freelist;
1351                 freelist = pw;
1352         }
1353 #ifdef DEBUG
1354         sfprintf(sfstderr,"%ld: free job=%d\n",(long)getpid(),pwtop->p_job);
1355         sfsync(sfstderr);
1356 #endif /* DEBUG */
1357         job_free((int)pwtop->p_job);
1358         return((struct process*)0);
1359 }
1360
1361 /*
1362  * unlink a job form the job list
1363  */
1364 static void job_unlink __PARAM__((register struct process *pw), (pw)) __OTORP__(register struct process *pw;){
1365         register struct process *px;
1366         if(pw==job.pwlist)
1367         {
1368                 job.pwlist = pw->p_nxtjob;
1369                 job.curpgid = 0;
1370                 return;
1371         }
1372         for(px=job.pwlist;px;px=px->p_nxtjob)
1373                 if(px->p_nxtjob == pw)
1374                 {
1375                         px->p_nxtjob = pw->p_nxtjob;
1376                         return;
1377                 }
1378 }
1379
1380 /*
1381  * get an unused job number
1382  * freejobs is a bit vector, 0 is unused
1383  */
1384
1385 static int job_alloc __PARAM__((void), ()){
1386         register int j=0;
1387         register unsigned mask = 1;
1388         register unsigned char *freeword;
1389         register int jmax = BYTE(sh.lim.child_max);
1390         /* skip to first word with a free slot */
1391         for(j=0;job.freejobs[j] == UCHAR_MAX; j++);
1392         if(j >= jmax)
1393         {
1394                 register struct process *pw;
1395                 for(j=1; j < sh.lim.child_max; j++)
1396                 {
1397                         if((pw=job_byjid(j))&& !job_unpost(pw,0))
1398                                 break;
1399                 }
1400                 j /= CHAR_BIT;
1401                 if(j >= jmax)
1402                         return(-1);
1403         }
1404         freeword = &job.freejobs[j];
1405         j *= CHAR_BIT;
1406         for(j++;mask&(*freeword);j++,mask <<=1);
1407         *freeword  |= mask;
1408         return(j);
1409 }
1410
1411 /*
1412  * return a job number
1413  */
1414
1415 static void job_free __PARAM__((register int n), (n)) __OTORP__(register int n;){
1416         register int j = (--n)/CHAR_BIT;
1417         register unsigned mask;
1418         n -= j*CHAR_BIT;
1419         mask = 1 << n;
1420         job.freejobs[j]  &= ~mask;
1421 }
1422
1423 static char *job_sigmsg __PARAM__((int sig), (sig)) __OTORP__(int sig;){
1424         static char signo[] = "Signal xxxx";
1425 #ifdef apollo
1426         /*
1427          * This code handles the formatting for the apollo specific signal
1428          * SIGAPOLLO. 
1429          */
1430         extern __MANGLE__ char *apollo_error __PROTO__((void));
1431         
1432         if ( sig == SIGAPOLLO )
1433                 return( apollo_error() );
1434 #endif /* apollo */
1435         if(sig<sh.sigmax && sh.sigmsg[sig])
1436                 return(sh.sigmsg[sig]);
1437 #if defined(SIGRTMIN) && defined(SIGRTMAX)
1438         if(sig>=SIGRTMIN && sig<=SIGRTMAX)
1439         {
1440                 static char sigrt[20];
1441                 sfsprintf(sigrt,sizeof(sigrt),"SIGRTMIN+%d",sig-SIGRTMIN);
1442                 return(sigrt);
1443         }
1444 #endif
1445         strncpy(signo+7,fmtbase((long)sig,10,0),4);
1446         return(signo);
1447 }
1448
1449 /*
1450  * see whether exit status has been saved and delete it
1451  * if pid==0, then oldest saved process is deleted
1452  * If pid is not found a -1 is returned.
1453  */
1454 int job_chksave __PARAM__((register pid_t pid), (pid)) __OTORP__(register pid_t pid;){
1455         register struct jobsave *jp = bck_list, *jpold=0;
1456         register int r= -1;
1457         while(jp)
1458         {
1459                 if(jp->pid==pid)
1460                         break;
1461                 if(pid==0 && !jp->next)
1462                         break;
1463                 jpold = jp;
1464                 jp = jp->next;
1465         }
1466         if(jp)
1467         {
1468                 r = 0;
1469                 if(pid)
1470                 {
1471                         if(jp->env!=sh.curenv)
1472                                 return(-1);
1473                         r = jp->exitval;
1474                 }
1475                 if(jpold)
1476                         jpold->next = jp->next;
1477                 else
1478                         bck_list = jp->next;
1479                 bck_count--;
1480                 free((char*)jp);
1481         }
1482         return(r);
1483 }