1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * A copy of the CDDL is also available via the Internet at
11 * http://www.opensource.org/licenses/cddl1.txt
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23
24 /*
25 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 #if defined(sun)
33 #pragma ident "@(#)jobs.c 1.28 07/05/14 SMI"
34 #endif
35
36 #include "defs.h"
37 #include "jobs.h"
38
39 /*
40 * Copyright 2008-2021 J. Schilling
41 *
42 * @(#)jobs.c 1.123 21/07/13 2008-2021 J. Schilling
43 */
44 #ifndef lint
45 static UConst char sccsid[] =
46 "@(#)jobs.c 1.123 21/07/13 2008-2021 J. Schilling";
47 #endif
48
49 /*
50 * Job control for UNIX Shell
51 */
52
53 #ifdef SCHILY_INCLUDES
54 #include <schily/ioctl.h> /* Must be before termios.h BSD botch */
55 #include <schily/termios.h>
56 #include <schily/types.h>
57 #include <schily/wait.h>
58 #include <schily/param.h>
59 #include <schily/fcntl.h>
60 #include <schily/errno.h>
61 #include <schily/times.h>
62 #include <schily/resource.h>
63 #else
64 #include <sys/termio.h>
65 #include <sys/types.h>
66 #include <sys/wait.h>
67 #include <sys/param.h>
68 #include <fcntl.h>
69 #include <errno.h>
70 #include <sys/resource.h>
71 #endif
72
73 #ifndef WCONTINUED
74 #define WCONTINUED 0 /* BSD from wait3() and POSIX */
75 #define WIFCONTINUED(s) 0 /* Can't be there without WCONTINUED */
76 #endif
77 #ifndef WIFCONTINUED
78 #define WIFCONTINUED(s) 0 /* May be missing separately */
79 #endif
80 #ifndef WNOWAIT
81 #define WNOWAIT 0 /* SVr4 / SunOS / POSIX */
82 #endif
83 #ifndef WEXITED
84 #define WEXITED 0 /* SVr4 / SunOS / POSIX */
85 #endif
86 #ifndef WTRAPPED
87 #define WTRAPPED 0 /* SVr4 / SunOS / POSIX */
88 #endif
89 #ifndef WSTOPPED /* Prefer POSIX name */
90 #ifdef WUNTRACED
91 #define WSTOPPED WUNTRACED /* SVr4 / SunOS / POSIX */
92 #else
93 #define WSTOPPED 0
94 #endif
95 #endif
96
97 #ifdef FORCE_WAITID /* Allow to enforce using waitid() to test */
98 #define HAVE_WAITID /* platforms where waitid() was considered */
99 #endif /* unasable by "configure" . */
100 #ifdef NO_WAITID
101 #undef HAVE_WAITID
102 #endif
103
104 /*
105 * The following larger block contains definitions that are needed when either
106 * waitid() is missing (e.g. SunOS-4.x) or defective (e.g. Linux, AIX, HP-UX
107 * Mac OS X).
108 */
109 #ifndef HAVE_WAITID /* Need to define everything for waitid() */
110 /*
111 * This is used to emulate waitid() via waitpid(), so we need to take
112 * care about things that don't work and things that are missing.
113 *
114 * AIX, Linux and Mac OS X, NetBSD return EINVAL if WNOWAIT is used
115 * with waitpid().
116 * XXX: We need to verify whether this is true as well with waitid().
117 */
118 #ifndef HAVE_WNOWAIT_WAITPID
119 #undef WNOWAIT
120 #define WNOWAIT 0
121 #endif
122
123 /*
124 * Minimal structure to emulate waitid() via waitpid().
125 * In case of a waitid() emulation, we mainly get a reduced si_status range.
126 */
127 #undef si_code
128 #undef si_pid
129 #undef si_status
130 #undef si_utime
131 #undef si_stime
132
133 typedef struct {
134 int si_code; /* Child status code */
135 pid_t si_pid; /* Child pid */
136 int si_status; /* Child exit code or signal number */
137 clock_t si_utime;
138 clock_t si_stime;
139 } my_siginfo_t;
140
141 #define siginfo_t my_siginfo_t
142 #undef waitid
143 #define waitid my_waitid
144 #undef id_t
145 #define id_t pid_t
146
147 /*
148 * End of definitions needed for waitid() emulation.
149 */
150 #endif /* HAVE_WAITID */
151
152 #ifdef DO_DOT_SH_PARAMS
153 static struct codename {
154 int c_code; /* The si_code value */
155 char *c_name; /* The name for si_code */
156 } _codename[] = {
157 { CLD_EXITED, "EXITED" }, /* Child normal exit() */
158 { CLD_KILLED, "KILLED" }, /* Child was killed by signal */
159 { CLD_DUMPED, "DUMPED" }, /* Killed child dumped core */
160 { CLD_TRAPPED, "TRAPPED" }, /* Traced child has stopped */
161 { CLD_STOPPED, "STOPPED" }, /* Child has stopped on signal */
162 { CLD_CONTINUED, "CONTINUED" }, /* Stopped child was continued */
163 { C_NOEXEC, "NOEXEC" }, /* No exec permissions on file */
164 { C_NOTFOUND, "NOTFOUND" } /* File not found */
165 };
166 #define CODENAMESIZE (sizeof (_codename) / sizeof (_codename[0]))
167 #endif
168
169
170 /*
171 * options to the printjob() function defined below
172 */
173 #define PR_CUR 00001 /* print job currency ('+', '-', or ' ') */
174 #define PR_JID 00002 /* print job ID */
175 #define PR_PGID 00004 /* print job's process group ID */
176 #define PR_STAT 00010 /* print status obtained from wait */
177 #define PR_CMD 00020 /* print cmd that invoked job */
178 #define PR_AMP 00040 /* print a '&' if in the background */
179 #define PR_PWD 00100 /* print jobs present working directory */
180
181 #define PR_DFL (PR_CUR|PR_JID|PR_STAT|PR_CMD) /* default options */
182 #define PR_LONG (PR_DFL|PR_PGID|PR_PWD) /* long options */
183
184 static struct termios mystty; /* default termio settings */
185 static int eofflg,
186 jobcnt, /* number of active jobs */
187 jobdone, /* number of active but finished jobs */
188 jobnote; /* jobs requiring notification */
189 static int jobfd; /* fd where stdin was moved during job */
190 #ifdef DO_PIPE_PARENT
191 static int jobsfd; /* saved topfd when jobfd > 0 */
192 #endif
193 static pid_t svpgid, /* saved process group ID */
194 svtgid; /* saved foreground process group ID */
195 static struct job *jobcur, /* active jobs listed in currency order */
196 **nextjob,
197 *thisjob,
198 *lastthisjob,
199 *joblst; /* active jobs listed in job ID order */
200
201 /*
202 * IRIX has waitjob() in libc.
203 */
204 #define waitjob sh_waitjob
205
206 static struct job *pgid2job __PR((pid_t pgid));
207 static struct job *str2job __PR((char *cmdp, char *job, int mustbejob));
208 char *code2str __PR((int code));
209 static void freejob __PR((struct job *jp));
210 void collect_fg_job __PR((void));
211 static int statjob __PR((struct job *jp,
212 siginfo_t *si, pid_t fg, int rc));
213 static void collectjobs __PR((int wnohang));
214 void freejobs __PR((void));
215 static void waitjob __PR((struct job *jp));
216 int settgid __PR((pid_t new, pid_t expexted));
217 static void restartjob __PR((struct job *jp, int fg));
218 static void printjob __PR((struct job *jp, int propts));
219 void startjobs __PR((void));
220 int endjobs __PR((int check_if));
221 void deallocjob __PR((struct job *jp));
222 pid_t curpgid __PR((void));
223 void setjobpgid __PR((pid_t pgid));
224 void resetjobfd __PR((void));
225 void setjobfd __PR((int fd, int sfd));
226 void allocjob __PR((char *cmdp,
227 unsigned char *cwdp, int monitor));
228 void clearjobs __PR((void));
229 void makejob __PR((int monitor, int fg));
230 struct job *
231 postjob __PR((pid_t pid, int fg, int blt));
232 void sysjobs __PR((int argc, unsigned char *argv[]));
233 void sysfgbg __PR((int argc, char *argv[]));
234 void syswait __PR((int argc, char *argv[]));
235 #define F_KILL 1
236 #define F_KILLPG 2
237 #define F_PGRP 3
238 #define F_SUSPEND 4
239 static void sigv __PR((char *cmdp, int sig, int f, char *args));
240 void sysstop __PR((int argc, char *argv[]));
241 static void listsigs __PR((void));
242 #if defined(DO_KILL_L_SIG) || defined(DO_GETOPT_UTILS)
243 static void namesigs __PR((char *argv[]));
244 #endif
245 void syskill __PR((int argc, char *argv[]));
246 void syssusp __PR((int argc, char *argv[]));
247 #ifdef DO_SYSPGRP
248 static void pr_pgrp __PR((pid_t pid, pid_t pgrp, pid_t sgrp));
249 void syspgrp __PR((int argc, char *argv[]));
250 #endif
251 pid_t wait_status __PR((pid_t id,
252 int *codep, int *statusp, int opts));
253 #ifdef DO_TIME
254 void prtime __PR((struct job *jp));
255 void ruget __PR((struct rusage *rup));
256 static void ruadd __PR((struct rusage *ru, struct rusage *ru2));
257 #endif
258 #ifndef HAVE_GETRUSAGE
259 int getrusage __PR((int who, struct rusage *r_usage));
260 #endif
261 #ifndef HAVE_WAITID
262 static int waitid __PR((idtype_t idtype, id_t id,
263 siginfo_t *infop, int opts));
264 #endif
265 #ifdef DO_TRAP_FROM_WAITID
266 static int didsignal __PR((siginfo_t *infop));
267 static void checksigs __PR((siginfo_t *infop));
268 #endif
269
270 #if !defined(HAVE_TCGETPGRP) && defined(TIOCGPGRP)
271 pid_t
tcgetpgrp(fd)272 tcgetpgrp(fd)
273 int fd;
274 {
275 pid_t pgid;
276 if (ioctl(fd, TIOCGPGRP, &pgid) == 0)
277 return (pgid);
278 return ((pid_t)-1);
279 }
280 #endif
281
282 #if !defined(HAVE_TCSETPGRP) && defined(TIOCSPGRP)
283 int
tcsetpgrp(fd,pgid)284 tcsetpgrp(fd, pgid)
285 int fd;
286 pid_t pgid;
287 {
288 return (ioctl(fd, TIOCSPGRP, &pgid));
289 }
290 #endif
291
292 #ifdef PROTOTYPES
293 static struct job *
pgid2job(pid_t pgid)294 pgid2job(pid_t pgid)
295 #else
296 static struct job *
297 pgid2job(pgid)
298 pid_t pgid;
299 #endif
300 {
301 struct job *jp;
302
303 for (jp = joblst; jp != 0 && jp->j_pid != pgid; jp = jp->j_nxtp)
304 /* LINTED */
305 ;
306
307 return (jp);
308 }
309
310 static struct job *
str2job(cmdp,job,mustbejob)311 str2job(cmdp, job, mustbejob)
312 char *cmdp;
313 char *job;
314 int mustbejob;
315 {
316 struct job *jp, *njp;
317 int i;
318
319 if (*job != '%')
320 jp = pgid2job(stoi((unsigned char *)job));
321 else if (*++job == 0 || *job == '+' || *job == '%' || *job == '-') {
322 jp = jobcur;
323 if (*job == '-' && jp)
324 jp = jp->j_curp;
325 } else if (*job >= '0' && *job <= '9') {
326 i = stoi((unsigned char *)job);
327 for (jp = joblst; jp && jp->j_jid != i; jp = jp->j_nxtp)
328 /* LINTED */
329 ;
330 } else if (*job == '?') {
331 int j;
332 char *p;
333 i = strlen(++job);
334 jp = 0;
335 for (njp = jobcur; njp; njp = njp->j_curp) {
336 if (njp->j_jid == 0)
337 continue;
338 for (p = njp->j_cmd, j = strlen(p); j >= i; p++, j--) {
339 if (strncmp(job, p, i) == 0) {
340 if (jp != 0) {
341 Failure((unsigned char *)cmdp,
342 ambiguous);
343 return ((struct job *)0);
344 }
345 jp = njp;
346 break;
347 }
348 }
349 }
350 } else {
351 i = strlen(job);
352 jp = 0;
353 for (njp = jobcur; njp; njp = njp->j_curp) {
354 if (njp->j_jid == 0)
355 continue;
356 if (strncmp(job, njp->j_cmd, i) == 0) {
357 if (jp != 0) {
358 Failure((unsigned char *)cmdp,
359 ambiguous);
360 return ((struct job *)0);
361 }
362 jp = njp;
363 }
364 }
365 }
366
367 if (mustbejob && (jp == 0 || jp->j_jid == 0)) {
368 Failure((unsigned char *)cmdp, nosuchjob);
369 return ((struct job *)0);
370 }
371 return (jp);
372 }
373
374 #ifdef DO_DOT_SH_PARAMS
375 char *
code2str(code)376 code2str(code)
377 int code;
378 {
379 int i;
380
381 for (i = 0; i < CODENAMESIZE; i++) {
382 if (code == _codename[i].c_code)
383 return (_codename[i].c_name);
384 }
385 return ("UNKNOWN");
386 }
387 #endif
388
389 static void
freejob(jp)390 freejob(jp)
391 struct job *jp;
392 {
393 struct job **njp;
394 struct job **cjp;
395
396 for (njp = &joblst; *njp && *njp != jp; njp = &(*njp)->j_nxtp)
397 /* LINTED */
398 ;
399
400 for (cjp = &jobcur; *cjp && *cjp != jp; cjp = &(*cjp)->j_curp)
401 /* LINTED */
402 ;
403
404 *njp = jp->j_nxtp;
405 *cjp = jp->j_curp;
406 free(jp);
407 if (jp == thisjob)
408 thisjob = NULL;
409 jobcnt--;
410 jobdone--;
411 }
412
413 /*
414 * Collect the foreground job.
415 * Used in the case where the subshell wants
416 * to exit, but needs to wait until the fg job
417 * is done.
418 */
419 void
collect_fg_job()420 collect_fg_job()
421 {
422 struct job *jp;
423 int err;
424 siginfo_t si;
425
426 for (jp = joblst; jp; jp = jp->j_nxtp)
427 if (jp->j_flag & J_FOREGND)
428 break;
429
430 if (!jp)
431 /* no foreground job */
432 return;
433
434 /*
435 * Wait on fg job until wait succeeds
436 * or it fails due to no waitable children.
437 */
438
439 /* CONSTCOND */
440 while (1) {
441 errno = 0;
442 si.si_pid = 0;
443 err = waitid(P_PID, jp->j_pid, &si, (WEXITED|WTRAPPED));
444 #ifdef DO_TRAP_FROM_WAITID
445 checksigs(&si); /* fault() with jobcontrol */
446 #endif
447 if (si.si_pid == jp->j_pid || (err == -1 && errno == ECHILD))
448 break;
449 }
450 }
451
452 /*
453 * analyze the status of a job
454 *
455 * On platforms with an incomplete and buggy waitid()/waitpid() implementation
456 * like Linux, we pass the process group id of the process, we did wait for in
457 * the parameter "fg". This value has been obtained before waitid() was called.
458 * Since WNOWAIT does not work and as a result, the related process no longer
459 * exists, we cannot call getpgid() here anymore.
460 */
461 static int
statjob(jp,si,fg,rc)462 statjob(jp, si, fg, rc)
463 struct job *jp; /* Job pointer for this job */
464 siginfo_t *si; /* Siginfo for the child to stat */
465 pid_t fg; /* Whether this is a foreground job */
466 int rc; /* Whether to set "exitcode" */
467 {
468 int code = si->si_code;
469 pid_t tgid;
470 int jdone = 0;
471
472 jp->j_xcode = code;
473 if (code == CLD_CONTINUED) {
474 if (jp->j_flag & J_STOPPED) {
475 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
476 jp->j_flag |= J_RUNNING;
477 if (!fg && jp->j_jid) {
478 jp->j_flag |= J_NOTIFY;
479 jobnote++;
480 }
481 }
482 } else if (code == CLD_STOPPED || code == CLD_TRAPPED) {
483 jp->j_xval = si->si_status; /* Stopsig */
484 jp->j_flag &= ~J_RUNNING;
485 jp->j_flag |= (J_SIGNALED|J_STOPPED);
486 jp->j_pgid = getpgid(jp->j_pid);
487 jp->j_tgid = jp->j_pgid;
488 if (fg) {
489 if ((tgid = settgid(mypgid, jp->j_pgid)) != 0)
490 jp->j_tgid = tgid;
491 else {
492 int fd = STDIN_FILENO;
493
494 jp->j_flag |= J_SAVETTY;
495 if (tcgetattr(fd, &jp->j_stty) < 0 &&
496 jobfd > 0 && !isatty(fd)) {
497 tcgetattr(fd = jobfd, &jp->j_stty);
498 }
499 (void) tcsetattr(fd, TCSANOW, &mystty);
500 }
501 }
502 if (jp->j_jid) {
503 jp->j_flag |= J_NOTIFY;
504 jobnote++;
505 }
506 } else {
507 jp->j_flag &= ~J_RUNNING;
508 jp->j_flag |= J_DONE;
509 jdone++;
510 jobdone++;
511 if (code == CLD_KILLED || code == CLD_DUMPED) {
512 jp->j_xval = si->si_status; /* Termsig */
513 jp->j_flag |= J_SIGNALED;
514 if (code == CLD_DUMPED)
515 jp->j_flag |= J_DUMPED;
516 if (!fg || jp->j_xval != SIGINT) {
517 jp->j_flag |= J_NOTIFY;
518 jobnote++;
519 }
520 } else { /* CLD_EXITED */
521 jp->j_xval = si->si_status; /* Exit status */
522 jp->j_flag &= ~J_SIGNALED;
523 if (!fg && jp->j_jid) {
524 jp->j_flag |= J_NOTIFY;
525 jobnote++;
526 }
527 #ifdef DO_DOL_SLASH
528 if (jp->j_xval == ERR_NOTFOUND &&
529 *excausep == C_NOTFOUND) {
530 jp->j_xcode = C_NOTFOUND;
531 *excausep = 0;
532 }
533 if (jp->j_xval == ERR_NOEXEC &&
534 *excausep == C_NOEXEC) {
535 jp->j_xcode = C_NOEXEC;
536 *excausep = 0;
537 }
538 #endif
539 }
540 if (fg) {
541 pid_t jgid = getpgid(jp->j_pid);
542
543 #if WNOWAIT == 0 /* Hack for Linux et al */
544 if (jgid == (pid_t)-1 && fg != (pid_t)-1)
545 jgid = fg;
546 #endif
547 /*
548 * The previous hack was to use "svpgid" in case that
549 * "jgid" was -1. This turned out to give problems with
550 * dosh 'nroff -u1 -Tlp -man $@ | col -x' | more
551 * but it turned out that "mypgid" was a better
552 * approximation. Since we now get the value from "fg",
553 * we go back to the original implementation for the
554 * second settgid() call.
555 */
556 if (!settgid(mypgid, jp->j_pgid) ||
557 !settgid(mypgid, jgid)) {
558 int fd = STDIN_FILENO;
559
560 if (tcgetattr(fd, &mystty) < 0 &&
561 jobfd > 0 && !isatty(fd))
562 tcgetattr(jobfd, &mystty);
563 }
564 }
565 }
566 if (rc) {
567 /*
568 * First check whether we have a prefilled exit code
569 * from a previous vfork()d child that matches this child.
570 */
571 if (ex.ex_code < C_NOEXEC || ex.ex_pid != si->si_pid) {
572 ex.ex_status = exitval = jp->j_xval;
573 ex.ex_code = jp->j_xcode;
574 ex.ex_pid = si->si_pid;
575 }
576 #ifdef SIGCHLD
577 ex.ex_signo = SIGCHLD;
578 #else
579 ex.ex_signo = 1000; /* Need to distinct this from builtin */
580 #endif
581 jp->j_xsig = ex.ex_signo;
582
583 if ((flags2 & fullexitcodeflg) == 0)
584 exitval &= 0xFF; /* As dumb as with historic wait */
585 if (jp->j_flag & J_SIGNALED)
586 exitval |= SIGFLG;
587 #ifdef DO_EXIT_MODFIX
588 else if (ex.ex_status != 0 && exitval == 0)
589 exitval = SIGFLG; /* Use special value 128 */
590 #endif
591 exitset(); /* Set retval from exitval for $? */
592 }
593 if (jdone && !(jp->j_flag & J_NOTIFY))
594 freejob(jp);
595 return (jdone);
596 }
597
598 /*
599 * collect the status of jobs that have recently exited or stopped -
600 * if wnohang == WNOHANG, wait until error, or all jobs are accounted for;
601 *
602 * called after each command is executed, with wnohang == 0, and as part
603 * of "wait" builtin with wnohang == WNOHANG
604 *
605 * We do not need to call chktrap here if waitpid(2) is called with
606 * wnohang == 0, because that only happens from syswait() which is called
607 * from builtin() where chktrap() is already called.
608 */
609 static void
collectjobs(wnohang)610 collectjobs(wnohang)
611 int wnohang;
612 {
613 pid_t pid;
614 struct job *jp;
615 int n;
616 siginfo_t si;
617 int wflags;
618
619 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
620 wflags = WSTOPPED|WCONTINUED;
621 else
622 wflags = 0;
623 wflags |= (WEXITED|WTRAPPED); /* Needed for waitid() */
624
625 for (n = jobcnt - jobdone; n > 0; n--) {
626 if (waitid(P_ALL, 0, &si, wnohang|wflags) < 0)
627 break;
628 #ifdef DO_TRAP_FROM_WAITID
629 checksigs(&si); /* fault() with jobcontrol */
630 #endif
631 pid = si.si_pid;
632 if (pid == 0)
633 break;
634 if ((jp = pgid2job(pid)) != NULL)
635 (void) statjob(jp, &si, 0, 0);
636 }
637 }
638
639 void
freejobs()640 freejobs()
641 {
642 struct job *jp;
643
644 collectjobs(WNOHANG);
645
646 if (jobnote) {
647 int save_fd = setb(STDERR_FILENO);
648 for (jp = joblst; jp; jp = jp->j_nxtp) {
649 if (jp->j_flag & J_NOTIFY) {
650 if (jp->j_jid)
651 printjob(jp, PR_DFL);
652 else if (jp->j_flag & J_FOREGND)
653 printjob(jp, PR_STAT);
654 else
655 printjob(jp, PR_STAT|PR_PGID);
656 }
657 }
658 (void) setb(save_fd);
659 }
660
661 if (jobdone) {
662 struct job *sjp;
663
664 for (jp = joblst; jp; jp = sjp) {
665 sjp = jp->j_nxtp;
666 #ifdef DO_POSIX_WAIT
667 if ((jp->j_flag & (J_DONE|J_REPORTED)) ==
668 (J_DONE|J_REPORTED))
669 freejob(jp);
670 #else
671 if (jp->j_flag & J_DONE)
672 freejob(jp);
673 #endif
674 }
675 }
676 }
677
678 /*
679 * Always called for a foreground job.
680 */
681 static void
waitjob(jp)682 waitjob(jp)
683 struct job *jp;
684 {
685 siginfo_t si;
686 int jdone;
687 pid_t pid = jp->j_pid;
688 int wflags;
689 int ret = 0;
690 int err = 0;
691 #ifdef DO_TIME
692 struct job j;
693 #endif
694 #if WNOWAIT == 0 /* This is AIX, Linux, Mac OS X or NetBSD. */
695 pid_t jgid; /* Needed because waitid() always reaps child */
696 #endif /* on the incomplete implementation there. */
697
698 #ifdef DO_TIME
699 ruget(&jp->j_rustart);
700 #endif
701
702 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
703 wflags = WSTOPPED;
704 else
705 wflags = 0;
706 wflags |= (WEXITED|WTRAPPED); /* Needed for waitid() */
707 #if WNOWAIT == 0
708 jgid = getpgid(pid); /* Get it now, we can't do it later */
709 #endif
710 do {
711 errno = 0;
712 ret = waitid(P_PID, pid, &si, wflags|WNOWAIT);
713 err = errno;
714 if (ret == -1 && err == ECHILD) { /* No children */
715 si.si_status = 0;
716 si.si_code = 0;
717 si.si_pid = 0;
718 break;
719 }
720 /*
721 * si.si_pid == 0: no status is available for pid
722 */
723
724 #ifdef DO_TRAP_FROM_WAITID
725 checksigs(&si); /* fault() with jobcontrol */
726 #endif
727 } while (si.si_pid != pid);
728
729 #if WNOWAIT != 0
730 /*
731 * On a complete waitid() implementation, we have WNOWAIT and thus are
732 * able to get the real process group for pid as the process still
733 * exists. Other systems may not have set the final process group of
734 * this pid before we start to waid and after the wait, the process
735 * cannot be retrieved anymore as it was already removed.
736 * To be always able to retrieve the progcess group for pid, we need
737 * to call statjob() here.
738 */
739 #ifdef DO_TIME
740 j = *jp;
741 #endif
742 jdone = statjob(jp, &si, 1, 1); /* Sets exitval, see below */
743 /*
744 * Avoid hang on FreeBSD, so wait/reap here only for died children.
745 */
746 if (si.si_code != CLD_STOPPED && si.si_code != CLD_TRAPPED) {
747 siginfo_t si2;
748
749 waitid(P_PID, pid, &si2, wflags);
750 #ifdef __needed__ /* Only on real SVr4 */
751 /* or on our emulation */
752 /* FreeBSD misses si_utime */
753 si.si_utime = si2.si_utime;
754 si.si_stime = si2.si_stime;
755 #endif
756 }
757 #else /* WNOWAIT == 0 */
758 /*
759 * Inclomplete waitid() implementation (e.g. Linux). We may fail
760 * to get the right process group for pid and fail to restore
761 * our process group in the terninal.
762 */
763 #ifdef DO_TIME
764 j = *jp;
765 #endif
766 jdone = statjob(jp, &si, jgid, 1); /* Sets exitval, see below */
767 #endif /* WNOWAIT != 0 */
768
769 #ifdef DO_PIPE_PARENT
770 /*
771 * This is a hack for now as long as we don't have a node for every
772 * process created by the main shell. We currently don't know whether
773 * we may call waitid() without WNOHANG. Currently we may miss a
774 * process for every pipeline we create and catch it only with the
775 * next foreground command.
776 */
777 /* CONSTCOND */
778 while (1) {
779 errno = 0;
780 si.si_pid = 0;
781 err = waitid(P_ALL, 0, &si, wflags|WCONTINUED|WNOHANG);
782 if (si.si_pid == 0 || (err == -1 && errno == ECHILD))
783 break;
784 #ifdef DO_TRAP_FROM_WAITID
785 checksigs(&si); /* fault() with jobcontrol */
786 #endif
787 if ((jp = pgid2job(si.si_pid)) != NULL)
788 (void) statjob(jp, &si, 0, 0);
789 }
790 #endif
791
792 #ifdef DO_TIME
793 /*
794 * Currently, jp is free()d by statjob() and we need to use a copy.
795 * This may change once we introduce an own process node for every
796 * process from a pipe created with DO_PIPE_PARENT.
797 */
798 if ((flags2 & (timeflg | systime)) == timeflg)
799 prtime(&j);
800 #endif
801
802 if (jdone && exitval && (flags & errflg))
803 exitsh(exitval);
804 flags |= eflag;
805 }
806
807 /*
808 * modify the foreground process group to *new* only if the
809 * current foreground process group is equal to *expected*
810 */
811 int
settgid(new,expected)812 settgid(new, expected)
813 pid_t new;
814 pid_t expected;
815 {
816 int fd = STDIN_FILENO;
817 pid_t current = tcgetpgrp(fd);
818
819 #ifdef JOB_DEBUG
820 fprintf(stderr, "settgid(new %ld, expected %ld) current %ld\n",
821 (long)new, (long)expected, (long)current);
822 #endif
823 /*
824 * "current" may be -1 in case that STDIN_FILENO was a renamed pipe,
825 * and errno in this case will be ENOTTY or EINVAL.
826 * Try to use the moved stdin in this case.
827 */
828 if (current == (pid_t)-1 && jobfd > 0 && !isatty(fd))
829 current = tcgetpgrp(fd = jobfd);
830
831 /*
832 * Another case is when tcgetpgrp() worked but returned a different id
833 * than expected. Do not try to call tcsetpgrp() in any of the cases.
834 */
835 if (current != expected) {
836 /*
837 * POSIX says: tcgetpgrp() returns a nonexisting process group
838 * id when no foreground process group was set up.
839 *
840 * Some older Linux versions (e.g. 2.6.18) return a nonexisting
841 * pgrp in case no process from the expected process group
842 * exists anymore. If no process with the returned process group
843 * exists, pretend success - otherwise return (current).
844 */
845 errno = 0;
846 if (current == (pid_t)-1 ||
847 kill(-current, 0) >= 0 || errno != ESRCH)
848 return (current);
849 }
850
851 if (new != current)
852 tcsetpgrp(fd, new);
853
854 return (0);
855 }
856
857 static void
restartjob(jp,fg)858 restartjob(jp, fg)
859 struct job *jp;
860 int fg;
861 {
862 if (jp == NULL)
863 return;
864 if (jp != jobcur) {
865 struct job *t;
866 for (t = jobcur; t->j_curp != jp; t = t->j_curp)
867 /* LINTED */
868 ;
869 t->j_curp = jp->j_curp;
870 jp->j_curp = jobcur;
871 jobcur = jp;
872 }
873 if (fg) {
874 if (jp->j_flag & J_SAVETTY) {
875 jp->j_stty.c_lflag &= ~TOSTOP;
876 jp->j_stty.c_lflag |= (mystty.c_lflag&TOSTOP);
877 jp->j_stty.c_cc[VSUSP] = mystty.c_cc[VSUSP];
878 #ifdef VDSUSP
879 jp->j_stty.c_cc[VDSUSP] = mystty.c_cc[VDSUSP];
880 #endif
881 (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &jp->j_stty);
882 }
883 (void) settgid(jp->j_tgid, mypgid);
884 }
885 /*
886 * First explicitly continue the foreground process as we otherwise may
887 * get a CLD_STOPPED message from waitid() in case of a longer pipeline
888 * where it may take some time to wakeup all processes from a group.
889 */
890 #ifdef SIGCONT
891 #ifdef DO_POSIX_WAIT
892 if (lastthisjob)
893 (void) kill(lastthisjob->j_pid, SIGCONT);
894 else if (thisjob)
895 #endif
896 (void) kill(thisjob->j_pid, SIGCONT);
897 (void) kill(-(jp->j_pgid), SIGCONT);
898 if (jp->j_tgid != jp->j_pgid)
899 (void) kill(-(jp->j_tgid), SIGCONT);
900 #endif
901 jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY);
902 jp->j_flag |= J_RUNNING;
903 if (fg) {
904 jp->j_flag |= J_FOREGND;
905 printjob(jp, PR_JID|PR_CMD);
906 waitjob(jp);
907 } else {
908 jp->j_flag &= ~J_FOREGND;
909 printjob(jp, PR_JID|PR_CMD|PR_AMP);
910 }
911 }
912
913 static void
printjob(jp,propts)914 printjob(jp, propts)
915 struct job *jp;
916 int propts;
917 {
918 int sp = 0;
919
920 if (jp == NULL)
921 return;
922 if (jp->j_flag & J_NOTIFY) {
923 jobnote--;
924 jp->j_flag &= ~J_NOTIFY;
925 }
926
927 if (propts & PR_JID) {
928 prc_buff('[');
929 prn_buff(jp->j_jid);
930 prc_buff(']');
931 sp = 1;
932 }
933
934 if (propts & PR_CUR) {
935 while (sp-- > 0)
936 prc_buff(SPACE);
937 sp = 1;
938 if (jobcur == jp)
939 prc_buff('+');
940 else if (jobcur != 0 && jobcur->j_curp == jp)
941 prc_buff('-');
942 else
943 sp++;
944 }
945
946 if (propts & PR_PGID) {
947 while (sp-- > 0)
948 prc_buff(SPACE);
949 prn_buff(jp->j_pgid);
950 sp = 1;
951 }
952
953 if (propts & PR_STAT) {
954 const char *gmsg;
955 while (sp-- > 0)
956 prc_buff(SPACE);
957 sp = 28;
958 if (jp->j_flag & J_SIGNALED) {
959 const char *sigstr;
960
961 if ((sigstr = strsignal(jp->j_xval)) != NULL) {
962 sp -= strlen(sigstr);
963 prs_buff((unsigned char *)sigstr);
964 } else {
965 sitos(jp->j_xval);
966 gmsg = gettext(signalnum);
967 sp -= strlen((char *)numbuf) + strlen(gmsg);
968 prs_buff((unsigned char *)gmsg);
969 prs_buff(numbuf);
970 }
971 if (jp->j_flag & J_DUMPED) {
972 gmsg = gettext(coredump);
973 sp -= strlen(gmsg);
974 prs_buff((unsigned char *)gmsg);
975 }
976 } else if (jp->j_flag & J_DONE) {
977 sitos(jp->j_xval);
978 gmsg = gettext(exited);
979 sp -= strlen(gmsg) + strlen((char *)numbuf) + 2;
980 prs_buff((unsigned char *)gmsg);
981 prc_buff('(');
982 sitos(jp->j_xval);
983 prs_buff(numbuf);
984 prc_buff(')');
985 } else {
986 gmsg = gettext(running);
987 sp -= strlen(gmsg);
988 prs_buff((unsigned char *)gmsg);
989 }
990 if (sp < 1)
991 sp = 1;
992 }
993
994 if (propts & PR_CMD) {
995 while (sp-- > 0)
996 prc_buff(SPACE);
997 prs_buff((unsigned char *)jp->j_cmd);
998 sp = 1;
999 }
1000
1001 if (propts & PR_AMP) {
1002 while (sp-- > 0)
1003 prc_buff(SPACE);
1004 prc_buff('&');
1005 sp = 1;
1006 }
1007
1008 if (propts & PR_PWD) {
1009 while (sp-- > 0)
1010 prc_buff(SPACE);
1011 prs_buff((unsigned char *)"(wd: ");
1012 prs_buff((unsigned char *)jp->j_pwd);
1013 prc_buff(')');
1014 }
1015
1016 prc_buff(NL);
1017 flushb();
1018 }
1019
1020 /*
1021 * called to initialize job control for each new input file to the shell,
1022 * and after the "exec" builtin
1023 */
1024 void
startjobs()1025 startjobs()
1026 {
1027 svpgid = mypgid;
1028
1029 if (tcgetattr(STDIN_FILENO, &mystty) == -1 ||
1030 (svtgid = tcgetpgrp(STDIN_FILENO)) == -1) {
1031 flags &= ~jcflg;
1032 return;
1033 }
1034
1035 flags |= jcflg;
1036
1037 #ifdef SIGTTOU
1038 handle(SIGTTOU, SIG_IGN);
1039 #endif
1040 #ifdef SIGTSTP
1041 handle(SIGTSTP, SIG_DFL);
1042 #endif
1043
1044 if (mysid != mypgid) {
1045 setpgid(0, 0); /* Make me a process group leader */
1046 mypgid = mypid; /* and remember my new pgid */
1047 (void) settgid(mypgid, svpgid); /* and set up my tty pgrp */
1048 }
1049 }
1050
1051 int
endjobs(check_if)1052 endjobs(check_if)
1053 int check_if;
1054 {
1055 if ((flags & (jcoff|jcflg)) != jcflg)
1056 return (1);
1057
1058 if (check_if && jobcnt && eofflg++ == 0) {
1059 struct job *jp;
1060 if (check_if & JOB_STOPPED) {
1061 for (jp = joblst; jp; jp = jp->j_nxtp) {
1062 if (jp->j_jid && (jp->j_flag & J_STOPPED)) {
1063 prs(_gettext(jobsstopped));
1064 prc(NL);
1065 return (0);
1066 }
1067 }
1068 }
1069 if (check_if & JOB_RUNNING) {
1070 for (jp = joblst; jp; jp = jp->j_nxtp) {
1071 if (jp->j_jid && (jp->j_flag & J_RUNNING)) {
1072 prs(_gettext(jobsrunning));
1073 prc(NL);
1074 return (0);
1075 }
1076 }
1077 }
1078 }
1079
1080 if (svpgid != mypgid) {
1081 (void) settgid(svtgid, mypgid);
1082 setpgid(0, svpgid);
1083 }
1084
1085 return (1);
1086 }
1087
1088 /*
1089 * Called by the shell to destroy a job slot from allocjob() if spawn failed.
1090 * We need to check whether we really need to have the jp parameter for
1091 * timing of builtin commands.
1092 */
1093 void
deallocjob(jp)1094 deallocjob(jp)
1095 struct job *jp;
1096 {
1097 if (jp == NULL)
1098 jp = thisjob;
1099 free(jp);
1100 if (jp == thisjob)
1101 thisjob = NULL;
1102 jobcnt--;
1103 }
1104
1105 void
clearcurjob()1106 clearcurjob()
1107 {
1108 #ifdef DO_POSIX_WAIT
1109 lastthisjob = thisjob; /* remember this for fg(1) command */
1110 thisjob = NULL;
1111 #endif
1112 }
1113
1114 #ifdef DO_PIPE_PARENT
1115 void *
curjob()1116 curjob()
1117 {
1118 return (thisjob);
1119 }
1120
1121 /*
1122 * Return current process group id.
1123 */
1124 pid_t
curpgid()1125 curpgid()
1126 {
1127 if (!thisjob)
1128 return (0);
1129 return (thisjob->j_pgid);
1130 }
1131
1132 /*
1133 * Set up "pgid" as process group id in case this has not been done already.
1134 */
1135 void
setjobpgid(pgid)1136 setjobpgid(pgid)
1137 pid_t pgid;
1138 {
1139 if (!thisjob)
1140 return;
1141 if (thisjob->j_jid) {
1142 thisjob->j_pgid = pgid;
1143 } else {
1144 thisjob->j_pgid = mypgid;
1145 }
1146 }
1147
1148 void
setjobfd(fd,sfd)1149 setjobfd(fd, sfd)
1150 int fd;
1151 int sfd;
1152 {
1153 jobfd = fd;
1154 jobsfd = sfd;
1155 }
1156
1157 void
resetjobfd()1158 resetjobfd()
1159 {
1160 /*
1161 * Restore stdin in case it was moved away.
1162 */
1163 if (jobfd > 0) {
1164 restore(jobsfd);
1165 jobsfd = jobfd = 0;
1166 }
1167 }
1168 #endif /* DO_PIPE_PARENT */
1169
1170 /*
1171 * Called by the shell to reserve a job slot for a job about to be spawned.
1172 * Resulting job slot is in "thisjob".
1173 */
1174 void
allocjob(cmdp,cwdp,monitor)1175 allocjob(cmdp, cwdp, monitor)
1176 char *cmdp;
1177 unsigned char *cwdp;
1178 int monitor;
1179 {
1180 struct job *jp, **jpp;
1181 int jid, cmdlen, cwdlen;
1182
1183 cmdlen = strlen(cmdp) + 1;
1184 if (cmdlen > 1 && cmdp[cmdlen-2] == '&') {
1185 cmdp[cmdlen-3] = 0;
1186 cmdlen -= 2;
1187 }
1188 cwdlen = strlen((char *)cwdp) + 1;
1189 jp = (struct job *) alloc(sizeof (struct job) + cmdlen + cwdlen);
1190 if (jp == 0)
1191 error(nostack);
1192 jobcnt++;
1193 jp->j_cmd = ((char *)jp) + sizeof (struct job);
1194 strcpy(jp->j_cmd, cmdp);
1195 jp->j_pwd = jp->j_cmd + cmdlen;
1196 strcpy(jp->j_pwd, (char *)cwdp);
1197 jp->j_nxtp = jp->j_curp = NULL;
1198 jp->j_flag = 0;
1199 jp->j_pid = jp->j_pgid = jp->j_tgid = 0;
1200 jp->j_xval = 0;
1201 jp->j_xcode = 0;
1202 jp->j_xsig = 0;
1203
1204 jpp = &joblst;
1205
1206 if (monitor) {
1207 /*
1208 * First skip all jobs without job id.
1209 */
1210 for (; *jpp; jpp = &(*jpp)->j_nxtp)
1211 if ((*jpp)->j_jid != 0)
1212 break;
1213 /*
1214 * Now find the end of the job list or the first
1215 * location where the job numbers are no longer
1216 * contiguous.
1217 */
1218 for (jid = 1; *jpp; jpp = &(*jpp)->j_nxtp, jid++)
1219 if ((*jpp)->j_jid != jid)
1220 break;
1221 } else
1222 jid = 0;
1223
1224 jp->j_jid = jid;
1225 nextjob = jpp; /* Remember where to insert this job via postjob() */
1226 thisjob = jp; /* This job is going to be inserted by postjob() */
1227 }
1228
1229 void
clearjobs()1230 clearjobs()
1231 {
1232 struct job *jp, *sjp;
1233
1234 for (jp = joblst; jp; jp = sjp) {
1235 sjp = jp->j_nxtp;
1236 #ifdef DO_POSIX_WAIT
1237 if ((jp->j_flag & (J_DONE|J_REPORTED)) ==
1238 (J_DONE|J_REPORTED))
1239 #endif
1240 free(jp);
1241 }
1242 joblst = NULL;
1243 jobcnt = 0;
1244 jobnote = 0;
1245 jobdone = 0;
1246 }
1247
1248 void
makejob(monitor,fg)1249 makejob(monitor, fg)
1250 int monitor;
1251 int fg;
1252 {
1253 if (monitor) {
1254 #ifndef DO_PIPE_PARENT
1255 mypgid = mypid;
1256 setpgid(0, 0);
1257 if (fg)
1258 tcsetpgrp(STDIN_FILENO, mypid);
1259 #endif
1260 #ifdef SIGTTOU
1261 handle(SIGTTOU, SIG_DFL);
1262 #endif
1263 #ifdef SIGTSTP
1264 handle(SIGTSTP, SIG_DFL);
1265 #endif
1266 } else if (!fg) {
1267 #ifdef HAVE_NICE
1268 #ifdef DO_BGNICE
1269 if (flags2 & bgniceflg)
1270 nice(5);
1271 #else
1272 #ifdef NICE
1273 nice(NICE);
1274 #endif
1275 #endif
1276 #endif
1277 #ifdef SIGTTIN
1278 handle(SIGTTIN, SIG_IGN);
1279 #endif
1280 handle(SIGINT, SIG_IGN);
1281 handle(SIGQUIT, SIG_IGN);
1282 if (!ioset)
1283 renamef(chkopen((unsigned char *)devnull, O_RDONLY),
1284 STDIN_FILENO);
1285 }
1286 }
1287
1288 /*
1289 * called by the shell after job has been spawned, to fill in the
1290 * job slot, and wait for the job if in the foreground
1291 */
1292 struct job *
postjob(pid,fg,blt)1293 postjob(pid, fg, blt)
1294 pid_t pid; /* The pid of the new job */
1295 int fg; /* Whether this is a foreground job */
1296 int blt; /* Whether this is a temp slot for a builtin */
1297 {
1298 int propts;
1299
1300 if (!blt) { /* Do not connect slots for builtin commands */
1301 if (*nextjob != joblst) /* Avoid joblst loop */
1302 thisjob->j_nxtp = *nextjob;
1303 *nextjob = thisjob;
1304 thisjob->j_curp = jobcur;
1305 jobcur = thisjob;
1306 }
1307
1308 /*
1309 * In case of the historic pipe setup, the rightmost program in a pipe
1310 * was the process group leader and it's pid was equal to j_pgid.
1311 * With the new optimized pipe setup where the shell is the parent
1312 * of all pipe processes, the process group leader is the leftmost
1313 * program in a pipe. postjob() hoewver is called for the rightmost
1314 * program as we wait for it.
1315 * We thus are not allowed to overwrite j_pgid in the latter case after
1316 * it has been set up for the process group leader via setjobpgid().
1317 */
1318 if (thisjob->j_jid) {
1319 if (thisjob->j_pgid == 0)
1320 thisjob->j_pgid = pid;
1321 propts = PR_JID|PR_PGID;
1322 } else {
1323 if (thisjob->j_pgid == 0)
1324 thisjob->j_pgid = mypgid;
1325 propts = PR_PGID;
1326 }
1327
1328 #ifdef DO_TIME
1329 gettimeofday(&thisjob->j_start, NULL);
1330 #endif
1331 thisjob->j_flag = J_RUNNING;
1332 thisjob->j_tgid = thisjob->j_pgid;
1333 thisjob->j_pid = pid;
1334 eofflg = 0;
1335
1336 if (fg) {
1337 thisjob->j_flag |= J_FOREGND;
1338 if (blt) {
1339 thisjob->j_flag |= J_BLTIN;
1340 #ifdef DO_TIME
1341 ruget(&thisjob->j_rustart);
1342 #endif
1343 } else {
1344 waitjob(thisjob);
1345 }
1346 } else {
1347 if (flags & ttyflg)
1348 printjob(thisjob, propts);
1349 assnum(&pcsadr, (long)pid);
1350 }
1351 return (thisjob);
1352 }
1353
1354 /*
1355 * the builtin "jobs" command
1356 */
1357 void
sysjobs(argc,argv)1358 sysjobs(argc, argv)
1359 int argc;
1360 unsigned char *argv[];
1361 {
1362 unsigned char *cmdp = *argv;
1363 struct job *jp;
1364 int propts, c;
1365 struct optv optv;
1366
1367 optinit(&optv);
1368 propts = 0;
1369
1370 if ((flags & jcflg) == 0) {
1371 Failure((unsigned char *)cmdp, nojc);
1372 return;
1373 }
1374 while ((c = optget(argc, argv, &optv, "lpx")) != -1) {
1375 if (propts) {
1376 gfailure((unsigned char *)usage, jobsuse);
1377 return;
1378 }
1379 switch (c) {
1380 case 'x':
1381 propts = -1;
1382 break;
1383 case 'p':
1384 propts = PR_PGID;
1385 break;
1386 case 'l':
1387 propts = PR_LONG;
1388 break;
1389 case '?':
1390 gfailure((unsigned char *)usage, jobsuse);
1391 return;
1392 }
1393 }
1394
1395 if (propts == -1) {
1396 unsigned char *bp;
1397 unsigned char *cp;
1398 unsigned char *savebp;
1399 for (savebp = bp = locstak(); optv.optind < argc;
1400 optv.optind++) {
1401 cp = argv[optv.optind];
1402 if (*cp == '%') {
1403 jp = str2job((char *)cmdp, (char *)cp, 1);
1404 if (jp == NULL)
1405 return;
1406 itos(jp->j_pid);
1407 cp = numbuf;
1408 }
1409 while (*cp) {
1410 GROWSTAK(bp);
1411 *bp++ = *cp++;
1412 }
1413 GROWSTAK(bp);
1414 *bp++ = SPACE;
1415 }
1416 savebp = endstak(bp);
1417 execexp(savebp, (Intptr_t)0, 0);
1418 return;
1419 }
1420
1421 collectjobs(WNOHANG);
1422
1423 if (propts == 0)
1424 propts = PR_DFL;
1425
1426 if (optv.optind == argc) {
1427 for (jp = joblst; jp; jp = jp->j_nxtp) {
1428 if (jp->j_jid)
1429 printjob(jp, propts);
1430 }
1431 } else do {
1432 printjob(str2job(C cmdp, C argv[optv.optind++], 1), propts);
1433 } while (optv.optind < argc);
1434 }
1435
1436 /*
1437 * the builtin "fg" and "bg" commands
1438 */
1439 /* ARGSUSED */
1440 void
sysfgbg(argc,argv)1441 sysfgbg(argc, argv)
1442 int argc;
1443 char *argv[];
1444 {
1445 char *cmdp = *argv;
1446 int fg = eq("fg", cmdp);
1447 #ifdef DO_GETOPT_UTILS
1448 /*
1449 * optskip() is sufficient, even ksh93 only supports "fg -- -1234".
1450 * Bourne Shell did not need "--", nor support -1234.
1451 */
1452 int ind = optskip(argc, UCP argv, fg?"fg [job ...]":"bg [job ...]");
1453
1454 if (ind-- < 0)
1455 return;
1456 argc -= ind;
1457 argv += ind;
1458 #endif
1459 if ((flags & jcflg) == 0) {
1460 Failure((unsigned char *)cmdp, nojc);
1461 return;
1462 }
1463
1464 if (*++argv == 0) {
1465 struct job *jp;
1466 for (jp = jobcur; ; jp = jp->j_curp) {
1467 if (jp == 0) {
1468 Failure((unsigned char *)cmdp, nocurjob);
1469 return;
1470 }
1471 if (jp->j_jid)
1472 break;
1473 }
1474 restartjob(jp, fg);
1475 } else {
1476 do {
1477 restartjob(str2job(cmdp, *argv, 1), fg);
1478 } while (*++argv);
1479 }
1480 }
1481
1482 /*
1483 * the builtin "wait" commands
1484 */
1485 void
syswait(argc,argv)1486 syswait(argc, argv)
1487 int argc;
1488 char *argv[];
1489 {
1490 char *cmdp = *argv;
1491 struct job *jp;
1492 int wflags;
1493 siginfo_t si;
1494 #ifdef DO_GETOPT_UTILS
1495 /*
1496 * optskip() is sufficient, even ksh93 only supports "wait -- -1234".
1497 * Bourne Shell did not need "--", nor support -1234.
1498 */
1499 int ind = optskip(argc, UCP argv, "wait [job ...]");
1500
1501 if (ind-- < 0)
1502 return;
1503 argc -= ind;
1504 argv += ind;
1505 #endif
1506
1507 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg))
1508 wflags = WSTOPPED;
1509 else
1510 wflags = 0;
1511 wflags |= (WEXITED|WTRAPPED); /* Needed for waitid() */
1512
1513 if (argc == 1) {
1514 struct job *sjp;
1515
1516 collectjobs(0);
1517
1518 for (jp = joblst; jp; jp = sjp) {
1519 sjp = jp->j_nxtp;
1520
1521 if (jp->j_flag & J_DONE)
1522 jp->j_flag |= J_REPORTED;
1523 }
1524 } else while (--argc) {
1525 if ((jp = str2job(cmdp, *++argv, 0)) == 0) {
1526 #ifdef DO_POSIX_WAIT
1527 exitval =
1528 ex.ex_status =
1529 ex.ex_code = ERR_NOTFOUND;
1530 exitset(); /* Set retval from exitval for $? */
1531 #endif
1532 continue;
1533 }
1534 #ifdef DO_POSIX_WAIT
1535 if ((jp->j_flag & J_REPORTED))
1536 continue;
1537 if ((jp->j_flag & J_DONE)) {
1538 ex.ex_status = exitval = jp->j_xval;
1539 ex.ex_code = jp->j_xcode;
1540 ex.ex_pid = jp->j_pid;
1541 ex.ex_signo = jp->j_xsig;
1542
1543 if ((flags2 & fullexitcodeflg) == 0)
1544 exitval &= 0xFF; /* As dumb as historic wait */
1545 if (jp->j_flag & J_SIGNALED)
1546 exitval |= SIGFLG;
1547 #ifdef DO_EXIT_MODFIX
1548 else if (ex.ex_status != 0 && exitval == 0)
1549 exitval = SIGFLG; /* Use special value 128 */
1550 #endif
1551 exitset(); /* Set retval from exitval for $? */
1552
1553 jp->j_flag |= J_REPORTED;
1554 continue;
1555 }
1556 #endif
1557 if (!(jp->j_flag & J_RUNNING))
1558 continue;
1559 if (waitid(P_PID, jp->j_pid, &si, wflags) < 0)
1560 break;
1561 #ifdef DO_TRAP_FROM_WAITID
1562 checksigs(&si); /* fault() with jobcontrol */
1563 #endif
1564 (void) statjob(jp, &si, 0, 1);
1565 jp->j_flag |= J_REPORTED;
1566 }
1567 }
1568
1569 /*
1570 * Convert a job spec in "args" into a process id and send "sig".
1571 * A leading '%' marks job specifiers.
1572 * A leading '-' names a process group id instead of a pricess id.
1573 */
1574 static void
sigv(cmdp,sig,f,args)1575 sigv(cmdp, sig, f, args)
1576 char *cmdp;
1577 int sig;
1578 int f;
1579 char *args;
1580 {
1581 int pgrp = 0;
1582 int stopme = 0;
1583 pid_t id;
1584
1585 if (*args == '%') {
1586 struct job *jp;
1587 jp = str2job(cmdp, args, 1);
1588 if (jp == NULL)
1589 return;
1590 id = jp->j_pgid;
1591 pgrp++;
1592 } else {
1593 if (*args == '-') {
1594 pgrp++;
1595 args++;
1596 }
1597 id = 0;
1598 do {
1599 if (*args < '0' || *args > '9') {
1600 failure((unsigned char *)cmdp, badid);
1601 return;
1602 }
1603 id = (id * 10) + (*args - '0');
1604 } while (*++args);
1605 if (id == 0) {
1606 id = mypgid;
1607 pgrp++;
1608 }
1609 }
1610
1611 #ifdef DO_SYSPGRP
1612 if (f == F_PGRP) {
1613 pid_t pgid = getpgid(id);
1614
1615 if (pgid == (pid_t)-1) {
1616 flushb();
1617 failure((unsigned char *)cmdp, "cannot get pgid");
1618 } else {
1619 pid_t sgrp = (pid_t)-1;
1620
1621 #ifdef HAVE_GETSID
1622 sgrp = getsid(id);
1623 #endif
1624 pr_pgrp(id, pgid, sgrp);
1625 }
1626 return;
1627 }
1628 #endif
1629
1630 #ifdef SIGSTOP
1631 if (sig == SIGSTOP) {
1632 /*
1633 * If the id equals our session group id, this is the id
1634 * of the session group leader and thus the login shell.
1635 *
1636 * If the id equals our process id and our process group id
1637 * equals our session group id, we are the login shell.
1638 */
1639 if (id == mysid || (id == mypid && mypgid == mysid)) {
1640 failure((unsigned char *)cmdp, loginsh);
1641 return;
1642 }
1643
1644 /*
1645 * If the id equals our process group id and our process group
1646 * id differs from our saved process group id, we are not the
1647 * login shell, but need to restore the previous process
1648 * group id first.
1649 */
1650 if (id == mypgid && mypgid != svpgid) {
1651 (void) settgid(svtgid, mypgid);
1652 setpgid(0, svpgid);
1653 stopme++;
1654 if (f == F_SUSPEND) /* Called by the suspend cmd */
1655 id = svpgid; /* Stop our caller as well */
1656 }
1657 }
1658 #endif
1659
1660 if (pgrp || f == F_KILLPG) {
1661 pgrp++;
1662 id = -id;
1663 }
1664
1665 if (kill(id, sig) < 0) {
1666
1667 switch (errno) {
1668 case EPERM:
1669 failure((unsigned char *)cmdp, eacces);
1670 break;
1671
1672 case EINVAL:
1673 failure((unsigned char *)cmdp, badsig);
1674 break;
1675
1676 default:
1677 if (pgrp) {
1678 failure((unsigned char *)cmdp,
1679 nosuchpgid);
1680 } else {
1681 failure((unsigned char *)cmdp,
1682 nosuchpid);
1683 }
1684 break;
1685 }
1686
1687 #ifdef SIGCONT
1688 } else if (sig == SIGTERM && pgrp) {
1689 (void) kill(id, SIGCONT);
1690 #endif
1691 }
1692
1693 if (stopme) {
1694 setpgid(0, mypgid);
1695 (void) settgid(mypgid, svpgid);
1696 }
1697 }
1698
1699 void
sysstop(argc,argv)1700 sysstop(argc, argv)
1701 int argc;
1702 char *argv[];
1703 {
1704 char *cmdp = *argv;
1705 #ifdef DO_GETOPT_UTILS
1706 int ind = optskip(argc, UCP argv, stopuse);
1707
1708 if (ind-- < 0)
1709 return;
1710 argc -= ind;
1711 argv += ind;
1712 #endif
1713 if (argc <= 1) {
1714 gfailure((unsigned char *)usage, stopuse);
1715 return;
1716 }
1717 #ifdef SIGSTOP
1718 while (*++argv)
1719 sigv(cmdp, SIGSTOP, F_KILL, *argv);
1720 #endif
1721 }
1722
1723 /*
1724 * List all signals on this platform
1725 */
1726 static void
listsigs()1727 listsigs()
1728 {
1729 int i;
1730 int maxtrap = MAX_SIG; /* MAXTRAP includes traps like ERR */
1731 int cnt = 0;
1732 char sep = 0;
1733 #if SIG2STR_MAX < 22
1734 #define SIG_BLEN 22 /* Enough for 64 bits */
1735 #else
1736 #define SIG_BLEN SIG2STR_MAX
1737 #endif
1738 char buf[SIG_BLEN]; /* Large enough for SIG* names, enough for num */
1739
1740 #ifdef SIGRTMAX
1741 i = SIGRTMAX + 1;
1742 if (i > maxtrap)
1743 maxtrap = i;
1744 #endif
1745 for (i = 1; i < maxtrap; i++) {
1746 if (sig2str(i, buf) < 0) {
1747 /*
1748 * The original code was just:
1749 * continue;
1750 * but we would not realize that there may be gaps in
1751 * the list. So print the number, usable as kill arg.
1752 */
1753 itos(i);
1754 strcpy(buf, C numbuf);
1755 }
1756 if (sep)
1757 prc_buff(sep);
1758 prs_buff((unsigned char *)buf);
1759 if ((flags & ttyflg) && (++cnt % 10))
1760 sep = TAB;
1761 else
1762 sep = NL;
1763 }
1764 prc_buff(NL);
1765 }
1766
1767 #if defined(DO_KILL_L_SIG) || defined(DO_GETOPT_UTILS)
1768 static void
namesigs(argv)1769 namesigs(argv)
1770 char *argv[];
1771 {
1772 int sig;
1773 char buf[SIG2STR_MAX];
1774
1775 while (*++argv) {
1776 sig = stoi((unsigned char *)*argv) & 0x7F;
1777 if (sig2str(sig, buf) < 0) {
1778 failure((unsigned char *)*argv, badsig);
1779 return;
1780 }
1781 prs_buff((unsigned char *)buf);
1782 prc_buff(NL);
1783 }
1784 }
1785 #endif
1786
1787 void
syskill(argc,argv)1788 syskill(argc, argv)
1789 int argc;
1790 char *argv[];
1791 {
1792 char *cmdp = *argv;
1793 int sig = SIGTERM;
1794 int pg = eq("killpg", cmdp);
1795 #ifdef DO_GETOPT_UTILS
1796 struct optv optv;
1797 int c;
1798 int lfl = 0;
1799 int sfl = 0;
1800
1801 optinit(&optv);
1802 optv.optflag |= OPT_NOFAIL;
1803 /*
1804 * Even ksh93 only supports "kill -- -1234".
1805 * With the SVr4 Bourne Shell, "--" was not needed nor supported,
1806 * but "kill -1234" used "-1234" as signal number and thus failed.
1807 */
1808 while ((c = optnext(argc, UCP argv, &optv, ":ls:", killuse)) != -1) {
1809 switch (c) {
1810 case 0: return; /* --help */
1811
1812 case 'l': lfl = 1;
1813 break;
1814 case 's':
1815 if (str2sig(optv.optarg, &sig)) {
1816 failure((unsigned char *)cmdp, badsig);
1817 return;
1818 }
1819 sfl = 1;
1820 break;
1821 case '?':
1822 if (!sfl) {
1823 if (str2sig(&argv[optv.ooptind][1],
1824 &sig) == 0) {
1825 optv.optind = optv.ooptind + 1;
1826 goto optdone;
1827 }
1828 }
1829 /* FALLTHROUGH */
1830 case ':':
1831 optbad(argc, UCP argv, &optv);
1832 gfailure((unsigned char *)usage, killuse);
1833 return;
1834 }
1835 }
1836 optdone:
1837 if (lfl + sfl > 1) {
1838 gfailure((unsigned char *)usage, killuse);
1839 return;
1840 }
1841 argc -= --optv.optind;
1842 argv += optv.optind;
1843 if (lfl) {
1844 if (argc > 1)
1845 namesigs(argv);
1846 else
1847 listsigs();
1848 return;
1849 }
1850 #endif
1851 if (argc == 1) {
1852 gfailure((unsigned char *)usage, killuse);
1853 return;
1854 }
1855
1856 #ifndef DO_GETOPT_UTILS
1857 if (argv[1][0] == '-') {
1858
1859 if (argc == 2) {
1860 if (!eq(argv[1], "-l")) {
1861 gfailure((unsigned char *)usage, killuse);
1862 return;
1863 }
1864 listsigs();
1865 return;
1866 #ifdef DO_KILL_L_SIG
1867 } else if (eq(argv[1], "-l")) {
1868 namesigs(++argv);
1869 return;
1870 #endif
1871 }
1872 if (str2sig(&argv[1][1], &sig)) {
1873 failure((unsigned char *)cmdp, badsig);
1874 return;
1875 }
1876 argv++;
1877 }
1878 #endif
1879
1880 while (*++argv)
1881 sigv(cmdp, sig, pg ? F_KILLPG : F_KILL, *argv);
1882 }
1883
1884 void
syssusp(argc,argv)1885 syssusp(argc, argv)
1886 int argc;
1887 char *argv[];
1888 {
1889 char *cmdp = *argv;
1890 #ifdef DO_GETOPT_UTILS
1891 int ind = optskip(argc, UCP argv, "suspend");
1892
1893 if (ind-- < 0)
1894 return;
1895 argc -= ind;
1896 argv += ind;
1897 #endif
1898
1899 if (argc != 1) {
1900 Failure((unsigned char *)cmdp, badopt);
1901 return;
1902 }
1903 #ifdef SIGSTOP
1904 sigv(cmdp, SIGSTOP, F_SUSPEND, "0");
1905 #endif
1906 }
1907
1908 #ifdef DO_SYSPGRP
1909 static void
pr_pgrp(pid,pgrp,sgrp)1910 pr_pgrp(pid, pgrp, sgrp)
1911 pid_t pid;
1912 pid_t pgrp;
1913 pid_t sgrp;
1914 {
1915 prs_buff(UC "pid: ");
1916 prs_buff(&numbuf[ltos((long)pid)]);
1917 prs_buff(UC " processgroup: ");
1918 prs_buff(&numbuf[ltos((long)pgrp)]);
1919 if (sgrp != (pid_t)-1) {
1920 prs_buff(UC " sessiongroup: ");
1921 prs_buff(&numbuf[ltos((long)sgrp)]);
1922 }
1923 prc_buff(NL);
1924 }
1925
1926 void
syspgrp(argc,argv)1927 syspgrp(argc, argv)
1928 int argc;
1929 char *argv[];
1930 {
1931 char *cmdp = *argv;
1932 #ifdef DO_GETOPT_UTILS
1933 int ind = optskip(argc, UCP argv, "pgrp [job ...]");
1934
1935 if (ind-- < 0)
1936 return;
1937 argc -= ind;
1938 argv += ind;
1939 #endif
1940
1941 if (argc == 1) {
1942 pid_t pgrp;
1943 pid_t sgrp;
1944
1945 #ifdef TIOCGPGRP
1946 /*
1947 * Prefer the ioctl() as the POSIX function tcgetpgrp() limits
1948 * access in a way that we cannot accept.
1949 */
1950 if (ioctl(STDIN_FILENO, TIOCGPGRP, (char *)&pgrp) < 0)
1951 pgrp = -1;
1952 #else
1953 pgrp = tcgetpgrp(STDIN_FILENO);
1954 #endif
1955 #if defined(HAVE_GETSID) && defined(HAVE_TCGETSID)
1956 #ifdef TIOCGSID
1957 /*
1958 * Prefer the ioctl() as the POSIX function tcgetsid() limits
1959 * access in a way that we cannot accept.
1960 */
1961 if (ioctl(STDIN_FILENO, TIOCGSID, (char *)&sgrp) < 0)
1962 sgrp = -1;
1963 #else
1964 sgrp = tcgetsid(STDIN_FILENO);
1965 #endif
1966 #endif
1967
1968 prs_buff(UC "ttyprocessgroup: ");
1969 prs_buff(&numbuf[sltos((long)pgrp)]);
1970 #if defined(HAVE_GETSID) && defined(HAVE_TCGETSID)
1971 prs_buff(UC " ttysessiongroup: ");
1972 prs_buff(&numbuf[sltos((long)sgrp)]);
1973 #endif
1974 prc_buff(NL);
1975 sgrp = (pid_t)-1;
1976 #ifdef HAVE_GETSID
1977 sgrp = getsid(0);
1978 #endif
1979 pr_pgrp(mypid, mypgid, sgrp);
1980 return;
1981 }
1982 #if !defined(HAVE_GETPGID) && !defined(HAVE_BSD_GETPGRP)
1983 failure((unsigned char *)cmdp, unimplemented);
1984 #else
1985 while (*++argv)
1986 sigv(cmdp, 0, F_PGRP, *argv);
1987 #endif
1988 }
1989 #endif
1990
1991 void
hupforegnd()1992 hupforegnd()
1993 {
1994 struct job *jp;
1995 #ifdef SIGCHLD
1996 sigset_t set, oset;
1997
1998 /*
1999 * add SIGCHLD to mask
2000 */
2001 sigemptyset(&set);
2002 sigaddset(&set, SIGCHLD);
2003 sigprocmask(SIG_BLOCK, &set, &oset);
2004 #endif
2005 for (jp = joblst; jp != NULL; jp = jp->j_nxtp) {
2006 if (jp->j_flag & J_FOREGND) {
2007 (void) kill(jp->j_pid, SIGHUP);
2008 break;
2009 }
2010 }
2011 #ifdef SIGCHLD
2012 sigprocmask(SIG_SETMASK, &oset, 0);
2013 #endif
2014 }
2015
2016 /*
2017 * Simple interface to waitid() that avoids the need to use our internal
2018 * siginfo_t emulation and our internal idtype_t emulation in case the
2019 * platform does not offer waitid().
2020 * It still allows to return more than the low 8 bits from exit().
2021 */
2022 pid_t
wait_status(pid,codep,statusp,opts)2023 wait_status(pid, codep, statusp, opts)
2024 pid_t pid;
2025 int *codep;
2026 int *statusp;
2027 int opts;
2028 {
2029 siginfo_t si;
2030 pid_t ret;
2031 idtype_t idtype;
2032 pid_t id;
2033
2034 if (pid > 0) {
2035 idtype = P_PID;
2036 id = pid;
2037 } else if (pid < -1) {
2038 idtype = P_PGID;
2039 id = -pid;
2040 } else if (pid == -1) {
2041 idtype = P_ALL;
2042 id = 0;
2043 } else {
2044 idtype = P_PGID;
2045 id = getpgid(0);
2046 }
2047 ret = waitid(idtype, id, &si, opts);
2048 if (ret == (pid_t)-1)
2049 return ((pid_t)-1);
2050 if (codep)
2051 *codep = si.si_code;
2052 if (statusp)
2053 *statusp = si.si_status;
2054 return (si.si_pid);
2055 }
2056
2057 #ifdef DO_TIME
2058 void
prtime(jp)2059 prtime(jp)
2060 struct job *jp;
2061 {
2062 struct timeval stop;
2063 struct rusage rustop;
2064 UIntmax_t cpu;
2065 UIntmax_t per;
2066 unsigned char *fmt;
2067 unsigned char *ofmt;
2068 unsigned char c;
2069 int save_fd = setb(STDERR_FILENO);
2070
2071 fmt = timefmtnod.namval;
2072 if (fmt == NULL) {
2073 fmt = flags2 & systime ?
2074 UC "\nreal %6:E\nuser %6U\nsys %6S" :
2075 UC "%:E real %U user %S sys %P%% cpu";
2076 }
2077 ofmt = fmt;
2078
2079 gettimeofday(&stop, NULL);
2080 ruget(&rustop);
2081
2082 timersub(&stop, &jp->j_start);
2083 timersub(&rustop.ru_utime, &jp->j_rustart.ru_utime);
2084 timersub(&rustop.ru_stime, &jp->j_rustart.ru_stime);
2085
2086 #ifdef USE_LONGLONG /* 64 bits result in 584942 years with usec res. */
2087 /*
2088 * Note that rustop.ru_utime.tv_sec is a long, so we need to cast
2089 * 1000000 in order to get a long long result from the multiplication.
2090 */
2091 cpu = rustop.ru_utime.tv_sec * (UIntmax_t)1000000 +
2092 rustop.ru_utime.tv_usec;
2093 cpu += rustop.ru_stime.tv_sec * (UIntmax_t)1000000 +
2094 rustop.ru_stime.tv_usec;
2095 per = stop.tv_sec * (UIntmax_t)1000000 +
2096 stop.tv_usec;
2097 if (per < 1)
2098 per = 1;
2099 per = 100 * cpu / per;
2100 cpu /= 1000000;
2101 #else /* 32 bits result in 49 days with msec resolution */
2102 cpu = rustop.ru_utime.tv_sec*1000 + rustop.ru_utime.tv_usec/1000;
2103 cpu += rustop.ru_stime.tv_sec*1000 + rustop.ru_stime.tv_usec/1000;
2104 per = stop.tv_sec*1000 + stop.tv_usec/1000;
2105 if (per < 1)
2106 per = 1;
2107 if (cpu > (UINT32_MAX / 100))
2108 per = cpu / (per / 100);
2109 else
2110 per = 100 * cpu / per;
2111 cpu /= 1000;
2112 #endif
2113
2114 while ((c = *fmt++) != '\0') {
2115 if (c == '%') {
2116 int dig = -1;
2117 int longopt = FALSE;
2118
2119 if ((c = *fmt++) == '\0')
2120 break;
2121 if (c >= '0' && c <= '9') {
2122 dig = c - '0';
2123 if ((c = *fmt++) == '\0')
2124 break;
2125 }
2126 if (c == 'l' || c == 'L' || c == ':') {
2127 longopt = c;
2128 if ((c = *fmt++) == '\0')
2129 break;
2130 }
2131 switch (c) {
2132 case 'T':
2133 if ((flags2 & systime) == 0 && dig > cpu) {
2134 fmt -= 3;
2135 goto out;
2136 }
2137 break;
2138 case 'J':
2139 prs_buff((unsigned char *)jp->j_cmd);
2140 break;
2141 case 'P':
2142 prull_buff(per);
2143 break;
2144 case 'E':
2145 prtv(&stop, dig, longopt);
2146 break;
2147 case 'S':
2148 prtv(&rustop.ru_stime, dig, longopt);
2149 break;
2150 case 'U':
2151 prtv(&rustop.ru_utime, dig, longopt);
2152 break;
2153
2154 #if !defined(__BEOS__) && !defined(__HAIKU__) && \
2155 !defined(OS390) && !defined(__MVS__)
2156 /* XXX dirty hack */
2157 case 'W':
2158 prl_buff(rustop.ru_nswap -
2159 jp->j_rustart.ru_nswap);
2160 break;
2161 #ifdef __future__
2162 case 'X': /* shared */
2163 ru_ixrss * pagesize()/1024 / tics
2164 break;
2165 case 'D': /* unshared data */
2166 ru_idrss * pagesize()/1024 / tics
2167 break;
2168 case 'K': /* unshared stack */
2169 ru_isrss * pagesize()/1024 / tics
2170 break;
2171 case 'M':
2172 ru_maxrss * pagesize()/1024(/2 ?)
2173 break;
2174 #else
2175 case 'X':
2176 case 'D':
2177 case 'K':
2178 case 'M':
2179 prc_buff('0');
2180 break;
2181 #endif
2182 case 'F':
2183 prl_buff(rustop.ru_majflt -
2184 jp->j_rustart.ru_majflt);
2185 break;
2186 case 'R':
2187 prl_buff(rustop.ru_minflt -
2188 jp->j_rustart.ru_minflt);
2189 break;
2190 case 'I':
2191 prl_buff(rustop.ru_inblock -
2192 jp->j_rustart.ru_inblock);
2193 break;
2194 case 'O':
2195 prl_buff(rustop.ru_oublock -
2196 jp->j_rustart.ru_oublock);
2197 break;
2198 case 'r':
2199 prl_buff(rustop.ru_msgrcv -
2200 jp->j_rustart.ru_msgrcv);
2201 break;
2202 case 's':
2203 prl_buff(rustop.ru_msgsnd -
2204 jp->j_rustart.ru_msgsnd);
2205 break;
2206 case 'k':
2207 prl_buff(rustop.ru_nsignals -
2208 jp->j_rustart.ru_nsignals);
2209 break;
2210 case 'w':
2211 prl_buff(rustop.ru_nvcsw -
2212 jp->j_rustart.ru_nvcsw);
2213 break;
2214 case 'c':
2215 prl_buff(rustop.ru_nivcsw -
2216 jp->j_rustart.ru_nivcsw);
2217 break;
2218 #endif
2219 default:
2220 prc_buff(c);
2221 }
2222 } else {
2223 prc_buff(c);
2224 }
2225 }
2226 out:
2227 if ((fmt - ofmt) > 0)
2228 prc_buff(NL);
2229 flushb();
2230
2231 (void) setb(save_fd);
2232 }
2233
2234 void
ruget(rup)2235 ruget(rup)
2236 struct rusage *rup;
2237 {
2238 struct rusage ruc;
2239
2240 getrusage(RUSAGE_SELF, rup);
2241 getrusage(RUSAGE_CHILDREN, &ruc);
2242 ruadd(rup, &ruc);
2243 }
2244
2245 static void
ruadd(ru,ru2)2246 ruadd(ru, ru2)
2247 struct rusage *ru;
2248 struct rusage *ru2;
2249 {
2250 timeradd(&ru->ru_utime, &ru2->ru_utime);
2251 timeradd(&ru->ru_stime, &ru2->ru_stime);
2252
2253 #if !defined(__BEOS__) && !defined(__HAIKU__) && \
2254 !defined(OS390) && !defined(__MVS__)
2255 #ifdef __future__
2256 if (ru2->ru_maxrss > ru->ru_maxrss)
2257 ru->ru_maxrss = ru2->ru_maxrss;
2258
2259 ru->ru_ixrss += ru2->ru_ixrss;
2260 ru->ru_idrss += ru2->ru_idrss;
2261 ru->ru_isrss += ru2->ru_isrss;
2262 #endif
2263 ru->ru_minflt += ru2->ru_minflt;
2264 ru->ru_majflt += ru2->ru_majflt;
2265 ru->ru_nswap += ru2->ru_nswap;
2266 ru->ru_inblock += ru2->ru_inblock;
2267 ru->ru_oublock += ru2->ru_oublock;
2268 ru->ru_msgsnd += ru2->ru_msgsnd;
2269 ru->ru_msgrcv += ru2->ru_msgrcv;
2270 ru->ru_nsignals += ru2->ru_nsignals;
2271 ru->ru_nvcsw += ru2->ru_nvcsw;
2272 ru->ru_nivcsw += ru2->ru_nivcsw;
2273 #endif /* !defined(__BEOS__) && !defined(__HAIKU__) */
2274 }
2275 #endif /* DO_TIME */
2276
2277 #ifndef HAVE_GETRUSAGE
2278 int
getrusage(who,r_usage)2279 getrusage(who, r_usage)
2280 int who;
2281 struct rusage *r_usage;
2282 {
2283 int ret = -1;
2284 #ifdef HAVE_TIMES
2285 struct tms tms;
2286
2287 times(&tms);
2288 #endif
2289 memset(r_usage, 0, sizeof (*r_usage));
2290 #ifdef HAVE_TIMES
2291 if (who == RUSAGE_SELF) {
2292 clock2tv(tms.tms_utime, &r_usage->ru_utime);
2293 clock2tv(tms.tms_stime, &r_usage->ru_stime);
2294 } else if (who == RUSAGE_CHILDREN) {
2295 clock2tv(tms.tms_cutime, &r_usage->ru_utime);
2296 clock2tv(tms.tms_cstime, &r_usage->ru_stime);
2297 }
2298 #endif
2299 return (ret);
2300 }
2301 #endif /* HAVE_GETRUSAGE */
2302
2303 #ifndef HAVE_WAITID
2304 static int
waitid(idtype,id,infop,opts)2305 waitid(idtype, id, infop, opts)
2306 idtype_t idtype;
2307 id_t id;
2308 siginfo_t *infop; /* Must be != NULL */
2309 int opts;
2310 {
2311 int exstat;
2312 pid_t pid;
2313 #ifdef __needed__
2314 struct tms tms;
2315 #endif
2316
2317 opts &= ~(WEXITED|WTRAPPED); /* waitpid() doesn't understand them */
2318 #if WSTOPPED != WUNTRACED
2319 if (opts & WSTOPPED) {
2320 opts &= ~WSTOPPED;
2321 opts |= WUNTRACED;
2322 }
2323 #endif
2324
2325 if (idtype == P_PID)
2326 pid = id;
2327 else if (idtype == P_PGID)
2328 pid = -id;
2329 else if (idtype == P_ALL)
2330 pid = -1;
2331 else
2332 pid = 0;
2333
2334 infop->si_utime = 0;
2335 infop->si_stime = 0;
2336 #ifdef __needed__
2337 if (WNOWAIT == 0 || (opts & WNOWAIT) == 0) {
2338 times(&tms);
2339 }
2340 #endif
2341 pid = waitpid(pid, &exstat, opts);
2342 infop->si_pid = pid;
2343 infop->si_code = 0;
2344 infop->si_status = 0;
2345
2346 if (pid == (pid_t)-1)
2347 return (-1);
2348
2349 #ifdef __needed__
2350 if (WNOWAIT == 0 || (opts & WNOWAIT) == 0) {
2351 infop->si_utime = tms.tms_cutime;
2352 infop->si_stime = tms.tms_cstime;
2353 times(&tms);
2354 infop->si_utime = tms.tms_cutime - infop->si_utime;
2355 infop->si_stime = tms.tms_cstime - infop->si_stime;
2356 }
2357 #endif
2358
2359 if (WIFEXITED(exstat)) {
2360 infop->si_code = CLD_EXITED;
2361 infop->si_status = WEXITSTATUS(exstat);
2362 } else if (WIFSIGNALED(exstat)) {
2363 if (WCOREDUMP(exstat))
2364 infop->si_code = CLD_DUMPED;
2365 else
2366 infop->si_code = CLD_KILLED;
2367 infop->si_status = WTERMSIG(exstat);
2368 } else if (WIFSTOPPED(exstat)) {
2369 #ifdef SIGTRAP
2370 if (WSTOPSIG(exstat) == SIGTRAP)
2371 infop->si_code = CLD_TRAPPED;
2372 else
2373 #endif
2374 infop->si_code = CLD_STOPPED;
2375 infop->si_status = WSTOPSIG(exstat);
2376 } else if (WIFCONTINUED(exstat)) {
2377 infop->si_code = CLD_CONTINUED;
2378 #ifdef SIGCONT
2379 infop->si_status = SIGCONT;
2380 #else
2381 infop->si_status = 0;
2382 #endif
2383 }
2384
2385 return (0);
2386 }
2387 #endif
2388
2389 #ifdef DO_TRAP_FROM_WAITID
2390 static int
didsignal(infop)2391 didsignal(infop)
2392 siginfo_t *infop;
2393 {
2394 if (infop->si_pid == 0)
2395 return (FALSE);
2396
2397 switch (infop->si_code) {
2398
2399 #ifdef CLD_KILLED
2400 case CLD_KILLED:
2401 #endif
2402 #ifdef CLD_DUMPED
2403 case CLD_DUMPED:
2404 #endif
2405 #ifdef CLD_TRAPPED
2406 case CLD_TRAPPED:
2407 #endif
2408 #ifdef CLD_STOPPED
2409 case CLD_STOPPED:
2410 #endif
2411 #ifdef CLD_CONTINUED
2412 case CLD_CONTINUED:
2413 #endif
2414 return (TRUE);
2415
2416 default:
2417 return (FALSE);
2418 }
2419 }
2420
2421 static void
checksigs(infop)2422 checksigs(infop)
2423 siginfo_t *infop;
2424 {
2425 if ((flags & (monitorflg|jcflg|jcoff)) == (monitorflg|jcflg)) {
2426 if (didsignal(infop) && infop->si_status) {
2427 fault(infop->si_status);
2428 }
2429 }
2430 }
2431 #endif
2432
2433 #ifdef DO_DOL_SLASH
2434
2435 #ifdef HAVE_SMMAP
2436 #include <schily/mman.h>
2437
2438 void
shmcreate()2439 shmcreate()
2440 {
2441 int f;
2442 char *addr;
2443 #ifdef _SC_PAGESIZE
2444 int size = (int)sysconf(_SC_PAGESIZE);
2445 #else
2446 int size = getpagesize();
2447 #endif
2448 static int myint;
2449
2450 #ifdef MAP_ANONYMOUS /* HP/UX */
2451 f = -1;
2452 addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE,
2453 MAP_SHARED|MAP_ANONYMOUS, f, 0);
2454 #else
2455 if ((f = open("/dev/zero", O_RDWR)) < 0)
2456 goto err;
2457 addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE,
2458 MAP_SHARED, f, 0);
2459 close(f);
2460 #endif
2461 if (addr == (char *)-1)
2462 goto err;
2463
2464 excausep = (int *)addr;
2465 return;
2466 err:
2467 /*
2468 * mmap() did not work, try to be silent...
2469 */
2470 excausep = &myint;
2471 }
2472 #else /* !HAVE_SMMAP */
2473 void
shmcreate()2474 shmcreate()
2475 {
2476 static int myint;
2477
2478 excausep = &myint;
2479 }
2480 #endif /* HAVE_SMMAP */
2481
2482 #endif /* DO_DOL_SLASH */
2483