1/*
2 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7/*	  All Rights Reserved	*/
8
9/*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15#pragma ident	"%Z%%M%	%I%	%E% SMI"
16
17/*
18 * Compatibility lib for BSD's wait3(). It is not
19 * binary compatible, since BSD's WNOHANG and WUNTRACED
20 * carry different #define values.
21 */
22#include <errno.h>
23#include <sys/types.h>
24#include <sys/time.h>
25#include <sys/times.h>
26#include <wait.h>
27#include <sys/siginfo.h>
28#include <sys/procset.h>
29#include <sys/param.h>
30#include <sys/resource.h>
31
32/*
33 * Since sysV does not support rusage as in BSD, an approximate approach
34 * is:
35 *	...
36 *	call times
37 *	call waitid
38 *	if ( a child is found )
39 *		call times again
40 *		rusage ~= diff in the 2 times call
41 *	...
42 *
43 */
44
45/*
46 * XXX:  There is now a wait3 function in libc which should be used instead
47 * of this local version of wait3.  With the addition of a wait3 prototype
48 * in <sys/wait.h> as per the X/Open XPG4v2 specification, compilation of
49 * the csh utility will result in warnings, hence the renaming of the local
50 * version.  Using the libc wait3 rather than the local version results in
51 * a failure with csh, however, this version should eventually be dropped
52 * in favor of the libc wait3 with appropriate updates made to sh.proc.c
53 * to account for the difference in implementation of the local versus
54 * the libc versions.  This should probably be done as part of an overall
55 * effort to rid csh of local versions of functions now in libc.
56 */
57
58static int wstat(int code, int status);
59
60pid_t
61csh_wait3(int *status, int options, struct rusage *rp)
62{
63	struct tms before_tms;
64	struct tms after_tms;
65	siginfo_t info;
66	int error;
67
68	if (rp)
69		memset((void *)rp, 0, sizeof (struct rusage));
70	memset((void *)&info, 0, sizeof (siginfo_t));
71	if (times(&before_tms) == -1)
72		return (-1);	/* errno is set by times() */
73
74	/*
75	 * BSD's wait3() only supports WNOHANG & WUNTRACED
76	 */
77	options |= (WNOHANG|WUNTRACED|WEXITED|WSTOPPED|WTRAPPED|WCONTINUED);
78	error = waitid(P_ALL, 0, &info, options);
79	if (error == 0) {
80		clock_t	diffu;	/* difference in usertime (ticks) */
81		clock_t	diffs;	/* difference in systemtime (ticks) */
82
83		if ((options & WNOHANG) && (info.si_pid == 0))
84			return (0);	/* no child found */
85
86		if (rp) {
87			if (times(&after_tms) == -1)
88				return (-1);	/* errno set by times() */
89			/*
90			 * The system/user time is an approximation only !!!
91			 */
92			diffu = after_tms.tms_cutime - before_tms.tms_cutime;
93			diffs = after_tms.tms_cstime - before_tms.tms_cstime;
94			rp->ru_utime.tv_sec = diffu/HZ;
95			rp->ru_utime.tv_usec = ((diffu % HZ) * 1000000) / HZ;
96			rp->ru_stime.tv_sec = diffs/HZ;
97			rp->ru_stime.tv_usec = ((diffs % HZ) * 1000000) / HZ;
98		}
99		*status = wstat(info.si_code, info.si_status);
100		return (info.si_pid);
101
102	} else {
103		return (-1);	/* error number is set by waitid() */
104	}
105}
106
107/*
108 * Convert the status code to old style wait status
109 */
110static int
111wstat(int code, int status)
112{
113	int stat = (status & 0377);
114
115	switch (code) {
116		case CLD_EXITED:
117			stat <<= 8;
118			break;
119		case CLD_DUMPED:
120			stat |= WCOREFLG;
121			break;
122		case CLD_KILLED:
123			break;
124		case CLD_TRAPPED:
125		case CLD_STOPPED:
126			stat <<= 8;
127			stat |= WSTOPFLG;
128			break;
129		case CLD_CONTINUED:
130			stat = WCONTFLG;
131			break;
132	}
133	return (stat);
134}
135
136pid_t
137csh_wait_noreap(void)
138{
139	siginfo_t info;
140
141	if (waitid(P_ALL, 0, &info,
142	    WEXITED | WTRAPPED | WSTOPPED | WCONTINUED | WNOWAIT) != 0)
143		return (-1);
144	return (info.si_pid);
145}
146