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