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