4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
43 open_psinfo(const char *arg
, int *perr
)
46 * Allocate enough space for procfs_path + arg + "/psinfo"
48 char *path
= alloca(strlen(arg
) + strlen(procfs_path
) + 9);
53 if (strchr(arg
, '/') == NULL
) {
54 (void) strcpy(path
, procfs_path
);
55 (void) strcat(path
, "/");
56 (void) strcat(path
, arg
);
58 (void) strcpy(path
, arg
);
60 (void) strcat(path
, "/psinfo");
63 * Attempt to open the psinfo file, and return the fd if we can
64 * confirm this is a regular file provided by /proc.
66 if ((fd
= open64(path
, O_RDONLY
)) >= 0) {
67 if (fstat64(fd
, &st
) != 0 || !S_ISREG(st
.st_mode
) ||
68 strcmp(st
.st_fstype
, "proc") != 0) {
72 } else if (errno
== EACCES
|| errno
== EPERM
)
79 open_core(const char *arg
, int *perr
)
82 uchar_t order
= ELFDATA2MSB
;
84 uchar_t order
= ELFDATA2LSB
;
91 * Attempt to open the core file, and return the fd if we can confirm
92 * this is an ELF file of type ET_CORE.
94 if ((fd
= open64(arg
, O_RDONLY
)) >= 0) {
95 if (read(fd
, &ehdr
, sizeof (ehdr
)) != sizeof (ehdr
)) {
98 } else if ((is_noelf
= memcmp(&ehdr
.e_ident
[EI_MAG0
], ELFMAG
,
99 SELFMAG
)) != 0 || ehdr
.e_type
!= ET_CORE
) {
103 ehdr
.e_ident
[EI_DATA
] != order
)
106 } else if (errno
== EACCES
|| errno
== EPERM
)
113 * Make the error message precisely match the type of arguments the caller
114 * wanted to process. This ensures that a tool which only accepts pids does
115 * not produce an error message saying "no such process or core file 'foo'".
118 open_error(int oflag
)
120 if ((oflag
& PR_ARG_ANY
) == PR_ARG_PIDS
)
123 if ((oflag
& PR_ARG_ANY
) == PR_ARG_CORES
)
126 return (G_NOPROCORCORE
);
130 proc_grab_common(const char *arg
, const char *path
, int oflag
, int gflag
,
131 int *perr
, const char **lwps
, psinfo_t
*psp
)
137 struct ps_prochandle
*Pr
;
143 if (lwps
!= NULL
&& (slash
= strrchr(arg
, '/')) != NULL
) {
145 * Check to see if the user has supplied an lwp range. First,
146 * try to grab it as a pid/lwp combo.
149 if ((oflag
& PR_ARG_PIDS
) &&
150 (fd
= open_psinfo(arg
, perr
)) != -1) {
151 if (read(fd
, &psinfo
,
152 sizeof (psinfo_t
)) == sizeof (psinfo_t
)) {
156 if (proc_lwp_range_valid(*lwps
) != 0) {
164 return (Pgrab(psinfo
.pr_pid
, gflag
,
172 * Next, try grabbing it as a corefile.
174 if ((oflag
& PR_ARG_CORES
) &&
175 (fd
= open_core(arg
, perr
)) != -1) {
178 if (proc_lwp_range_valid(*lwps
) != 0) {
183 if ((Pr
= Pfgrab_core(fd
, path
== NULL
?
184 dirname(core
) : path
, perr
)) != NULL
) {
186 (void) memcpy(psp
, Ppsinfo(Pr
),
199 if ((oflag
& PR_ARG_PIDS
) && (fd
= open_psinfo(arg
, perr
)) != -1) {
200 if (read(fd
, &psinfo
, sizeof (psinfo_t
)) == sizeof (psinfo_t
)) {
206 return (Pgrab(psinfo
.pr_pid
, gflag
, perr
));
210 * If the read failed, the process may have gone away;
211 * we continue checking for core files or fail with G_NOPROC
216 if ((oflag
& PR_ARG_CORES
) && (fd
= open_core(arg
, perr
)) != -1) {
218 if ((Pr
= Pfgrab_core(fd
, path
== NULL
? dirname(core
) : path
,
221 (void) memcpy(psp
, Ppsinfo(Pr
),
232 * We were unable to open the corefile. If we have no meaningful
233 * information, report the (ambiguous) error from open_error().
237 *perr
= open_error(oflag
);
242 struct ps_prochandle
*
243 proc_arg_xgrab(const char *arg
, const char *path
, int oflag
, int gflag
,
244 int *perr
, const char **lwps
)
246 return (proc_grab_common(arg
, path
, oflag
, gflag
, perr
, lwps
, NULL
));
249 struct ps_prochandle
*
250 proc_arg_grab(const char *arg
, int oflag
, int gflag
, int *perr
)
252 return (proc_grab_common(arg
, NULL
, oflag
, gflag
, perr
, NULL
, NULL
));
256 proc_arg_psinfo(const char *arg
, int oflag
, psinfo_t
*psp
, int *perr
)
263 if (proc_grab_common(arg
, NULL
, oflag
, 0, perr
, NULL
, psp
) == NULL
)
266 return (psp
->pr_pid
);
270 proc_arg_xpsinfo(const char *arg
, int oflag
, psinfo_t
*psp
, int *perr
,
278 if (proc_grab_common(arg
, NULL
, oflag
, 0, perr
, lwps
, psp
) == NULL
)
281 return (psp
->pr_pid
);
285 * Convert psinfo_t.pr_psargs string into itself, replacing unprintable
286 * characters with space along the way. Stop on a null character.
289 proc_unctrl_psinfo(psinfo_t
*psp
)
291 char *s
= &psp
->pr_psargs
[0];
295 while (n
-- != 0 && (c
= (*s
& UCHAR_MAX
)) != '\0') {
305 proc_lwp_get_range(char *range
, id_t
*low
, id_t
*high
)
310 *low
= (id_t
)strtol(range
, &range
, 10);
312 if (*range
== '\0' || *range
== ',') {
324 *high
= (id_t
)strtol(range
, &range
, 10);
326 if (*range
!= '\0' && *range
!= ',') {
340 * Determine if the specified lwpid is in the given set of lwpids.
341 * The set can include multiple lwpid ranges separated by commas
342 * and has the following syntax:
344 * lwp_range[,lwp_range]*
346 * where lwp_range is specifed as:
349 * n-m n <= lwpid <= m
354 proc_lwp_in_set(const char *set
, lwpid_t lwpid
)
357 id_t id
= (id_t
)lwpid
;
359 char *range
= (char *)set
;
362 * A NULL set indicates that all LWPs are valid.
367 while (range
!= NULL
) {
368 comma
= strchr(range
, ',');
371 if (proc_lwp_get_range(range
, &low
, &high
) != 0) {
382 if (id
>= low
&& id
<= high
)
390 proc_lwp_range_valid(const char *set
)
393 char *range
= (char *)set
;
397 if (range
== NULL
|| *range
== '\0' || *range
== ',')
400 while (range
!= NULL
) {
401 comma
= strchr(range
, ',');
404 if ((ret
= proc_lwp_get_range(range
, &low
, &high
)) != 0) {
421 * Walk all processes or LWPs in /proc and call func() for each.
422 * Omit system processes (like process-IDs 0, 2, and 3).
423 * Stop calling func() if it returns non 0 value and return it.
426 proc_walk(proc_walk_f
*func
, void *arg
, int flag
)
429 struct dirent
*dirent
;
431 char pidstr
[PATH_MAX
];
433 lwpsinfo_t
*lwpsinfo
;
442 if (flag
!= PR_WALK_PROC
&& flag
!= PR_WALK_LWP
) {
446 if ((procdir
= opendir(procfs_path
)) == NULL
)
448 while (dirent
= readdir(procdir
)) {
449 if (dirent
->d_name
[0] == '.') /* skip . and .. */
451 pid
= (id_t
)strtol(dirent
->d_name
, &errptr
, 10);
452 if (errptr
!= NULL
&& *errptr
!= '\0')
454 /* PR_WALK_PROC case */
455 (void) snprintf(pidstr
, sizeof (pidstr
),
456 "%s/%ld/psinfo", procfs_path
, pid
);
457 fd
= open(pidstr
, O_RDONLY
);
460 if (read(fd
, &psinfo
, sizeof (psinfo
)) != sizeof (psinfo
) ||
461 (psinfo
.pr_flag
& SSYS
)) {
466 if (flag
== PR_WALK_PROC
) {
467 if ((ret
= func(&psinfo
, &psinfo
.pr_lwp
, arg
)) != 0)
471 /* PR_WALK_LWP case */
472 (void) snprintf(pidstr
, sizeof (pidstr
),
473 "%s/%ld/lpsinfo", procfs_path
, pid
);
474 fd
= open(pidstr
, O_RDONLY
);
477 if (read(fd
, &prheader
, sizeof (prheader
)) !=
482 bufsz
= prheader
.pr_nent
* prheader
.pr_entsize
;
483 if ((buf
= malloc(bufsz
)) == NULL
) {
489 if (pread(fd
, buf
, bufsz
, sizeof (prheader
)) != bufsz
) {
495 for (i
= 0; i
< prheader
.pr_nent
;
496 i
++, ptr
+= prheader
.pr_entsize
) {
498 lwpsinfo
= (lwpsinfo_t
*)ptr
;
499 if ((ret
= func(&psinfo
, lwpsinfo
, arg
)) != 0) {
506 (void) closedir(procdir
);