xref: /illumos-gate/usr/src/ucblib/libucb/port/sys/wait4.c (revision 55fea89d)
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
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
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