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