xref: /illumos-gate/usr/src/cmd/csh/wait3.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 
58 static int wstat(int code, int status);
59 
60 pid_t
61 csh_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  */
110 static int
111 wstat(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 
136 pid_t
137 csh_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