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