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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * wait() family of functions.
31 *
32 * The first minor difference between the Linux and Solaris family of wait()
33 * calls is that the values for WNOHANG and WUNTRACED are different. Solaris
34 * also has additional options (WCONTINUED, WNOWAIT) which should be flagged as
35 * invalid on Linux. Thankfully, the exit status values are identical between
36 * the two implementations.
37 *
38 * Things get very different and very complicated when we introduce the Linux
39 * threading model. Under linux, both threads and child processes are
40 * represented as processes. However, the behavior of wait() with respect to
41 * each child varies according to the flags given to clone()
42 *
43 * SIGCHLD The SIGCHLD signal should be sent on termination
44 * CLONE_THREAD The child shares the same thread group as the parent
45 * CLONE_DETACHED The parent receives no notification when the child exits
46 *
47 * The following flags control the Linux behavior w.r.t. the above attributes:
48 *
49 * __WALL Wait on all children, regardless of type
50 * __WCLONE Wait only on non-SIGCHLD children
51 * __WNOTHREAD Don't wait on children of other threads in this group
52 *
53 * The following chart shows whether wait() returns when the child exits:
54 *
55 * default __WCLONE __WALL
56 * no SIGCHLD - X X
57 * SIGCHLD X - X
58 *
59 * The following chart shows whether wait() returns when the grandchild exits:
60 *
61 * default __WNOTHREAD
62 * no CLONE_THREAD - -
63 * CLONE_THREAD X -
64 *
65 * The CLONE_DETACHED flag is universal - when the child exits, no state is
66 * stored and wait() has no effect.
67 *
68 * XXX Support the above combination of options, or some reasonable subset that
69 * covers at least fork() and pthread_create().
70 */
71
72 #include <errno.h>
73 #include <sys/wait.h>
74 #include <sys/lx_types.h>
75 #include <sys/lx_signal.h>
76 #include <sys/lx_misc.h>
77 #include <sys/lx_syscall.h>
78 #include <sys/times.h>
79 #include <strings.h>
80 #include <unistd.h>
81 #include <assert.h>
82
83 /*
84 * Convert between Linux options and Solaris options, returning -1 if any
85 * invalid flags are found.
86 */
87 #define LX_WNOHANG 0x1
88 #define LX_WUNTRACED 0x2
89
90 #define LX_WNOTHREAD 0x20000000
91 #define LX_WALL 0x40000000
92 #define LX_WCLONE 0x80000000
93
94 #define LX_P_ALL 0x0
95 #define LX_P_PID 0x1
96 #define LX_P_GID 0x2
97
98 static int
99 ltos_options(uintptr_t options)
100 {
101 int newoptions = 0;
102
103 if (((options) & ~(LX_WNOHANG | LX_WUNTRACED | LX_WNOTHREAD |
104 LX_WALL | LX_WCLONE)) != 0) {
105 return (-1);
106 }
107 /* XXX implement LX_WNOTHREAD, LX_WALL, LX_WCLONE */
108
109 if (options & LX_WNOHANG)
110 newoptions |= WNOHANG;
111 if (options & LX_WUNTRACED)
112 newoptions |= WUNTRACED;
113
114 return (newoptions);
115 }
116
117 static int
118 lx_wstat(int code, int status)
119 {
120 int stat = 0;
121
122 switch (code) {
123 case CLD_EXITED:
124 stat = status << 8;
125 break;
126 case CLD_DUMPED:
127 stat = stol_signo[status];
128 assert(stat != -1);
129 stat |= WCOREFLG;
130 break;
131 case CLD_KILLED:
132 stat = stol_signo[status];
133 assert(stat != -1);
134 break;
135 case CLD_TRAPPED:
136 case CLD_STOPPED:
137 stat = stol_signo[status];
138 assert(stat != -1);
139 stat <<= 8;
140 stat |= WSTOPFLG;
141 break;
142 case CLD_CONTINUED:
143 stat = WCONTFLG;
144 break;
145 }
146
147 return (stat);
148 }
149
150 /* wrapper to make solaris waitid work properly with ptrace */
151 static int
152 lx_waitid_helper(idtype_t idtype, id_t id, siginfo_t *info, int options)
153 {
154 do {
155 /*
156 * It's possible that we return EINVAL here if the idtype is
157 * P_PID or P_PGID and id is out of bounds for a valid pid or
158 * pgid, but Linux expects to see ECHILD. No good way occurs to
159 * handle this so we'll punt for now.
160 */
161 if (waitid(idtype, id, info, options) < 0)
162 return (-errno);
163
164 /*
165 * If the WNOHANG flag was specified and no child was found
166 * return 0.
167 */
168 if ((options & WNOHANG) && info->si_pid == 0)
169 return (0);
170
171 /*
172 * It's possible that we may have a spurious return for one of
173 * the child processes created by the ptrace subsystem. If
174 * that's the case, we simply try again.
175 */
176 } while (lx_ptrace_wait(info) == -1);
177 return (0);
178 }
179
180 int
181 lx_wait4(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
182 {
183 siginfo_t info = { 0 };
184 struct rusage ru = { 0 };
185 idtype_t idtype;
186 id_t id;
187 int options, status = 0;
188 pid_t pid = (pid_t)p1;
189 int rval;
190
191 if ((options = ltos_options(p3)) == -1)
192 return (-EINVAL);
193
194 /*
195 * While not listed as a valid return code, Linux's wait4(2) does,
196 * in fact, get an EFAULT if either the status pointer or rusage
197 * pointer is invalid. Since a failed waitpid should leave child
198 * process in a state where a future wait4(2) will succeed, we
199 * check them by copying out the values their buffers originally
200 * contained. (We need to do this as a failed system call should
201 * never affect the contents of a passed buffer.)
202 *
203 * This will fail if the buffers in question are write-only.
204 */
205 if ((void *)p2 != NULL &&
206 ((uucopy((void *)p2, &status, sizeof (status)) != 0) ||
207 (uucopy(&status, (void *)p2, sizeof (status)) != 0)))
208 return (-EFAULT);
209
210 if ((void *)p4 != NULL) {
211 if ((uucopy((void *)p4, &ru, sizeof (ru)) != 0) ||
212 (uucopy(&ru, (void *)p4, sizeof (ru)) != 0))
213 return (-EFAULT);
214 }
215
216 if (pid < -1) {
217 idtype = P_PGID;
218 id = -pid;
219 } else if (pid == -1) {
220 idtype = P_ALL;
221 id = 0;
222 } else if (pid == 0) {
223 idtype = P_PGID;
224 id = getpgrp();
225 } else {
226 idtype = P_PID;
227 id = pid;
228 }
229
230 options |= WEXITED | WTRAPPED;
231
232 if ((rval = lx_waitid_helper(idtype, id, &info, options)) < 0)
233 return (rval);
234 /*
235 * If the WNOHANG flag was specified and no child was found return 0.
236 */
237 if ((options & WNOHANG) && info.si_pid == 0)
238 return (0);
239
240 status = lx_wstat(info.si_code, info.si_status);
241
242 /*
243 * Unfortunately if this attempt to copy out either the status or the
244 * rusage fails, the process will be in an inconsistent state as
245 * subsequent calls to wait for the same child will fail where they
246 * should succeed on a Linux system. This, however, is rather
247 * unlikely since we tested the validity of both above.
248 */
249 if (p2 != NULL && uucopy(&status, (void *)p2, sizeof (status)) != 0)
250 return (-EFAULT);
251
252 if (p4 != NULL && (rval = lx_getrusage(LX_RUSAGE_CHILDREN, p4)) != 0)
253 return (rval);
254
255 return (info.si_pid);
256 }
257
258 int
259 lx_waitpid(uintptr_t p1, uintptr_t p2, uintptr_t p3)
260 {
261 return (lx_wait4(p1, p2, p3, NULL));
262 }
263
264 int
265 lx_waitid(uintptr_t idtype, uintptr_t id, uintptr_t infop, uintptr_t opt)
266 {
267 int rval, options;
268 siginfo_t s_infop = {0};
269 if ((options = ltos_options(opt)) == -1)
270 return (-1);
271 switch (idtype) {
272 case LX_P_ALL:
273 idtype = P_ALL;
274 break;
275 case LX_P_PID:
276 idtype = P_PID;
277 break;
278 case LX_P_GID:
279 idtype = P_GID;
280 break;
281 default:
282 return (-EINVAL);
283 }
284 if ((rval = lx_waitid_helper(idtype, (id_t)id, &s_infop, options)) < 0)
285 return (rval);
286
287 return (stol_siginfo(&s_infop, (lx_siginfo_t *)infop));
288 }