1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/stat.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <libgen.h>
33*0Sstevel@tonic-gate #include <limits.h>
34*0Sstevel@tonic-gate #include <alloca.h>
35*0Sstevel@tonic-gate #include <unistd.h>
36*0Sstevel@tonic-gate #include <string.h>
37*0Sstevel@tonic-gate #include <fcntl.h>
38*0Sstevel@tonic-gate #include <ctype.h>
39*0Sstevel@tonic-gate #include <errno.h>
40*0Sstevel@tonic-gate #include <dirent.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include "libproc.h"
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate static int
45*0Sstevel@tonic-gate open_psinfo(const char *arg, int *perr)
46*0Sstevel@tonic-gate {
47*0Sstevel@tonic-gate 	/*
48*0Sstevel@tonic-gate 	 * Allocate enough space for "/proc/" + arg + "/psinfo"
49*0Sstevel@tonic-gate 	 */
50*0Sstevel@tonic-gate 	char *path = alloca(strlen(arg) + 14);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate 	struct stat64 st;
53*0Sstevel@tonic-gate 	int fd;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	if (strchr(arg, '/') == NULL) {
56*0Sstevel@tonic-gate 		(void) strcpy(path, "/proc/");
57*0Sstevel@tonic-gate 		(void) strcat(path, arg);
58*0Sstevel@tonic-gate 	} else
59*0Sstevel@tonic-gate 		(void) strcpy(path, arg);
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	(void) strcat(path, "/psinfo");
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	/*
64*0Sstevel@tonic-gate 	 * Attempt to open the psinfo file, and return the fd if we can
65*0Sstevel@tonic-gate 	 * confirm this is a regular file provided by /proc.
66*0Sstevel@tonic-gate 	 */
67*0Sstevel@tonic-gate 	if ((fd = open64(path, O_RDONLY)) >= 0) {
68*0Sstevel@tonic-gate 		if (fstat64(fd, &st) != 0 || !S_ISREG(st.st_mode) ||
69*0Sstevel@tonic-gate 		    strcmp(st.st_fstype, "proc") != 0) {
70*0Sstevel@tonic-gate 			(void) close(fd);
71*0Sstevel@tonic-gate 			fd = -1;
72*0Sstevel@tonic-gate 		}
73*0Sstevel@tonic-gate 	} else if (errno == EACCES || errno == EPERM)
74*0Sstevel@tonic-gate 		*perr = G_PERM;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	return (fd);
77*0Sstevel@tonic-gate }
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate static int
80*0Sstevel@tonic-gate open_core(const char *arg, int *perr)
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN
83*0Sstevel@tonic-gate 	uchar_t order = ELFDATA2MSB;
84*0Sstevel@tonic-gate #else
85*0Sstevel@tonic-gate 	uchar_t order = ELFDATA2LSB;
86*0Sstevel@tonic-gate #endif
87*0Sstevel@tonic-gate 	GElf_Ehdr ehdr;
88*0Sstevel@tonic-gate 	int fd;
89*0Sstevel@tonic-gate 	int is_noelf = -1;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/*
92*0Sstevel@tonic-gate 	 * Attempt to open the core file, and return the fd if we can confirm
93*0Sstevel@tonic-gate 	 * this is an ELF file of type ET_CORE.
94*0Sstevel@tonic-gate 	 */
95*0Sstevel@tonic-gate 	if ((fd = open64(arg, O_RDONLY)) >= 0) {
96*0Sstevel@tonic-gate 		if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) {
97*0Sstevel@tonic-gate 			(void) close(fd);
98*0Sstevel@tonic-gate 			fd = -1;
99*0Sstevel@tonic-gate 		} else if ((is_noelf = memcmp(&ehdr.e_ident[EI_MAG0], ELFMAG,
100*0Sstevel@tonic-gate 			    SELFMAG)) != 0 || ehdr.e_type != ET_CORE) {
101*0Sstevel@tonic-gate 				(void) close(fd);
102*0Sstevel@tonic-gate 				fd = -1;
103*0Sstevel@tonic-gate 				if (is_noelf == 0 &&
104*0Sstevel@tonic-gate 				    ehdr.e_ident[EI_DATA] != order)
105*0Sstevel@tonic-gate 					*perr = G_ISAINVAL;
106*0Sstevel@tonic-gate 		}
107*0Sstevel@tonic-gate 	} else if (errno == EACCES || errno == EPERM)
108*0Sstevel@tonic-gate 		*perr = G_PERM;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	return (fd);
111*0Sstevel@tonic-gate }
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /*
114*0Sstevel@tonic-gate  * Make the error message precisely match the type of arguments the caller
115*0Sstevel@tonic-gate  * wanted to process.  This ensures that a tool which only accepts pids does
116*0Sstevel@tonic-gate  * not produce an error message saying "no such process or core file 'foo'".
117*0Sstevel@tonic-gate  */
118*0Sstevel@tonic-gate static int
119*0Sstevel@tonic-gate open_error(int oflag)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	if ((oflag & PR_ARG_ANY) == PR_ARG_PIDS)
122*0Sstevel@tonic-gate 		return (G_NOPROC);
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	if ((oflag & PR_ARG_ANY) == PR_ARG_CORES)
125*0Sstevel@tonic-gate 		return (G_NOCORE);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	return (G_NOPROCORCORE);
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static void *
131*0Sstevel@tonic-gate proc_grab_common(const char *arg, const char *path, int oflag, int gflag,
132*0Sstevel@tonic-gate     int *perr, const char **lwps, psinfo_t *psp)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	psinfo_t psinfo;
135*0Sstevel@tonic-gate 	char *core;
136*0Sstevel@tonic-gate 	int fd;
137*0Sstevel@tonic-gate 	char *slash;
138*0Sstevel@tonic-gate 	struct ps_prochandle *Pr;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	*perr = 0;
141*0Sstevel@tonic-gate 	if (lwps)
142*0Sstevel@tonic-gate 		*lwps = NULL;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	if (lwps != NULL && (slash = strrchr(arg, '/')) != NULL) {
145*0Sstevel@tonic-gate 		/*
146*0Sstevel@tonic-gate 		 * Check to see if the user has supplied an lwp range.  First,
147*0Sstevel@tonic-gate 		 * try to grab it as a pid/lwp combo.
148*0Sstevel@tonic-gate 		 */
149*0Sstevel@tonic-gate 		*slash = '\0';
150*0Sstevel@tonic-gate 		if ((oflag & PR_ARG_PIDS) &&
151*0Sstevel@tonic-gate 		    (fd = open_psinfo(arg, perr)) != -1) {
152*0Sstevel@tonic-gate 			if (read(fd, &psinfo,
153*0Sstevel@tonic-gate 			    sizeof (psinfo_t)) == sizeof (psinfo_t)) {
154*0Sstevel@tonic-gate 				(void) close(fd);
155*0Sstevel@tonic-gate 				*lwps = slash + 1;
156*0Sstevel@tonic-gate 				*slash = '/';
157*0Sstevel@tonic-gate 				if (proc_lwp_range_valid(*lwps) != 0) {
158*0Sstevel@tonic-gate 					*perr = G_BADLWPS;
159*0Sstevel@tonic-gate 					return (NULL);
160*0Sstevel@tonic-gate 				}
161*0Sstevel@tonic-gate 				if (psp) {
162*0Sstevel@tonic-gate 					*psp = psinfo;
163*0Sstevel@tonic-gate 					return (psp);
164*0Sstevel@tonic-gate 				} else  {
165*0Sstevel@tonic-gate 					return (Pgrab(psinfo.pr_pid, gflag,
166*0Sstevel@tonic-gate 					    perr));
167*0Sstevel@tonic-gate 				}
168*0Sstevel@tonic-gate 			}
169*0Sstevel@tonic-gate 			(void) close(fd);
170*0Sstevel@tonic-gate 		}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 		/*
173*0Sstevel@tonic-gate 		 * Next, try grabbing it as a corefile.
174*0Sstevel@tonic-gate 		 */
175*0Sstevel@tonic-gate 		if ((oflag & PR_ARG_CORES) &&
176*0Sstevel@tonic-gate 		    (fd = open_core(arg, perr)) != -1) {
177*0Sstevel@tonic-gate 			*lwps = slash + 1;
178*0Sstevel@tonic-gate 			*slash = '/';
179*0Sstevel@tonic-gate 			if (proc_lwp_range_valid(*lwps) != 0) {
180*0Sstevel@tonic-gate 				*perr = G_BADLWPS;
181*0Sstevel@tonic-gate 				return (NULL);
182*0Sstevel@tonic-gate 			}
183*0Sstevel@tonic-gate 			core = alloca(strlen(arg) + 1);
184*0Sstevel@tonic-gate 			(void) strcpy(core, arg);
185*0Sstevel@tonic-gate 			if ((Pr = Pfgrab_core(fd, path == NULL ?
186*0Sstevel@tonic-gate 			    dirname(core) : path, perr)) != NULL) {
187*0Sstevel@tonic-gate 				if (psp) {
188*0Sstevel@tonic-gate 					(void) memcpy(psp, Ppsinfo(Pr),
189*0Sstevel@tonic-gate 					    sizeof (psinfo_t));
190*0Sstevel@tonic-gate 					Prelease(Pr, 0);
191*0Sstevel@tonic-gate 					return (psp);
192*0Sstevel@tonic-gate 				} else {
193*0Sstevel@tonic-gate 					return (Pr);
194*0Sstevel@tonic-gate 				}
195*0Sstevel@tonic-gate 			}
196*0Sstevel@tonic-gate 		}
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 		*slash = '/';
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	if ((oflag & PR_ARG_PIDS) && (fd = open_psinfo(arg, perr)) != -1) {
202*0Sstevel@tonic-gate 		if (read(fd, &psinfo, sizeof (psinfo_t)) == sizeof (psinfo_t)) {
203*0Sstevel@tonic-gate 			(void) close(fd);
204*0Sstevel@tonic-gate 			if (psp) {
205*0Sstevel@tonic-gate 				*psp = psinfo;
206*0Sstevel@tonic-gate 				return (psp);
207*0Sstevel@tonic-gate 			} else {
208*0Sstevel@tonic-gate 				return (Pgrab(psinfo.pr_pid, gflag, perr));
209*0Sstevel@tonic-gate 			}
210*0Sstevel@tonic-gate 		}
211*0Sstevel@tonic-gate 		/*
212*0Sstevel@tonic-gate 		 * If the read failed, the process may have gone away;
213*0Sstevel@tonic-gate 		 * we continue checking for core files or fail with G_NOPROC
214*0Sstevel@tonic-gate 		 */
215*0Sstevel@tonic-gate 		(void) close(fd);
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if ((oflag & PR_ARG_CORES) && (fd = open_core(arg, perr)) != -1) {
219*0Sstevel@tonic-gate 		core = alloca(strlen(arg) + 1);
220*0Sstevel@tonic-gate 		(void) strcpy(core, arg);
221*0Sstevel@tonic-gate 		if ((Pr = Pfgrab_core(fd, path == NULL ? dirname(core) : path,
222*0Sstevel@tonic-gate 		    perr)) != NULL) {
223*0Sstevel@tonic-gate 			if (psp) {
224*0Sstevel@tonic-gate 				(void) memcpy(psp, Ppsinfo(Pr),
225*0Sstevel@tonic-gate 				    sizeof (psinfo_t));
226*0Sstevel@tonic-gate 				Prelease(Pr, 0);
227*0Sstevel@tonic-gate 				return (psp);
228*0Sstevel@tonic-gate 			} else {
229*0Sstevel@tonic-gate 				return (Pr);
230*0Sstevel@tonic-gate 			}
231*0Sstevel@tonic-gate 		}
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	/*
235*0Sstevel@tonic-gate 	 * We were unable to open the corefile.  If we have no meaningful
236*0Sstevel@tonic-gate 	 * information, report the (ambiguous) error from open_error().
237*0Sstevel@tonic-gate 	 */
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	if (*perr == 0)
240*0Sstevel@tonic-gate 		*perr = open_error(oflag);
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	return (NULL);
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate struct ps_prochandle *
246*0Sstevel@tonic-gate proc_arg_xgrab(const char *arg, const char *path, int oflag, int gflag,
247*0Sstevel@tonic-gate     int *perr, const char **lwps)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	return (proc_grab_common(arg, path, oflag, gflag, perr, lwps, NULL));
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate struct ps_prochandle *
253*0Sstevel@tonic-gate proc_arg_grab(const char *arg, int oflag, int gflag, int *perr)
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate 	return (proc_grab_common(arg, NULL, oflag, gflag, perr, NULL, NULL));
256*0Sstevel@tonic-gate }
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate pid_t
259*0Sstevel@tonic-gate proc_arg_psinfo(const char *arg, int oflag, psinfo_t *psp, int *perr)
260*0Sstevel@tonic-gate {
261*0Sstevel@tonic-gate 	psinfo_t psinfo;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	if (psp == NULL)
264*0Sstevel@tonic-gate 		psp = &psinfo;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (proc_grab_common(arg, NULL, oflag, 0, perr, NULL, psp) == NULL)
267*0Sstevel@tonic-gate 		return (-1);
268*0Sstevel@tonic-gate 	else
269*0Sstevel@tonic-gate 		return (psp->pr_pid);
270*0Sstevel@tonic-gate }
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate pid_t
273*0Sstevel@tonic-gate proc_arg_xpsinfo(const char *arg, int oflag, psinfo_t *psp, int *perr,
274*0Sstevel@tonic-gate     const char **lwps)
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate 	psinfo_t psinfo;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if (psp == NULL)
279*0Sstevel@tonic-gate 		psp = &psinfo;
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	if (proc_grab_common(arg, NULL, oflag, 0, perr, lwps, psp) == NULL)
282*0Sstevel@tonic-gate 		return (-1);
283*0Sstevel@tonic-gate 	else
284*0Sstevel@tonic-gate 		return (psp->pr_pid);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate /*
288*0Sstevel@tonic-gate  * Convert psinfo_t.pr_psargs string into itself, replacing unprintable
289*0Sstevel@tonic-gate  * characters with space along the way.  Stop on a null character.
290*0Sstevel@tonic-gate  */
291*0Sstevel@tonic-gate void
292*0Sstevel@tonic-gate proc_unctrl_psinfo(psinfo_t *psp)
293*0Sstevel@tonic-gate {
294*0Sstevel@tonic-gate 	char *s = &psp->pr_psargs[0];
295*0Sstevel@tonic-gate 	size_t n = PRARGSZ;
296*0Sstevel@tonic-gate 	int c;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	while (n-- != 0 && (c = (*s & UCHAR_MAX)) != '\0') {
299*0Sstevel@tonic-gate 		if (!isprint(c))
300*0Sstevel@tonic-gate 			c = ' ';
301*0Sstevel@tonic-gate 		*s++ = (char)c;
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	*s = '\0';
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate static int
308*0Sstevel@tonic-gate proc_lwp_get_range(char *range, id_t *low, id_t *high)
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	if (*range == '-')
311*0Sstevel@tonic-gate 		*low = 0;
312*0Sstevel@tonic-gate 	else
313*0Sstevel@tonic-gate 		*low = (id_t)strtol(range, &range, 10);
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	if (*range == '\0' || *range == ',') {
316*0Sstevel@tonic-gate 		*high = *low;
317*0Sstevel@tonic-gate 		return (0);
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 	if (*range != '-') {
320*0Sstevel@tonic-gate 		return (-1);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 	range++;
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	if (*range == '\0')
325*0Sstevel@tonic-gate 		*high = INT_MAX;
326*0Sstevel@tonic-gate 	else
327*0Sstevel@tonic-gate 		*high = (id_t)strtol(range, &range, 10);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	if (*range != '\0' && *range != ',') {
330*0Sstevel@tonic-gate 		return (-1);
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	if (*high < *low) {
334*0Sstevel@tonic-gate 		id_t tmp = *high;
335*0Sstevel@tonic-gate 		*high = *low;
336*0Sstevel@tonic-gate 		*low = tmp;
337*0Sstevel@tonic-gate 	}
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	return (0);
340*0Sstevel@tonic-gate }
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate /*
343*0Sstevel@tonic-gate  * Determine if the specified lwpid is in the given set of lwpids.
344*0Sstevel@tonic-gate  * The set can include multiple lwpid ranges separated by commas
345*0Sstevel@tonic-gate  * and has the following syntax:
346*0Sstevel@tonic-gate  *
347*0Sstevel@tonic-gate  * 	lwp_range[,lwp_range]*
348*0Sstevel@tonic-gate  *
349*0Sstevel@tonic-gate  * where lwp_range is specifed as:
350*0Sstevel@tonic-gate  *
351*0Sstevel@tonic-gate  * 	-n			lwpid <= n
352*0Sstevel@tonic-gate  * 	n-m			n <= lwpid <= m
353*0Sstevel@tonic-gate  * 	n-			lwpid >= n
354*0Sstevel@tonic-gate  * 	n			lwpid == n
355*0Sstevel@tonic-gate  */
356*0Sstevel@tonic-gate int
357*0Sstevel@tonic-gate proc_lwp_in_set(const char *set, lwpid_t lwpid)
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	id_t low, high;
360*0Sstevel@tonic-gate 	id_t id = (id_t)lwpid;
361*0Sstevel@tonic-gate 	char *comma;
362*0Sstevel@tonic-gate 	char *range = (char *)set;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	/*
365*0Sstevel@tonic-gate 	 * A NULL set indicates that all LWPs are valid.
366*0Sstevel@tonic-gate 	 */
367*0Sstevel@tonic-gate 	if (set == NULL)
368*0Sstevel@tonic-gate 		return (1);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	while (range != NULL) {
371*0Sstevel@tonic-gate 		comma = strchr(range, ',');
372*0Sstevel@tonic-gate 		if (comma != NULL)
373*0Sstevel@tonic-gate 			*comma = '\0';
374*0Sstevel@tonic-gate 		if (proc_lwp_get_range(range, &low, &high) != 0) {
375*0Sstevel@tonic-gate 			if (comma != NULL)
376*0Sstevel@tonic-gate 				*comma = ',';
377*0Sstevel@tonic-gate 			return (0);
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 		if (comma != NULL) {
380*0Sstevel@tonic-gate 			*comma = ',';
381*0Sstevel@tonic-gate 			range = comma + 1;
382*0Sstevel@tonic-gate 		} else {
383*0Sstevel@tonic-gate 			range = NULL;
384*0Sstevel@tonic-gate 		}
385*0Sstevel@tonic-gate 		if (id >= low && id <= high)
386*0Sstevel@tonic-gate 			return (1);
387*0Sstevel@tonic-gate 	}
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	return (0);
390*0Sstevel@tonic-gate }
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate int
393*0Sstevel@tonic-gate proc_lwp_range_valid(const char *set)
394*0Sstevel@tonic-gate {
395*0Sstevel@tonic-gate 	char *comma;
396*0Sstevel@tonic-gate 	char *range = (char *)set;
397*0Sstevel@tonic-gate 	id_t low, high;
398*0Sstevel@tonic-gate 	int ret;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	if (range == NULL || *range == '\0' || *range == ',')
401*0Sstevel@tonic-gate 		return (-1);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	while (range != NULL) {
404*0Sstevel@tonic-gate 		comma = strchr(range, ',');
405*0Sstevel@tonic-gate 		if (comma != NULL)
406*0Sstevel@tonic-gate 			*comma = '\0';
407*0Sstevel@tonic-gate 		if ((ret = proc_lwp_get_range(range, &low, &high)) != 0) {
408*0Sstevel@tonic-gate 			if (comma != NULL)
409*0Sstevel@tonic-gate 				*comma = ',';
410*0Sstevel@tonic-gate 			return (ret);
411*0Sstevel@tonic-gate 		}
412*0Sstevel@tonic-gate 		if (comma != NULL) {
413*0Sstevel@tonic-gate 			*comma = ',';
414*0Sstevel@tonic-gate 			range = comma + 1;
415*0Sstevel@tonic-gate 		} else {
416*0Sstevel@tonic-gate 			range = NULL;
417*0Sstevel@tonic-gate 		}
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	return (0);
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate /*
424*0Sstevel@tonic-gate  * Walk all processes or LWPs in /proc and call func() for each.
425*0Sstevel@tonic-gate  * Stop calling func() if it returns non 0 value and return it.
426*0Sstevel@tonic-gate  */
427*0Sstevel@tonic-gate int
428*0Sstevel@tonic-gate proc_walk(proc_walk_f *func, void *arg, int flag)
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate 	DIR *procdir;
431*0Sstevel@tonic-gate 	struct dirent *dirent;
432*0Sstevel@tonic-gate 	char *errptr;
433*0Sstevel@tonic-gate 	char pidstr[80];
434*0Sstevel@tonic-gate 	psinfo_t psinfo;
435*0Sstevel@tonic-gate 	lwpsinfo_t *lwpsinfo;
436*0Sstevel@tonic-gate 	prheader_t prheader;
437*0Sstevel@tonic-gate 	void *buf;
438*0Sstevel@tonic-gate 	char *ptr;
439*0Sstevel@tonic-gate 	int bufsz;
440*0Sstevel@tonic-gate 	id_t pid;
441*0Sstevel@tonic-gate 	int fd, i;
442*0Sstevel@tonic-gate 	int ret = 0;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	if (flag != PR_WALK_PROC && flag != PR_WALK_LWP) {
445*0Sstevel@tonic-gate 		errno = EINVAL;
446*0Sstevel@tonic-gate 		return (-1);
447*0Sstevel@tonic-gate 	}
448*0Sstevel@tonic-gate 	if ((procdir = opendir("/proc")) == NULL)
449*0Sstevel@tonic-gate 		return (-1);
450*0Sstevel@tonic-gate 	while (dirent = readdir(procdir)) {
451*0Sstevel@tonic-gate 		if (dirent->d_name[0] == '.')	/* skip . and .. */
452*0Sstevel@tonic-gate 			continue;
453*0Sstevel@tonic-gate 		pid = (id_t)strtol(dirent->d_name, &errptr, 10);
454*0Sstevel@tonic-gate 		if (errptr != NULL && *errptr != '\0')
455*0Sstevel@tonic-gate 			continue;
456*0Sstevel@tonic-gate 		/* PR_WALK_PROC case */
457*0Sstevel@tonic-gate 		(void) snprintf(pidstr, sizeof (pidstr),
458*0Sstevel@tonic-gate 		    "/proc/%ld/psinfo", pid);
459*0Sstevel@tonic-gate 		fd = open(pidstr, O_RDONLY);
460*0Sstevel@tonic-gate 		if (fd < 0)
461*0Sstevel@tonic-gate 			continue;
462*0Sstevel@tonic-gate 		if (read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
463*0Sstevel@tonic-gate 			(void) close(fd);
464*0Sstevel@tonic-gate 			continue;
465*0Sstevel@tonic-gate 		}
466*0Sstevel@tonic-gate 		(void) close(fd);
467*0Sstevel@tonic-gate 		if (flag == PR_WALK_PROC) {
468*0Sstevel@tonic-gate 			if ((ret = func(&psinfo, &psinfo.pr_lwp, arg)) != 0)
469*0Sstevel@tonic-gate 				break;
470*0Sstevel@tonic-gate 			continue;
471*0Sstevel@tonic-gate 		}
472*0Sstevel@tonic-gate 		/* PR_WALK_LWP case */
473*0Sstevel@tonic-gate 		(void) snprintf(pidstr, sizeof (pidstr),
474*0Sstevel@tonic-gate 		    "/proc/%ld/lpsinfo", pid);
475*0Sstevel@tonic-gate 		fd = open(pidstr, O_RDONLY);
476*0Sstevel@tonic-gate 		if (fd < 0)
477*0Sstevel@tonic-gate 			continue;
478*0Sstevel@tonic-gate 		if (read(fd, &prheader, sizeof (prheader)) !=
479*0Sstevel@tonic-gate 		    sizeof (prheader)) {
480*0Sstevel@tonic-gate 			(void) close(fd);
481*0Sstevel@tonic-gate 			continue;
482*0Sstevel@tonic-gate 		}
483*0Sstevel@tonic-gate 		bufsz = prheader.pr_nent * prheader.pr_entsize;
484*0Sstevel@tonic-gate 		if ((buf = malloc(bufsz)) == NULL) {
485*0Sstevel@tonic-gate 			(void) close(fd);
486*0Sstevel@tonic-gate 			ret = -1;
487*0Sstevel@tonic-gate 			break;
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 		ptr = buf;
490*0Sstevel@tonic-gate 		if (pread(fd, buf, bufsz, sizeof (prheader)) != bufsz) {
491*0Sstevel@tonic-gate 			free(buf);
492*0Sstevel@tonic-gate 			(void) close(fd);
493*0Sstevel@tonic-gate 			continue;
494*0Sstevel@tonic-gate 		}
495*0Sstevel@tonic-gate 		(void) close(fd);
496*0Sstevel@tonic-gate 		for (i = 0; i < prheader.pr_nent;
497*0Sstevel@tonic-gate 		    i++, ptr += prheader.pr_entsize) {
498*0Sstevel@tonic-gate 			/*LINTED ALIGNMENT*/
499*0Sstevel@tonic-gate 			lwpsinfo = (lwpsinfo_t *)ptr;
500*0Sstevel@tonic-gate 			if ((ret = func(&psinfo, lwpsinfo, arg)) != 0) {
501*0Sstevel@tonic-gate 				free(buf);
502*0Sstevel@tonic-gate 				break;
503*0Sstevel@tonic-gate 			}
504*0Sstevel@tonic-gate 		}
505*0Sstevel@tonic-gate 		free(buf);
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate 	(void) closedir(procdir);
508*0Sstevel@tonic-gate 	return (ret);
509*0Sstevel@tonic-gate }
510