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 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1988 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32/*
33 * All of the wait*() functions are cancellation points.
34 */
35#pragma weak _waitpid = waitpid
36#pragma weak _wait = wait
37
38#include "lint.h"
39#include <unistd.h>
40#include <string.h>
41#include <errno.h>
42#include <wait.h>
43#include <sys/types.h>
44#include <sys/siginfo.h>
45#include <sys/times.h>
46#include <sys/resource.h>
47
48/*
49 * Convert the siginfo_t code and status fields to an old style wait status.
50 */
51static int
52wstat(int code, int status)
53{
54	int stat = (status & 0377);
55
56	switch (code) {
57	case CLD_EXITED:
58		stat <<= 8;
59		break;
60	case CLD_DUMPED:
61		stat |= WCOREFLG;
62		break;
63	case CLD_KILLED:
64		break;
65	case CLD_TRAPPED:
66	case CLD_STOPPED:
67		stat <<= 8;
68		stat |= WSTOPFLG;
69		break;
70	case CLD_CONTINUED:
71		stat = WCONTFLG;
72		break;
73	}
74	return (stat);
75}
76
77pid_t
78waitpid(pid_t pid, int *stat_loc, int options)
79{
80	idtype_t idtype;
81	id_t id;
82	siginfo_t info;
83	int error;
84
85	if (pid > 0) {
86		idtype = P_PID;
87		id = pid;
88	} else if (pid < -1) {
89		idtype = P_PGID;
90		id = -pid;
91	} else if (pid == -1) {
92		idtype = P_ALL;
93		id = 0;
94	} else {
95		idtype = P_PGID;
96		id = getpgid(0);
97	}
98
99	options |= (WEXITED|WTRAPPED);
100
101	if ((error = waitid(idtype, id, &info, options)) < 0)
102		return (error);
103
104	if (stat_loc)
105		*stat_loc = wstat(info.si_code, info.si_status);
106
107	return (info.si_pid);
108}
109
110pid_t
111wait(int *stat_loc)
112{
113	return (waitpid(-1, stat_loc, 0));
114}
115
116pid_t
117wait4(pid_t pid, int *stat_loc, int options, struct rusage *rp)
118{
119	struct tms	before_tms;
120	struct tms	after_tms;
121	siginfo_t	info;
122	int		error;
123	int		noptions;
124	idtype_t	idtype;
125
126	if (rp)
127		(void) memset(rp, 0, sizeof (struct rusage));
128	(void) memset(&info, 0, sizeof (siginfo_t));
129
130	if (times(&before_tms) == (clock_t)-1)
131		return (-1);		/* errno is set by times() */
132
133	/*
134	 * SunOS's wait4() previously supported only WNOHANG &
135	 * WUNTRACED.  XPG4v2 mandates that wait3() (which calls
136	 * wait4()) also support WCONTINUED.
137	 */
138	if (options & ~(WNOHANG|WUNTRACED|WCONTINUED)) {
139		errno = EINVAL;
140		return (-1);
141	}
142	noptions = options | WEXITED | WTRAPPED;
143
144	/*
145	 * Emulate undocumented 4.x semantics for 1186845
146	 */
147	if (pid < 0) {
148		pid = -pid;
149		idtype = P_PGID;
150	} else if (pid == 0) {
151		idtype = P_ALL;
152	} else {
153		idtype = P_PID;
154	}
155
156	error = waitid(idtype, pid, &info, noptions);
157	if (error == 0) {
158		clock_t diffu;	/* difference in usertime (ticks) */
159		clock_t diffs;	/* difference in systemtime (ticks) */
160		clock_t hz;
161
162		if ((options & WNOHANG) && info.si_pid == 0)
163			return (0);	/* no child found */
164
165		if (rp) {
166			if (times(&after_tms) == (clock_t)-1)
167				return (-1);	/* errno set by times() */
168			/*
169			 * The system/user time is an approximation only !!!
170			 */
171			diffu = after_tms.tms_cutime - before_tms.tms_cutime;
172			diffs = after_tms.tms_cstime - before_tms.tms_cstime;
173			hz = CLK_TCK;
174			rp->ru_utime.tv_sec = diffu / hz;
175			rp->ru_utime.tv_usec = (diffu % hz) * (1000000 / hz);
176			rp->ru_stime.tv_sec = diffs / hz;
177			rp->ru_stime.tv_usec = (diffs % hz) * (1000000 / hz);
178		}
179		if (stat_loc)
180			*stat_loc = wstat(info.si_code, info.si_status);
181		return (info.si_pid);
182	} else {
183		return (-1);		/* error number is set by waitid() */
184	}
185}
186
187pid_t
188wait3(int *stat_loc, int options, struct rusage *rp)
189{
190	return (wait4(0, stat_loc, options, rp));
191}
192