[Midnightbsd-cvs] src [9409] trunk/lib/libprocstat: make libprocstat(3) extract procstat notes from a process core file.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sat Mar 4 16:43:04 EST 2017
Revision: 9409
http://svnweb.midnightbsd.org/src/?rev=9409
Author: laffer1
Date: 2017-03-04 16:43:03 -0500 (Sat, 04 Mar 2017)
Log Message:
-----------
make libprocstat(3) extract procstat notes from a process core file.
Modified Paths:
--------------
trunk/lib/libprocstat/Makefile
trunk/lib/libprocstat/Symbol.map
trunk/lib/libprocstat/libprocstat.3
trunk/lib/libprocstat/libprocstat.c
trunk/lib/libprocstat/libprocstat.h
trunk/lib/libprocstat/libprocstat_internal.h
Modified: trunk/lib/libprocstat/Makefile
===================================================================
--- trunk/lib/libprocstat/Makefile 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/Makefile 2017-03-04 21:43:03 UTC (rev 9409)
@@ -6,6 +6,7 @@
SRCS= cd9660.c \
common_kvm.c \
+ core.c \
libprocstat.c \
msdosfs.c \
ntfs.c \
@@ -19,8 +20,8 @@
CFLAGS+= -I. -I${.CURDIR} -D_KVM_VNODE
SHLIB_MAJOR= 1
-DPADD= ${LIBKVM} ${LIBUTIL}
-LDADD= -lkvm -lutil
+DPADD= ${LIBELF} ${LIBKVM} ${LIBUTIL}
+LDADD= -lelf -lkvm -lutil
MAN= libprocstat.3
Modified: trunk/lib/libprocstat/Symbol.map
===================================================================
--- trunk/lib/libprocstat/Symbol.map 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/Symbol.map 2017-03-04 21:43:03 UTC (rev 9409)
@@ -16,5 +16,22 @@
};
FBSD_1.3 {
+ procstat_freeargv;
+ procstat_freeauxv;
+ procstat_freeenvv;
+ procstat_freegroups;
+ procstat_freekstack;
+ procstat_freevmmap;
procstat_get_shm_info;
+ procstat_getargv;
+ procstat_getauxv;
+ procstat_getenvv;
+ procstat_getgroups;
+ procstat_getkstack;
+ procstat_getosrel;
+ procstat_getpathname;
+ procstat_getrlimit;
+ procstat_getumask;
+ procstat_getvmmap;
+ procstat_open_core;
};
Modified: trunk/lib/libprocstat/libprocstat.3
===================================================================
--- trunk/lib/libprocstat/libprocstat.3 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.3 2017-03-04 21:43:03 UTC (rev 9409)
@@ -24,17 +24,33 @@
.\"
.\" $MidnightBSD$
.\"
-.Dd April 1, 2012
+.Dd April 20, 2013
.Dt LIBPROCSTAT 3
.Os
.Sh NAME
+.Nm procstat_open_core ,
.Nm procstat_open_kvm ,
.Nm procstat_open_sysctl ,
.Nm procstat_close ,
+.Nm procstat_getargv ,
+.Nm procstat_getauxv ,
+.Nm procstat_getenvv ,
.Nm procstat_getfiles ,
+.Nm procstat_getgroups ,
+.Nm procstat_getkstack ,
+.Nm procstat_getosrel ,
+.Nm procstat_getpathname ,
.Nm procstat_getprocs ,
+.Nm procstat_getumask ,
+.Nm procstat_getvmmap ,
+.Nm procstat_freeargv ,
+.Nm procstat_freeauxv ,
+.Nm procstat_freeenvv ,
.Nm procstat_freefiles ,
+.Nm procstat_freegroups ,
+.Nm procstat_freekstack ,
.Nm procstat_freeprocs ,
+.Nm procstat_freevmmap ,
.Nm procstat_get_pipe_info ,
.Nm procstat_get_pts_info ,
.Nm procstat_get_shm_info ,
@@ -50,12 +66,40 @@
.Ft void
.Fn procstat_close "struct procstat *procstat"
.Ft void
+.Fo procstat_freeargv
+.Fa "struct procstat *procstat"
+.Fc
+.Ft void
+.Fo procstat_freeauxv
+.Fa "struct procstat *procstat"
+.Fa "Elf_Auxinfo *auxv"
+.Fc
+.Ft void
+.Fo procstat_freeenvv
+.Fa "struct procstat *procstat"
+.Fc
+.Ft void
.Fo procstat_freefiles
.Fa "struct procstat *procstat"
.Fa "struct filestat_list *head"
.Fc
.Ft void
+.Fo procstat_freegroups
+.Fa "struct procstat *procstat"
+.Fa "gid_t *groups"
+.Fc
+.Ft void
+.Fo procstat_freekstack
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_kstack *kkstp"
+.Fc
+.Ft void
.Fn procstat_freeprocs "struct procstat *procstat" "struct kinfo_proc *p"
+.Ft void
+.Fo procstat_freevmmap
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_vmentry *vmmap"
+.Fc
.Ft int
.Fo procstat_get_pipe_info
.Fa "struct procstat *procstat"
@@ -91,6 +135,26 @@
.Fa "struct vnstat *vn"
.Fa "char *errbuf"
.Fc
+.Ft "char **"
+.Fo procstat_getargv
+.Fa "struct procstat *procstat"
+.Fa "const struct kinfo_proc *kp"
+.Fa "size_t nchr"
+.Fa "char *errbuf"
+.Fc
+.Ft "Elf_Auxinfo *"
+.Fo procstat_getauxv
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
+.Ft "char **"
+.Fo procstat_getenvv
+.Fa "struct procstat *procstat"
+.Fa "const struct kinfo_proc *kp"
+.Fa "size_t nchr"
+.Fa "char *errbuf"
+.Fc
.Ft "struct filestat_list *"
.Fo procstat_getfiles
.Fa "struct procstat *procstat"
@@ -97,6 +161,24 @@
.Fa "struct kinfo_proc *kp"
.Fa "int mmapped"
.Fc
+.Ft "gid_t *"
+.Fo procstat_getgroups
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
+.Ft int
+.Fo procstat_getosrel
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "int *osrelp"
+.Fc
+.Ft "struct kinfo_kstack *"
+.Fo procstat_getkstack
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
.Ft "struct kinfo_proc *"
.Fo procstat_getprocs
.Fa "struct procstat *procstat"
@@ -104,7 +186,35 @@
.Fa "int arg"
.Fa "unsigned int *count"
.Fc
+.Ft "int"
+.Fo procstat_getpathname
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "char *pathname"
+.Fa "size_t maxlen"
+.Fc
+.Ft "int"
+.Fo procstat_getrlimit
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "int which"
+.Fa "struct rlimit* rlimit"
+.Fc
+.Ft "int"
+.Fo procstat_getumask
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned short *maskp"
+.Fc
+.Ft "struct kinfo_vmentry *"
+.Fo procstat_getvmmap
+.Fa "struct procstat *procstat"
+.Fa "struct kinfo_proc *kp"
+.Fa "unsigned int *count"
+.Fc
.Ft "struct procstat *"
+.Fn procstat_open_core "const char *filename"
+.Ft "struct procstat *"
.Fn procstat_open_kvm "const char *nlistf" "const char *memf"
.Ft "struct procstat *"
.Fn procstat_open_sysctl void
@@ -116,7 +226,11 @@
.Xr sysctl 3
library backend, and for post-mortem analysis via the
.Xr kvm 3
-library backend.
+library backend, or from the process
+.Xr core 5
+file, searching for statistics in special
+.Xr elf 3
+note sections.
.Pp
The
.Fn procstat_open_kvm
@@ -129,6 +243,16 @@
library routines, respectively, to access kernel state information
used to retrieve processes and files states.
The
+.Fn procstat_open_core
+uses
+.Xr elf 3
+routines to access statistics stored as a set of notes in a process
+.Xr core 5
+file, written by the kernel at the moment of the process abnormal termination.
+The
+.Fa filename
+argument is the process core file name.
+The
.Fa nlistf
argument is the executable image of the kernel being examined.
If this argument is
@@ -145,7 +269,7 @@
See
.Xr kvm_open 3
for more details.
-Both functions dynamically allocate and return a
+The functions dynamically allocate and return a
.Vt procstat
structure pointer used in the rest of the
.Nm libprocstat
@@ -179,6 +303,63 @@
function call.
.Pp
The
+.Fn procstat_getargv
+function gets a pointer to the
+.Vt procstat
+structure from one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure from the array obtained from the
+.Fn kvm_getprocs
+function, and returns a null-terminated argument vector that corresponds to
+the command line arguments passed to the process.
+The
+.Fa nchr
+argument indicates the maximum number of characters, including null bytes,
+to use in building the strings.
+If this amount is exceeded, the string causing the overflow is truncated and
+the partial result is returned.
+This is handy for programs that print only a one line summary of a
+command and should not copy out large amounts of text only to ignore it.
+If
+.Fa nchr
+is zero, no limit is imposed and all argument strings are returned.
+The values of the returned argument vector refer the strings stored
+in the
+.Vt procstat
+internal buffer.
+A subsequent call of the function with the same
+.Vt procstat
+argument will reuse the buffer.
+To free the allocated memory
+.Fn procstat_freeargv
+function call can be used, or it will be released on
+.Fn procstat_close .
+.Pp
+The
+.Fn procstat_getenvv
+function is similar to
+.Fn procstat_getargv
+but returns the vector of environment strings.
+The caller may free the allocated memory with a subsequent
+.Fn procstat_freeenv
+function call.
+.Pp
+The
+.Fn procstat_getauxv
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the auxiliary vector as a dynamically allocated array of
+.Vt Elf_Auxinfo
+elements.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freeauxv
+function call.
+.Pp
+The
.Fn procstat_getfiles
function gets a pointer to the
.Vt procstat
@@ -197,6 +378,89 @@
function call.
.Pp
The
+.Fn procstat_getgroups
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the process groups as a dynamically allocated array of
+.Vt gid_t
+elements.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freegroups
+function call.
+.Pp
+The
+.Fn procstat_getkstack
+function gets a pointer to the
+.Vt procstat
+structure initialized with one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure, and returns kernel stacks of the process as a dynamically allocated
+array of
+.Vt kinfo_kstack
+structures.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freekstack
+function call.
+.Pp
+The
+.Fn procstat_getosrel
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns osrel date in the 3rd reference parameter.
+.Pp
+The
+.Fn procstat_getpathname
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and copies the path of the process executable to
+.Fa pathname
+buffer, limiting to
+.Fa maxlen
+characters.
+.Pp
+The
+.Fn procstat_getrlimit
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, resource index
+.Fa which ,
+and returns the actual resource limit in the 4th reference parameter.
+.Pp
+The
+.Fn procstat_getumask
+function gets a pointer to the
+.Vt procstat
+structure, a pointer to
+.Vt kinfo_proc
+structure, and returns the process umask in the 3rd reference parameter.
+.Pp
+The
+.Fn procstat_getvmmap
+function gets a pointer to the
+.Vt procstat
+structure initialized with one of the
+.Fn procstat_open_*
+functions, a pointer to
+.Vt kinfo_proc
+structure, and returns VM layout of the process as a dynamically allocated
+array of
+.Vt kinfo_vmentry
+structures.
+The caller is responsible to free the allocated memory with a subsequent
+.Fn procstat_freevmmap
+function call.
+.Pp
+The
.Fn procstat_get_pipe_info ,
.Fn procstat_get_pts_info ,
.Fn procstat_get_shm_info ,
@@ -250,10 +514,12 @@
.Xr pipe 2 ,
.Xr shm_open 2 ,
.Xr socket 2 ,
+.Xr elf 3 ,
.Xr kvm 3 ,
.Xr queue 3 ,
.Xr sysctl 3 ,
.Xr pts 4 ,
+.Xr core 5 ,
.Xr vnode 9
.Sh HISTORY
The
Modified: trunk/lib/libprocstat/libprocstat.c
===================================================================
--- trunk/lib/libprocstat/libprocstat.c 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.c 2017-03-04 21:43:03 UTC (rev 9409)
@@ -36,7 +36,12 @@
__MBSDID("$MidnightBSD$");
#include <sys/param.h>
+#include <sys/elf.h>
#include <sys/time.h>
+#include <sys/resourcevar.h>
+#define _WANT_UCRED
+#include <sys/ucred.h>
+#undef _WANT_UCRED
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/stat.h>
@@ -96,13 +101,22 @@
#include <libprocstat.h>
#include "libprocstat_internal.h"
#include "common_kvm.h"
+#include "core.h"
int statfs(const char *, struct statfs *); /* XXX */
#define PROCSTAT_KVM 1
#define PROCSTAT_SYSCTL 2
+#define PROCSTAT_CORE 3
+static char **getargv(struct procstat *procstat, struct kinfo_proc *kp,
+ size_t nchr, int env);
static char *getmnton(kvm_t *kd, struct mount *m);
+static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core,
+ int *cntp);
+static Elf_Auxinfo *procstat_getauxv_core(struct procstat_core *core,
+ unsigned int *cntp);
+static Elf_Auxinfo *procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
static struct filestat_list *procstat_getfiles_kvm(
struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
static struct filestat_list *procstat_getfiles_sysctl(
@@ -128,6 +142,33 @@
struct vnstat *vn, char *errbuf);
static int procstat_get_vnode_info_sysctl(struct filestat *fst,
struct vnstat *vn, char *errbuf);
+static gid_t *procstat_getgroups_core(struct procstat_core *core,
+ unsigned int *count);
+static gid_t * procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp,
+ unsigned int *count);
+static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count);
+static struct kinfo_kstack *procstat_getkstack_sysctl(pid_t pid,
+ int *cntp);
+static int procstat_getosrel_core(struct procstat_core *core,
+ int *osrelp);
+static int procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp,
+ int *osrelp);
+static int procstat_getosrel_sysctl(pid_t pid, int *osrelp);
+static int procstat_getpathname_core(struct procstat_core *core,
+ char *pathname, size_t maxlen);
+static int procstat_getpathname_sysctl(pid_t pid, char *pathname,
+ size_t maxlen);
+static int procstat_getrlimit_core(struct procstat_core *core, int which,
+ struct rlimit* rlimit);
+static int procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp,
+ int which, struct rlimit* rlimit);
+static int procstat_getrlimit_sysctl(pid_t pid, int which,
+ struct rlimit* rlimit);
+static int procstat_getumask_core(struct procstat_core *core,
+ unsigned short *maskp);
+static int procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp,
+ unsigned short *maskp);
+static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp);
static int vntype2psfsttype(int type);
void
@@ -137,6 +178,10 @@
assert(procstat);
if (procstat->type == PROCSTAT_KVM)
kvm_close(procstat->kd);
+ else if (procstat->type == PROCSTAT_CORE)
+ procstat_core_close(procstat->core);
+ procstat_freeargv(procstat);
+ procstat_freeenvv(procstat);
free(procstat);
}
@@ -177,6 +222,27 @@
return (procstat);
}
+struct procstat *
+procstat_open_core(const char *filename)
+{
+ struct procstat *procstat;
+ struct procstat_core *core;
+
+ procstat = calloc(1, sizeof(*procstat));
+ if (procstat == NULL) {
+ warn("malloc()");
+ return (NULL);
+ }
+ core = procstat_core_open(filename);
+ if (core == NULL) {
+ free(procstat);
+ return (NULL);
+ }
+ procstat->type = PROCSTAT_CORE;
+ procstat->core = core;
+ return (procstat);
+}
+
struct kinfo_proc *
procstat_getprocs(struct procstat *procstat, int what, int arg,
unsigned int *count)
@@ -231,6 +297,15 @@
}
/* Perform simple consistency checks. */
if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
+ warnx("kinfo_proc structure size mismatch (len = %zu)", len);
+ goto fail;
+ }
+ *count = len / sizeof(*p);
+ return (p);
+ } else if (procstat->type == PROCSTAT_CORE) {
+ p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
+ &len);
+ if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
warnx("kinfo_proc structure size mismatch");
goto fail;
}
@@ -258,13 +333,17 @@
struct filestat_list *
procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
{
-
- if (procstat->type == PROCSTAT_SYSCTL)
+
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ return (procstat_getfiles_kvm(procstat, kp, mmapped));
+ case PROCSTAT_SYSCTL:
+ case PROCSTAT_CORE:
return (procstat_getfiles_sysctl(procstat, kp, mmapped));
- else if (procstat->type == PROCSTAT_KVM)
- return (procstat_getfiles_kvm(procstat, kp, mmapped));
- else
+ default:
+ warnx("unknown access method: %d", procstat->type);
return (NULL);
+ }
}
void
@@ -647,8 +726,62 @@
return (0);
}
+static struct kinfo_file *
+kinfo_getfile_core(struct procstat_core *core, int *cntp)
+{
+ int cnt;
+ size_t len;
+ char *buf, *bp, *eb;
+ struct kinfo_file *kif, *kp, *kf;
+
+ buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
+ if (buf == NULL)
+ return (NULL);
+ /*
+ * XXXMG: The code below is just copy&past from libutil.
+ * The code duplication can be avoided if libutil
+ * is extended to provide something like:
+ * struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
+ * size_t len, int *cntp);
+ */
+
+ /* Pass 1: count items */
+ cnt = 0;
+ bp = buf;
+ eb = buf + len;
+ while (bp < eb) {
+ kf = (struct kinfo_file *)(uintptr_t)bp;
+ bp += kf->kf_structsize;
+ cnt++;
+ }
+
+ kif = calloc(cnt, sizeof(*kif));
+ if (kif == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ bp = buf;
+ eb = buf + len;
+ kp = kif;
+ /* Pass 2: unpack */
+ while (bp < eb) {
+ kf = (struct kinfo_file *)(uintptr_t)bp;
+ /* Copy/expand into pre-zeroed buffer */
+ memcpy(kp, kf, kf->kf_structsize);
+ /* Advance to next packed record */
+ bp += kf->kf_structsize;
+ /* Set field size to fixed length, advance */
+ kp->kf_structsize = sizeof(*kp);
+ kp++;
+ }
+ free(buf);
+ *cntp = cnt;
+ return (kif); /* Caller must free() return value */
+}
+
static struct filestat_list *
-procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
+ int mmapped)
{
struct kinfo_file *kif, *files;
struct kinfo_vmentry *kve, *vmentries;
@@ -664,8 +797,16 @@
assert(kp);
if (kp->ki_fd == NULL)
return (NULL);
-
- files = kinfo_getfile(kp->ki_pid, &cnt);
+ switch(procstat->type) {
+ case PROCSTAT_SYSCTL:
+ files = kinfo_getfile(kp->ki_pid, &cnt);
+ break;
+ case PROCSTAT_CORE:
+ files = kinfo_getfile_core(procstat->core, &cnt);
+ break;
+ default:
+ assert(!"invalid type");
+ }
if (files == NULL && errno != EPERM) {
warn("kinfo_getfile()");
return (NULL);
@@ -703,7 +844,7 @@
STAILQ_INSERT_TAIL(head, entry, next);
}
if (mmapped != 0) {
- vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
+ vmentries = procstat_getvmmap(procstat, kp, &cnt);
procstat->vmentries = vmentries;
if (vmentries == NULL || cnt == 0)
goto fail;
@@ -743,7 +884,8 @@
if (procstat->type == PROCSTAT_KVM) {
return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
errbuf));
- } else if (procstat->type == PROCSTAT_SYSCTL) {
+ } else if (procstat->type == PROCSTAT_SYSCTL ||
+ procstat->type == PROCSTAT_CORE) {
return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
} else {
warnx("unknown access method: %d", procstat->type);
@@ -807,7 +949,8 @@
if (procstat->type == PROCSTAT_KVM) {
return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
errbuf));
- } else if (procstat->type == PROCSTAT_SYSCTL) {
+ } else if (procstat->type == PROCSTAT_SYSCTL ||
+ procstat->type == PROCSTAT_CORE) {
return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
} else {
warnx("unknown access method: %d", procstat->type);
@@ -869,7 +1012,8 @@
if (procstat->type == PROCSTAT_KVM) {
return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
errbuf));
- } else if (procstat->type == PROCSTAT_SYSCTL) {
+ } else if (procstat->type == PROCSTAT_SYSCTL ||
+ procstat->type == PROCSTAT_CORE) {
return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
} else {
warnx("unknown access method: %d", procstat->type);
@@ -949,7 +1093,8 @@
if (procstat->type == PROCSTAT_KVM) {
return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
errbuf));
- } else if (procstat->type == PROCSTAT_SYSCTL) {
+ } else if (procstat->type == PROCSTAT_SYSCTL ||
+ procstat->type == PROCSTAT_CORE) {
return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
} else {
warnx("unknown access method: %d", procstat->type);
@@ -1156,7 +1301,8 @@
if (procstat->type == PROCSTAT_KVM) {
return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
errbuf));
- } else if (procstat->type == PROCSTAT_SYSCTL) {
+ } else if (procstat->type == PROCSTAT_SYSCTL ||
+ procstat->type == PROCSTAT_CORE) {
return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
} else {
warnx("unknown access method: %d", procstat->type);
@@ -1407,3 +1553,866 @@
mhead = mt;
return (mt->mntonname);
}
+
+/*
+ * Auxiliary structures and functions to get process environment or
+ * command line arguments.
+ */
+struct argvec {
+ char *buf;
+ size_t bufsize;
+ char **argv;
+ size_t argc;
+};
+
+static struct argvec *
+argvec_alloc(size_t bufsize)
+{
+ struct argvec *av;
+
+ av = malloc(sizeof(*av));
+ if (av == NULL)
+ return (NULL);
+ av->bufsize = bufsize;
+ av->buf = malloc(av->bufsize);
+ if (av->buf == NULL) {
+ free(av);
+ return (NULL);
+ }
+ av->argc = 32;
+ av->argv = malloc(sizeof(char *) * av->argc);
+ if (av->argv == NULL) {
+ free(av->buf);
+ free(av);
+ return (NULL);
+ }
+ return av;
+}
+
+static void
+argvec_free(struct argvec * av)
+{
+
+ free(av->argv);
+ free(av->buf);
+ free(av);
+}
+
+static char **
+getargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env)
+{
+ int error, name[4], argc, i;
+ struct argvec *av, **avp;
+ enum psc_type type;
+ size_t len;
+ char *p, **argv;
+
+ assert(procstat);
+ assert(kp);
+ if (procstat->type == PROCSTAT_KVM) {
+ warnx("can't use kvm access method");
+ return (NULL);
+ }
+ if (procstat->type != PROCSTAT_SYSCTL &&
+ procstat->type != PROCSTAT_CORE) {
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+
+ if (nchr == 0 || nchr > ARG_MAX)
+ nchr = ARG_MAX;
+
+ avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv);
+ av = *avp;
+
+ if (av == NULL)
+ {
+ av = argvec_alloc(nchr);
+ if (av == NULL)
+ {
+ warn("malloc(%zu)", nchr);
+ return (NULL);
+ }
+ *avp = av;
+ } else if (av->bufsize < nchr) {
+ av->buf = reallocf(av->buf, nchr);
+ if (av->buf == NULL) {
+ warn("malloc(%zu)", nchr);
+ return (NULL);
+ }
+ }
+ if (procstat->type == PROCSTAT_SYSCTL) {
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
+ name[3] = kp->ki_pid;
+ len = nchr;
+ error = sysctl(name, 4, av->buf, &len, NULL, 0);
+ if (error != 0 && errno != ESRCH && errno != EPERM)
+ warn("sysctl(kern.proc.%s)", env ? "env" : "args");
+ if (error != 0 || len == 0)
+ return (NULL);
+ } else /* procstat->type == PROCSTAT_CORE */ {
+ type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV;
+ len = nchr;
+ if (procstat_core_get(procstat->core, type, av->buf, &len)
+ == NULL) {
+ return (NULL);
+ }
+ }
+
+ argv = av->argv;
+ argc = av->argc;
+ i = 0;
+ for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) {
+ argv[i++] = p;
+ if (i < argc)
+ continue;
+ /* Grow argv. */
+ argc += argc;
+ argv = realloc(argv, sizeof(char *) * argc);
+ if (argv == NULL) {
+ warn("malloc(%zu)", sizeof(char *) * argc);
+ return (NULL);
+ }
+ av->argv = argv;
+ av->argc = argc;
+ }
+ argv[i] = NULL;
+
+ return (argv);
+}
+
+/*
+ * Return process command line arguments.
+ */
+char **
+procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
+{
+
+ return (getargv(procstat, p, nchr, 0));
+}
+
+/*
+ * Free the buffer allocated by procstat_getargv().
+ */
+void
+procstat_freeargv(struct procstat *procstat)
+{
+
+ if (procstat->argv != NULL) {
+ argvec_free(procstat->argv);
+ procstat->argv = NULL;
+ }
+}
+
+/*
+ * Return process environment.
+ */
+char **
+procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
+{
+
+ return (getargv(procstat, p, nchr, 1));
+}
+
+/*
+ * Free the buffer allocated by procstat_getenvv().
+ */
+void
+procstat_freeenvv(struct procstat *procstat)
+{
+ if (procstat->envv != NULL) {
+ argvec_free(procstat->envv);
+ procstat->envv = NULL;
+ }
+}
+
+static struct kinfo_vmentry *
+kinfo_getvmmap_core(struct procstat_core *core, int *cntp)
+{
+ int cnt;
+ size_t len;
+ char *buf, *bp, *eb;
+ struct kinfo_vmentry *kiv, *kp, *kv;
+
+ buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len);
+ if (buf == NULL)
+ return (NULL);
+
+ /*
+ * XXXMG: The code below is just copy&past from libutil.
+ * The code duplication can be avoided if libutil
+ * is extended to provide something like:
+ * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf,
+ * size_t len, int *cntp);
+ */
+
+ /* Pass 1: count items */
+ cnt = 0;
+ bp = buf;
+ eb = buf + len;
+ while (bp < eb) {
+ kv = (struct kinfo_vmentry *)(uintptr_t)bp;
+ bp += kv->kve_structsize;
+ cnt++;
+ }
+
+ kiv = calloc(cnt, sizeof(*kiv));
+ if (kiv == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ bp = buf;
+ eb = buf + len;
+ kp = kiv;
+ /* Pass 2: unpack */
+ while (bp < eb) {
+ kv = (struct kinfo_vmentry *)(uintptr_t)bp;
+ /* Copy/expand into pre-zeroed buffer */
+ memcpy(kp, kv, kv->kve_structsize);
+ /* Advance to next packed record */
+ bp += kv->kve_structsize;
+ /* Set field size to fixed length, advance */
+ kp->kve_structsize = sizeof(*kp);
+ kp++;
+ }
+ free(buf);
+ *cntp = cnt;
+ return (kiv); /* Caller must free() return value */
+}
+
+struct kinfo_vmentry *
+procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned int *cntp)
+{
+
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ warnx("kvm method is not supported");
+ return (NULL);
+ case PROCSTAT_SYSCTL:
+ return (kinfo_getvmmap(kp->ki_pid, cntp));
+ case PROCSTAT_CORE:
+ return (kinfo_getvmmap_core(procstat->core, cntp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freevmmap(struct procstat *procstat __unused,
+ struct kinfo_vmentry *vmmap)
+{
+
+ free(vmmap);
+}
+
+static gid_t *
+procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp)
+{
+ struct proc proc;
+ struct ucred ucred;
+ gid_t *groups;
+ size_t len;
+
+ assert(kd != NULL);
+ assert(kp != NULL);
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+ sizeof(proc))) {
+ warnx("can't read proc struct at %p for pid %d",
+ kp->ki_paddr, kp->ki_pid);
+ return (NULL);
+ }
+ if (proc.p_ucred == NOCRED)
+ return (NULL);
+ if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred,
+ sizeof(ucred))) {
+ warnx("can't read ucred struct at %p for pid %d",
+ proc.p_ucred, kp->ki_pid);
+ return (NULL);
+ }
+ len = ucred.cr_ngroups * sizeof(gid_t);
+ groups = malloc(len);
+ if (groups == NULL) {
+ warn("malloc(%zu)", len);
+ return (NULL);
+ }
+ if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) {
+ warnx("can't read groups at %p for pid %d",
+ ucred.cr_groups, kp->ki_pid);
+ free(groups);
+ return (NULL);
+ }
+ *cntp = ucred.cr_ngroups;
+ return (groups);
+}
+
+static gid_t *
+procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp)
+{
+ int mib[4];
+ size_t len;
+ gid_t *groups;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_GROUPS;
+ mib[3] = pid;
+ len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t);
+ groups = malloc(len);
+ if (groups == NULL) {
+ warn("malloc(%zu)", len);
+ return (NULL);
+ }
+ if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) {
+ warn("sysctl: kern.proc.groups: %d", pid);
+ free(groups);
+ return (NULL);
+ }
+ *cntp = len / sizeof(gid_t);
+ return (groups);
+}
+
+static gid_t *
+procstat_getgroups_core(struct procstat_core *core, unsigned int *cntp)
+{
+ size_t len;
+ gid_t *groups;
+
+ groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len);
+ if (groups == NULL)
+ return (NULL);
+ *cntp = len / sizeof(gid_t);
+ return (groups);
+}
+
+gid_t *
+procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned int *cntp)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ return (procstat_getgroups_kvm(procstat->kd, kp, cntp));
+ case PROCSTAT_SYSCTL:
+ return (procstat_getgroups_sysctl(kp->ki_pid, cntp));
+ case PROCSTAT_CORE:
+ return (procstat_getgroups_core(procstat->core, cntp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freegroups(struct procstat *procstat __unused, gid_t *groups)
+{
+
+ free(groups);
+}
+
+static int
+procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp)
+{
+ struct filedesc fd;
+
+ assert(kd != NULL);
+ assert(kp != NULL);
+ if (kp->ki_fd == NULL)
+ return (-1);
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) {
+ warnx("can't read filedesc at %p for pid %d", kp->ki_fd,
+ kp->ki_pid);
+ return (-1);
+ }
+ *maskp = fd.fd_cmask;
+ return (0);
+}
+
+static int
+procstat_getumask_sysctl(pid_t pid, unsigned short *maskp)
+{
+ int error;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_UMASK;
+ mib[3] = pid;
+ len = sizeof(*maskp);
+ error = sysctl(mib, 4, maskp, &len, NULL, 0);
+ if (error != 0 && errno != ESRCH)
+ warn("sysctl: kern.proc.umask: %d", pid);
+ return (error);
+}
+
+static int
+procstat_getumask_core(struct procstat_core *core, unsigned short *maskp)
+{
+ size_t len;
+ unsigned short *buf;
+
+ buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len);
+ if (buf == NULL)
+ return (-1);
+ if (len < sizeof(*maskp)) {
+ free(buf);
+ return (-1);
+ }
+ *maskp = *buf;
+ free(buf);
+ return (0);
+}
+
+int
+procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned short *maskp)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ return (procstat_getumask_kvm(procstat->kd, kp, maskp));
+ case PROCSTAT_SYSCTL:
+ return (procstat_getumask_sysctl(kp->ki_pid, maskp));
+ case PROCSTAT_CORE:
+ return (procstat_getumask_core(procstat->core, maskp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (-1);
+ }
+}
+
+static int
+procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which,
+ struct rlimit* rlimit)
+{
+ struct proc proc;
+ unsigned long offset;
+
+ assert(kd != NULL);
+ assert(kp != NULL);
+ assert(which >= 0 && which < RLIM_NLIMITS);
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+ sizeof(proc))) {
+ warnx("can't read proc struct at %p for pid %d",
+ kp->ki_paddr, kp->ki_pid);
+ return (-1);
+ }
+ if (proc.p_limit == NULL)
+ return (-1);
+ offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which;
+ if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) {
+ warnx("can't read rlimit struct at %p for pid %d",
+ (void *)offset, kp->ki_pid);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit)
+{
+ int error, name[5];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_RLIMIT;
+ name[3] = pid;
+ name[4] = which;
+ len = sizeof(struct rlimit);
+ error = sysctl(name, 5, rlimit, &len, NULL, 0);
+ if (error < 0 && errno != ESRCH) {
+ warn("sysctl: kern.proc.rlimit: %d", pid);
+ return (-1);
+ }
+ if (error < 0 || len != sizeof(struct rlimit))
+ return (-1);
+ return (0);
+}
+
+static int
+procstat_getrlimit_core(struct procstat_core *core, int which,
+ struct rlimit* rlimit)
+{
+ size_t len;
+ struct rlimit* rlimits;
+
+ if (which < 0 || which >= RLIM_NLIMITS) {
+ errno = EINVAL;
+ warn("getrlimit: which");
+ return (-1);
+ }
+ rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len);
+ if (rlimits == NULL)
+ return (-1);
+ if (len < sizeof(struct rlimit) * RLIM_NLIMITS) {
+ free(rlimits);
+ return (-1);
+ }
+ *rlimit = rlimits[which];
+ return (0);
+}
+
+int
+procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which,
+ struct rlimit* rlimit)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ return (procstat_getrlimit_kvm(procstat->kd, kp, which,
+ rlimit));
+ case PROCSTAT_SYSCTL:
+ return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit));
+ case PROCSTAT_CORE:
+ return (procstat_getrlimit_core(procstat->core, which, rlimit));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (-1);
+ }
+}
+
+static int
+procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen)
+{
+ int error, name[4];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_PATHNAME;
+ name[3] = pid;
+ len = maxlen;
+ error = sysctl(name, 4, pathname, &len, NULL, 0);
+ if (error != 0 && errno != ESRCH)
+ warn("sysctl: kern.proc.pathname: %d", pid);
+ if (len == 0)
+ pathname[0] = '\0';
+ return (error);
+}
+
+static int
+procstat_getpathname_core(struct procstat_core *core, char *pathname,
+ size_t maxlen)
+{
+ struct kinfo_file *files;
+ int cnt, i, result;
+
+ files = kinfo_getfile_core(core, &cnt);
+ if (files == NULL)
+ return (-1);
+ result = -1;
+ for (i = 0; i < cnt; i++) {
+ if (files[i].kf_fd != KF_FD_TYPE_TEXT)
+ continue;
+ strncpy(pathname, files[i].kf_path, maxlen);
+ result = 0;
+ break;
+ }
+ free(files);
+ return (result);
+}
+
+int
+procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
+ char *pathname, size_t maxlen)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ warnx("kvm method is not supported");
+ return (-1);
+ case PROCSTAT_SYSCTL:
+ return (procstat_getpathname_sysctl(kp->ki_pid, pathname,
+ maxlen));
+ case PROCSTAT_CORE:
+ return (procstat_getpathname_core(procstat->core, pathname,
+ maxlen));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (-1);
+ }
+}
+
+static int
+procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp)
+{
+ struct proc proc;
+
+ assert(kd != NULL);
+ assert(kp != NULL);
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+ sizeof(proc))) {
+ warnx("can't read proc struct at %p for pid %d",
+ kp->ki_paddr, kp->ki_pid);
+ return (-1);
+ }
+ *osrelp = proc.p_osrel;
+ return (0);
+}
+
+static int
+procstat_getosrel_sysctl(pid_t pid, int *osrelp)
+{
+ int error, name[4];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_OSREL;
+ name[3] = pid;
+ len = sizeof(*osrelp);
+ error = sysctl(name, 4, osrelp, &len, NULL, 0);
+ if (error != 0 && errno != ESRCH)
+ warn("sysctl: kern.proc.osrel: %d", pid);
+ return (error);
+}
+
+static int
+procstat_getosrel_core(struct procstat_core *core, int *osrelp)
+{
+ size_t len;
+ int *buf;
+
+ buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len);
+ if (buf == NULL)
+ return (-1);
+ if (len < sizeof(*osrelp)) {
+ free(buf);
+ return (-1);
+ }
+ *osrelp = *buf;
+ free(buf);
+ return (0);
+}
+
+int
+procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ return (procstat_getosrel_kvm(procstat->kd, kp, osrelp));
+ case PROCSTAT_SYSCTL:
+ return (procstat_getosrel_sysctl(kp->ki_pid, osrelp));
+ case PROCSTAT_CORE:
+ return (procstat_getosrel_core(procstat->core, osrelp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (-1);
+ }
+}
+
+#define PROC_AUXV_MAX 256
+
+#if __ELF_WORD_SIZE == 64
+static const char *elf32_sv_names[] = {
+ "Linux ELF32",
+ "FreeBSD ELF32",
+};
+
+static int
+is_elf32_sysctl(pid_t pid)
+{
+ int error, name[4];
+ size_t len, i;
+ static char sv_name[256];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_SV_NAME;
+ name[3] = pid;
+ len = sizeof(sv_name);
+ error = sysctl(name, 4, sv_name, &len, NULL, 0);
+ if (error != 0 || len == 0)
+ return (0);
+ for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
+ if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+static Elf_Auxinfo *
+procstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ Elf32_Auxinfo *auxv32;
+ void *ptr;
+ size_t len;
+ unsigned int i, count;
+ int name[4];
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_AUXV;
+ name[3] = pid;
+ len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
+ auxv = NULL;
+ auxv32 = malloc(len);
+ if (auxv32 == NULL) {
+ warn("malloc(%zu)", len);
+ goto out;
+ }
+ if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) {
+ if (errno != ESRCH && errno != EPERM)
+ warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+ goto out;
+ }
+ count = len / sizeof(Elf_Auxinfo);
+ auxv = malloc(count * sizeof(Elf_Auxinfo));
+ if (auxv == NULL) {
+ warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
+ goto out;
+ }
+ for (i = 0; i < count; i++) {
+ /*
+ * XXX: We expect that values for a_type on a 32-bit platform
+ * are directly mapped to values on 64-bit one, which is not
+ * necessarily true.
+ */
+ auxv[i].a_type = auxv32[i].a_type;
+ ptr = &auxv32[i].a_un;
+ auxv[i].a_un.a_val = *((uint32_t *)ptr);
+ }
+ *cntp = count;
+out:
+ free(auxv32);
+ return (auxv);
+}
+#endif /* __ELF_WORD_SIZE == 64 */
+
+static Elf_Auxinfo *
+procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ int name[4];
+ size_t len;
+
+#if __ELF_WORD_SIZE == 64
+ if (is_elf32_sysctl(pid))
+ return (procstat_getauxv32_sysctl(pid, cntp));
+#endif
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_AUXV;
+ name[3] = pid;
+ len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
+ auxv = malloc(len);
+ if (auxv == NULL) {
+ warn("malloc(%zu)", len);
+ return (NULL);
+ }
+ if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) {
+ if (errno != ESRCH && errno != EPERM)
+ warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
+ free(auxv);
+ return (NULL);
+ }
+ *cntp = len / sizeof(Elf_Auxinfo);
+ return (auxv);
+}
+
+static Elf_Auxinfo *
+procstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
+{
+ Elf_Auxinfo *auxv;
+ size_t len;
+
+ auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
+ if (auxv == NULL)
+ return (NULL);
+ *cntp = len / sizeof(Elf_Auxinfo);
+ return (auxv);
+}
+
+Elf_Auxinfo *
+procstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned int *cntp)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ warnx("kvm method is not supported");
+ return (NULL);
+ case PROCSTAT_SYSCTL:
+ return (procstat_getauxv_sysctl(kp->ki_pid, cntp));
+ case PROCSTAT_CORE:
+ return (procstat_getauxv_core(procstat->core, cntp));
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
+{
+
+ free(auxv);
+}
+
+static struct kinfo_kstack *
+procstat_getkstack_sysctl(pid_t pid, int *cntp)
+{
+ struct kinfo_kstack *kkstp;
+ int error, name[4];
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_KSTACK;
+ name[3] = pid;
+
+ len = 0;
+ error = sysctl(name, 4, NULL, &len, NULL, 0);
+ if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
+ warn("sysctl: kern.proc.kstack: %d", pid);
+ return (NULL);
+ }
+ if (error == -1 && errno == ENOENT) {
+ warnx("sysctl: kern.proc.kstack unavailable"
+ " (options DDB or options STACK required in kernel)");
+ return (NULL);
+ }
+ if (error == -1)
+ return (NULL);
+ kkstp = malloc(len);
+ if (kkstp == NULL) {
+ warn("malloc(%zu)", len);
+ return (NULL);
+ }
+ if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) {
+ warn("sysctl: kern.proc.pid: %d", pid);
+ free(kkstp);
+ return (NULL);
+ }
+ *cntp = len / sizeof(*kkstp);
+
+ return (kkstp);
+}
+
+struct kinfo_kstack *
+procstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned int *cntp)
+{
+ switch(procstat->type) {
+ case PROCSTAT_KVM:
+ warnx("kvm method is not supported");
+ return (NULL);
+ case PROCSTAT_SYSCTL:
+ return (procstat_getkstack_sysctl(kp->ki_pid, cntp));
+ case PROCSTAT_CORE:
+ warnx("core method is not supported");
+ return (NULL);
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freekstack(struct procstat *procstat __unused,
+ struct kinfo_kstack *kkstp)
+{
+
+ free(kkstp);
+}
Modified: trunk/lib/libprocstat/libprocstat.h
===================================================================
--- trunk/lib/libprocstat/libprocstat.h 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat.h 2017-03-04 21:43:03 UTC (rev 9409)
@@ -30,6 +30,14 @@
#define _LIBPROCSTAT_H_
/*
+ * XXX: sys/elf.h conflicts with zfs_context.h. Workaround this by not
+ * including conflicting parts when building zfs code.
+ */
+#ifndef ZFS
+#include <sys/elf.h>
+#endif
+
+/*
* Vnode types.
*/
#define PS_FST_VTYPE_VNON 1
@@ -90,7 +98,10 @@
#define PS_FST_FFLAG_HASLOCK 0x4000
#define PS_FST_FFLAG_CAPABILITY 0x8000
+struct kinfo_kstack;
+struct kinfo_vmentry;
struct procstat;
+struct rlimit;
struct filestat {
int fs_type; /* Descriptor type. */
int fs_flags; /* filestat specific flags. */
@@ -146,9 +157,19 @@
__BEGIN_DECLS
void procstat_close(struct procstat *procstat);
+void procstat_freeargv(struct procstat *procstat);
+#ifndef ZFS
+void procstat_freeauxv(struct procstat *procstat, Elf_Auxinfo *auxv);
+#endif
+void procstat_freeenvv(struct procstat *procstat);
+void procstat_freegroups(struct procstat *procstat, gid_t *groups);
+void procstat_freekstack(struct procstat *procstat,
+ struct kinfo_kstack *kkstp);
void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p);
void procstat_freefiles(struct procstat *procstat,
struct filestat_list *head);
+void procstat_freevmmap(struct procstat *procstat,
+ struct kinfo_vmentry *vmmap);
struct filestat_list *procstat_getfiles(struct procstat *procstat,
struct kinfo_proc *kp, int mmapped);
struct kinfo_proc *procstat_getprocs(struct procstat *procstat,
@@ -163,6 +184,29 @@
struct sockstat *sock, char *errbuf);
int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
struct vnstat *vn, char *errbuf);
+char **procstat_getargv(struct procstat *procstat, struct kinfo_proc *p,
+ size_t nchr);
+#ifndef ZFS
+Elf_Auxinfo *procstat_getauxv(struct procstat *procstat,
+ struct kinfo_proc *kp, unsigned int *cntp);
+#endif
+char **procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p,
+ size_t nchr);
+gid_t *procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned int *count);
+struct kinfo_kstack *procstat_getkstack(struct procstat *procstat,
+ struct kinfo_proc *kp, unsigned int *count);
+int procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp,
+ int *osrelp);
+int procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
+ char *pathname, size_t maxlen);
+int procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp,
+ int which, struct rlimit* rlimit);
+int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
+ unsigned short* umask);
+struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat,
+ struct kinfo_proc *kp, unsigned int *count);
+struct procstat *procstat_open_core(const char *filename);
struct procstat *procstat_open_sysctl(void);
struct procstat *procstat_open_kvm(const char *nlistf, const char *memf);
__END_DECLS
Modified: trunk/lib/libprocstat/libprocstat_internal.h
===================================================================
--- trunk/lib/libprocstat/libprocstat_internal.h 2017-03-04 21:40:08 UTC (rev 9408)
+++ trunk/lib/libprocstat/libprocstat_internal.h 2017-03-04 21:43:03 UTC (rev 9409)
@@ -34,6 +34,9 @@
kvm_t *kd;
void *vmentries;
void *files;
+ void *argv;
+ void *envv;
+ struct procstat_core *core;
};
#endif /* !_LIBPROCSTAT_INTERNAL_H_ */
More information about the Midnightbsd-cvs
mailing list