1 | /* $NetBSD: proc.c,v 1.38 2019/01/05 16:54:00 christos Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1980, 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the University nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | #ifndef lint |
34 | #if 0 |
35 | static char sccsid[] = "@(#)proc.c 8.1 (Berkeley) 5/31/93" ; |
36 | #else |
37 | __RCSID("$NetBSD: proc.c,v 1.38 2019/01/05 16:54:00 christos Exp $" ); |
38 | #endif |
39 | #endif /* not lint */ |
40 | |
41 | #include <sys/types.h> |
42 | #include <sys/wait.h> |
43 | |
44 | #include <errno.h> |
45 | #include <stdarg.h> |
46 | #include <stdlib.h> |
47 | #include <string.h> |
48 | #include <unistd.h> |
49 | |
50 | #include "csh.h" |
51 | #include "dir.h" |
52 | #include "extern.h" |
53 | #include "proc.h" |
54 | |
55 | #define BIGINDEX 9 /* largest desirable job index */ |
56 | |
57 | extern int insource; |
58 | |
59 | static void pflushall(void); |
60 | static void pflush(struct process *); |
61 | static void pclrcurr(struct process *); |
62 | static void padd(struct command *); |
63 | static int pprint(struct process *, int); |
64 | static void ptprint(struct process *); |
65 | static void pads(Char *); |
66 | static void pkill(Char **v, int); |
67 | static struct process *pgetcurr(struct process *); |
68 | static void okpcntl(void); |
69 | |
70 | /* |
71 | * pchild - called at interrupt level by the SIGCHLD signal |
72 | * indicating that at least one child has terminated or stopped |
73 | * thus at least one wait system call will definitely return a |
74 | * childs status. Top level routines (like pwait) must be sure |
75 | * to mask interrupts when playing with the proclist data structures! |
76 | */ |
77 | /* ARGSUSED */ |
78 | void |
79 | pchild(int notused) |
80 | { |
81 | struct rusage ru; |
82 | struct process *fp, *pp; |
83 | int jobflags, pid, w; |
84 | |
85 | loop: |
86 | errno = 0; /* reset, just in case */ |
87 | pid = wait3(&w, |
88 | (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); |
89 | |
90 | if (pid <= 0) { |
91 | if (errno == EINTR) { |
92 | errno = 0; |
93 | goto loop; |
94 | } |
95 | pnoprocesses = pid == -1; |
96 | return; |
97 | } |
98 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) |
99 | if (pid == pp->p_pid) |
100 | goto found; |
101 | goto loop; |
102 | found: |
103 | if (pid == atoi(short2str(value(STRchild)))) |
104 | unsetv(STRchild); |
105 | pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); |
106 | if (WIFSTOPPED(w)) { |
107 | pp->p_flags |= PSTOPPED; |
108 | pp->p_reason = WSTOPSIG(w); |
109 | } |
110 | else { |
111 | if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) |
112 | (void)clock_gettime(CLOCK_MONOTONIC, &pp->p_etime); |
113 | |
114 | pp->p_rusage = ru; |
115 | if (WIFSIGNALED(w)) { |
116 | if (WTERMSIG(w) == SIGINT) |
117 | pp->p_flags |= PINTERRUPTED; |
118 | else |
119 | pp->p_flags |= PSIGNALED; |
120 | if (WCOREDUMP(w)) |
121 | pp->p_flags |= PDUMPED; |
122 | pp->p_reason = WTERMSIG(w); |
123 | } |
124 | else { |
125 | pp->p_reason = WEXITSTATUS(w); |
126 | if (pp->p_reason != 0) |
127 | pp->p_flags |= PAEXITED; |
128 | else |
129 | pp->p_flags |= PNEXITED; |
130 | } |
131 | } |
132 | jobflags = 0; |
133 | fp = pp; |
134 | do { |
135 | if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && |
136 | !child && adrof(STRtime) && |
137 | fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec |
138 | >= atoi(short2str(value(STRtime)))) |
139 | fp->p_flags |= PTIME; |
140 | jobflags |= fp->p_flags; |
141 | } while ((fp = fp->p_friends) != pp); |
142 | pp->p_flags &= ~PFOREGND; |
143 | if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { |
144 | pp->p_flags &= ~PPTIME; |
145 | pp->p_flags |= PTIME; |
146 | } |
147 | if ((jobflags & (PRUNNING | PREPORTED)) == 0) { |
148 | fp = pp; |
149 | do { |
150 | if (fp->p_flags & PSTOPPED) |
151 | fp->p_flags |= PREPORTED; |
152 | } while ((fp = fp->p_friends) != pp); |
153 | while (fp->p_pid != fp->p_jobid) |
154 | fp = fp->p_friends; |
155 | if (jobflags & PSTOPPED) { |
156 | if (pcurrent && pcurrent != fp) |
157 | pprevious = pcurrent; |
158 | pcurrent = fp; |
159 | } |
160 | else |
161 | pclrcurr(fp); |
162 | if (jobflags & PFOREGND) { |
163 | if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) || |
164 | #ifdef IIASA |
165 | jobflags & PAEXITED || |
166 | #endif |
167 | !eq(dcwd->di_name, fp->p_cwd->di_name)) { |
168 | ; /* print in pjwait */ |
169 | } |
170 | /* PWP: print a newline after ^C */ |
171 | else if (jobflags & PINTERRUPTED) { |
172 | (void)vis_fputc('\r' | QUOTE, cshout); |
173 | (void)fputc('\n', cshout); |
174 | } |
175 | } |
176 | else { |
177 | if (jobflags & PNOTIFY || adrof(STRnotify)) { |
178 | (void)vis_fputc('\r' | QUOTE, cshout); |
179 | (void)fputc('\n', cshout); |
180 | (void)pprint(pp, NUMBER | NAME | REASON); |
181 | if ((jobflags & PSTOPPED) == 0) |
182 | pflush(pp); |
183 | } |
184 | else { |
185 | fp->p_flags |= PNEEDNOTE; |
186 | neednote++; |
187 | } |
188 | } |
189 | } |
190 | goto loop; |
191 | } |
192 | |
193 | void |
194 | pnote(void) |
195 | { |
196 | struct process *pp; |
197 | sigset_t osigset, nsigset; |
198 | int flags; |
199 | |
200 | neednote = 0; |
201 | sigemptyset(&nsigset); |
202 | (void)sigaddset(&nsigset, SIGCHLD); |
203 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { |
204 | if (pp->p_flags & PNEEDNOTE) { |
205 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
206 | pp->p_flags &= ~PNEEDNOTE; |
207 | flags = pprint(pp, NUMBER | NAME | REASON); |
208 | if ((flags & (PRUNNING | PSTOPPED)) == 0) |
209 | pflush(pp); |
210 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
211 | } |
212 | } |
213 | } |
214 | |
215 | /* |
216 | * pwait - wait for current job to terminate, maintaining integrity |
217 | * of current and previous job indicators. |
218 | */ |
219 | void |
220 | pwait(void) |
221 | { |
222 | struct process *fp, *pp; |
223 | sigset_t osigset, nsigset; |
224 | |
225 | /* |
226 | * Here's where dead procs get flushed. |
227 | */ |
228 | sigemptyset(&nsigset); |
229 | (void)sigaddset(&nsigset, SIGCHLD); |
230 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
231 | for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) |
232 | if (pp->p_pid == 0) { |
233 | fp->p_next = pp->p_next; |
234 | free(pp->p_command); |
235 | if (pp->p_cwd && --pp->p_cwd->di_count == 0) |
236 | if (pp->p_cwd->di_next == 0) |
237 | dfree(pp->p_cwd); |
238 | free(pp); |
239 | pp = fp; |
240 | } |
241 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
242 | pjwait(pcurrjob); |
243 | } |
244 | |
245 | |
246 | /* |
247 | * pjwait - wait for a job to finish or become stopped |
248 | * It is assumed to be in the foreground state (PFOREGND) |
249 | */ |
250 | void |
251 | pjwait(struct process *pp) |
252 | { |
253 | struct process *fp; |
254 | sigset_t osigset, nsigset; |
255 | int jobflags, reason; |
256 | |
257 | while (pp->p_pid != pp->p_jobid) |
258 | pp = pp->p_friends; |
259 | fp = pp; |
260 | |
261 | do { |
262 | if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) |
263 | (void)fprintf(csherr, "BUG: waiting for background job!\n" ); |
264 | } while ((fp = fp->p_friends) != pp); |
265 | /* |
266 | * Now keep pausing as long as we are not interrupted (SIGINT), and the |
267 | * target process, or any of its friends, are running |
268 | */ |
269 | fp = pp; |
270 | sigemptyset(&nsigset); |
271 | (void)sigaddset(&nsigset, SIGCHLD); |
272 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
273 | for (;;) { |
274 | sigemptyset(&nsigset); |
275 | (void)sigaddset(&nsigset, SIGCHLD); |
276 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); |
277 | jobflags = 0; |
278 | do |
279 | jobflags |= fp->p_flags; |
280 | while ((fp = (fp->p_friends)) != pp); |
281 | if ((jobflags & PRUNNING) == 0) |
282 | break; |
283 | #ifdef JOBDEBUG |
284 | (void)fprintf(csherr, "starting to sigsuspend for SIGCHLD on %d\n" , |
285 | fp->p_pid); |
286 | #endif /* JOBDEBUG */ |
287 | nsigset = osigset; |
288 | (void)sigdelset(&nsigset, SIGCHLD); |
289 | (void)sigsuspend(&nsigset); |
290 | } |
291 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
292 | if (tpgrp > 0) /* get tty back */ |
293 | (void)tcsetpgrp(FSHTTY, tpgrp); |
294 | if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || |
295 | !eq(dcwd->di_name, fp->p_cwd->di_name)) { |
296 | if (jobflags & PSTOPPED) { |
297 | (void) fputc('\n', cshout); |
298 | if (adrof(STRlistjobs)) { |
299 | Char *jobcommand[3]; |
300 | |
301 | jobcommand[0] = STRjobs; |
302 | if (eq(value(STRlistjobs), STRlong)) |
303 | jobcommand[1] = STRml; |
304 | else |
305 | jobcommand[1] = NULL; |
306 | jobcommand[2] = NULL; |
307 | |
308 | dojobs(jobcommand, NULL); |
309 | (void)pprint(pp, SHELLDIR); |
310 | } |
311 | else |
312 | (void)pprint(pp, AREASON | SHELLDIR); |
313 | } |
314 | else |
315 | (void)pprint(pp, AREASON | SHELLDIR); |
316 | } |
317 | if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && |
318 | (!gointr || !eq(gointr, STRminus))) { |
319 | if ((jobflags & PSTOPPED) == 0) |
320 | pflush(pp); |
321 | pintr1(0); |
322 | } |
323 | reason = 0; |
324 | fp = pp; |
325 | do { |
326 | if (fp->p_reason) |
327 | reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? |
328 | fp->p_reason | META : fp->p_reason; |
329 | } while ((fp = fp->p_friends) != pp); |
330 | if ((reason != 0) && (adrof(STRprintexitvalue))) { |
331 | (void)fprintf(cshout, "Exit %d\n" , reason); |
332 | } |
333 | set(STRstatus, putn(reason)); |
334 | if (reason && exiterr) |
335 | exitstat(); |
336 | pflush(pp); |
337 | } |
338 | |
339 | /* |
340 | * dowait - wait for all processes to finish |
341 | */ |
342 | void |
343 | /*ARGSUSED*/ |
344 | dowait(Char **v, struct command *t) |
345 | { |
346 | struct process *pp; |
347 | sigset_t osigset, nsigset; |
348 | |
349 | pjobs++; |
350 | sigemptyset(&nsigset); |
351 | (void)sigaddset(&nsigset, SIGCHLD); |
352 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
353 | loop: |
354 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
355 | if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ |
356 | pp->p_flags & PRUNNING) { |
357 | sigemptyset(&nsigset); |
358 | (void)sigsuspend(&nsigset); |
359 | goto loop; |
360 | } |
361 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
362 | pjobs = 0; |
363 | } |
364 | |
365 | /* |
366 | * pflushall - flush all jobs from list (e.g. at fork()) |
367 | */ |
368 | static void |
369 | pflushall(void) |
370 | { |
371 | struct process *pp; |
372 | |
373 | for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) |
374 | if (pp->p_pid) |
375 | pflush(pp); |
376 | } |
377 | |
378 | /* |
379 | * pflush - flag all process structures in the same job as the |
380 | * the argument process for deletion. The actual free of the |
381 | * space is not done here since pflush is called at interrupt level. |
382 | */ |
383 | static void |
384 | pflush(struct process *pp) |
385 | { |
386 | struct process *np; |
387 | int idx; |
388 | |
389 | if (pp->p_pid == 0) { |
390 | (void)fprintf(csherr, "BUG: process flushed twice" ); |
391 | return; |
392 | } |
393 | while (pp->p_pid != pp->p_jobid) |
394 | pp = pp->p_friends; |
395 | pclrcurr(pp); |
396 | if (pp == pcurrjob) |
397 | pcurrjob = 0; |
398 | idx = pp->p_index; |
399 | np = pp; |
400 | do { |
401 | np->p_index = np->p_pid = 0; |
402 | np->p_flags &= ~PNEEDNOTE; |
403 | } while ((np = np->p_friends) != pp); |
404 | if (idx == pmaxindex) { |
405 | for (np = proclist.p_next, idx = 0; np; np = np->p_next) |
406 | if (np->p_index > idx) |
407 | idx = np->p_index; |
408 | pmaxindex = idx; |
409 | } |
410 | } |
411 | |
412 | /* |
413 | * pclrcurr - make sure the given job is not the current or previous job; |
414 | * pp MUST be the job leader |
415 | */ |
416 | static void |
417 | pclrcurr(struct process *pp) |
418 | { |
419 | if (pp == pcurrent) { |
420 | if (pprevious != NULL) { |
421 | pcurrent = pprevious; |
422 | pprevious = pgetcurr(pp); |
423 | } |
424 | else { |
425 | pcurrent = pgetcurr(pp); |
426 | pprevious = pgetcurr(pp); |
427 | } |
428 | } else if (pp == pprevious) |
429 | pprevious = pgetcurr(pp); |
430 | } |
431 | |
432 | /* +4 here is 1 for '\0', 1 ea for << >& >> */ |
433 | static Char command[PMAXLEN + 4]; |
434 | static size_t cmdlen; |
435 | static Char *cmdp; |
436 | |
437 | /* |
438 | * palloc - allocate a process structure and fill it up. |
439 | * an important assumption is made that the process is running. |
440 | */ |
441 | void |
442 | palloc(int pid, struct command *t) |
443 | { |
444 | struct process *pp; |
445 | int i; |
446 | |
447 | pp = (struct process *)xcalloc(1, (size_t)sizeof(struct process)); |
448 | pp->p_pid = pid; |
449 | pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; |
450 | if (t->t_dflg & F_TIME) |
451 | pp->p_flags |= PPTIME; |
452 | cmdp = command; |
453 | cmdlen = 0; |
454 | padd(t); |
455 | *cmdp++ = 0; |
456 | if (t->t_dflg & F_PIPEOUT) { |
457 | pp->p_flags |= PPOU; |
458 | if (t->t_dflg & F_STDERR) |
459 | pp->p_flags |= PERR; |
460 | } |
461 | pp->p_command = Strsave(command); |
462 | if (pcurrjob) { |
463 | struct process *fp; |
464 | |
465 | /* careful here with interrupt level */ |
466 | pp->p_cwd = 0; |
467 | pp->p_index = pcurrjob->p_index; |
468 | pp->p_friends = pcurrjob; |
469 | pp->p_jobid = pcurrjob->p_pid; |
470 | for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends) |
471 | continue; |
472 | fp->p_friends = pp; |
473 | } |
474 | else { |
475 | pcurrjob = pp; |
476 | pp->p_jobid = pid; |
477 | pp->p_friends = pp; |
478 | pp->p_cwd = dcwd; |
479 | dcwd->di_count++; |
480 | if (pmaxindex < BIGINDEX) |
481 | pp->p_index = ++pmaxindex; |
482 | else { |
483 | struct process *np; |
484 | |
485 | for (i = 1;; i++) { |
486 | for (np = proclist.p_next; np; np = np->p_next) |
487 | if (np->p_index == i) |
488 | goto tryagain; |
489 | pp->p_index = i; |
490 | if (i > pmaxindex) |
491 | pmaxindex = i; |
492 | break; |
493 | tryagain:; |
494 | } |
495 | } |
496 | if (pcurrent == NULL) |
497 | pcurrent = pp; |
498 | else if (pprevious == NULL) |
499 | pprevious = pp; |
500 | } |
501 | pp->p_next = proclist.p_next; |
502 | proclist.p_next = pp; |
503 | (void)clock_gettime(CLOCK_MONOTONIC, &pp->p_btime); |
504 | } |
505 | |
506 | static void |
507 | padd(struct command *t) |
508 | { |
509 | Char **argp; |
510 | |
511 | if (t == 0) |
512 | return; |
513 | switch (t->t_dtyp) { |
514 | case NODE_PAREN: |
515 | pads(STRLparensp); |
516 | padd(t->t_dspr); |
517 | pads(STRspRparen); |
518 | break; |
519 | case NODE_COMMAND: |
520 | for (argp = t->t_dcom; *argp; argp++) { |
521 | pads(*argp); |
522 | if (argp[1]) |
523 | pads(STRspace); |
524 | } |
525 | break; |
526 | case NODE_OR: |
527 | case NODE_AND: |
528 | case NODE_PIPE: |
529 | case NODE_LIST: |
530 | padd(t->t_dcar); |
531 | switch (t->t_dtyp) { |
532 | case NODE_OR: |
533 | pads(STRspor2sp); |
534 | break; |
535 | case NODE_AND: |
536 | pads(STRspand2sp); |
537 | break; |
538 | case NODE_PIPE: |
539 | pads(STRsporsp); |
540 | break; |
541 | case NODE_LIST: |
542 | pads(STRsemisp); |
543 | break; |
544 | } |
545 | padd(t->t_dcdr); |
546 | return; |
547 | } |
548 | if ((t->t_dflg & F_PIPEIN) == 0 && t->t_dlef) { |
549 | pads((t->t_dflg & F_READ) ? STRspLarrow2sp : STRspLarrowsp); |
550 | pads(t->t_dlef); |
551 | } |
552 | if ((t->t_dflg & F_PIPEOUT) == 0 && t->t_drit) { |
553 | pads((t->t_dflg & F_APPEND) ? STRspRarrow2 : STRspRarrow); |
554 | if (t->t_dflg & F_STDERR) |
555 | pads(STRand); |
556 | pads(STRspace); |
557 | pads(t->t_drit); |
558 | } |
559 | } |
560 | |
561 | static void |
562 | pads(Char *cp) |
563 | { |
564 | size_t i; |
565 | |
566 | /* |
567 | * Avoid the Quoted Space alias hack! Reported by: |
568 | * sam@john-bigboote.ICS.UCI.EDU (Sam Horrocks) |
569 | */ |
570 | if (cp[0] == STRQNULL[0]) |
571 | cp++; |
572 | |
573 | i = Strlen(cp); |
574 | |
575 | if (cmdlen >= PMAXLEN) |
576 | return; |
577 | if (cmdlen + i >= PMAXLEN) { |
578 | (void)Strcpy(cmdp, STRsp3dots); |
579 | cmdlen = PMAXLEN; |
580 | cmdp += 4; |
581 | return; |
582 | } |
583 | (void)Strcpy(cmdp, cp); |
584 | cmdp += i; |
585 | cmdlen += i; |
586 | } |
587 | |
588 | /* |
589 | * psavejob - temporarily save the current job on a one level stack |
590 | * so another job can be created. Used for { } in exp6 |
591 | * and `` in globbing. |
592 | */ |
593 | void |
594 | psavejob(void) |
595 | { |
596 | pholdjob = pcurrjob; |
597 | pcurrjob = NULL; |
598 | } |
599 | |
600 | /* |
601 | * prestjob - opposite of psavejob. This may be missed if we are interrupted |
602 | * somewhere, but pendjob cleans up anyway. |
603 | */ |
604 | void |
605 | prestjob(void) |
606 | { |
607 | pcurrjob = pholdjob; |
608 | pholdjob = NULL; |
609 | } |
610 | |
611 | /* |
612 | * pendjob - indicate that a job (set of commands) has been completed |
613 | * or is about to begin. |
614 | */ |
615 | void |
616 | pendjob(void) |
617 | { |
618 | struct process *pp, *tp; |
619 | |
620 | if (pcurrjob && (pcurrjob->p_flags & (PFOREGND | PSTOPPED)) == 0) { |
621 | pp = pcurrjob; |
622 | while (pp->p_pid != pp->p_jobid) |
623 | pp = pp->p_friends; |
624 | (void)fprintf(cshout, "[%d]" , pp->p_index); |
625 | tp = pp; |
626 | do { |
627 | (void)fprintf(cshout, " %ld" , (long)pp->p_pid); |
628 | pp = pp->p_friends; |
629 | } while (pp != tp); |
630 | (void)fputc('\n', cshout); |
631 | } |
632 | pholdjob = pcurrjob = 0; |
633 | } |
634 | |
635 | /* |
636 | * pprint - print a job |
637 | */ |
638 | static int |
639 | pprint(struct process *pp, int flag) |
640 | { |
641 | static struct rusage zru; |
642 | struct process *tp; |
643 | const char *format; |
644 | int jobflags, pstatus, reason, status; |
645 | int hadnl; |
646 | |
647 | hadnl = 1; /* did we just have a newline */ |
648 | (void)fpurge(cshout); |
649 | |
650 | while (pp->p_pid != pp->p_jobid) |
651 | pp = pp->p_friends; |
652 | if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { |
653 | pp->p_flags &= ~PPTIME; |
654 | pp->p_flags |= PTIME; |
655 | } |
656 | tp = pp; |
657 | status = reason = -1; |
658 | jobflags = 0; |
659 | do { |
660 | jobflags |= pp->p_flags; |
661 | pstatus = pp->p_flags & PALLSTATES; |
662 | if (tp != pp && !hadnl && !(flag & FANCY) && |
663 | ((pstatus == status && pp->p_reason == reason) || |
664 | !(flag & REASON))) { |
665 | (void)fputc(' ', cshout); |
666 | hadnl = 0; |
667 | } |
668 | else { |
669 | if (tp != pp && !hadnl) { |
670 | (void)fputc('\n', cshout); |
671 | hadnl = 1; |
672 | } |
673 | if (flag & NUMBER) { |
674 | if (pp == tp) |
675 | (void)fprintf(cshout, "[%d]%s %c " , pp->p_index, |
676 | pp->p_index < 10 ? " " : "" , |
677 | pp == pcurrent ? '+' : |
678 | (pp == pprevious ? '-' : ' ')); |
679 | else |
680 | (void)fprintf(cshout, " " ); |
681 | hadnl = 0; |
682 | } |
683 | if (flag & FANCY) { |
684 | (void)fprintf(cshout, "%5ld " , (long)pp->p_pid); |
685 | hadnl = 0; |
686 | } |
687 | if (flag & (REASON | AREASON)) { |
688 | if (flag & NAME) |
689 | format = "%-23s" ; |
690 | else |
691 | format = "%s" ; |
692 | if (pstatus == status) { |
693 | if (pp->p_reason == reason) { |
694 | (void)fprintf(cshout, format, "" ); |
695 | hadnl = 0; |
696 | goto prcomd; |
697 | } |
698 | else |
699 | reason = pp->p_reason; |
700 | } else { |
701 | status = pstatus; |
702 | reason = pp->p_reason; |
703 | } |
704 | switch (status) { |
705 | case PRUNNING: |
706 | (void)fprintf(cshout, format, "Running " ); |
707 | hadnl = 0; |
708 | break; |
709 | case PINTERRUPTED: |
710 | case PSTOPPED: |
711 | case PSIGNALED: |
712 | /* |
713 | * tell what happened to the background job |
714 | * From: Michael Schroeder |
715 | * <mlschroe@immd4.informatik.uni-erlangen.de> |
716 | */ |
717 | if ((flag & REASON) |
718 | || ((flag & AREASON) |
719 | && reason != SIGINT |
720 | && (reason != SIGPIPE |
721 | || (pp->p_flags & PPOU) == 0))) { |
722 | (void)fprintf(cshout, format, |
723 | sys_siglist[(unsigned char) |
724 | pp->p_reason]); |
725 | hadnl = 0; |
726 | } |
727 | break; |
728 | case PNEXITED: |
729 | case PAEXITED: |
730 | if (flag & REASON) { |
731 | if (pp->p_reason) |
732 | (void)fprintf(cshout, "Exit %-18d" , pp->p_reason); |
733 | else |
734 | (void)fprintf(cshout, format, "Done" ); |
735 | hadnl = 0; |
736 | } |
737 | break; |
738 | default: |
739 | (void)fprintf(csherr, "BUG: status=%-9o" , status); |
740 | } |
741 | } |
742 | } |
743 | prcomd: |
744 | if (flag & NAME) { |
745 | (void)fprintf(cshout, "%s" , vis_str(pp->p_command)); |
746 | if (pp->p_flags & PPOU) |
747 | (void)fprintf(cshout, " |" ); |
748 | if (pp->p_flags & PERR) |
749 | (void)fputc('&', cshout); |
750 | hadnl = 0; |
751 | } |
752 | if (flag & (REASON | AREASON) && pp->p_flags & PDUMPED) { |
753 | (void)fprintf(cshout, " (core dumped)" ); |
754 | hadnl = 0; |
755 | } |
756 | if (tp == pp->p_friends) { |
757 | if (flag & AMPERSAND) { |
758 | (void)fprintf(cshout, " &" ); |
759 | hadnl = 0; |
760 | } |
761 | if (flag & JOBDIR && |
762 | !eq(tp->p_cwd->di_name, dcwd->di_name)) { |
763 | (void)fprintf(cshout, " (wd: " ); |
764 | dtildepr(value(STRhome), tp->p_cwd->di_name); |
765 | (void)fputc(')', cshout); |
766 | hadnl = 0; |
767 | } |
768 | } |
769 | if (pp->p_flags & PPTIME && !(status & (PSTOPPED | PRUNNING))) { |
770 | if (!hadnl) |
771 | (void)fprintf(cshout, "\n\t" ); |
772 | prusage(cshout, &zru, &pp->p_rusage, &pp->p_etime, |
773 | &pp->p_btime); |
774 | hadnl = 1; |
775 | } |
776 | if (tp == pp->p_friends) { |
777 | if (!hadnl) { |
778 | (void)fputc('\n', cshout); |
779 | hadnl = 1; |
780 | } |
781 | if (flag & SHELLDIR && !eq(tp->p_cwd->di_name, dcwd->di_name)) { |
782 | (void)fprintf(cshout, "(wd now: " ); |
783 | dtildepr(value(STRhome), dcwd->di_name); |
784 | (void)fprintf(cshout, ")\n" ); |
785 | hadnl = 1; |
786 | } |
787 | } |
788 | } while ((pp = pp->p_friends) != tp); |
789 | if (jobflags & PTIME && (jobflags & (PSTOPPED | PRUNNING)) == 0) { |
790 | if (jobflags & NUMBER) |
791 | (void)fprintf(cshout, " " ); |
792 | ptprint(tp); |
793 | hadnl = 1; |
794 | } |
795 | (void)fflush(cshout); |
796 | return (jobflags); |
797 | } |
798 | |
799 | static void |
800 | ptprint(struct process *tp) |
801 | { |
802 | static struct rusage zru; |
803 | static struct timespec ztime; |
804 | struct rusage ru; |
805 | struct timespec tetime, diff; |
806 | struct process *pp; |
807 | |
808 | pp = tp; |
809 | ru = zru; |
810 | tetime = ztime; |
811 | do { |
812 | ruadd(&ru, &pp->p_rusage); |
813 | timespecsub(&pp->p_etime, &pp->p_btime, &diff); |
814 | if (timespeccmp(&diff, &tetime, >)) |
815 | tetime = diff; |
816 | } while ((pp = pp->p_friends) != tp); |
817 | prusage(cshout, &zru, &ru, &tetime, &ztime); |
818 | } |
819 | |
820 | /* |
821 | * dojobs - print all jobs |
822 | */ |
823 | void |
824 | /*ARGSUSED*/ |
825 | dojobs(Char **v, struct command *t) |
826 | { |
827 | struct process *pp; |
828 | int flag, i; |
829 | |
830 | flag = NUMBER | NAME | REASON; |
831 | if (chkstop) |
832 | chkstop = 2; |
833 | if (*++v) { |
834 | if (v[1] || !eq(*v, STRml)) |
835 | stderror(ERR_JOBS); |
836 | flag |= FANCY | JOBDIR; |
837 | } |
838 | for (i = 1; i <= pmaxindex; i++) |
839 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
840 | if (pp->p_index == i && pp->p_pid == pp->p_jobid) { |
841 | pp->p_flags &= ~PNEEDNOTE; |
842 | if (!(pprint(pp, flag) & (PRUNNING | PSTOPPED))) |
843 | pflush(pp); |
844 | break; |
845 | } |
846 | } |
847 | |
848 | /* |
849 | * dofg - builtin - put the job into the foreground |
850 | */ |
851 | void |
852 | /*ARGSUSED*/ |
853 | dofg(Char **v, struct command *t) |
854 | { |
855 | struct process *pp; |
856 | |
857 | okpcntl(); |
858 | ++v; |
859 | do { |
860 | pp = pfind(*v); |
861 | pstart(pp, 1); |
862 | pjwait(pp); |
863 | } while (*v && *++v); |
864 | } |
865 | |
866 | /* |
867 | * %... - builtin - put the job into the foreground |
868 | */ |
869 | void |
870 | /*ARGSUSED*/ |
871 | dofg1(Char **v, struct command *t) |
872 | { |
873 | struct process *pp; |
874 | |
875 | okpcntl(); |
876 | pp = pfind(v[0]); |
877 | pstart(pp, 1); |
878 | pjwait(pp); |
879 | } |
880 | |
881 | /* |
882 | * dobg - builtin - put the job into the background |
883 | */ |
884 | void |
885 | /*ARGSUSED*/ |
886 | dobg(Char **v, struct command *t) |
887 | { |
888 | struct process *pp; |
889 | |
890 | okpcntl(); |
891 | ++v; |
892 | do { |
893 | pp = pfind(*v); |
894 | pstart(pp, 0); |
895 | } while (*v && *++v); |
896 | } |
897 | |
898 | /* |
899 | * %... & - builtin - put the job into the background |
900 | */ |
901 | void |
902 | /*ARGSUSED*/ |
903 | dobg1(Char **v, struct command *t) |
904 | { |
905 | struct process *pp; |
906 | |
907 | pp = pfind(v[0]); |
908 | pstart(pp, 0); |
909 | } |
910 | |
911 | /* |
912 | * dostop - builtin - stop the job |
913 | */ |
914 | void |
915 | /*ARGSUSED*/ |
916 | dostop(Char **v, struct command *t) |
917 | { |
918 | pkill(++v, SIGSTOP); |
919 | } |
920 | |
921 | /* |
922 | * dokill - builtin - superset of kill (1) |
923 | */ |
924 | void |
925 | /*ARGSUSED*/ |
926 | dokill(Char **v, struct command *t) |
927 | { |
928 | Char *signame; |
929 | char *name; |
930 | long signum; |
931 | char *ep; |
932 | |
933 | signum = SIGTERM; |
934 | v++; |
935 | if (v[0] && v[0][0] == '-') { |
936 | if (v[0][1] == 'l') { |
937 | if (v[1]) { |
938 | if (!Isdigit(v[1][0])) |
939 | stderror(ERR_NAME | ERR_BADSIG); |
940 | |
941 | signum = strtol(short2str(v[1]), &ep, 10); |
942 | if (signum < 0 || signum >= NSIG) |
943 | stderror(ERR_NAME | ERR_BADSIG); |
944 | else if (signum == 0) |
945 | (void)fputc('0', cshout); /* 0's symbolic name is '0' */ |
946 | else |
947 | (void)fprintf(cshout, "%s " , sys_signame[signum]); |
948 | } else { |
949 | for (signum = 1; signum < NSIG; signum++) { |
950 | (void)fprintf(cshout, "%s " , sys_signame[signum]); |
951 | if (signum == NSIG / 2) |
952 | (void)fputc('\n', cshout); |
953 | } |
954 | } |
955 | (void)fputc('\n', cshout); |
956 | return; |
957 | } |
958 | if (Isdigit(v[0][1])) { |
959 | signum = strtol(short2str(v[0] + 1), &ep, 10); |
960 | if (signum < 0 || signum >= NSIG || *ep) |
961 | stderror(ERR_NAME | ERR_BADSIG); |
962 | } |
963 | else { |
964 | if (v[0][1] == 's' && v[0][2] == '\0') |
965 | signame = *(++v); |
966 | else |
967 | signame = &v[0][1]; |
968 | |
969 | if (signame == NULL || v[1] == NULL) |
970 | stderror(ERR_NAME | ERR_TOOFEW); |
971 | |
972 | name = short2str(signame); |
973 | for (signum = 1; signum < NSIG; signum++) |
974 | if (!strcasecmp(sys_signame[signum], name) || |
975 | (!strncasecmp("SIG" , name, 3) && /* skip "SIG" prefix */ |
976 | !strcasecmp(sys_signame[signum], name + 3))) |
977 | break; |
978 | |
979 | if (signum == NSIG) { |
980 | if (signame[0] == '0') |
981 | signum = 0; |
982 | else { |
983 | setname(vis_str(signame)); |
984 | stderror(ERR_NAME | ERR_UNKSIG); |
985 | } |
986 | } |
987 | } |
988 | v++; |
989 | } |
990 | pkill(v, (int)signum); |
991 | } |
992 | |
993 | static void |
994 | pkill(Char **v, int signum) |
995 | { |
996 | struct process *pp, *np; |
997 | Char *cp; |
998 | sigset_t nsigset; |
999 | int err1, jobflags, pid; |
1000 | char *ep; |
1001 | |
1002 | jobflags = 0; |
1003 | err1 = 0; |
1004 | sigemptyset(&nsigset); |
1005 | (void)sigaddset(&nsigset, SIGCHLD); |
1006 | if (setintr) |
1007 | (void)sigaddset(&nsigset, SIGINT); |
1008 | (void)sigprocmask(SIG_BLOCK, &nsigset, NULL); |
1009 | gflag = 0, tglob(v); |
1010 | if (gflag) { |
1011 | v = globall(v); |
1012 | if (v == 0) |
1013 | stderror(ERR_NAME | ERR_NOMATCH); |
1014 | } |
1015 | else { |
1016 | v = gargv = saveblk(v); |
1017 | trim(v); |
1018 | } |
1019 | |
1020 | while (v && (cp = *v)) { |
1021 | if (*cp == '%') { |
1022 | np = pp = pfind(cp); |
1023 | do |
1024 | jobflags |= np->p_flags; |
1025 | while ((np = np->p_friends) != pp); |
1026 | switch (signum) { |
1027 | case SIGSTOP: |
1028 | case SIGTSTP: |
1029 | case SIGTTIN: |
1030 | case SIGTTOU: |
1031 | if ((jobflags & PRUNNING) == 0) { |
1032 | (void)fprintf(csherr, "%s: Already suspended\n" , |
1033 | vis_str(cp)); |
1034 | err1++; |
1035 | goto cont; |
1036 | } |
1037 | break; |
1038 | /* |
1039 | * suspend a process, kill -CONT %, then type jobs; the shell |
1040 | * says it is suspended, but it is running; thanks jaap.. |
1041 | */ |
1042 | case SIGCONT: |
1043 | pstart(pp, 0); |
1044 | goto cont; |
1045 | } |
1046 | if (kill(-pp->p_jobid, signum) < 0) { |
1047 | (void)fprintf(csherr, "%s: %s\n" , vis_str(cp), |
1048 | strerror(errno)); |
1049 | err1++; |
1050 | } |
1051 | if (signum == SIGTERM || signum == SIGHUP) |
1052 | (void)kill(-pp->p_jobid, SIGCONT); |
1053 | } |
1054 | else if (!(Isdigit(*cp) || *cp == '-')) |
1055 | stderror(ERR_NAME | ERR_JOBARGS); |
1056 | else { |
1057 | pid = (pid_t)strtoul(short2str(cp), &ep, 0); |
1058 | if (*ep) { |
1059 | (void)fprintf(csherr, "%s: Badly formed number\n" , |
1060 | short2str(cp)); |
1061 | err1++; |
1062 | goto cont; |
1063 | } else if (kill(pid, signum) < 0) { |
1064 | (void)fprintf(csherr, "%d: %s\n" , pid, strerror(errno)); |
1065 | err1++; |
1066 | goto cont; |
1067 | } |
1068 | if (signum == SIGTERM || signum == SIGHUP) |
1069 | (void)kill((pid_t) pid, SIGCONT); |
1070 | } |
1071 | cont: |
1072 | v++; |
1073 | } |
1074 | if (gargv) |
1075 | blkfree(gargv), gargv = 0; |
1076 | (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL); |
1077 | if (err1) |
1078 | stderror(ERR_SILENT); |
1079 | } |
1080 | |
1081 | /* |
1082 | * pstart - start the job in foreground/background |
1083 | */ |
1084 | void |
1085 | pstart(struct process *pp, int foregnd) |
1086 | { |
1087 | struct process *np; |
1088 | sigset_t osigset, nsigset; |
1089 | long jobflags; |
1090 | |
1091 | jobflags = 0; |
1092 | sigemptyset(&nsigset); |
1093 | (void)sigaddset(&nsigset, SIGCHLD); |
1094 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
1095 | np = pp; |
1096 | do { |
1097 | jobflags |= np->p_flags; |
1098 | if (np->p_flags & (PRUNNING | PSTOPPED)) { |
1099 | np->p_flags |= PRUNNING; |
1100 | np->p_flags &= ~PSTOPPED; |
1101 | if (foregnd) |
1102 | np->p_flags |= PFOREGND; |
1103 | else |
1104 | np->p_flags &= ~PFOREGND; |
1105 | } |
1106 | } while ((np = np->p_friends) != pp); |
1107 | if (!foregnd) |
1108 | pclrcurr(pp); |
1109 | (void)pprint(pp, foregnd ? NAME | JOBDIR : NUMBER | NAME | AMPERSAND); |
1110 | if (foregnd) |
1111 | (void)tcsetpgrp(FSHTTY, pp->p_jobid); |
1112 | if (jobflags & PSTOPPED) |
1113 | (void)kill(-pp->p_jobid, SIGCONT); |
1114 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
1115 | } |
1116 | |
1117 | void |
1118 | panystop(int neednl) |
1119 | { |
1120 | struct process *pp; |
1121 | |
1122 | chkstop = 2; |
1123 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
1124 | if (pp->p_flags & PSTOPPED) |
1125 | stderror(ERR_STOPPED, neednl ? "\n" : "" ); |
1126 | } |
1127 | |
1128 | struct process * |
1129 | pfind(Char *cp) |
1130 | { |
1131 | struct process *pp, *np; |
1132 | |
1133 | if (cp == 0 || cp[1] == 0 || eq(cp, STRcent2) || eq(cp, STRcentplus)) { |
1134 | if (pcurrent == NULL) |
1135 | stderror(ERR_NAME | ERR_JOBCUR); |
1136 | return (pcurrent); |
1137 | } |
1138 | if (eq(cp, STRcentminus) || eq(cp, STRcenthash)) { |
1139 | if (pprevious == NULL) |
1140 | stderror(ERR_NAME | ERR_JOBPREV); |
1141 | return (pprevious); |
1142 | } |
1143 | if (Isdigit(cp[1])) { |
1144 | int idx = atoi(short2str(cp + 1)); |
1145 | |
1146 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
1147 | if (pp->p_index == idx && pp->p_pid == pp->p_jobid) |
1148 | return (pp); |
1149 | stderror(ERR_NAME | ERR_NOSUCHJOB); |
1150 | } |
1151 | np = NULL; |
1152 | for (pp = proclist.p_next; pp; pp = pp->p_next) |
1153 | if (pp->p_pid == pp->p_jobid) { |
1154 | if (cp[1] == '?') { |
1155 | Char *dp; |
1156 | |
1157 | for (dp = pp->p_command; *dp; dp++) { |
1158 | if (*dp != cp[2]) |
1159 | continue; |
1160 | if (prefix(cp + 2, dp)) |
1161 | goto match; |
1162 | } |
1163 | } |
1164 | else if (prefix(cp + 1, pp->p_command)) { |
1165 | match: |
1166 | if (np) |
1167 | stderror(ERR_NAME | ERR_AMBIG); |
1168 | np = pp; |
1169 | } |
1170 | } |
1171 | if (np) |
1172 | return (np); |
1173 | stderror(ERR_NAME | (cp[1] == '?' ? ERR_JOBPAT : ERR_NOSUCHJOB)); |
1174 | /* NOTREACHED */ |
1175 | } |
1176 | |
1177 | /* |
1178 | * pgetcurr - find most recent job that is not pp, preferably stopped |
1179 | */ |
1180 | static struct process * |
1181 | pgetcurr(struct process *pp) |
1182 | { |
1183 | struct process *np, *xp; |
1184 | |
1185 | xp = NULL; |
1186 | for (np = proclist.p_next; np; np = np->p_next) |
1187 | if (np != pcurrent && np != pp && np->p_pid && |
1188 | np->p_pid == np->p_jobid) { |
1189 | if (np->p_flags & PSTOPPED) |
1190 | return (np); |
1191 | if (xp == NULL) |
1192 | xp = np; |
1193 | } |
1194 | return (xp); |
1195 | } |
1196 | |
1197 | /* |
1198 | * donotify - flag the job so as to report termination asynchronously |
1199 | */ |
1200 | void |
1201 | /*ARGSUSED*/ |
1202 | donotify(Char **v, struct command *t) |
1203 | { |
1204 | struct process *pp; |
1205 | |
1206 | pp = pfind(*++v); |
1207 | pp->p_flags |= PNOTIFY; |
1208 | } |
1209 | |
1210 | /* |
1211 | * Do the fork and whatever should be done in the child side that |
1212 | * should not be done if we are not forking at all (like for simple builtin's) |
1213 | * Also do everything that needs any signals fiddled with in the parent side |
1214 | * |
1215 | * Wanttty tells whether process and/or tty pgrps are to be manipulated: |
1216 | * -1: leave tty alone; inherit pgrp from parent |
1217 | * 0: already have tty; manipulate process pgrps only |
1218 | * 1: want to claim tty; manipulate process and tty pgrps |
1219 | * It is usually just the value of tpgrp. |
1220 | */ |
1221 | |
1222 | int |
1223 | pfork(struct command *t /* command we are forking for */, int wanttty) |
1224 | { |
1225 | int pgrp, pid; |
1226 | sigset_t osigset, nsigset; |
1227 | int ignint; |
1228 | |
1229 | ignint = 0; |
1230 | /* |
1231 | * A child will be uninterruptible only under very special conditions. |
1232 | * Remember that the semantics of '&' is implemented by disconnecting the |
1233 | * process from the tty so signals do not need to ignored just for '&'. |
1234 | * Thus signals are set to default action for children unless: we have had |
1235 | * an "onintr -" (then specifically ignored) we are not playing with |
1236 | * signals (inherit action) |
1237 | */ |
1238 | if (setintr) |
1239 | ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) |
1240 | || (gointr && eq(gointr, STRminus)); |
1241 | /* |
1242 | * Check for maximum nesting of 16 processes to avoid Forking loops |
1243 | */ |
1244 | if (child == 16) |
1245 | stderror(ERR_NESTING, 16); |
1246 | /* |
1247 | * Hold SIGCHLD until we have the process installed in our table. |
1248 | */ |
1249 | sigemptyset(&nsigset); |
1250 | (void)sigaddset(&nsigset, SIGCHLD); |
1251 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
1252 | while ((pid = fork()) < 0) |
1253 | if (setintr == 0) |
1254 | (void)sleep(FORKSLEEP); |
1255 | else { |
1256 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
1257 | stderror(ERR_NOPROC); |
1258 | } |
1259 | if (pid == 0) { |
1260 | settimes(); |
1261 | pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); |
1262 | pflushall(); |
1263 | pcurrjob = NULL; |
1264 | child++; |
1265 | if (setintr) { |
1266 | setintr = 0; /* until I think otherwise */ |
1267 | /* |
1268 | * Children just get blown away on SIGINT, SIGQUIT unless "onintr |
1269 | * -" seen. |
1270 | */ |
1271 | (void)signal(SIGINT, ignint ? SIG_IGN : SIG_DFL); |
1272 | (void)signal(SIGQUIT, ignint ? SIG_IGN : SIG_DFL); |
1273 | if (wanttty >= 0) { |
1274 | /* make stoppable */ |
1275 | (void)signal(SIGTSTP, SIG_DFL); |
1276 | (void)signal(SIGTTIN, SIG_DFL); |
1277 | (void)signal(SIGTTOU, SIG_DFL); |
1278 | } |
1279 | (void)signal(SIGTERM, parterm); |
1280 | } |
1281 | else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { |
1282 | (void)signal(SIGINT, SIG_IGN); |
1283 | (void)signal(SIGQUIT, SIG_IGN); |
1284 | } |
1285 | pgetty(wanttty, pgrp); |
1286 | /* |
1287 | * Nohup and nice apply only to NODE_COMMAND's but it would be nice |
1288 | * (?!?) if you could say "nohup (foo;bar)" Then the parser would have |
1289 | * to know about nice/nohup/time |
1290 | */ |
1291 | if (t->t_dflg & F_NOHUP) |
1292 | (void)signal(SIGHUP, SIG_IGN); |
1293 | if (t->t_dflg & F_NICE) |
1294 | (void)setpriority(PRIO_PROCESS, 0, t->t_nice); |
1295 | } |
1296 | else { |
1297 | if (wanttty >= 0) |
1298 | (void)setpgid(pid, pcurrjob ? pcurrjob->p_jobid : pid); |
1299 | palloc(pid, t); |
1300 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
1301 | } |
1302 | |
1303 | return (pid); |
1304 | } |
1305 | |
1306 | static void |
1307 | okpcntl(void) |
1308 | { |
1309 | if (tpgrp == -1) |
1310 | stderror(ERR_JOBCONTROL); |
1311 | if (tpgrp == 0) |
1312 | stderror(ERR_JOBCTRLSUB); |
1313 | /* NOTREACHED */ |
1314 | } |
1315 | |
1316 | /* |
1317 | * if we don't have vfork(), things can still go in the wrong order |
1318 | * resulting in the famous 'Stopped (tty output)'. But some systems |
1319 | * don't permit the setpgid() call, (these are more recent secure |
1320 | * systems such as ibm's aix). Then we'd rather print an error message |
1321 | * than hang the shell! |
1322 | * I am open to suggestions how to fix that. |
1323 | */ |
1324 | void |
1325 | pgetty(int wanttty, int pgrp) |
1326 | { |
1327 | sigset_t osigset, nsigset; |
1328 | |
1329 | /* |
1330 | * christos: I am blocking the tty signals till I've set things |
1331 | * correctly.... |
1332 | */ |
1333 | if (wanttty > 0) { |
1334 | sigemptyset(&nsigset); |
1335 | (void)sigaddset(&nsigset, SIGTSTP); |
1336 | (void)sigaddset(&nsigset, SIGTTIN); |
1337 | (void)sigaddset(&nsigset, SIGTTOU); |
1338 | (void)sigprocmask(SIG_BLOCK, &nsigset, &osigset); |
1339 | } |
1340 | /* |
1341 | * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> |
1342 | * Don't check for tpgrp >= 0 so even non-interactive shells give |
1343 | * background jobs process groups Same for the comparison in the other part |
1344 | * of the #ifdef |
1345 | */ |
1346 | if (wanttty >= 0) |
1347 | if (setpgid(0, pgrp) == -1) { |
1348 | (void)fprintf(csherr, "csh: setpgid error.\n" ); |
1349 | xexit(0); |
1350 | } |
1351 | |
1352 | if (wanttty > 0) { |
1353 | (void)tcsetpgrp(FSHTTY, pgrp); |
1354 | (void)sigprocmask(SIG_SETMASK, &osigset, NULL); |
1355 | } |
1356 | |
1357 | if (tpgrp > 0) |
1358 | tpgrp = 0; /* gave tty away */ |
1359 | } |
1360 | |