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