3333
3434#include <sys/types.h>
3535#include <sys/event.h>
36+ #include <sys/sysctl.h>
3637#include <sys/time.h>
38+ #include <sys/tree.h>
3739#include <sys/wait.h>
3840
3941#include <err.h>
4648#include <sysexits.h>
4749#include <unistd.h>
4850
51+ struct pid {
52+ RB_ENTRY (pid ) entry ;
53+ pid_t pid ;
54+ };
55+
56+ static int
57+ pidcmp (const struct pid * a , const struct pid * b )
58+ {
59+ return (a -> pid > b -> pid ? 1 : a -> pid < b -> pid ? -1 : 0 );
60+ }
61+
62+ RB_HEAD (pidtree , pid );
63+ static struct pidtree pids = RB_INITIALIZER (& pids );
64+ RB_GENERATE_STATIC (pidtree , pid , entry , pidcmp );
65+
4966static void
5067usage (void )
5168{
52- fprintf (stderr , "usage: pwait [-t timeout] [-ov ] pid ...\n" );
69+ fprintf (stderr , "usage: pwait [-t timeout] [-opv ] pid ...\n" );
5370 exit (EX_USAGE );
5471}
5572
@@ -61,22 +78,28 @@ main(int argc, char *argv[])
6178{
6279 struct itimerval itv ;
6380 struct kevent * e ;
81+ struct pid k , * p ;
6482 char * end , * s ;
6583 double timeout ;
84+ size_t sz ;
6685 long pid ;
6786 pid_t mypid ;
68- int i , kq , n , nleft , opt , status ;
69- bool oflag , tflag , verbose ;
87+ int i , kq , n , ndone , nleft , opt , pid_max , ret , status ;
88+ bool oflag , pflag , tflag , verbose ;
7089
7190 oflag = false;
91+ pflag = false;
7292 tflag = false;
7393 verbose = false;
7494 memset (& itv , 0 , sizeof (itv ));
7595
76- while ((opt = getopt (argc , argv , "ot :v" )) != -1 ) {
96+ while ((opt = getopt (argc , argv , "opt :v" )) != -1 ) {
7797 switch (opt ) {
7898 case 'o' :
79- oflag = 1 ;
99+ oflag = true;
100+ break ;
101+ case 'p' :
102+ pflag = true;
80103 break ;
81104 case 't' :
82105 tflag = true;
@@ -128,16 +151,17 @@ main(int argc, char *argv[])
128151 usage ();
129152 }
130153
131- kq = kqueue ();
132- if (kq == -1 ) {
154+ if ((kq = kqueue ()) < 0 )
133155 err (EX_OSERR , "kqueue" );
134- }
135156
136- e = malloc ((argc + tflag ) * sizeof (struct kevent ));
137- if (e == NULL ) {
157+ sz = sizeof (pid_max );
158+ if (sysctlbyname ("kern.pid_max" , & pid_max , & sz , NULL , 0 ) != 0 ) {
159+ pid_max = 99999 ;
160+ }
161+ if ((e = malloc ((argc + tflag ) * sizeof (* e ))) == NULL ) {
138162 err (EX_OSERR , "malloc" );
139163 }
140- nleft = 0 ;
164+ ndone = nleft = 0 ;
141165 mypid = getpid ();
142166 for (n = 0 ; n < argc ; n ++ ) {
143167 s = argv [n ];
@@ -147,35 +171,37 @@ main(int argc, char *argv[])
147171 }
148172 errno = 0 ;
149173 pid = strtol (s , & end , 10 );
150- if (pid < 0 || * end != '\0' || errno != 0 ) {
174+ if (pid < 0 || pid > pid_max || * end != '\0' || errno != 0 ) {
151175 warnx ("%s: bad process id" , s );
152176 continue ;
153177 }
154178 if (pid == mypid ) {
155179 warnx ("%s: skipping my own pid" , s );
156180 continue ;
157181 }
158- for (i = 0 ; i < nleft ; i ++ ) {
159- if (e [i ].ident == (uintptr_t )pid ) {
160- break ;
161- }
182+ if ((p = malloc (sizeof (* p ))) == NULL ) {
183+ err (EX_OSERR , NULL );
162184 }
163- if (i < nleft ) {
185+ p -> pid = pid ;
186+ if (RB_INSERT (pidtree , & pids , p ) != NULL ) {
164187 /* Duplicate. */
188+ free (p );
165189 continue ;
166190 }
167191 EV_SET (e + nleft , pid , EVFILT_PROC , EV_ADD , NOTE_EXIT , 0 , NULL );
168192 if (kevent (kq , e + nleft , 1 , NULL , 0 , NULL ) == -1 ) {
193+ if (errno != ESRCH )
194+ err (EX_OSERR , "kevent()" );
169195 warn ("%ld" , pid );
170- if ( oflag ) {
171- exit ( EX_OK );
172- }
196+ RB_REMOVE ( pidtree , & pids , p );
197+ free ( p );
198+ ndone ++ ;
173199 } else {
174200 nleft ++ ;
175201 }
176202 }
177203
178- if (nleft > 0 && tflag ) {
204+ if (( ndone == 0 || ! oflag ) && nleft > 0 && tflag ) {
179205 /*
180206 * Explicitly detect SIGALRM so that an exit status of 124
181207 * can be returned rather than 142.
@@ -190,7 +216,8 @@ main(int argc, char *argv[])
190216 err (EX_OSERR , "setitimer" );
191217 }
192218 }
193- while (nleft > 0 ) {
219+ ret = EX_OK ;
220+ while ((ndone == 0 || !oflag ) && ret == EX_OK && nleft > 0 ) {
194221 n = kevent (kq , NULL , 0 , e , nleft + tflag , NULL );
195222 if (n == -1 ) {
196223 err (EX_OSERR , "kevent" );
@@ -200,29 +227,34 @@ main(int argc, char *argv[])
200227 if (verbose ) {
201228 printf ("timeout\n" );
202229 }
203- exit ( 124 ) ;
230+ ret = 124 ;
204231 }
232+ pid = e [i ].ident ;
205233 if (verbose ) {
206234 status = e [i ].data ;
207235 if (WIFEXITED (status )) {
208236 printf ("%ld: exited with status %d.\n" ,
209- (long )e [i ].ident ,
210- WEXITSTATUS (status ));
237+ pid , WEXITSTATUS (status ));
211238 } else if (WIFSIGNALED (status )) {
212239 printf ("%ld: killed by signal %d.\n" ,
213- (long )e [i ].ident ,
214- WTERMSIG (status ));
240+ pid , WTERMSIG (status ));
215241 } else {
216- printf ("%ld: terminated.\n" ,
217- (long )e [i ].ident );
242+ printf ("%ld: terminated.\n" , pid );
218243 }
219244 }
220- if (oflag ) {
221- exit (EX_OK );
245+ k .pid = pid ;
246+ if ((p = RB_FIND (pidtree , & pids , & k )) != NULL ) {
247+ RB_REMOVE (pidtree , & pids , p );
248+ free (p );
249+ ndone ++ ;
222250 }
223251 -- nleft ;
224252 }
225253 }
226-
227- exit (EX_OK );
254+ if (pflag ) {
255+ RB_FOREACH (p , pidtree , & pids ) {
256+ printf ("%d\n" , p -> pid );
257+ }
258+ }
259+ exit (ret );
228260}
0 commit comments