1 | /* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.proc.c,v 1.2 1997-10-14 21:25:16 lcs Exp $ */ |
---|
2 | /* |
---|
3 | * sh.proc.c: Job manipulations |
---|
4 | */ |
---|
5 | /*- |
---|
6 | * Copyright (c) 1980, 1991 The Regents of the University of California. |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * 3. All advertising materials mentioning features or use of this software |
---|
18 | * must display the following acknowledgement: |
---|
19 | * This product includes software developed by the University of |
---|
20 | * California, Berkeley and its contributors. |
---|
21 | * 4. Neither the name of the University nor the names of its contributors |
---|
22 | * may be used to endorse or promote products derived from this software |
---|
23 | * without specific prior written permission. |
---|
24 | * |
---|
25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
35 | * SUCH DAMAGE. |
---|
36 | */ |
---|
37 | #include "sh.h" |
---|
38 | |
---|
39 | RCSID("$Id: sh.proc.c,v 1.2 1997-10-14 21:25:16 lcs Exp $") |
---|
40 | |
---|
41 | #include "ed.h" |
---|
42 | #include "tc.h" |
---|
43 | #include "tc.wait.h" |
---|
44 | |
---|
45 | #ifdef aiws |
---|
46 | # undef HZ |
---|
47 | # define HZ 16 |
---|
48 | #endif /* aiws */ |
---|
49 | |
---|
50 | #if (defined(_BSD) && defined(_BSD_INCLUDES)) || (defined(IRIS4D) && __STDC__) |
---|
51 | # define BSDWAIT |
---|
52 | #endif |
---|
53 | #ifndef WTERMSIG |
---|
54 | # define WTERMSIG(w) (((union wait *) &(w))->w_termsig) |
---|
55 | # ifndef BSDWAIT |
---|
56 | # define BSDWAIT |
---|
57 | # endif |
---|
58 | #endif /* !WTERMSIG */ |
---|
59 | #ifndef WEXITSTATUS |
---|
60 | # define WEXITSTATUS(w) (((union wait *) &(w))->w_retcode) |
---|
61 | #endif /* !WEXITSTATUS */ |
---|
62 | #ifndef WSTOPSIG |
---|
63 | # define WSTOPSIG(w) (((union wait *) &(w))->w_stopsig) |
---|
64 | #endif /* WSTOPSIG */ |
---|
65 | |
---|
66 | #ifndef WCOREDUMP |
---|
67 | # ifdef BSDWAIT |
---|
68 | # define WCOREDUMP(w) (((union wait *) &(w))->w_coredump) |
---|
69 | # else /* !BSDWAIT */ |
---|
70 | # define WCOREDUMP(w) ((w) & 0200) |
---|
71 | # endif /* !BSDWAIT */ |
---|
72 | #endif /* !WCOREDUMP */ |
---|
73 | |
---|
74 | /* |
---|
75 | * C Shell - functions that manage processes, handling hanging, termination |
---|
76 | */ |
---|
77 | |
---|
78 | #define BIGINDEX 9 /* largest desirable job index */ |
---|
79 | |
---|
80 | #ifdef BSDTIMES |
---|
81 | # if defined(SUNOS4) || defined(hp9000) |
---|
82 | static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0L, 0L, 0L, 0L, |
---|
83 | 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}; |
---|
84 | |
---|
85 | # else /* !SUNOS4 && !hp9000 */ |
---|
86 | # ifdef masscomp |
---|
87 | /* |
---|
88 | * Initialization of this structure under RTU 4.1A & RTU 5.0 is problematic |
---|
89 | * because the first two elements are unions of a time_t and a struct timeval. |
---|
90 | * So we'll just have to trust the loader to do the "right thing", DAS DEC-90. |
---|
91 | */ |
---|
92 | static struct rusage zru; |
---|
93 | # else /* masscomp */ |
---|
94 | static struct rusage zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, |
---|
95 | 0, 0, 0, 0, 0, 0}; |
---|
96 | # endif /* masscomp */ |
---|
97 | # endif /* !SUNOS4 && !hp9000 */ |
---|
98 | #else /* ! BSDTIMES */ |
---|
99 | # ifdef _SEQUENT_ |
---|
100 | static struct process_stats zru = {{0L, 0L}, {0L, 0L}, 0, 0, 0, 0, 0, 0, 0, |
---|
101 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
---|
102 | # else /* !_SEQUENT_ */ |
---|
103 | static struct tms zru = {0L, 0L, 0L, 0L}, lru = {0L, 0L, 0L, 0L}; |
---|
104 | # endif /* !_SEQUENT_ */ |
---|
105 | #endif /* !BSDTIMES */ |
---|
106 | |
---|
107 | #ifndef RUSAGE_CHILDREN |
---|
108 | # define RUSAGE_CHILDREN -1 |
---|
109 | #endif |
---|
110 | |
---|
111 | static void pflushall __P((void)); |
---|
112 | static void pflush __P((struct process *)); |
---|
113 | static void pclrcurr __P((struct process *)); |
---|
114 | static void padd __P((struct command *)); |
---|
115 | static int pprint __P((struct process *, int)); |
---|
116 | static void ptprint __P((struct process *)); |
---|
117 | static void pads __P((Char *)); |
---|
118 | static void pkill __P((Char **, int)); |
---|
119 | static struct process *pgetcurr __P((struct process *)); |
---|
120 | static void okpcntl __P((void)); |
---|
121 | |
---|
122 | /* |
---|
123 | * pchild - called at interrupt level by the SIGCHLD signal |
---|
124 | * indicating that at least one child has terminated or stopped |
---|
125 | * thus at least one wait system call will definitely return a |
---|
126 | * childs status. Top level routines (like pwait) must be sure |
---|
127 | * to mask interrupts when playing with the proclist data structures! |
---|
128 | */ |
---|
129 | sigret_t |
---|
130 | /*ARGSUSED*/ |
---|
131 | pchild(snum) |
---|
132 | int snum; |
---|
133 | { |
---|
134 | register struct process *pp; |
---|
135 | register struct process *fp; |
---|
136 | register int pid; |
---|
137 | #if defined(BSDJOBS) || (!defined(BSDTIMES) && (defined(ODT) || defined(aiws) || defined(uts))) |
---|
138 | extern int insource; |
---|
139 | #endif /* BSDJOBS */ |
---|
140 | #ifdef BSDWAIT |
---|
141 | union wait w; |
---|
142 | #else /* !BSDWAIT */ |
---|
143 | int w; |
---|
144 | #endif /* !BSDWAIT */ |
---|
145 | int jobflags; |
---|
146 | #ifdef BSDTIMES |
---|
147 | struct rusage ru; |
---|
148 | #else /* !BSDTIMES */ |
---|
149 | # ifdef _SEQUENT_ |
---|
150 | struct process_stats ru; |
---|
151 | struct process_stats cpst1, cpst2; |
---|
152 | timeval_t tv; |
---|
153 | # else /* !_SEQUENT_ */ |
---|
154 | struct tms proctimes; |
---|
155 | |
---|
156 | if (!timesdone) { |
---|
157 | timesdone++; |
---|
158 | (void) times(&shtimes); |
---|
159 | } |
---|
160 | # endif /* _SEQUENT_ */ |
---|
161 | #endif /* BSDTIMES */ |
---|
162 | |
---|
163 | #ifdef JOBDEBUG |
---|
164 | xprintf("pchild()\n"); |
---|
165 | #endif /* JOBDEBUG */ |
---|
166 | |
---|
167 | /* Christos on where the signal(SIGCHLD, pchild) shoud be: |
---|
168 | * |
---|
169 | * I think that it should go *after* the wait, unlike most signal handlers. |
---|
170 | * |
---|
171 | * In release two (for which I have manuals), it says that wait will remove |
---|
172 | * the first child from the queue of dead children. |
---|
173 | * All the rest of the children that die while in the signal handler of the |
---|
174 | * SIGC(H)LD, will be placed in the queue. If signal is called to re-establish |
---|
175 | * the signal handler, and there are items in the queue, the process will |
---|
176 | * receive another SIGC(H)LD before signal returns. BTW this is from the |
---|
177 | * manual page on comp-sim... Maybe it is not applicable to the hp's, but |
---|
178 | * I read on the news in comp.unix.wizards or comp.unix.questions yesterday |
---|
179 | * that another person was claiming the the signal() call should be after |
---|
180 | * the wait(). |
---|
181 | */ |
---|
182 | |
---|
183 | loop: |
---|
184 | errno = 0; /* reset, just in case */ |
---|
185 | #ifdef JOBDEBUG |
---|
186 | xprintf("Waiting...\n"); |
---|
187 | flush(); |
---|
188 | #endif |
---|
189 | #ifdef BSDJOBS |
---|
190 | # ifdef BSDTIMES |
---|
191 | /* both a wait3 and rusage */ |
---|
192 | # if !defined(BSDWAIT) || defined(NeXT) || defined(MACH) || (defined(IRIS4D) && __STDC__ && SYSVREL <= 3) |
---|
193 | pid = wait3(&w, |
---|
194 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); |
---|
195 | # else /* BSDWAIT */ |
---|
196 | pid = wait3(&w.w_status, |
---|
197 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); |
---|
198 | # endif /* BSDWAIT */ |
---|
199 | # else /* !BSDTIMES */ |
---|
200 | # ifdef _SEQUENT_ |
---|
201 | (void) get_process_stats(&tv, PS_SELF, 0, &cpst1); |
---|
202 | pid = waitpid(-1, &w, |
---|
203 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); |
---|
204 | (void) get_process_stats(&tv, PS_SELF, 0, &cpst2); |
---|
205 | pr_stat_sub(&cpst2, &cpst1, &ru); |
---|
206 | # else /* !_SEQUENT_ */ |
---|
207 | # ifndef POSIX |
---|
208 | /* we have a wait3, but no rusage stuff */ |
---|
209 | pid = wait3(&w.w_status, |
---|
210 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); |
---|
211 | # else /* POSIX */ |
---|
212 | pid = waitpid(-1, &w, |
---|
213 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); |
---|
214 | # endif /* POSIX */ |
---|
215 | # endif /* !_SEQUENT_ */ |
---|
216 | # endif /* !BSDTIMES */ |
---|
217 | #else /* !BSDJOBS */ |
---|
218 | # ifdef BSDTIMES |
---|
219 | # define HAVEwait3 |
---|
220 | /* both a wait3 and rusage */ |
---|
221 | # ifdef hpux |
---|
222 | pid = wait3(&w.w_status, WNOHANG, 0); |
---|
223 | # else /* !hpux */ |
---|
224 | pid = wait3(&w.w_status, WNOHANG, &ru); |
---|
225 | # endif /* !hpux */ |
---|
226 | # else /* !BSDTIMES */ |
---|
227 | # ifdef ODT /* For Sco Unix 3.2.0 or ODT 1.0 */ |
---|
228 | # define HAVEwait3 |
---|
229 | pid = waitpid(-1, &w, |
---|
230 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG)); |
---|
231 | # endif /* ODT */ |
---|
232 | # if defined(aiws) || defined(uts) |
---|
233 | # define HAVEwait3 |
---|
234 | pid = wait3(&w.w_status, |
---|
235 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), 0); |
---|
236 | # endif /* aiws || uts */ |
---|
237 | # ifndef HAVEwait3 |
---|
238 | # ifdef UNRELSIGS |
---|
239 | /* no wait3, therefore no rusage */ |
---|
240 | /* on Sys V, this may hang. I hope it's not going to be a problem */ |
---|
241 | # ifdef _MINIX |
---|
242 | pid = wait(&w); |
---|
243 | # else /* !_MINIX */ |
---|
244 | pid = ourwait(&w.w_status); |
---|
245 | # endif /* _MINIX */ |
---|
246 | # else /* UNRELSIGS */ |
---|
247 | /* |
---|
248 | * XXX: for greater than 3 we should use waitpid(). |
---|
249 | * but then again, SVR4 falls into the POSIX/BSDJOBS category. |
---|
250 | */ |
---|
251 | pid = wait(&w.w_status); |
---|
252 | # endif /* SYSVREL >= 3 */ |
---|
253 | # endif /* HAVEwait3 */ |
---|
254 | # endif /* BSDTIMES */ |
---|
255 | # ifndef BSDSIGS |
---|
256 | (void) sigset(SIGCHLD, pchild); |
---|
257 | # endif /* !BSDSIGS */ |
---|
258 | #endif /* BSDJOBS */ |
---|
259 | |
---|
260 | #ifdef JOBDEBUG |
---|
261 | { |
---|
262 | char buffer[100]; |
---|
263 | xsprintf(buffer, "pid %d, retval %x termsig %x retcode %x\n", |
---|
264 | pid, w, WTERMSIG(w), WEXITSTATUS(w)); |
---|
265 | xprintf(buffer); |
---|
266 | flush(); |
---|
267 | } |
---|
268 | #endif /* JOBDEBUG */ |
---|
269 | |
---|
270 | if (pid <= 0) { |
---|
271 | #ifdef JOBDEBUG |
---|
272 | xprintf("errno == %d\n", errno); |
---|
273 | #endif |
---|
274 | if (errno == EINTR) { |
---|
275 | errno = 0; |
---|
276 | goto loop; |
---|
277 | } |
---|
278 | pnoprocesses = pid == -1; |
---|
279 | #ifndef SIGVOID |
---|
280 | return (0); |
---|
281 | #else /* !SIGVOID */ |
---|
282 | return; |
---|
283 | #endif /* SIGVOID */ |
---|
284 | } |
---|
285 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) |
---|
286 | if (pid == pp->p_procid) |
---|
287 | goto found; |
---|
288 | #ifndef BSDJOBS |
---|
289 | /* this should never have happened */ |
---|
290 | stderror(ERR_SYNC, pid); |
---|
291 | xexit(0); |
---|
292 | #else /* BSDJOBS */ |
---|
293 | goto loop; |
---|
294 | #endif /* BSDJOBS */ |
---|
295 | found: |
---|
296 | if (pid == atoi(short2str(value(STRchild)))) |
---|
297 | unsetv(STRchild); |
---|
298 | pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); |
---|
299 | if (WIFSTOPPED(w)) { |
---|
300 | pp->p_flags |= PSTOPPED; |
---|
301 | pp->p_reason = WSTOPSIG(w); |
---|
302 | } |
---|
303 | else { |
---|
304 | if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) |
---|
305 | #ifndef BSDTIMES |
---|
306 | # ifdef _SEQUENT_ |
---|
307 | (void) get_process_stats(&pp->p_etime, PS_SELF, NULL, NULL); |
---|
308 | # else /* !_SEQUENT_ */ |
---|
309 | # ifndef COHERENT |
---|
310 | pp->p_etime = times(&proctimes); |
---|
311 | # else /* !COHERENT */ |
---|
312 | pp->p_etime = HZ * time(NULL); |
---|
313 | times(&proctimes); |
---|
314 | # endif /* !COHERENT */ |
---|
315 | # endif /* !_SEQUENT_ */ |
---|
316 | #else /* BSDTIMES */ |
---|
317 | (void) gettimeofday(&pp->p_etime, NULL); |
---|
318 | #endif /* BSDTIMES */ |
---|
319 | |
---|
320 | |
---|
321 | #if defined(BSDTIMES) || defined(_SEQUENT_) |
---|
322 | pp->p_rusage = ru; |
---|
323 | #else /* !BSDTIMES && !_SEQUENT_ */ |
---|
324 | (void) times(&proctimes); |
---|
325 | pp->p_utime = proctimes.tms_cutime - shtimes.tms_cutime; |
---|
326 | pp->p_stime = proctimes.tms_cstime - shtimes.tms_cstime; |
---|
327 | shtimes = proctimes; |
---|
328 | #endif /* !BSDTIMES && !_SEQUENT_ */ |
---|
329 | if (WIFSIGNALED(w)) { |
---|
330 | if (WTERMSIG(w) == SIGINT) |
---|
331 | pp->p_flags |= PINTERRUPTED; |
---|
332 | else |
---|
333 | pp->p_flags |= PSIGNALED; |
---|
334 | if (WCOREDUMP(w)) |
---|
335 | pp->p_flags |= PDUMPED; |
---|
336 | pp->p_reason = WTERMSIG(w); |
---|
337 | } |
---|
338 | else { |
---|
339 | pp->p_reason = WEXITSTATUS(w); |
---|
340 | if (pp->p_reason != 0) |
---|
341 | pp->p_flags |= PAEXITED; |
---|
342 | else |
---|
343 | pp->p_flags |= PNEXITED; |
---|
344 | } |
---|
345 | } |
---|
346 | jobflags = 0; |
---|
347 | fp = pp; |
---|
348 | do { |
---|
349 | if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && |
---|
350 | !child && adrof(STRtime) && |
---|
351 | #ifdef BSDTIMES |
---|
352 | fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec |
---|
353 | #else /* !BSDTIMES */ |
---|
354 | # ifdef _SEQUENT_ |
---|
355 | fp->p_rusage.ps_utime.tv_sec + fp->p_rusage.ps_stime.tv_sec |
---|
356 | # else /* !_SEQUENT_ */ |
---|
357 | # ifndef POSIX |
---|
358 | (fp->p_utime + fp->p_stime) / HZ |
---|
359 | # else /* POSIX */ |
---|
360 | (fp->p_utime + fp->p_stime) / clk_tck |
---|
361 | # endif /* POSIX */ |
---|
362 | # endif /* !_SEQUENT_ */ |
---|
363 | #endif /* !BSDTIMES */ |
---|
364 | >= atoi(short2str(value(STRtime)))) |
---|
365 | fp->p_flags |= PTIME; |
---|
366 | jobflags |= fp->p_flags; |
---|
367 | } while ((fp = fp->p_friends) != pp); |
---|
368 | pp->p_flags &= ~PFOREGND; |
---|
369 | if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { |
---|
370 | pp->p_flags &= ~PPTIME; |
---|
371 | pp->p_flags |= PTIME; |
---|
372 | } |
---|
373 | if ((jobflags & (PRUNNING | PREPORTED)) == 0) { |
---|
374 | fp = pp; |
---|
375 | do { |
---|
376 | if (fp->p_flags & PSTOPPED) |
---|
377 | fp->p_flags |= PREPORTED; |
---|
378 | } while ((fp = fp->p_friends) != pp); |
---|
379 | while (fp->p_procid != fp->p_jobid) |
---|
380 | fp = fp->p_friends; |
---|
381 | if (jobflags & PSTOPPED) { |
---|
382 | if (pcurrent && pcurrent != fp) |
---|
383 | pprevious = pcurrent; |
---|
384 | pcurrent = fp; |
---|
385 | } |
---|
386 | else |
---|
387 | pclrcurr(fp); |
---|
388 | if (jobflags & PFOREGND) { |
---|
389 | if (!(jobflags & (PSIGNALED | PSTOPPED | PPTIME) || |
---|
390 | #ifdef IIASA |
---|
391 | jobflags & PAEXITED || |
---|
392 | #endif /* IIASA */ |
---|
393 | !eq(dcwd->di_name, fp->p_cwd->di_name))) { |
---|
394 | /* PWP: print a newline after ^C */ |
---|
395 | if (jobflags & PINTERRUPTED) { |
---|
396 | #ifdef SHORT_STRINGS |
---|
397 | xputchar('\r' | QUOTE), xputchar('\n'); |
---|
398 | #else /* !SHORT_STRINGS */ |
---|
399 | xprintf("\215\n"); /* \215 is a quoted ^M */ |
---|
400 | #endif /* !SHORT_STRINGS */ |
---|
401 | } |
---|
402 | #ifdef notdef |
---|
403 | else if ((jobflags & (PTIME|PSTOPPED)) == PTIME) |
---|
404 | ptprint(fp); |
---|
405 | #endif |
---|
406 | } |
---|
407 | } |
---|
408 | else { |
---|
409 | if (jobflags & PNOTIFY || adrof(STRnotify)) { |
---|
410 | #ifdef SHORT_STRINGS |
---|
411 | xputchar('\r' | QUOTE), xputchar('\n'); |
---|
412 | #else /* !SHORT_STRINGS */ |
---|
413 | xprintf("\215\n"); /* \215 is a quoted ^M */ |
---|
414 | #endif /* !SHORT_STRINGS */ |
---|
415 | (void) pprint(pp, NUMBER | NAME | REASON); |
---|
416 | if ((jobflags & PSTOPPED) == 0) |
---|
417 | pflush(pp); |
---|
418 | { |
---|
419 | extern Char GettingInput; |
---|
420 | |
---|
421 | if (GettingInput) { |
---|
422 | errno = 0; |
---|
423 | (void) Rawmode(); |
---|
424 | #ifdef notdef |
---|
425 | /* |
---|
426 | * don't really want to do that, because it |
---|
427 | * will erase our message in case of multi-line |
---|
428 | * input |
---|
429 | */ |
---|
430 | ClearLines(); |
---|
431 | #endif |
---|
432 | ClearDisp(); |
---|
433 | Refresh(); |
---|
434 | } |
---|
435 | } |
---|
436 | } |
---|
437 | else { |
---|
438 | fp->p_flags |= PNEEDNOTE; |
---|
439 | neednote++; |
---|
440 | } |
---|
441 | } |
---|
442 | } |
---|
443 | #if defined(BSDJOBS) || defined(HAVEwait3) |
---|
444 | goto loop; |
---|
445 | #endif /* BSDJOBS || HAVEwait3 */ |
---|
446 | } |
---|
447 | |
---|
448 | void |
---|
449 | pnote() |
---|
450 | { |
---|
451 | register struct process *pp; |
---|
452 | int flags; |
---|
453 | #ifdef BSDSIGS |
---|
454 | sigmask_t omask; |
---|
455 | #endif /* BSDSIGS */ |
---|
456 | |
---|
457 | neednote = 0; |
---|
458 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { |
---|
459 | if (pp->p_flags & PNEEDNOTE) { |
---|
460 | #ifdef BSDSIGS |
---|
461 | omask = sigblock(sigmask(SIGCHLD)); |
---|
462 | #else /* !BSDSIGS */ |
---|
463 | (void) sighold(SIGCHLD); |
---|
464 | #endif /* !BSDSIGS */ |
---|
465 | pp->p_flags &= ~PNEEDNOTE; |
---|
466 | flags = pprint(pp, NUMBER | NAME | REASON); |
---|
467 | if ((flags & (PRUNNING | PSTOPPED)) == 0) |
---|
468 | pflush(pp); |
---|
469 | #ifdef BSDSIGS |
---|
470 | (void) sigsetmask(omask); |
---|
471 | #else /* !BSDSIGS */ |
---|
472 | (void) sigrelse(SIGCHLD); |
---|
473 | #endif /* !BSDSIGS */ |
---|
474 | } |
---|
475 | } |
---|
476 | } |
---|
477 | |
---|
478 | /* |
---|
479 | * pwait - wait for current job to terminate, maintaining integrity |
---|
480 | * of current and previous job indicators. |
---|
481 | */ |
---|
482 | void |
---|
483 | pwait() |
---|
484 | { |
---|
485 | register struct process *fp, *pp; |
---|
486 | #ifdef BSDSIGS |
---|
487 | sigmask_t omask; |
---|
488 | #endif /* BSDSIGS */ |
---|
489 | |
---|
490 | /* |
---|
491 | * Here's where dead procs get flushed. |
---|
492 | */ |
---|
493 | #ifdef BSDSIGS |
---|
494 | omask = sigblock(sigmask(SIGCHLD)); |
---|
495 | #else /* !BSDSIGS */ |
---|
496 | (void) sighold(SIGCHLD); |
---|
497 | #endif /* !BSDSIGS */ |
---|
498 | for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) |
---|
499 | if (pp->p_procid == 0) { |
---|
500 | fp->p_next = pp->p_next; |
---|
501 | xfree((ptr_t) pp->p_command); |
---|
502 | if (pp->p_cwd && --pp->p_cwd->di_count == 0) |
---|
503 | if (pp->p_cwd->di_next == 0) |
---|
504 | dfree(pp->p_cwd); |
---|
505 | xfree((ptr_t) pp); |
---|
506 | pp = fp; |
---|
507 | } |
---|
508 | #ifdef BSDSIGS |
---|
509 | (void) sigsetmask(omask); |
---|
510 | #else /* !BSDSIGS */ |
---|
511 | (void) sigrelse(SIGCHLD); |
---|
512 | # ifdef notdef |
---|
513 | if (setintr) |
---|
514 | sigignore(SIGINT); |
---|
515 | # endif |
---|
516 | #endif /* !BSDSIGS */ |
---|
517 | pjwait(pcurrjob); |
---|
518 | } |
---|
519 | |
---|
520 | |
---|
521 | /* |
---|
522 | * pjwait - wait for a job to finish or become stopped |
---|
523 | * It is assumed to be in the foreground state (PFOREGND) |
---|
524 | */ |
---|
525 | void |
---|
526 | pjwait(pp) |
---|
527 | register struct process *pp; |
---|
528 | { |
---|
529 | register struct process *fp; |
---|
530 | int jobflags, reason; |
---|
531 | #ifdef BSDSIGS |
---|
532 | sigmask_t omask; |
---|
533 | #endif /* BSDSIGS */ |
---|
534 | #ifdef UNRELSIGS |
---|
535 | sigret_t (*inthandler)(); |
---|
536 | #endif /* UNRELSIGS */ |
---|
537 | while (pp->p_procid != pp->p_jobid) |
---|
538 | pp = pp->p_friends; |
---|
539 | fp = pp; |
---|
540 | |
---|
541 | do { |
---|
542 | if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) |
---|
543 | xprintf("BUG: waiting for background job!\n"); |
---|
544 | } while ((fp = fp->p_friends) != pp); |
---|
545 | /* |
---|
546 | * Now keep pausing as long as we are not interrupted (SIGINT), and the |
---|
547 | * target process, or any of its friends, are running |
---|
548 | */ |
---|
549 | fp = pp; |
---|
550 | #ifdef BSDSIGS |
---|
551 | omask = sigblock(sigmask(SIGCHLD)); |
---|
552 | #endif /* BSDSIGS */ |
---|
553 | #ifdef UNRELSIGS |
---|
554 | if (setintr) |
---|
555 | inthandler = signal(SIGINT, SIG_IGN); |
---|
556 | #endif /* UNRELSIGS */ |
---|
557 | for (;;) { |
---|
558 | #ifndef BSDSIGS |
---|
559 | (void) sighold(SIGCHLD); |
---|
560 | #endif /* !BSDSIGS */ |
---|
561 | jobflags = 0; |
---|
562 | do |
---|
563 | jobflags |= fp->p_flags; |
---|
564 | while ((fp = (fp->p_friends)) != pp); |
---|
565 | if ((jobflags & PRUNNING) == 0) |
---|
566 | break; |
---|
567 | #ifdef JOBDEBUG |
---|
568 | xprintf("starting to sigpause for SIGCHLD on %d\n", fp->p_procid); |
---|
569 | #endif /* JOBDEBUG */ |
---|
570 | #ifdef BSDSIGS |
---|
571 | /* sigpause(sigblock((sigmask_t) 0) &~ sigmask(SIGCHLD)); */ |
---|
572 | (void) sigpause(omask & ~sigmask(SIGCHLD)); |
---|
573 | #else /* !BSDSIGS */ |
---|
574 | (void) sigpause(SIGCHLD); |
---|
575 | #endif /* !BSDSIGS */ |
---|
576 | } |
---|
577 | #ifdef BSDSIGS |
---|
578 | (void) sigsetmask(omask); |
---|
579 | #else /* !BSDSIGS */ |
---|
580 | (void) sigrelse(SIGCHLD); |
---|
581 | #endif /* !BSDSIGS */ |
---|
582 | #ifdef UNRELSIGS |
---|
583 | if (setintr) |
---|
584 | (void) signal(SIGINT, inthandler); |
---|
585 | #endif /* UNRELSIGS */ |
---|
586 | #ifdef BSDJOBS |
---|
587 | if (tpgrp > 0) /* get tty back */ |
---|
588 | (void) tcsetpgrp(FSHTTY, tpgrp); |
---|
589 | #endif /* BSDJOBS */ |
---|
590 | if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || |
---|
591 | !eq(dcwd->di_name, fp->p_cwd->di_name)) { |
---|
592 | if (jobflags & PSTOPPED) { |
---|
593 | xputchar('\n'); |
---|
594 | if (adrof(STRlistjobs)) { |
---|
595 | Char *jobcommand[3]; |
---|
596 | |
---|
597 | jobcommand[0] = STRjobs; |
---|
598 | if (eq(value(STRlistjobs), STRlong)) |
---|
599 | jobcommand[1] = STRml; |
---|
600 | else |
---|
601 | jobcommand[1] = NULL; |
---|
602 | jobcommand[2] = NULL; |
---|
603 | |
---|
604 | dojobs(jobcommand, NULL); |
---|
605 | (void) pprint(pp, SHELLDIR); |
---|
606 | } |
---|
607 | else |
---|
608 | (void) pprint(pp, AREASON | SHELLDIR); |
---|
609 | } |
---|
610 | else |
---|
611 | (void) pprint(pp, AREASON | SHELLDIR); |
---|
612 | } |
---|
613 | if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && |
---|
614 | (!gointr || !eq(gointr, STRminus))) { |
---|
615 | if ((jobflags & PSTOPPED) == 0) |
---|
616 | pflush(pp); |
---|
617 | pintr1(0); |
---|
618 | /* NOTREACHED */ |
---|
619 | } |
---|
620 | reason = 0; |
---|
621 | fp = pp; |
---|
622 | do { |
---|
623 | if (fp->p_reason) |
---|
624 | reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? |
---|
625 | fp->p_reason | META : fp->p_reason; |
---|
626 | } while ((fp = fp->p_friends) != pp); |
---|
627 | /* |
---|
628 | * Don't report on backquoted jobs, cause it will mess up |
---|
629 | * their output. |
---|
630 | */ |
---|
631 | if ((reason != 0) && (adrof(STRprintexitvalue)) && |
---|
632 | (pp->p_flags & PBACKQ) == 0) |
---|
633 | xprintf("Exit %d\n", reason); |
---|
634 | set(STRstatus, putn(reason)); |
---|
635 | if (reason && exiterr) |
---|
636 | exitstat(); |
---|
637 | pflush(pp); |
---|
638 | } |
---|
639 | |
---|
640 | /* |
---|
641 | * dowait - wait for all processes to finish |
---|
642 | */ |
---|
643 | |
---|
644 | /*ARGSUSED*/ |
---|
645 | void |
---|
646 | dowait(v, c) |
---|
647 | Char **v; |
---|
648 | struct command *c; |
---|
649 | { |
---|
650 | register struct process *pp; |
---|
651 | #ifdef BSDSIGS |
---|
652 | sigmask_t omask; |
---|
653 | #endif /* BSDSIGS */ |
---|
654 | |
---|
655 | pjobs++; |
---|
656 | #ifdef BSDSIGS |
---|
657 | omask = sigblock(sigmask(SIGCHLD)); |
---|
658 | loop: |
---|
659 | #else /* !BSDSIGS */ |
---|
660 | if (setintr) |
---|
661 | (void) sigrelse(SIGINT); |
---|
662 | loop: |
---|
663 | (void) sighold(SIGCHLD); |
---|
664 | #endif /* !BSDSIGS */ |
---|
665 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
---|
666 | if (pp->p_procid && /* pp->p_procid == pp->p_jobid && */ |
---|
667 | pp->p_flags & PRUNNING) { |
---|
668 | #ifdef BSDSIGS |
---|
669 | (void) sigpause((sigmask_t) 0); |
---|
670 | #else /* !BSDSIGS */ |
---|
671 | (void) sigpause(SIGCHLD); |
---|
672 | #endif /* !BSDSIGS */ |
---|
673 | goto loop; |
---|
674 | } |
---|
675 | #ifdef BSDSIGS |
---|
676 | (void) sigsetmask(omask); |
---|
677 | #else /* !BSDSIGS */ |
---|
678 | (void) sigrelse(SIGCHLD); |
---|
679 | #endif /* !BSDSIGS */ |
---|
680 | pjobs = 0; |
---|
681 | } |
---|
682 | |
---|
683 | /* |
---|
684 | * pflushall - flush all jobs from list (e.g. at fork()) |
---|
685 | */ |
---|
686 | static void |
---|
687 | pflushall() |
---|
688 | { |
---|
689 | register struct process *pp; |
---|
690 | |
---|
691 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) |
---|
692 | if (pp->p_procid) |
---|
693 | pflush(pp); |
---|
694 | } |
---|
695 | |
---|
696 | /* |
---|
697 | * pflush - flag all process structures in the same job as the |
---|
698 | * the argument process for deletion. The actual free of the |
---|
699 | * space is not done here since pflush is called at interrupt level. |
---|
700 | */ |
---|
701 | static void |
---|
702 | pflush(pp) |
---|
703 | register struct process *pp; |
---|
704 | { |
---|
705 | register struct process *np; |
---|
706 | register int idx; |
---|
707 | |
---|
708 | if (pp->p_procid == 0) { |
---|
709 | xprintf("BUG: process flushed twice"); |
---|
710 | return; |
---|
711 | } |
---|
712 | while (pp->p_procid != pp->p_jobid) |
---|
713 | pp = pp->p_friends; |
---|
714 | pclrcurr(pp); |
---|
715 | if (pp == pcurrjob) |
---|
716 | pcurrjob = 0; |
---|
717 | idx = pp->p_index; |
---|
718 | np = pp; |
---|
719 | do { |
---|
720 | np->p_index = np->p_procid = 0; |
---|
721 | np->p_flags &= ~PNEEDNOTE; |
---|
722 | } while ((np = np->p_friends) != pp); |
---|
723 | if (idx == pmaxindex) { |
---|
724 | for (np = proclist.p_next, idx = 0; np; np = np->p_next) |
---|
725 | if (np->p_index > idx) |
---|
726 | idx = np->p_index; |
---|
727 | pmaxindex = idx; |
---|
728 | } |
---|
729 | } |
---|
730 | |
---|
731 | /* |
---|
732 | * pclrcurr - make sure the given job is not the current or previous job; |
---|
733 | * pp MUST be the job leader |
---|
734 | */ |
---|
735 | static void |
---|
736 | pclrcurr(pp) |
---|
737 | register struct process *pp; |
---|
738 | { |
---|
739 | if (pp == pcurrent) |
---|
740 | if (pprevious != NULL) { |
---|
741 | pcurrent = pprevious; |
---|
742 | pprevious = pgetcurr(pp); |
---|
743 | } |
---|
744 | else { |
---|
745 | pcurrent = pgetcurr(pp); |
---|
746 | pprevious = pgetcurr(pp); |
---|
747 | } |
---|
748 | else if (pp == pprevious) |
---|
749 | pprevious = pgetcurr(pp); |
---|
750 | } |
---|
751 | |
---|
752 | /* +4 here is 1 for '\0', 1 ea for << >& >> */ |
---|
753 | static Char command[PMAXLEN + 4]; |
---|
754 | static int cmdlen; |
---|
755 | static Char *cmdp; |
---|
756 | |
---|
757 | /* |
---|
758 | * palloc - allocate a process structure and fill it up. |
---|
759 | * an important assumption is made that the process is running. |
---|
760 | */ |
---|
761 | void |
---|
762 | palloc(pid, t) |
---|
763 | int pid; |
---|
764 | register struct command *t; |
---|
765 | { |
---|
766 | register struct process *pp; |
---|
767 | int i; |
---|
768 | |
---|
769 | pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); |
---|
770 | pp->p_procid = pid; |
---|
771 | pp->p_flags = ((t->t_dflg & F_AMPERSAND) ? 0 : PFOREGND) | PRUNNING; |
---|
772 | if (t->t_dflg & F_TIME) |
---|
773 | pp->p_flags |= PPTIME; |
---|
774 | if (t->t_dflg & F_BACKQ) |
---|
775 | pp->p_flags |= PBACKQ; |
---|
776 | cmdp = command; |
---|
777 | cmdlen = 0; |
---|
778 | padd(t); |
---|
779 | *cmdp++ = 0; |
---|
780 | if (t->t_dflg & F_PIPEOUT) { |
---|
781 | pp->p_flags |= PPOU; |
---|
782 | if (t->t_dflg & F_STDERR) |
---|
783 | pp->p_flags |= PDIAG; |
---|
784 | } |
---|
785 | pp->p_command = Strsave(command); |
---|
786 | if (pcurrjob) { |
---|
787 | struct process *fp; |
---|
788 | |
---|
789 | /* careful here with interrupt level */ |
---|
790 | pp->p_cwd = 0; |
---|
791 | pp->p_index = pcurrjob->p_index; |
---|
792 | pp->p_friends = pcurrjob; |
---|
793 | pp->p_jobid = pcurrjob->p_procid; |
---|
794 | for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) |
---|
795 | continue; |
---|
796 | fp->p_friends = pp; |
---|
797 | } |
---|
798 | else { |
---|
799 | pcurrjob = pp; |
---|
800 | pp->p_jobid = pid; |
---|
801 | pp->p_friends = pp; |
---|
802 | pp->p_cwd = dcwd; |
---|
803 | dcwd->di_count++; |
---|
804 | if (pmaxindex < BIGINDEX) |
---|
805 | pp->p_index = ++pmaxindex; |
---|
806 | else { |
---|
807 | struct process *np; |
---|
808 | |
---|
809 | for (i = 1;; i++) { |
---|
810 | for (np = proclist.p_next; np; np = np->p_next) |
---|
811 | if (np->p_index == i) |
---|
812 | goto tryagain; |
---|
813 | pp->p_index = i; |
---|
814 | if (i > pmaxindex) |
---|
815 | pmaxindex = i; |
---|
816 | break; |
---|
817 | tryagain:; |
---|
818 | } |
---|
819 | } |
---|
820 | if (pcurrent == NULL) |
---|
821 | pcurrent = pp; |
---|
822 | else if (pprevious == NULL) |
---|
823 | pprevious = pp; |
---|
824 | } |
---|
825 | pp->p_next = proclist.p_next; |
---|
826 | proclist.p_next = pp; |
---|
827 | #ifdef BSDTIMES |
---|
828 | (void) gettimeofday(&pp->p_btime, NULL); |
---|
829 | #else /* !BSDTIMES */ |
---|
830 | # ifdef _SEQUENT_ |
---|
831 | (void) get_process_stats(&pp->p_btime, PS_SELF, NULL, NULL); |
---|
832 | # else /* !_SEQUENT_ */ |
---|
833 | { |
---|
834 | struct tms tmptimes; |
---|
835 | |
---|
836 | # ifndef COHERENT |
---|
837 | pp->p_btime = times(&tmptimes); |
---|
838 | # else /* !COHERENT */ |
---|
839 | pp->p_btime = HZ * time(NULL); |
---|
840 | times(&tmptimes); |
---|
841 | # endif /* !COHERENT */ |
---|
842 | } |
---|
843 | # endif /* !_SEQUENT_ */ |
---|
844 | #endif /* !BSDTIMES */ |
---|
845 | } |
---|
846 | |
---|
847 | static void |
---|
848 | padd(t) |
---|
849 | register struct command *t; |
---|
850 | { |
---|
851 | Char **argp; |
---|
852 | |
---|
853 | if (t == 0) |
---|
854 | return; |
---|
855 | switch (t->t_dtyp) { |
---|
856 | |
---|
857 | case NODE_PAREN: |
---|
858 | pads(STRLparensp); |
---|
859 | padd(t->t_dspr); |
---|
860 | pads(STRspRparen); |
---|
861 | break; |
---|
862 | |
---|
863 | case NODE_COMMAND: |
---|
864 | for (argp = t->t_dcom; *argp; argp++) { |
---|
865 | pads(*argp); |
---|
866 | if (argp[1]) |
---|
867 | pads(STRspace); |
---|
868 | } |
---|
869 | break; |
---|
870 | |
---|
871 | case NODE_OR: |
---|
872 | case NODE_AND: |
---|
873 | case NODE_PIPE: |
---|
874 | case NODE_LIST: |
---|
875 | padd(t->t_dcar); |
---|
876 | switch (t->t_dtyp) { |
---|
877 | case NODE_OR: |
---|
878 | pads(STRspor2sp); |
---|
879 | break; |
---|
880 | case NODE_AND: |
---|
881 | pads(STRspand2sp); |
---|
882 | break; |
---|
883 | case NODE_PIPE: |
---|
884 | pads(STRsporsp); |
---|
885 | break; |
---|
886 | case NODE_LIST: |
---|
887 | pads(STRsemisp); |
---|
888 | break; |
---|
889 | default: |
---|
890 | break; |
---|
891 | } |
---|
892 | padd(t->t_dcdr); |
---|
893 | return; |
---|
894 | |
---|
895 | default: |
---|
896 | break; |
---|
897 | } |
---|
898 | if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { |
---|
899 | pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); |
---|
900 | pads(t->t_dlef); |
---|
901 | } |
---|
902 | if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { |
---|
903 | pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); |
---|
904 | if (t->t_dflg & F_STDERR) |
---|
905 | pads(STRand); |
---|
906 | pads(STRspace); |
---|
907 | pads(t->t_drit); |
---|
908 | } |
---|
909 | } |
---|
910 | |
---|
911 | static void |
---|
912 | pads(cp) |
---|
913 | Char *cp; |
---|
914 | { |
---|
915 | register int i; |
---|
916 | |
---|
917 | /* |
---|
918 | * Avoid the Quoted Space alias hack! Reported by: |
---|
919 | * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) |
---|
920 | */ |
---|
921 | if (cp[0] == STRQNULL[0]) |
---|
922 | cp++; |
---|
923 | |
---|
924 | i = Strlen(cp); |
---|
925 | |
---|
926 | if (cmdlen >= PMAXLEN) |
---|
927 | return; |
---|
928 | if (cmdlen + i >= PMAXLEN) { |
---|
929 | (void) Strcpy(cmdp, STRsp3dots); |
---|
930 | cmdlen = PMAXLEN; |
---|
931 | cmdp += 4; |
---|
932 | return; |
---|
933 | } |
---|
934 | (void) Strcpy(cmdp, cp); |
---|
935 | cmdp += i; |
---|
936 | cmdlen += i; |
---|
937 | } |
---|
938 | |
---|
939 | /* |
---|
940 | * psavejob - temporarily save the current job on a one level stack |
---|
941 | * so another job can be created. Used for { } in exp6 |
---|
942 | * and `` in globbing. |
---|
943 | */ |
---|
944 | void |
---|
945 | psavejob() |
---|
946 | { |
---|
947 | pholdjob = pcurrjob; |
---|
948 | pcurrjob = NULL; |
---|
949 | } |
---|
950 | |
---|
951 | /* |
---|
952 | * prestjob - opposite of psavejob. This may be missed if we are interrupted |
---|
953 | * somewhere, but pendjob cleans up anyway. |
---|
954 | */ |
---|
955 | void |
---|
956 | prestjob() |
---|
957 | { |
---|
958 | pcurrjob = pholdjob; |
---|
959 | pholdjob = NULL; |
---|
960 | } |
---|
961 | |
---|
962 | /* |
---|
963 | * pendjob - indicate that a job (set of commands) has been completed |
---|
964 | * or is about to begin. |
---|
965 | */ |
---|
966 | void |
---|
967 | pendjob() |
---|
968 | { |
---|
969 | register struct process *pp, *tp; |
---|
970 | |
---|
971 | if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { |
---|
972 | pp = pcurrjob; |
---|
973 | while (pp->p_procid != pp->p_jobid) |
---|
974 | pp = pp->p_friends; |
---|
975 | xprintf("[%d]", pp->p_index); |
---|
976 | tp = pp; |
---|
977 | do { |
---|
978 | xprintf(" %d", pp->p_procid); |
---|
979 | pp = pp->p_friends; |
---|
980 | } while (pp != tp); |
---|
981 | xputchar('\n'); |
---|
982 | } |
---|
983 | pholdjob = pcurrjob = 0; |
---|
984 | } |
---|
985 | |
---|
986 | /* |
---|
987 | * pprint - print a job |
---|
988 | */ |
---|
989 | |
---|
990 | /* |
---|
991 | * Hacks have been added for SVR4 to deal with pipe's being spawned in |
---|
992 | * reverse order |
---|
993 | * |
---|
994 | * David Dawes (dawes@physics.su.oz.au) Oct 1991 |
---|
995 | */ |
---|
996 | |
---|
997 | static int |
---|
998 | pprint(pp, flag) |
---|
999 | register struct process *pp; |
---|
1000 | bool flag; |
---|
1001 | { |
---|
1002 | register status, reason; |
---|
1003 | struct process *tp; |
---|
1004 | extern char *linp, linbuf[]; |
---|
1005 | int jobflags, pstatus, pcond; |
---|
1006 | char *format; |
---|
1007 | |
---|
1008 | #ifdef BACKPIPE |
---|
1009 | struct process *pipehead = NULL, *pipetail = NULL, *pmarker = NULL; |
---|
1010 | int inpipe = 0; |
---|
1011 | #endif /* BACKPIPE */ |
---|
1012 | |
---|
1013 | while (pp->p_procid != pp->p_jobid) |
---|
1014 | pp = pp->p_friends; |
---|
1015 | if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { |
---|
1016 | pp->p_flags &= ~PPTIME; |
---|
1017 | pp->p_flags |= PTIME; |
---|
1018 | } |
---|
1019 | tp = pp; |
---|
1020 | status = reason = -1; |
---|
1021 | jobflags = 0; |
---|
1022 | do { |
---|
1023 | #ifdef BACKPIPE |
---|
1024 | /* |
---|
1025 | * The pipeline is reversed, so locate the real head of the pipeline |
---|
1026 | * if pp is at the tail of a pipe (and not already in a pipeline) |
---|
1027 | */ |
---|
1028 | if ((pp->p_friends->p_flags & PPOU) && !inpipe && (flag & NAME)) { |
---|
1029 | inpipe = 1; |
---|
1030 | pipetail = pp; |
---|
1031 | do |
---|
1032 | pp = pp->p_friends; |
---|
1033 | while (pp->p_friends->p_flags & PPOU); |
---|
1034 | pipehead = pp; |
---|
1035 | pmarker = pp; |
---|
1036 | /* |
---|
1037 | * pmarker is used to hold the place of the proc being processed, so |
---|
1038 | * we can search for the next one downstream later. |
---|
1039 | */ |
---|
1040 | } |
---|
1041 | pcond = (tp != pp || (inpipe && tp == pp)); |
---|
1042 | #else /* !BACKPIPE */ |
---|
1043 | pcond = (tp != pp); |
---|
1044 | #endif /* BACKPIPE */ |
---|
1045 | |
---|
1046 | jobflags |= pp->p_flags; |
---|
1047 | pstatus = pp->p_flags & PALLSTATES; |
---|
1048 | if (pcond && linp != linbuf && !(flag & FANCY) && |
---|
1049 | ((pstatus == status && pp->p_reason == reason) || |
---|
1050 | !(flag & REASON))) |
---|
1051 | xputchar(' '); |
---|
1052 | else { |
---|
1053 | if (pcond && linp != linbuf) |
---|
1054 | xputchar('\n'); |
---|
1055 | if (flag & NUMBER) { |
---|
1056 | #ifdef BACKPIPE |
---|
1057 | pcond = ((pp == tp && !inpipe) || |
---|
1058 | (inpipe && pipetail == tp && pp == pipehead)); |
---|
1059 | #else /* BACKPIPE */ |
---|
1060 | pcond = (pp == tp); |
---|
1061 | #endif /* BACKPIPE */ |
---|
1062 | if (pcond) |
---|
1063 | xprintf("[%d]%s %c ", pp->p_index, |
---|
1064 | pp->p_index < 10 ? " " : "", |
---|
1065 | pp == pcurrent ? '+' : |
---|
1066 | (pp == pprevious ? '-' : ' ')); |
---|
1067 | else |
---|
1068 | xprintf(" "); |
---|
1069 | } |
---|
1070 | if (flag & FANCY) { |
---|
1071 | #ifdef TCF |
---|
1072 | extern char *sitename(); |
---|
1073 | |
---|
1074 | #endif /* TCF */ |
---|
1075 | xprintf("%5d ", pp->p_procid); |
---|
1076 | #ifdef TCF |
---|
1077 | xprintf("%11s ", sitename(pp->p_procid)); |
---|
1078 | #endif /* TCF */ |
---|
1079 | } |
---|
1080 | if (flag & (REASON | AREASON)) { |
---|
1081 | if (flag & NAME) |
---|
1082 | #ifdef SUSPENDED |
---|
1083 | format = "%-23s"; |
---|
1084 | #else /* !SUSPENDED */ |
---|
1085 | format = "%-21s"; |
---|
1086 | #endif /* !SUSPENDED */ |
---|
1087 | else |
---|
1088 | format = "%s"; |
---|
1089 | if (pstatus == status) |
---|
1090 | if (pp->p_reason == reason) { |
---|
1091 | xprintf(format, ""); |
---|
1092 | goto prcomd; |
---|
1093 | } |
---|
1094 | else |
---|
1095 | reason = pp->p_reason; |
---|
1096 | else { |
---|
1097 | status = pstatus; |
---|
1098 | reason = pp->p_reason; |
---|
1099 | } |
---|
1100 | switch (status) { |
---|
1101 | |
---|
1102 | case PRUNNING: |
---|
1103 | xprintf(format, "Running "); |
---|
1104 | break; |
---|
1105 | |
---|
1106 | case PINTERRUPTED: |
---|
1107 | case PSTOPPED: |
---|
1108 | case PSIGNALED: |
---|
1109 | /* |
---|
1110 | * tell what happened to the background job |
---|
1111 | * From: Michael Schroeder |
---|
1112 | * <mlschroe@immd4.informatik.uni-erlangen.de> |
---|
1113 | */ |
---|
1114 | if ((flag & REASON) |
---|
1115 | || ((flag & AREASON) |
---|
1116 | && reason != SIGINT |
---|
1117 | && (reason != SIGPIPE |
---|
1118 | || (pp->p_flags & PPOU) == 0))) |
---|
1119 | xprintf(format, mesg[pp->p_reason & ASCII].pname); |
---|
1120 | else |
---|
1121 | reason = -1; |
---|
1122 | break; |
---|
1123 | |
---|
1124 | case PNEXITED: |
---|
1125 | case PAEXITED: |
---|
1126 | if (flag & REASON) |
---|
1127 | if (pp->p_reason) |
---|
1128 | #ifdef SUSPENDED |
---|
1129 | xprintf("Exit %-18d", pp->p_reason); |
---|
1130 | #else /* SUSPENDED */ |
---|
1131 | xprintf("Exit %-16d", pp->p_reason); |
---|
1132 | #endif /* SUSPENDED */ |
---|
1133 | else |
---|
1134 | xprintf(format, "Done"); |
---|
1135 | break; |
---|
1136 | |
---|
1137 | default: |
---|
1138 | xprintf("BUG: status=%-9o", status); |
---|
1139 | } |
---|
1140 | } |
---|
1141 | } |
---|
1142 | prcomd: |
---|
1143 | if (flag & NAME) { |
---|
1144 | xprintf("%S", pp->p_command); |
---|
1145 | if (pp->p_flags & PPOU) |
---|
1146 | xprintf(" |"); |
---|
1147 | if (pp->p_flags & PDIAG) |
---|
1148 | xprintf("&"); |
---|
1149 | } |
---|
1150 | if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) |
---|
1151 | xprintf(" (core dumped)"); |
---|
1152 | if (tp == pp->p_friends) { |
---|
1153 | if (flag & AMPERSAND) |
---|
1154 | xprintf(" &"); |
---|
1155 | if (flag & JOBDIR && |
---|
1156 | !eq(tp->p_cwd->di_name, dcwd->di_name)) { |
---|
1157 | xprintf(" (wd: "); |
---|
1158 | dtildepr(value(STRhome), tp->p_cwd->di_name); |
---|
1159 | xprintf(")"); |
---|
1160 | } |
---|
1161 | } |
---|
1162 | if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { |
---|
1163 | if (linp != linbuf) |
---|
1164 | xprintf("\n\t"); |
---|
1165 | #if defined(BSDTIMES) || defined(_SEQUENT_) |
---|
1166 | prusage(&zru, &pp->p_rusage, &pp->p_etime, |
---|
1167 | &pp->p_btime); |
---|
1168 | #else /* !BSDTIMES && !SEQUENT */ |
---|
1169 | lru.tms_utime = pp->p_utime; |
---|
1170 | lru.tms_stime = pp->p_stime; |
---|
1171 | lru.tms_cutime = 0; |
---|
1172 | lru.tms_cstime = 0; |
---|
1173 | prusage(&zru, &lru, pp->p_etime, |
---|
1174 | pp->p_btime); |
---|
1175 | #endif /* !BSDTIMES && !SEQUENT */ |
---|
1176 | |
---|
1177 | } |
---|
1178 | #ifdef BACKPIPE |
---|
1179 | pcond = ((tp == pp->p_friends && !inpipe) || |
---|
1180 | (inpipe && pipehead->p_friends == tp && pp == pipetail)); |
---|
1181 | #else /* !BACKPIPE */ |
---|
1182 | pcond = (tp == pp->p_friends); |
---|
1183 | #endif /* BACKPIPE */ |
---|
1184 | if (pcond) { |
---|
1185 | if (linp != linbuf) |
---|
1186 | xputchar('\n'); |
---|
1187 | if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { |
---|
1188 | xprintf("(wd now: "); |
---|
1189 | dtildepr(value(STRhome), dcwd->di_name); |
---|
1190 | xprintf(")\n"); |
---|
1191 | } |
---|
1192 | } |
---|
1193 | #ifdef BACKPIPE |
---|
1194 | if (inpipe) { |
---|
1195 | /* |
---|
1196 | * if pmaker == pipetail, we are finished that pipeline, and |
---|
1197 | * can now skip to past the head |
---|
1198 | */ |
---|
1199 | if (pmarker == pipetail) { |
---|
1200 | inpipe = 0; |
---|
1201 | pp = pipehead; |
---|
1202 | } |
---|
1203 | else { |
---|
1204 | /* |
---|
1205 | * set pp to one before the one we want next, so the while below |
---|
1206 | * increments to the correct spot. |
---|
1207 | */ |
---|
1208 | do |
---|
1209 | pp = pp->p_friends; |
---|
1210 | while (pp->p_friends->p_friends != pmarker); |
---|
1211 | pmarker = pp->p_friends; |
---|
1212 | } |
---|
1213 | } |
---|
1214 | pcond = ((pp = pp->p_friends) != tp || inpipe); |
---|
1215 | #else /* !BACKPIPE */ |
---|
1216 | pcond = ((pp = pp->p_friends) != tp); |
---|
1217 | #endif /* BACKPIPE */ |
---|
1218 | } while (pcond); |
---|
1219 | |
---|
1220 | if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { |
---|
1221 | if (jobflags & NUMBER) |
---|
1222 | xprintf(" "); |
---|
1223 | ptprint(tp); |
---|
1224 | } |
---|
1225 | return (jobflags); |
---|
1226 | } |
---|
1227 | |
---|
1228 | /* |
---|
1229 | * All 4.3 BSD derived implementations are buggy and I've had enough. |
---|
1230 | * The following implementation produces similar code and works in all |
---|
1231 | * cases. The 4.3BSD one works only for <, >, != |
---|
1232 | */ |
---|
1233 | # undef timercmp |
---|
1234 | # define timercmp(tvp, uvp, cmp) \ |
---|
1235 | (((tvp)->tv_sec == (uvp)->tv_sec) ? \ |
---|
1236 | ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ |
---|
1237 | ((tvp)->tv_sec cmp (uvp)->tv_sec)) |
---|
1238 | |
---|
1239 | static void |
---|
1240 | ptprint(tp) |
---|
1241 | register struct process *tp; |
---|
1242 | { |
---|
1243 | #ifdef BSDTIMES |
---|
1244 | struct timeval tetime, diff; |
---|
1245 | static struct timeval ztime; |
---|
1246 | struct rusage ru; |
---|
1247 | static struct rusage zru; |
---|
1248 | register struct process *pp = tp; |
---|
1249 | |
---|
1250 | ru = zru; |
---|
1251 | tetime = ztime; |
---|
1252 | do { |
---|
1253 | ruadd(&ru, &pp->p_rusage); |
---|
1254 | tvsub(&diff, &pp->p_etime, &pp->p_btime); |
---|
1255 | if (timercmp(&diff, &tetime, >)) |
---|
1256 | tetime = diff; |
---|
1257 | } while ((pp = pp->p_friends) != tp); |
---|
1258 | prusage(&zru, &ru, &tetime, &ztime); |
---|
1259 | #else /* !BSDTIMES */ |
---|
1260 | # ifdef _SEQUENT_ |
---|
1261 | timeval_t tetime, diff; |
---|
1262 | static timeval_t ztime; |
---|
1263 | struct process_stats ru; |
---|
1264 | static struct process_stats zru; |
---|
1265 | register struct process *pp = tp; |
---|
1266 | |
---|
1267 | ru = zru; |
---|
1268 | tetime = ztime; |
---|
1269 | do { |
---|
1270 | ruadd(&ru, &pp->p_rusage); |
---|
1271 | tvsub(&diff, &pp->p_etime, &pp->p_btime); |
---|
1272 | if (timercmp(&diff, &tetime, >)) |
---|
1273 | tetime = diff; |
---|
1274 | } while ((pp = pp->p_friends) != tp); |
---|
1275 | prusage(&zru, &ru, &tetime, &ztime); |
---|
1276 | # else /* !_SEQUENT_ */ |
---|
1277 | # ifndef POSIX |
---|
1278 | static time_t ztime = 0; |
---|
1279 | static time_t zu_time = 0; |
---|
1280 | static time_t zs_time = 0; |
---|
1281 | time_t tetime, diff; |
---|
1282 | time_t u_time, s_time; |
---|
1283 | |
---|
1284 | # else /* POSIX */ |
---|
1285 | static clock_t ztime = 0; |
---|
1286 | static clock_t zu_time = 0; |
---|
1287 | static clock_t zs_time = 0; |
---|
1288 | clock_t tetime, diff; |
---|
1289 | clock_t u_time, s_time; |
---|
1290 | |
---|
1291 | # endif /* POSIX */ |
---|
1292 | struct tms zts, rts; |
---|
1293 | register struct process *pp = tp; |
---|
1294 | |
---|
1295 | u_time = zu_time; |
---|
1296 | s_time = zs_time; |
---|
1297 | tetime = ztime; |
---|
1298 | do { |
---|
1299 | u_time += pp->p_utime; |
---|
1300 | s_time += pp->p_stime; |
---|
1301 | diff = pp->p_etime - pp->p_btime; |
---|
1302 | if (diff > tetime) |
---|
1303 | tetime = diff; |
---|
1304 | } while ((pp = pp->p_friends) != tp); |
---|
1305 | zts.tms_utime = zu_time; |
---|
1306 | zts.tms_stime = zs_time; |
---|
1307 | zts.tms_cutime = 0; |
---|
1308 | zts.tms_cstime = 0; |
---|
1309 | rts.tms_utime = u_time; |
---|
1310 | rts.tms_stime = s_time; |
---|
1311 | rts.tms_cutime = 0; |
---|
1312 | rts.tms_cstime = 0; |
---|
1313 | prusage(&zts, &rts, tetime, ztime); |
---|
1314 | # endif /* !_SEQUENT_ */ |
---|
1315 | #endif /* !BSDTIMES */ |
---|
1316 | } |
---|
1317 | |
---|
1318 | /* |
---|
1319 | * dojobs - print all jobs |
---|
1320 | */ |
---|
1321 | /*ARGSUSED*/ |
---|
1322 | void |
---|
1323 | dojobs(v, c) |
---|
1324 | Char **v; |
---|
1325 | struct command *c; |
---|
1326 | { |
---|
1327 | register struct process *pp; |
---|
1328 | register int flag = NUMBER | NAME | REASON; |
---|
1329 | int i; |
---|
1330 | |
---|
1331 | if (chkstop) |
---|
1332 | chkstop = 2; |
---|
1333 | if (*++v) { |
---|
1334 | if (v[1] || !eq(*v, STRml)) |
---|
1335 | stderror(ERR_JOBS); |
---|
1336 | flag |= FANCY | JOBDIR; |
---|
1337 | } |
---|
1338 | for (i = 1; i <= pmaxindex; i++) |
---|
1339 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
---|
1340 | if (pp->p_index == i && pp->p_procid == pp->p_jobid) { |
---|
1341 | pp->p_flags &= ~PNEEDNOTE; |
---|
1342 | if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) |
---|
1343 | pflush(pp); |
---|
1344 | break; |
---|
1345 | } |
---|
1346 | } |
---|
1347 | |
---|
1348 | /* |
---|
1349 | * dofg - builtin - put the job into the foreground |
---|
1350 | */ |
---|
1351 | /*ARGSUSED*/ |
---|
1352 | void |
---|
1353 | dofg(v, c) |
---|
1354 | Char **v; |
---|
1355 | struct command *c; |
---|
1356 | { |
---|
1357 | register struct process *pp; |
---|
1358 | |
---|
1359 | okpcntl(); |
---|
1360 | ++v; |
---|
1361 | do { |
---|
1362 | pp = pfind(*v); |
---|
1363 | pstart(pp, 1); |
---|
1364 | #ifndef BSDSIGS |
---|
1365 | # ifdef notdef |
---|
1366 | if (setintr) |
---|
1367 | sigignore(SIGINT); |
---|
1368 | # endif |
---|
1369 | #endif /* !BSDSIGS */ |
---|
1370 | pjwait(pp); |
---|
1371 | } while (*v && *++v); |
---|
1372 | } |
---|
1373 | |
---|
1374 | /* |
---|
1375 | * %... - builtin - put the job into the foreground |
---|
1376 | */ |
---|
1377 | /*ARGSUSED*/ |
---|
1378 | void |
---|
1379 | dofg1(v, c) |
---|
1380 | Char **v; |
---|
1381 | struct command *c; |
---|
1382 | { |
---|
1383 | register struct process *pp; |
---|
1384 | |
---|
1385 | okpcntl(); |
---|
1386 | pp = pfind(v[0]); |
---|
1387 | pstart(pp, 1); |
---|
1388 | #ifndef BSDSIGS |
---|
1389 | # ifdef notdef |
---|
1390 | if (setintr) |
---|
1391 | sigignore(SIGINT); |
---|
1392 | # endif |
---|
1393 | #endif /* !BSDSIGS */ |
---|
1394 | pjwait(pp); |
---|
1395 | } |
---|
1396 | |
---|
1397 | /* |
---|
1398 | * dobg - builtin - put the job into the background |
---|
1399 | */ |
---|
1400 | /*ARGSUSED*/ |
---|
1401 | void |
---|
1402 | dobg(v, c) |
---|
1403 | Char **v; |
---|
1404 | struct command *c; |
---|
1405 | { |
---|
1406 | register struct process *pp; |
---|
1407 | |
---|
1408 | okpcntl(); |
---|
1409 | ++v; |
---|
1410 | do { |
---|
1411 | pp = pfind(*v); |
---|
1412 | pstart(pp, 0); |
---|
1413 | } while (*v && *++v); |
---|
1414 | } |
---|
1415 | |
---|
1416 | /* |
---|
1417 | * %... & - builtin - put the job into the background |
---|
1418 | */ |
---|
1419 | /*ARGSUSED*/ |
---|
1420 | void |
---|
1421 | dobg1(v, c) |
---|
1422 | Char **v; |
---|
1423 | struct command *c; |
---|
1424 | { |
---|
1425 | register struct process *pp; |
---|
1426 | |
---|
1427 | pp = pfind(v[0]); |
---|
1428 | pstart(pp, 0); |
---|
1429 | } |
---|
1430 | |
---|
1431 | /* |
---|
1432 | * dostop - builtin - stop the job |
---|
1433 | */ |
---|
1434 | /*ARGSUSED*/ |
---|
1435 | void |
---|
1436 | dostop(v, c) |
---|
1437 | Char **v; |
---|
1438 | struct command *c; |
---|
1439 | { |
---|
1440 | #ifdef BSDJOBS |
---|
1441 | pkill(++v, SIGSTOP); |
---|
1442 | #endif /* BSDJOBS */ |
---|
1443 | } |
---|
1444 | |
---|
1445 | /* |
---|
1446 | * dokill - builtin - superset of kill (1) |
---|
1447 | */ |
---|
1448 | /*ARGSUSED*/ |
---|
1449 | void |
---|
1450 | dokill(v, c) |
---|
1451 | Char **v; |
---|
1452 | struct command *c; |
---|
1453 | { |
---|
1454 | register int signum, len = 0; |
---|
1455 | register char *name; |
---|
1456 | extern int T_Cols; |
---|
1457 | |
---|
1458 | v++; |
---|
1459 | if (v[0] && v[0][0] == '-') { |
---|
1460 | if (v[0][1] == 'l') { |
---|
1461 | for (signum = 1; signum <= NSIG && signum < mesg_size; signum++) { |
---|
1462 | if ((name = mesg[signum].iname) != NULL) { |
---|
1463 | len += strlen(name) + 1; |
---|
1464 | if (len >= T_Cols - 1) { |
---|
1465 | xputchar('\n'); |
---|
1466 | len = strlen(name) + 1; |
---|
1467 | } |
---|
1468 | xprintf("%s ", name); |
---|
1469 | } |
---|
1470 | } |
---|
1471 | xputchar('\n'); |
---|
1472 | return; |
---|
1473 | } |
---|
1474 | if (Isdigit(v[0][1])) { |
---|
1475 | signum = atoi(short2str(v[0] + 1)); |
---|
1476 | if (signum < 0 || signum > NSIG) |
---|
1477 | stderror(ERR_NAME | ERR_BADSIG); |
---|
1478 | } |
---|
1479 | else { |
---|
1480 | for (signum = 1; signum <= NSIG && signum < mesg_size; signum++) |
---|
1481 | if (mesg[signum].iname && |
---|
1482 | eq(&v[0][1], str2short(mesg[signum].iname))) |
---|
1483 | goto gotsig; |
---|
1484 | setname(short2str(&v[0][1])); |
---|
1485 | stderror(ERR_NAME | ERR_UNKSIG); |
---|
1486 | } |
---|
1487 | gotsig: |
---|
1488 | v++; |
---|
1489 | } |
---|
1490 | else |
---|
1491 | signum = SIGTERM; |
---|
1492 | pkill(v, signum); |
---|
1493 | } |
---|
1494 | |
---|
1495 | static void |
---|
1496 | pkill(v, signum) |
---|
1497 | Char **v; |
---|
1498 | int signum; |
---|
1499 | { |
---|
1500 | register struct process *pp, *np; |
---|
1501 | int jobflags = 0, err1 = 0; |
---|
1502 | pid_t pid; |
---|
1503 | #ifdef BSDSIGS |
---|
1504 | sigmask_t omask; |
---|
1505 | #endif /* BSDSIGS */ |
---|
1506 | Char *cp; |
---|
1507 | |
---|
1508 | #ifdef BSDSIGS |
---|
1509 | omask = sigmask(SIGCHLD); |
---|
1510 | if (setintr) |
---|
1511 | omask |= sigmask(SIGINT); |
---|
1512 | omask = sigblock(omask) & ~omask; |
---|
1513 | #else /* !BSDSIGS */ |
---|
1514 | if (setintr) |
---|
1515 | (void) sighold(SIGINT); |
---|
1516 | (void) sighold(SIGCHLD); |
---|
1517 | #endif /* !BSDSIGS */ |
---|
1518 | gflag = 0, tglob(v); |
---|
1519 | if (gflag) { |
---|
1520 | v = globall(v); |
---|
1521 | if (v == 0) |
---|
1522 | stderror(ERR_NAME | ERR_NOMATCH); |
---|
1523 | } |
---|
1524 | else { |
---|
1525 | v = gargv = saveblk(v); |
---|
1526 | trim(v); |
---|
1527 | } |
---|
1528 | |
---|
1529 | while (v && (cp = *v)) { |
---|
1530 | if (*cp == '%') { |
---|
1531 | np = pp = pfind(cp); |
---|
1532 | do |
---|
1533 | jobflags |= np->p_flags; |
---|
1534 | while ((np = np->p_friends) != pp); |
---|
1535 | #ifdef BSDJOBS |
---|
1536 | switch (signum) { |
---|
1537 | |
---|
1538 | case SIGSTOP: |
---|
1539 | case SIGTSTP: |
---|
1540 | case SIGTTIN: |
---|
1541 | case SIGTTOU: |
---|
1542 | if ((jobflags & PRUNNING) == 0) { |
---|
1543 | # ifdef SUSPENDED |
---|
1544 | xprintf("%S: Already suspended\n", cp); |
---|
1545 | # else /* !SUSPENDED */ |
---|
1546 | xprintf("%S: Already stopped\n", cp); |
---|
1547 | # endif /* !SUSPENDED */ |
---|
1548 | err1++; |
---|
1549 | goto cont; |
---|
1550 | } |
---|
1551 | break; |
---|
1552 | /* |
---|
1553 | * suspend a process, kill -CONT %, then type jobs; the shell |
---|
1554 | * says it is suspended, but it is running; thanks jaap.. |
---|
1555 | */ |
---|
1556 | case SIGCONT: |
---|
1557 | pstart(pp, 0); |
---|
1558 | goto cont; |
---|
1559 | default: |
---|
1560 | break; |
---|
1561 | } |
---|
1562 | #endif /* BSDJOBS */ |
---|
1563 | if (killpg(pp->p_jobid, signum) < 0) { |
---|
1564 | xprintf("%S: %s\n", cp, strerror(errno)); |
---|
1565 | err1++; |
---|
1566 | } |
---|
1567 | #ifdef BSDJOBS |
---|
1568 | if (signum == SIGTERM || signum == SIGHUP) |
---|
1569 | (void) killpg(pp->p_jobid, SIGCONT); |
---|
1570 | #endif /* BSDJOBS */ |
---|
1571 | } |
---|
1572 | else if (!(Isdigit(*cp) || *cp == '-')) |
---|
1573 | stderror(ERR_NAME | ERR_JOBARGS); |
---|
1574 | else { |
---|
1575 | pid = atoi(short2str(cp)); |
---|
1576 | if (kill(pid, signum) < 0) { |
---|
1577 | xprintf("%d: %s\n", pid, strerror(errno)); |
---|
1578 | err1++; |
---|
1579 | goto cont; |
---|
1580 | } |
---|
1581 | #ifdef BSDJOBS |
---|
1582 | if (signum == SIGTERM || signum == SIGHUP) |
---|
1583 | (void) kill(pid, SIGCONT); |
---|
1584 | #endif /* BSDJOBS */ |
---|
1585 | } |
---|
1586 | cont: |
---|
1587 | v++; |
---|
1588 | } |
---|
1589 | if (gargv) |
---|
1590 | blkfree(gargv), gargv = 0; |
---|
1591 | #ifdef BSDSIGS |
---|
1592 | (void) sigsetmask(omask); |
---|
1593 | #else /* !BSDSIGS */ |
---|
1594 | (void) sigrelse(SIGCHLD); |
---|
1595 | if (setintr) |
---|
1596 | (void) sigrelse(SIGINT); |
---|
1597 | #endif /* !BSDSIGS */ |
---|
1598 | if (err1) |
---|
1599 | stderror(ERR_SILENT); |
---|
1600 | } |
---|
1601 | |
---|
1602 | /* |
---|
1603 | * pstart - start the job in foreground/background |
---|
1604 | */ |
---|
1605 | void |
---|
1606 | pstart(pp, foregnd) |
---|
1607 | register struct process *pp; |
---|
1608 | int foregnd; |
---|
1609 | { |
---|
1610 | register struct process *np; |
---|
1611 | #ifdef BSDSIGS |
---|
1612 | sigmask_t omask; |
---|
1613 | #endif /* BSDSIGS */ |
---|
1614 | long jobflags = 0; |
---|
1615 | |
---|
1616 | #ifdef BSDSIGS |
---|
1617 | omask = sigblock(sigmask(SIGCHLD)); |
---|
1618 | #else /* !BSDSIGS */ |
---|
1619 | (void) sighold(SIGCHLD); |
---|
1620 | #endif |
---|
1621 | np = pp; |
---|
1622 | do { |
---|
1623 | jobflags |= np->p_flags; |
---|
1624 | if (np->p_flags & (PRUNNING | PSTOPPED)) { |
---|
1625 | np->p_flags |= PRUNNING; |
---|
1626 | np->p_flags &= ~PSTOPPED; |
---|
1627 | if (foregnd) |
---|
1628 | np->p_flags |= PFOREGND; |
---|
1629 | else |
---|
1630 | np->p_flags &= ~PFOREGND; |
---|
1631 | } |
---|
1632 | } while ((np = np->p_friends) != pp); |
---|
1633 | if (!foregnd) |
---|
1634 | pclrcurr(pp); |
---|
1635 | (void) pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); |
---|
1636 | #ifdef BSDJOBS |
---|
1637 | if (foregnd) { |
---|
1638 | (void) tcsetpgrp(FSHTTY, pp->p_jobid); |
---|
1639 | } |
---|
1640 | /* |
---|
1641 | * 1. child process of csh (shell script) receives SIGTTIN/SIGTTOU |
---|
1642 | * 2. parent process (csh) receives SIGCHLD |
---|
1643 | * 3. The "csh" signal handling function pchild() is invoked |
---|
1644 | * with a SIGCHLD signal. |
---|
1645 | * 4. pchild() calls wait3(WNOHANG) which returns 0. |
---|
1646 | * The child process is NOT ready to be waited for at this time. |
---|
1647 | * pchild() returns without picking-up the correct status |
---|
1648 | * for the child process which generated the SIGCHILD. |
---|
1649 | * 5. CONSEQUENCE : csh is UNaware that the process is stopped |
---|
1650 | * 6. THIS LINE HAS BEEN COMMENTED OUT : if (jobflags&PSTOPPED) |
---|
1651 | * (beto@aixwiz.austin.ibm.com - aug/03/91) |
---|
1652 | */ |
---|
1653 | |
---|
1654 | /* if (jobflags & PSTOPPED) */ |
---|
1655 | (void) killpg(pp->p_jobid, SIGCONT); |
---|
1656 | #endif /* BSDJOBS */ |
---|
1657 | #ifdef BSDSIGS |
---|
1658 | (void) sigsetmask(omask); |
---|
1659 | #else /* !BSDSIGS */ |
---|
1660 | (void) sigrelse(SIGCHLD); |
---|
1661 | #endif /* !BSDSIGS */ |
---|
1662 | } |
---|
1663 | |
---|
1664 | void |
---|
1665 | panystop(neednl) |
---|
1666 | bool neednl; |
---|
1667 | { |
---|
1668 | register struct process *pp; |
---|
1669 | |
---|
1670 | chkstop = 2; |
---|
1671 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
---|
1672 | if (pp->p_flags & PSTOPPED) |
---|
1673 | stderror(ERR_STOPPED, neednl ? "\n" : ""); |
---|
1674 | } |
---|
1675 | |
---|
1676 | struct process * |
---|
1677 | pfind(cp) |
---|
1678 | Char *cp; |
---|
1679 | { |
---|
1680 | register struct process *pp, *np; |
---|
1681 | |
---|
1682 | if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { |
---|
1683 | if (pcurrent == NULL) |
---|
1684 | stderror(ERR_NAME | ERR_JOBCUR); |
---|
1685 | return (pcurrent); |
---|
1686 | } |
---|
1687 | if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { |
---|
1688 | if (pprevious == NULL) |
---|
1689 | stderror(ERR_NAME | ERR_JOBPREV); |
---|
1690 | return (pprevious); |
---|
1691 | } |
---|
1692 | if (Isdigit(cp[1])) { |
---|
1693 | int idx = atoi(short2str(cp + 1)); |
---|
1694 | |
---|
1695 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
---|
1696 | if (pp->p_index == idx && pp->p_procid == pp->p_jobid) |
---|
1697 | return (pp); |
---|
1698 | stderror(ERR_NAME | ERR_NOSUCHJOB); |
---|
1699 | } |
---|
1700 | np = NULL; |
---|
1701 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
---|
1702 | if (pp->p_procid == pp->p_jobid) { |
---|
1703 | if (cp[1] == '?') { |
---|
1704 | register Char *dp; |
---|
1705 | |
---|
1706 | for (dp = pp->p_command; *dp; dp++) { |
---|
1707 | if (*dp != cp[2]) |
---|
1708 | continue; |
---|
1709 | if (prefix(cp + 2, dp)) |
---|
1710 | goto match; |
---|
1711 | } |
---|
1712 | } |
---|
1713 | else if (prefix(cp + 1, pp->p_command)) { |
---|
1714 | match: |
---|
1715 | if (np) |
---|
1716 | stderror(ERR_NAME | ERR_AMBIG); |
---|
1717 | np = pp; |
---|
1718 | } |
---|
1719 | } |
---|
1720 | if (np) |
---|
1721 | return (np); |
---|
1722 | stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); |
---|
1723 | /* NOTREACHED */ |
---|
1724 | return (0); |
---|
1725 | } |
---|
1726 | |
---|
1727 | |
---|
1728 | /* |
---|
1729 | * pgetcurr - find most recent job that is not pp, preferably stopped |
---|
1730 | */ |
---|
1731 | static struct process * |
---|
1732 | pgetcurr(pp) |
---|
1733 | register struct process *pp; |
---|
1734 | { |
---|
1735 | register struct process *np; |
---|
1736 | register struct process *xp = NULL; |
---|
1737 | |
---|
1738 | for (np = proclist.p_next; np; np = np->p_next) |
---|
1739 | if (np != pcurrent && np != pp && np->p_procid && |
---|
1740 | np->p_procid == np->p_jobid) { |
---|
1741 | if (np->p_flags & PSTOPPED) |
---|
1742 | return (np); |
---|
1743 | if (xp == NULL) |
---|
1744 | xp = np; |
---|
1745 | } |
---|
1746 | return (xp); |
---|
1747 | } |
---|
1748 | |
---|
1749 | /* |
---|
1750 | * donotify - flag the job so as to report termination asynchronously |
---|
1751 | */ |
---|
1752 | /*ARGSUSED*/ |
---|
1753 | void |
---|
1754 | donotify(v, c) |
---|
1755 | Char **v; |
---|
1756 | struct command *c; |
---|
1757 | { |
---|
1758 | register struct process *pp; |
---|
1759 | |
---|
1760 | pp = pfind(*++v); |
---|
1761 | pp->p_flags |= PNOTIFY; |
---|
1762 | } |
---|
1763 | |
---|
1764 | /* |
---|
1765 | * Do the fork and whatever should be done in the child side that |
---|
1766 | * should not be done if we are not forking at all (like for simple builtin's) |
---|
1767 | * Also do everything that needs any signals fiddled with in the parent side |
---|
1768 | * |
---|
1769 | * Wanttty tells whether process and/or tty pgrps are to be manipulated: |
---|
1770 | * -1: leave tty alone; inherit pgrp from parent |
---|
1771 | * 0: already have tty; manipulate process pgrps only |
---|
1772 | * 1: want to claim tty; manipulate process and tty pgrps |
---|
1773 | * It is usually just the value of tpgrp. |
---|
1774 | */ |
---|
1775 | |
---|
1776 | int |
---|
1777 | pfork(t, wanttty) |
---|
1778 | struct command *t; /* command we are forking for */ |
---|
1779 | int wanttty; |
---|
1780 | { |
---|
1781 | register int pid; |
---|
1782 | bool ignint = 0; |
---|
1783 | int pgrp; |
---|
1784 | #ifdef BSDSIGS |
---|
1785 | sigmask_t omask; |
---|
1786 | #endif /* BSDSIGS */ |
---|
1787 | #ifdef SIGSYNCH |
---|
1788 | sigvec_t osv; |
---|
1789 | static sigvec_t nsv = {synch_handler, ~0, 0}; |
---|
1790 | #endif /* SIGSYNCH */ |
---|
1791 | |
---|
1792 | /* |
---|
1793 | * A child will be uninterruptible only under very special conditions. |
---|
1794 | * Remember that the semantics of '&' is implemented by disconnecting the |
---|
1795 | * process from the tty so signals do not need to ignored just for '&'. |
---|
1796 | * Thus signals are set to default action for children unless: we have had |
---|
1797 | * an "onintr -" (then specifically ignored) we are not playing with |
---|
1798 | * signals (inherit action) |
---|
1799 | */ |
---|
1800 | if (setintr) |
---|
1801 | ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) |
---|
1802 | || (gointr && eq(gointr, STRminus)); |
---|
1803 | |
---|
1804 | #ifdef COHERENT |
---|
1805 | ignint |= gointr && eq(gointr, STRminus); |
---|
1806 | #endif /* COHERENT */ |
---|
1807 | |
---|
1808 | /* |
---|
1809 | * Check for maximum nesting of 16 processes to avoid Forking loops |
---|
1810 | */ |
---|
1811 | if (child == 16) |
---|
1812 | stderror(ERR_NESTING, 16); |
---|
1813 | /* |
---|
1814 | * Hold SIGCHLD until we have the process installed in our table. |
---|
1815 | */ |
---|
1816 | #ifdef SIGSYNCH |
---|
1817 | if (mysigvec(SIGSYNCH, &nsv, &osv)) |
---|
1818 | stderror(ERR_SYSTEM, "pfork: sigvec set", strerror(errno)); |
---|
1819 | #endif /* SIGSYNCH */ |
---|
1820 | #ifdef BSDSIGS |
---|
1821 | omask = sigblock(sigmask(SIGCHLD)); |
---|
1822 | #else /* !BSDSIGS */ |
---|
1823 | (void) sighold(SIGCHLD); |
---|
1824 | #endif /* !BSDSIGS */ |
---|
1825 | while ((pid = fork()) < 0) |
---|
1826 | if (setintr == 0) |
---|
1827 | (void) sleep(FORKSLEEP); |
---|
1828 | else { |
---|
1829 | #ifdef BSDSIGS |
---|
1830 | (void) sigsetmask(omask); |
---|
1831 | #else /* !BSDSIGS */ |
---|
1832 | (void) sigrelse(SIGINT); |
---|
1833 | (void) sigrelse(SIGCHLD); |
---|
1834 | #endif /* !BSDSIGS */ |
---|
1835 | stderror(ERR_NOPROC); |
---|
1836 | } |
---|
1837 | if (pid == 0) { |
---|
1838 | settimes(); |
---|
1839 | pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); |
---|
1840 | pflushall(); |
---|
1841 | pcurrjob = NULL; |
---|
1842 | #if !defined(BSDTIMES) && !defined(_SEQUENT_) |
---|
1843 | timesdone = 0; |
---|
1844 | #endif /* !defined(BSDTIMES) && !defined(_SEQUENT_) */ |
---|
1845 | child++; |
---|
1846 | if (setintr) { |
---|
1847 | setintr = 0; /* until I think otherwise */ |
---|
1848 | #ifndef BSDSIGS |
---|
1849 | (void) sigrelse(SIGCHLD); |
---|
1850 | #endif /* !BSDSIGS */ |
---|
1851 | /* |
---|
1852 | * Children just get blown away on SIGINT, SIGQUIT unless "onintr |
---|
1853 | * -" seen. |
---|
1854 | */ |
---|
1855 | (void) signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); |
---|
1856 | (void) signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); |
---|
1857 | #ifdef BSDJOBS |
---|
1858 | if (wanttty >= 0) { |
---|
1859 | /* make stoppable */ |
---|
1860 | (void) signal(SIGTSTP, SIG_DFL); |
---|
1861 | (void) signal(SIGTTIN, SIG_DFL); |
---|
1862 | (void) signal(SIGTTOU, SIG_DFL); |
---|
1863 | } |
---|
1864 | #endif /* BSDJOBS */ |
---|
1865 | (void) signal(SIGTERM, parterm); |
---|
1866 | } |
---|
1867 | else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { |
---|
1868 | (void) signal(SIGINT, SIG_IGN); |
---|
1869 | (void) signal(SIGQUIT, SIG_IGN); |
---|
1870 | } |
---|
1871 | #ifdef OREO |
---|
1872 | sigignore(SIGIO); /* ignore SIGIO in child too */ |
---|
1873 | #endif /* OREO */ |
---|
1874 | |
---|
1875 | pgetty(wanttty, pgrp); |
---|
1876 | /* |
---|
1877 | * Nohup and nice apply only to NODE_COMMAND's but it would be nice |
---|
1878 | * (?!?) if you could say "nohup (foo;bar)" Then the parser would have |
---|
1879 | * to know about nice/nohup/time |
---|
1880 | */ |
---|
1881 | if (t->t_dflg & F_NOHUP) |
---|
1882 | (void) signal(SIGHUP, SIG_IGN); |
---|
1883 | if (t->t_dflg & F_NICE) |
---|
1884 | #ifdef BSDNICE |
---|
1885 | (void) setpriority(PRIO_PROCESS, 0, t->t_nice); |
---|
1886 | #else /* !BSDNICE */ |
---|
1887 | (void) nice(t->t_nice); |
---|
1888 | #endif /* !BSDNICE */ |
---|
1889 | #ifdef F_VER |
---|
1890 | if (t->t_dflg & F_VER) { |
---|
1891 | tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); |
---|
1892 | dohash(NULL, NULL); |
---|
1893 | } |
---|
1894 | #endif /* F_VER */ |
---|
1895 | #ifdef SIGSYNCH |
---|
1896 | /* rfw 8/89 now parent can continue */ |
---|
1897 | if (kill(getppid(), SIGSYNCH)) |
---|
1898 | stderror(ERR_SYSTEM, "pfork child: kill", strerror(errno)); |
---|
1899 | #endif /* SIGSYNCH */ |
---|
1900 | |
---|
1901 | } |
---|
1902 | else { |
---|
1903 | #ifdef POSIXJOBS |
---|
1904 | if (wanttty >= 0) { |
---|
1905 | /* |
---|
1906 | * `Walking' process group fix from Beto Appleton. |
---|
1907 | * (beto@aixwiz.austin.ibm.com) |
---|
1908 | * If setpgid fails at this point that means that |
---|
1909 | * our process leader has died. We flush the current |
---|
1910 | * job and become the process leader ourselves. |
---|
1911 | * The parent will figure that out later. |
---|
1912 | */ |
---|
1913 | pgrp = pcurrjob ? pcurrjob->p_jobid : pid; |
---|
1914 | if (setpgid(pid, pgrp) == -1 && errno == EPERM) { |
---|
1915 | pflush(pcurrjob); |
---|
1916 | pcurrjob = NULL; |
---|
1917 | if (setpgid(pid, pgrp = pid) == -1) { |
---|
1918 | stderror(ERR_SYSTEM, "setpgid parent:", strerror(errno)); |
---|
1919 | xexit(0); |
---|
1920 | } |
---|
1921 | } |
---|
1922 | } |
---|
1923 | #endif /* POSIXJOBS */ |
---|
1924 | palloc(pid, t); |
---|
1925 | #ifdef SIGSYNCH |
---|
1926 | /* |
---|
1927 | * rfw 8/89 Wait for child to own terminal. Solves half of ugly |
---|
1928 | * synchronization problem. With this change, we know that the only |
---|
1929 | * reason setpgrp to a previous process in a pipeline can fail is that |
---|
1930 | * the previous process has already exited. Without this hack, he may |
---|
1931 | * either have exited or not yet started to run. Two uglies become |
---|
1932 | * one. |
---|
1933 | */ |
---|
1934 | sigpause(omask & ~SYNCHMASK); |
---|
1935 | if (mysigvec(SIGSYNCH, &osv, NULL)) |
---|
1936 | stderror(ERR_SYSTEM, "pfork parent: sigvec restore", |
---|
1937 | strerror(errno)); |
---|
1938 | #endif /* SIGSYNCH */ |
---|
1939 | |
---|
1940 | #ifdef BSDSIGS |
---|
1941 | (void) sigsetmask(omask); |
---|
1942 | #else /* !BSDSIGS */ |
---|
1943 | (void) sigrelse(SIGCHLD); |
---|
1944 | #endif /* !BSDSIGS */ |
---|
1945 | } |
---|
1946 | return (pid); |
---|
1947 | } |
---|
1948 | |
---|
1949 | static void |
---|
1950 | okpcntl() |
---|
1951 | { |
---|
1952 | if (tpgrp == -1) |
---|
1953 | stderror(ERR_JOBCONTROL); |
---|
1954 | if (tpgrp == 0) |
---|
1955 | stderror(ERR_JOBCTRLSUB); |
---|
1956 | } |
---|
1957 | |
---|
1958 | /* |
---|
1959 | * if we don't have vfork(), things can still go in the wrong order |
---|
1960 | * resulting in the famous 'Stopped (tty output)'. But some systems |
---|
1961 | * don't permit the setpgid() call, (these are more recent secure |
---|
1962 | * systems such as ibm's aix), when they do. Then we'd rather print |
---|
1963 | * an error message than hang the shell! |
---|
1964 | * I am open to suggestions how to fix that. |
---|
1965 | */ |
---|
1966 | void |
---|
1967 | pgetty(wanttty, pgrp) |
---|
1968 | int wanttty, pgrp; |
---|
1969 | { |
---|
1970 | #ifdef BSDJOBS |
---|
1971 | # if defined(BSDSIGS) && defined(POSIXJOBS) |
---|
1972 | sigmask_t omask = 0; |
---|
1973 | # endif /* BSDSIGS && POSIXJOBS */ |
---|
1974 | |
---|
1975 | # ifdef JOBDEBUG |
---|
1976 | xprintf("wanttty %d\n", wanttty); |
---|
1977 | # endif |
---|
1978 | |
---|
1979 | # ifdef POSIXJOBS |
---|
1980 | /* |
---|
1981 | * christos: I am blocking the tty signals till I've set things |
---|
1982 | * correctly.... |
---|
1983 | */ |
---|
1984 | if (wanttty > 0) |
---|
1985 | # ifdef BSDSIGS |
---|
1986 | omask = sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)); |
---|
1987 | # else /* !BSDSIGS */ |
---|
1988 | { |
---|
1989 | (void) sighold(SIGTSTP); |
---|
1990 | (void) sighold(SIGTTIN); |
---|
1991 | } |
---|
1992 | # endif /* !BSDSIGS */ |
---|
1993 | # endif /* POSIXJOBS */ |
---|
1994 | |
---|
1995 | # ifndef POSIXJOBS |
---|
1996 | if (wanttty > 0) |
---|
1997 | (void) tcsetpgrp(FSHTTY, pgrp); |
---|
1998 | # endif /* !POSIXJOBS */ |
---|
1999 | |
---|
2000 | /* |
---|
2001 | * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> |
---|
2002 | * Don't check for tpgrp >= 0 so even non-interactive shells give |
---|
2003 | * background jobs process groups Same for the comparison in the other part |
---|
2004 | * of the #ifdef |
---|
2005 | */ |
---|
2006 | if (wanttty >= 0) |
---|
2007 | if (setpgid(0, pgrp) == -1) { |
---|
2008 | # ifdef POSIXJOBS |
---|
2009 | /* Walking process group fix; see above */ |
---|
2010 | if (setpgid(0, pgrp = getpid()) == -1) { |
---|
2011 | # endif /* POSIXJOBS */ |
---|
2012 | stderror(ERR_SYSTEM, "setpgid child:\n", strerror(errno)); |
---|
2013 | xexit(0); |
---|
2014 | # ifdef POSIXJOBS |
---|
2015 | } |
---|
2016 | wanttty = 1; /* Now we really want the tty, since we became the |
---|
2017 | * the process group leader |
---|
2018 | */ |
---|
2019 | # endif /* POSIXJOBS */ |
---|
2020 | } |
---|
2021 | |
---|
2022 | # ifdef POSIXJOBS |
---|
2023 | # ifdef _SEQUENT_ |
---|
2024 | /* The controlling terminal is lost if all processes in the |
---|
2025 | * terminal process group are zombies. In this case tcgetpgrp() |
---|
2026 | * returns 0. If this happens we must set the terminal process |
---|
2027 | * group again. |
---|
2028 | */ |
---|
2029 | if (wanttty == 0 && tcgetpgrp(FSHTTY) == 0) |
---|
2030 | wanttty = 1; |
---|
2031 | # endif /* _SEQUENT_ */ |
---|
2032 | if (wanttty > 0) { |
---|
2033 | /* |
---|
2034 | * tcsetpgrp will set SIGTTOU to all the the processes in |
---|
2035 | * the background according to POSIX... We ignore this here. |
---|
2036 | */ |
---|
2037 | sigret_t (*old)() = sigset(SIGTTOU, SIG_IGN); |
---|
2038 | (void) tcsetpgrp(FSHTTY, pgrp); |
---|
2039 | (void) sigset(SIGTTOU, old); |
---|
2040 | |
---|
2041 | # ifdef BSDSIGS |
---|
2042 | (void) sigsetmask(omask); |
---|
2043 | # else /* BSDSIGS */ |
---|
2044 | (void) sigrelse(SIGTSTP); |
---|
2045 | (void) sigrelse(SIGTTIN); |
---|
2046 | # endif /* !BSDSIGS */ |
---|
2047 | } |
---|
2048 | # endif /* POSIXJOBS */ |
---|
2049 | |
---|
2050 | if (tpgrp > 0) |
---|
2051 | tpgrp = 0; /* gave tty away */ |
---|
2052 | #endif /* BSDJOBS */ |
---|
2053 | } |
---|