xref: /onnv-gate/usr/src/lib/libproc/common/proc_arg.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
218509SRoger.Faulkner@Sun.COM 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/stat.h>
288509SRoger.Faulkner@Sun.COM #include <sys/proc.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <libgen.h>
310Sstevel@tonic-gate #include <limits.h>
320Sstevel@tonic-gate #include <alloca.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <fcntl.h>
360Sstevel@tonic-gate #include <ctype.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <dirent.h>
390Sstevel@tonic-gate 
402712Snn35248 #include "Pcontrol.h"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static int
open_psinfo(const char * arg,int * perr)430Sstevel@tonic-gate open_psinfo(const char *arg, int *perr)
440Sstevel@tonic-gate {
450Sstevel@tonic-gate 	/*
462712Snn35248 	 * Allocate enough space for procfs_path + arg + "/psinfo"
470Sstevel@tonic-gate 	 */
482712Snn35248 	char *path = alloca(strlen(arg) + strlen(procfs_path) + 9);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate 	struct stat64 st;
510Sstevel@tonic-gate 	int fd;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if (strchr(arg, '/') == NULL) {
542712Snn35248 		(void) strcpy(path, procfs_path);
552712Snn35248 		(void) strcat(path, "/");
560Sstevel@tonic-gate 		(void) strcat(path, arg);
570Sstevel@tonic-gate 	} else
580Sstevel@tonic-gate 		(void) strcpy(path, arg);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	(void) strcat(path, "/psinfo");
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	/*
630Sstevel@tonic-gate 	 * Attempt to open the psinfo file, and return the fd if we can
640Sstevel@tonic-gate 	 * confirm this is a regular file provided by /proc.
650Sstevel@tonic-gate 	 */
660Sstevel@tonic-gate 	if ((fd = open64(path, O_RDONLY)) >= 0) {
670Sstevel@tonic-gate 		if (fstat64(fd, &st) != 0 || !S_ISREG(st.st_mode) ||
680Sstevel@tonic-gate 		    strcmp(st.st_fstype, "proc") != 0) {
690Sstevel@tonic-gate 			(void) close(fd);
700Sstevel@tonic-gate 			fd = -1;
710Sstevel@tonic-gate 		}
720Sstevel@tonic-gate 	} else if (errno == EACCES || errno == EPERM)
730Sstevel@tonic-gate 		*perr = G_PERM;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	return (fd);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static int
open_core(const char * arg,int * perr)790Sstevel@tonic-gate open_core(const char *arg, int *perr)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate #ifdef _BIG_ENDIAN
820Sstevel@tonic-gate 	uchar_t order = ELFDATA2MSB;
830Sstevel@tonic-gate #else
840Sstevel@tonic-gate 	uchar_t order = ELFDATA2LSB;
850Sstevel@tonic-gate #endif
860Sstevel@tonic-gate 	GElf_Ehdr ehdr;
870Sstevel@tonic-gate 	int fd;
880Sstevel@tonic-gate 	int is_noelf = -1;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	/*
910Sstevel@tonic-gate 	 * Attempt to open the core file, and return the fd if we can confirm
920Sstevel@tonic-gate 	 * this is an ELF file of type ET_CORE.
930Sstevel@tonic-gate 	 */
940Sstevel@tonic-gate 	if ((fd = open64(arg, O_RDONLY)) >= 0) {
950Sstevel@tonic-gate 		if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) {
960Sstevel@tonic-gate 			(void) close(fd);
970Sstevel@tonic-gate 			fd = -1;
980Sstevel@tonic-gate 		} else if ((is_noelf = memcmp(&ehdr.e_ident[EI_MAG0], ELFMAG,
998509SRoger.Faulkner@Sun.COM 		    SELFMAG)) != 0 || ehdr.e_type != ET_CORE) {
1008509SRoger.Faulkner@Sun.COM 			(void) close(fd);
1018509SRoger.Faulkner@Sun.COM 			fd = -1;
1028509SRoger.Faulkner@Sun.COM 			if (is_noelf == 0 &&
1038509SRoger.Faulkner@Sun.COM 			    ehdr.e_ident[EI_DATA] != order)
1048509SRoger.Faulkner@Sun.COM 				*perr = G_ISAINVAL;
1050Sstevel@tonic-gate 		}
1060Sstevel@tonic-gate 	} else if (errno == EACCES || errno == EPERM)
1070Sstevel@tonic-gate 		*perr = G_PERM;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	return (fd);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Make the error message precisely match the type of arguments the caller
1140Sstevel@tonic-gate  * wanted to process.  This ensures that a tool which only accepts pids does
1150Sstevel@tonic-gate  * not produce an error message saying "no such process or core file 'foo'".
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate static int
open_error(int oflag)1180Sstevel@tonic-gate open_error(int oflag)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	if ((oflag & PR_ARG_ANY) == PR_ARG_PIDS)
1210Sstevel@tonic-gate 		return (G_NOPROC);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if ((oflag & PR_ARG_ANY) == PR_ARG_CORES)
1240Sstevel@tonic-gate 		return (G_NOCORE);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	return (G_NOPROCORCORE);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static void *
proc_grab_common(const char * arg,const char * path,int oflag,int gflag,int * perr,const char ** lwps,psinfo_t * psp)1300Sstevel@tonic-gate proc_grab_common(const char *arg, const char *path, int oflag, int gflag,
1310Sstevel@tonic-gate     int *perr, const char **lwps, psinfo_t *psp)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	psinfo_t psinfo;
1340Sstevel@tonic-gate 	char *core;
1350Sstevel@tonic-gate 	int fd;
1360Sstevel@tonic-gate 	char *slash;
1370Sstevel@tonic-gate 	struct ps_prochandle *Pr;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	*perr = 0;
1400Sstevel@tonic-gate 	if (lwps)
1410Sstevel@tonic-gate 		*lwps = NULL;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if (lwps != NULL && (slash = strrchr(arg, '/')) != NULL) {
1440Sstevel@tonic-gate 		/*
1450Sstevel@tonic-gate 		 * Check to see if the user has supplied an lwp range.  First,
1460Sstevel@tonic-gate 		 * try to grab it as a pid/lwp combo.
1470Sstevel@tonic-gate 		 */
1480Sstevel@tonic-gate 		*slash = '\0';
1490Sstevel@tonic-gate 		if ((oflag & PR_ARG_PIDS) &&
1500Sstevel@tonic-gate 		    (fd = open_psinfo(arg, perr)) != -1) {
1510Sstevel@tonic-gate 			if (read(fd, &psinfo,
1520Sstevel@tonic-gate 			    sizeof (psinfo_t)) == sizeof (psinfo_t)) {
1530Sstevel@tonic-gate 				(void) close(fd);
1540Sstevel@tonic-gate 				*lwps = slash + 1;
1550Sstevel@tonic-gate 				*slash = '/';
1560Sstevel@tonic-gate 				if (proc_lwp_range_valid(*lwps) != 0) {
1570Sstevel@tonic-gate 					*perr = G_BADLWPS;
1580Sstevel@tonic-gate 					return (NULL);
1590Sstevel@tonic-gate 				}
1600Sstevel@tonic-gate 				if (psp) {
1610Sstevel@tonic-gate 					*psp = psinfo;
1620Sstevel@tonic-gate 					return (psp);
1630Sstevel@tonic-gate 				} else  {
1640Sstevel@tonic-gate 					return (Pgrab(psinfo.pr_pid, gflag,
1650Sstevel@tonic-gate 					    perr));
1660Sstevel@tonic-gate 				}
1670Sstevel@tonic-gate 			}
1680Sstevel@tonic-gate 			(void) close(fd);
1690Sstevel@tonic-gate 		}
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 		/*
1720Sstevel@tonic-gate 		 * Next, try grabbing it as a corefile.
1730Sstevel@tonic-gate 		 */
1740Sstevel@tonic-gate 		if ((oflag & PR_ARG_CORES) &&
1750Sstevel@tonic-gate 		    (fd = open_core(arg, perr)) != -1) {
1760Sstevel@tonic-gate 			*lwps = slash + 1;
1770Sstevel@tonic-gate 			*slash = '/';
1780Sstevel@tonic-gate 			if (proc_lwp_range_valid(*lwps) != 0) {
1790Sstevel@tonic-gate 				*perr = G_BADLWPS;
1800Sstevel@tonic-gate 				return (NULL);
1810Sstevel@tonic-gate 			}
182*13093SRoger.Faulkner@Oracle.COM 			core = strdupa(arg);
1830Sstevel@tonic-gate 			if ((Pr = Pfgrab_core(fd, path == NULL ?
1840Sstevel@tonic-gate 			    dirname(core) : path, perr)) != NULL) {
1850Sstevel@tonic-gate 				if (psp) {
1860Sstevel@tonic-gate 					(void) memcpy(psp, Ppsinfo(Pr),
1870Sstevel@tonic-gate 					    sizeof (psinfo_t));
1880Sstevel@tonic-gate 					Prelease(Pr, 0);
1890Sstevel@tonic-gate 					return (psp);
1900Sstevel@tonic-gate 				} else {
1910Sstevel@tonic-gate 					return (Pr);
1920Sstevel@tonic-gate 				}
1930Sstevel@tonic-gate 			}
1940Sstevel@tonic-gate 		}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 		*slash = '/';
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if ((oflag & PR_ARG_PIDS) && (fd = open_psinfo(arg, perr)) != -1) {
2000Sstevel@tonic-gate 		if (read(fd, &psinfo, sizeof (psinfo_t)) == sizeof (psinfo_t)) {
2010Sstevel@tonic-gate 			(void) close(fd);
2020Sstevel@tonic-gate 			if (psp) {
2030Sstevel@tonic-gate 				*psp = psinfo;
2040Sstevel@tonic-gate 				return (psp);
2050Sstevel@tonic-gate 			} else {
2060Sstevel@tonic-gate 				return (Pgrab(psinfo.pr_pid, gflag, perr));
2070Sstevel@tonic-gate 			}
2080Sstevel@tonic-gate 		}
2090Sstevel@tonic-gate 		/*
2100Sstevel@tonic-gate 		 * If the read failed, the process may have gone away;
2110Sstevel@tonic-gate 		 * we continue checking for core files or fail with G_NOPROC
2120Sstevel@tonic-gate 		 */
2130Sstevel@tonic-gate 		(void) close(fd);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if ((oflag & PR_ARG_CORES) && (fd = open_core(arg, perr)) != -1) {
217*13093SRoger.Faulkner@Oracle.COM 		core = strdupa(arg);
2180Sstevel@tonic-gate 		if ((Pr = Pfgrab_core(fd, path == NULL ? dirname(core) : path,
2190Sstevel@tonic-gate 		    perr)) != NULL) {
2200Sstevel@tonic-gate 			if (psp) {
2210Sstevel@tonic-gate 				(void) memcpy(psp, Ppsinfo(Pr),
2220Sstevel@tonic-gate 				    sizeof (psinfo_t));
2230Sstevel@tonic-gate 				Prelease(Pr, 0);
2240Sstevel@tonic-gate 				return (psp);
2250Sstevel@tonic-gate 			} else {
2260Sstevel@tonic-gate 				return (Pr);
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 		}
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * We were unable to open the corefile.  If we have no meaningful
2330Sstevel@tonic-gate 	 * information, report the (ambiguous) error from open_error().
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if (*perr == 0)
2370Sstevel@tonic-gate 		*perr = open_error(oflag);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	return (NULL);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate struct ps_prochandle *
proc_arg_xgrab(const char * arg,const char * path,int oflag,int gflag,int * perr,const char ** lwps)2430Sstevel@tonic-gate proc_arg_xgrab(const char *arg, const char *path, int oflag, int gflag,
2440Sstevel@tonic-gate     int *perr, const char **lwps)
2450Sstevel@tonic-gate {
2460Sstevel@tonic-gate 	return (proc_grab_common(arg, path, oflag, gflag, perr, lwps, NULL));
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate struct ps_prochandle *
proc_arg_grab(const char * arg,int oflag,int gflag,int * perr)2500Sstevel@tonic-gate proc_arg_grab(const char *arg, int oflag, int gflag, int *perr)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	return (proc_grab_common(arg, NULL, oflag, gflag, perr, NULL, NULL));
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate pid_t
proc_arg_psinfo(const char * arg,int oflag,psinfo_t * psp,int * perr)2560Sstevel@tonic-gate proc_arg_psinfo(const char *arg, int oflag, psinfo_t *psp, int *perr)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate 	psinfo_t psinfo;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (psp == NULL)
2610Sstevel@tonic-gate 		psp = &psinfo;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	if (proc_grab_common(arg, NULL, oflag, 0, perr, NULL, psp) == NULL)
2640Sstevel@tonic-gate 		return (-1);
2650Sstevel@tonic-gate 	else
2660Sstevel@tonic-gate 		return (psp->pr_pid);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate pid_t
proc_arg_xpsinfo(const char * arg,int oflag,psinfo_t * psp,int * perr,const char ** lwps)2700Sstevel@tonic-gate proc_arg_xpsinfo(const char *arg, int oflag, psinfo_t *psp, int *perr,
2710Sstevel@tonic-gate     const char **lwps)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	psinfo_t psinfo;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (psp == NULL)
2760Sstevel@tonic-gate 		psp = &psinfo;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (proc_grab_common(arg, NULL, oflag, 0, perr, lwps, psp) == NULL)
2790Sstevel@tonic-gate 		return (-1);
2800Sstevel@tonic-gate 	else
2810Sstevel@tonic-gate 		return (psp->pr_pid);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*
2850Sstevel@tonic-gate  * Convert psinfo_t.pr_psargs string into itself, replacing unprintable
2860Sstevel@tonic-gate  * characters with space along the way.  Stop on a null character.
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate void
proc_unctrl_psinfo(psinfo_t * psp)2890Sstevel@tonic-gate proc_unctrl_psinfo(psinfo_t *psp)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	char *s = &psp->pr_psargs[0];
2920Sstevel@tonic-gate 	size_t n = PRARGSZ;
2930Sstevel@tonic-gate 	int c;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	while (n-- != 0 && (c = (*s & UCHAR_MAX)) != '\0') {
2960Sstevel@tonic-gate 		if (!isprint(c))
2970Sstevel@tonic-gate 			c = ' ';
2980Sstevel@tonic-gate 		*s++ = (char)c;
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	*s = '\0';
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate static int
proc_lwp_get_range(char * range,id_t * low,id_t * high)3050Sstevel@tonic-gate proc_lwp_get_range(char *range, id_t *low, id_t *high)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	if (*range == '-')
3080Sstevel@tonic-gate 		*low = 0;
3090Sstevel@tonic-gate 	else
3100Sstevel@tonic-gate 		*low = (id_t)strtol(range, &range, 10);
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (*range == '\0' || *range == ',') {
3130Sstevel@tonic-gate 		*high = *low;
3140Sstevel@tonic-gate 		return (0);
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	if (*range != '-') {
3170Sstevel@tonic-gate 		return (-1);
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 	range++;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (*range == '\0')
3220Sstevel@tonic-gate 		*high = INT_MAX;
3230Sstevel@tonic-gate 	else
3240Sstevel@tonic-gate 		*high = (id_t)strtol(range, &range, 10);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	if (*range != '\0' && *range != ',') {
3270Sstevel@tonic-gate 		return (-1);
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (*high < *low) {
3310Sstevel@tonic-gate 		id_t tmp = *high;
3320Sstevel@tonic-gate 		*high = *low;
3330Sstevel@tonic-gate 		*low = tmp;
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	return (0);
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate  * Determine if the specified lwpid is in the given set of lwpids.
3410Sstevel@tonic-gate  * The set can include multiple lwpid ranges separated by commas
3420Sstevel@tonic-gate  * and has the following syntax:
3430Sstevel@tonic-gate  *
3440Sstevel@tonic-gate  * 	lwp_range[,lwp_range]*
3450Sstevel@tonic-gate  *
3460Sstevel@tonic-gate  * where lwp_range is specifed as:
3470Sstevel@tonic-gate  *
3480Sstevel@tonic-gate  * 	-n			lwpid <= n
3490Sstevel@tonic-gate  * 	n-m			n <= lwpid <= m
3500Sstevel@tonic-gate  * 	n-			lwpid >= n
3510Sstevel@tonic-gate  * 	n			lwpid == n
3520Sstevel@tonic-gate  */
3530Sstevel@tonic-gate int
proc_lwp_in_set(const char * set,lwpid_t lwpid)3540Sstevel@tonic-gate proc_lwp_in_set(const char *set, lwpid_t lwpid)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	id_t low, high;
3570Sstevel@tonic-gate 	id_t id = (id_t)lwpid;
3580Sstevel@tonic-gate 	char *comma;
3590Sstevel@tonic-gate 	char *range = (char *)set;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * A NULL set indicates that all LWPs are valid.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	if (set == NULL)
3650Sstevel@tonic-gate 		return (1);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	while (range != NULL) {
3680Sstevel@tonic-gate 		comma = strchr(range, ',');
3690Sstevel@tonic-gate 		if (comma != NULL)
3700Sstevel@tonic-gate 			*comma = '\0';
3710Sstevel@tonic-gate 		if (proc_lwp_get_range(range, &low, &high) != 0) {
3720Sstevel@tonic-gate 			if (comma != NULL)
3730Sstevel@tonic-gate 				*comma = ',';
3740Sstevel@tonic-gate 			return (0);
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 		if (comma != NULL) {
3770Sstevel@tonic-gate 			*comma = ',';
3780Sstevel@tonic-gate 			range = comma + 1;
3790Sstevel@tonic-gate 		} else {
3800Sstevel@tonic-gate 			range = NULL;
3810Sstevel@tonic-gate 		}
3820Sstevel@tonic-gate 		if (id >= low && id <= high)
3830Sstevel@tonic-gate 			return (1);
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	return (0);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate int
proc_lwp_range_valid(const char * set)3900Sstevel@tonic-gate proc_lwp_range_valid(const char *set)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	char *comma;
3930Sstevel@tonic-gate 	char *range = (char *)set;
3940Sstevel@tonic-gate 	id_t low, high;
3950Sstevel@tonic-gate 	int ret;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if (range == NULL || *range == '\0' || *range == ',')
3980Sstevel@tonic-gate 		return (-1);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	while (range != NULL) {
4010Sstevel@tonic-gate 		comma = strchr(range, ',');
4020Sstevel@tonic-gate 		if (comma != NULL)
4030Sstevel@tonic-gate 			*comma = '\0';
4040Sstevel@tonic-gate 		if ((ret = proc_lwp_get_range(range, &low, &high)) != 0) {
4050Sstevel@tonic-gate 			if (comma != NULL)
4060Sstevel@tonic-gate 				*comma = ',';
4070Sstevel@tonic-gate 			return (ret);
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 		if (comma != NULL) {
4100Sstevel@tonic-gate 			*comma = ',';
4110Sstevel@tonic-gate 			range = comma + 1;
4120Sstevel@tonic-gate 		} else {
4130Sstevel@tonic-gate 			range = NULL;
4140Sstevel@tonic-gate 		}
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	return (0);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate  * Walk all processes or LWPs in /proc and call func() for each.
4228509SRoger.Faulkner@Sun.COM  * Omit system processes (like process-IDs 0, 2, and 3).
4230Sstevel@tonic-gate  * Stop calling func() if it returns non 0 value and return it.
4240Sstevel@tonic-gate  */
4250Sstevel@tonic-gate int
proc_walk(proc_walk_f * func,void * arg,int flag)4260Sstevel@tonic-gate proc_walk(proc_walk_f *func, void *arg, int flag)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate 	DIR *procdir;
4290Sstevel@tonic-gate 	struct dirent *dirent;
4300Sstevel@tonic-gate 	char *errptr;
4312712Snn35248 	char pidstr[PATH_MAX];
4320Sstevel@tonic-gate 	psinfo_t psinfo;
4330Sstevel@tonic-gate 	lwpsinfo_t *lwpsinfo;
4340Sstevel@tonic-gate 	prheader_t prheader;
4350Sstevel@tonic-gate 	void *buf;
4360Sstevel@tonic-gate 	char *ptr;
4370Sstevel@tonic-gate 	int bufsz;
4380Sstevel@tonic-gate 	id_t pid;
4390Sstevel@tonic-gate 	int fd, i;
4400Sstevel@tonic-gate 	int ret = 0;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (flag != PR_WALK_PROC && flag != PR_WALK_LWP) {
4430Sstevel@tonic-gate 		errno = EINVAL;
4440Sstevel@tonic-gate 		return (-1);
4450Sstevel@tonic-gate 	}
4462712Snn35248 	if ((procdir = opendir(procfs_path)) == NULL)
4470Sstevel@tonic-gate 		return (-1);
4480Sstevel@tonic-gate 	while (dirent = readdir(procdir)) {
4490Sstevel@tonic-gate 		if (dirent->d_name[0] == '.')	/* skip . and .. */
4500Sstevel@tonic-gate 			continue;
4510Sstevel@tonic-gate 		pid = (id_t)strtol(dirent->d_name, &errptr, 10);
4520Sstevel@tonic-gate 		if (errptr != NULL && *errptr != '\0')
4530Sstevel@tonic-gate 			continue;
4540Sstevel@tonic-gate 		/* PR_WALK_PROC case */
4550Sstevel@tonic-gate 		(void) snprintf(pidstr, sizeof (pidstr),
4562712Snn35248 		    "%s/%ld/psinfo", procfs_path, pid);
4570Sstevel@tonic-gate 		fd = open(pidstr, O_RDONLY);
4580Sstevel@tonic-gate 		if (fd < 0)
4590Sstevel@tonic-gate 			continue;
4608509SRoger.Faulkner@Sun.COM 		if (read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo) ||
4618509SRoger.Faulkner@Sun.COM 		    (psinfo.pr_flag & SSYS)) {
4620Sstevel@tonic-gate 			(void) close(fd);
4630Sstevel@tonic-gate 			continue;
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 		(void) close(fd);
4660Sstevel@tonic-gate 		if (flag == PR_WALK_PROC) {
4670Sstevel@tonic-gate 			if ((ret = func(&psinfo, &psinfo.pr_lwp, arg)) != 0)
4680Sstevel@tonic-gate 				break;
4690Sstevel@tonic-gate 			continue;
4700Sstevel@tonic-gate 		}
4710Sstevel@tonic-gate 		/* PR_WALK_LWP case */
4720Sstevel@tonic-gate 		(void) snprintf(pidstr, sizeof (pidstr),
4732712Snn35248 		    "%s/%ld/lpsinfo", procfs_path, pid);
4740Sstevel@tonic-gate 		fd = open(pidstr, O_RDONLY);
4750Sstevel@tonic-gate 		if (fd < 0)
4760Sstevel@tonic-gate 			continue;
4770Sstevel@tonic-gate 		if (read(fd, &prheader, sizeof (prheader)) !=
4780Sstevel@tonic-gate 		    sizeof (prheader)) {
4790Sstevel@tonic-gate 			(void) close(fd);
4800Sstevel@tonic-gate 			continue;
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 		bufsz = prheader.pr_nent * prheader.pr_entsize;
4830Sstevel@tonic-gate 		if ((buf = malloc(bufsz)) == NULL) {
4840Sstevel@tonic-gate 			(void) close(fd);
4850Sstevel@tonic-gate 			ret = -1;
4860Sstevel@tonic-gate 			break;
4870Sstevel@tonic-gate 		}
4880Sstevel@tonic-gate 		ptr = buf;
4890Sstevel@tonic-gate 		if (pread(fd, buf, bufsz, sizeof (prheader)) != bufsz) {
4900Sstevel@tonic-gate 			free(buf);
4910Sstevel@tonic-gate 			(void) close(fd);
4920Sstevel@tonic-gate 			continue;
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 		(void) close(fd);
4950Sstevel@tonic-gate 		for (i = 0; i < prheader.pr_nent;
4960Sstevel@tonic-gate 		    i++, ptr += prheader.pr_entsize) {
4970Sstevel@tonic-gate 			/*LINTED ALIGNMENT*/
4980Sstevel@tonic-gate 			lwpsinfo = (lwpsinfo_t *)ptr;
4990Sstevel@tonic-gate 			if ((ret = func(&psinfo, lwpsinfo, arg)) != 0) {
5000Sstevel@tonic-gate 				free(buf);
5010Sstevel@tonic-gate 				break;
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 		free(buf);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 	(void) closedir(procdir);
5070Sstevel@tonic-gate 	return (ret);
5080Sstevel@tonic-gate }
509