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 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1995-1997, by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 /* Portions Copyright(c) 1988, Sun Microsystems Inc. */
32 /* All Rights Reserved */
33
34 /*LINTLIBRARY*/
35
36 /*
37 * Compatibility lib for SunOS's wait4().
38 */
39
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/times.h>
43 #include <sys/wait.h>
44 #include <sys/siginfo.h>
45 #include <sys/procset.h>
46 #include <sys/param.h>
47 #include <sys/resource.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <errno.h>
51
52 /*
53 * Since sysV does not support rusage as in BSD, an approximate approach
54 * is:
55 * ...
56 * call times
57 * call waitid
58 * if ( a child is found )
59 * call times again
60 * rusage ~= diff in the 2 times call
61 * ...
62 */
63
64 /*
65 * forward declaration
66 */
67 static int wstat(int, int);
68
69 pid_t
wait4(pid_t pid,int * status,int options,struct rusage * rp)70 wait4(pid_t pid, int *status, int options, struct rusage *rp)
71 {
72 struct tms before_tms;
73 struct tms after_tms;
74 siginfo_t info;
75 int error;
76 int noptions;
77 idtype_t idtype;
78
79 if ((long)status == -1L || (long)rp == -1L) {
80 errno = EFAULT;
81 return (-1);
82 }
83
84 if (rp)
85 (void) memset(rp, 0, sizeof (struct rusage));
86 (void) memset(&info, 0, sizeof (siginfo_t));
87 if (times(&before_tms) < 0)
88 return (-1); /* errno is set by times() */
89
90 /*
91 * SunOS's wait4() only supports WNOHANG & WUNTRACED
92 */
93 if (options & ~(WNOHANG|WUNTRACED))
94 return (EINVAL); /* used to be done by the kernel */
95 noptions = options | WEXITED | WTRAPPED;
96
97 /*
98 * Emulate undocumented 4.x semantics for 1186845
99 */
100 if (pid < 0) {
101 pid = -pid;
102 idtype = P_PGID;
103 } else if (pid == 0)
104 idtype = P_ALL;
105 else
106 idtype = P_PID;
107
108 error = waitid(idtype, pid, &info, noptions);
109 if (error == 0) {
110 clock_t diffu; /* difference in usertime (ticks) */
111 clock_t diffs; /* difference in systemtime (ticks) */
112
113 if ((options & WNOHANG) && (info.si_pid == 0))
114 return (0); /* no child found */
115
116 if (rp) {
117 if (times(&after_tms) < 0)
118 return (-1); /* errno set by times() */
119 /*
120 * The system/user time is an approximation only !!!
121 */
122 diffu = after_tms.tms_cutime - before_tms.tms_cutime;
123 diffs = after_tms.tms_cstime - before_tms.tms_cstime;
124 rp->ru_utime.tv_sec = diffu / HZ;
125 rp->ru_utime.tv_usec = (diffu % HZ) * (1000000 / HZ);
126 rp->ru_stime.tv_sec = diffs/ HZ;
127 rp->ru_stime.tv_usec = (diffs % HZ) * (1000000 / HZ);
128 }
129 if (status)
130 *status = wstat(info.si_code, info.si_status);
131 return (info.si_pid);
132 } else {
133 return (-1); /* error number is set by waitid() */
134 }
135 }
136
137 /*
138 * Convert the status code to old style wait status
139 */
140 static int
wstat(int code,int status)141 wstat(int code, int status)
142 {
143 int stat = (status & 0377);
144
145 switch (code) {
146 case CLD_EXITED:
147 stat <<= 8;
148 break;
149 case CLD_DUMPED:
150 stat |= WCOREFLG;
151 break;
152 case CLD_KILLED:
153 break;
154 case CLD_TRAPPED:
155 case CLD_STOPPED:
156 stat <<= 8;
157 stat |= WSTOPFLG;
158 break;
159 case CLD_CONTINUED:
160 stat = WCONTFLG;
161 break;
162 }
163 return (stat);
164 }
165