mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-27 04:53:28 +00:00
MF7: 185716 (head 185548 + followups). KERN_PROC_* kinfo updates.
Approved by: re (kensmith)
This commit is contained in:
parent
e8ed639521
commit
3b7212732b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/releng/7.1/; revision=185717
@ -9,7 +9,8 @@ LIB= util
|
||||
SHLIB_MAJOR= 7
|
||||
|
||||
SRCS= _secure_path.c auth.c gr_util.c expand_number.c flopen.c fparseln.c \
|
||||
humanize_number.c kld.c login.c login_auth.c login_cap.c login_class.c \
|
||||
humanize_number.c kinfo_getfile.c kinfo_getvmmap.c kld.c \
|
||||
login.c login_auth.c login_cap.c login_class.c \
|
||||
login_crypt.c login_ok.c login_times.c login_tty.c logout.c \
|
||||
logwtmp.c pidfile.c property.c pty.c pw_util.c realhostname.c \
|
||||
stub.c trimdomain.c uucplock.c
|
||||
|
72
lib/libutil/kinfo_getfile.c
Normal file
72
lib/libutil/kinfo_getfile.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libutil.h"
|
||||
|
||||
struct kinfo_file *
|
||||
kinfo_getfile(pid_t pid, int *cntp)
|
||||
{
|
||||
int mib[4];
|
||||
int error;
|
||||
int cnt;
|
||||
size_t len;
|
||||
char *buf, *bp, *eb;
|
||||
struct kinfo_file *kif, *kp, *kf;
|
||||
|
||||
len = 0;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_FILEDESC;
|
||||
mib[3] = pid;
|
||||
|
||||
error = sysctl(mib, 4, NULL, &len, NULL, 0);
|
||||
if (error)
|
||||
return (0);
|
||||
len = len * 4 / 3;
|
||||
buf = malloc(len);
|
||||
if (buf == NULL)
|
||||
return (0);
|
||||
error = sysctl(mib, 4, buf, &len, NULL, 0);
|
||||
if (error) {
|
||||
free(buf);
|
||||
return (0);
|
||||
}
|
||||
/* 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 (0);
|
||||
}
|
||||
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 */
|
||||
}
|
72
lib/libutil/kinfo_getvmmap.c
Normal file
72
lib/libutil/kinfo_getvmmap.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libutil.h"
|
||||
|
||||
struct kinfo_vmentry *
|
||||
kinfo_getvmmap(pid_t pid, int *cntp)
|
||||
{
|
||||
int mib[4];
|
||||
int error;
|
||||
int cnt;
|
||||
size_t len;
|
||||
char *buf, *bp, *eb;
|
||||
struct kinfo_vmentry *kiv, *kp, *kv;
|
||||
|
||||
len = 0;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_VMMAP;
|
||||
mib[3] = pid;
|
||||
|
||||
error = sysctl(mib, 4, NULL, &len, NULL, 0);
|
||||
if (error)
|
||||
return (0);
|
||||
len = len * 4 / 3;
|
||||
buf = malloc(len);
|
||||
if (buf == NULL)
|
||||
return (0);
|
||||
error = sysctl(mib, 4, buf, &len, NULL, 0);
|
||||
if (error) {
|
||||
free(buf);
|
||||
return (0);
|
||||
}
|
||||
/* 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 (0);
|
||||
}
|
||||
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 */
|
||||
}
|
@ -64,6 +64,8 @@ struct termios;
|
||||
struct winsize;
|
||||
struct utmp;
|
||||
struct in_addr;
|
||||
struct kinfo_file;
|
||||
struct kinfo_vmentry;
|
||||
|
||||
__BEGIN_DECLS
|
||||
void clean_environment(const char * const *_white,
|
||||
@ -99,6 +101,10 @@ int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr,
|
||||
|
||||
int kld_isloaded(const char *name);
|
||||
int kld_load(const char *name);
|
||||
struct kinfo_file *
|
||||
kinfo_getfile(pid_t _pid, int *_cntp);
|
||||
struct kinfo_vmentry *
|
||||
kinfo_getvmmap(pid_t _pid, int *_cntp);
|
||||
|
||||
#ifdef _STDIO_H_ /* avoid adding new includes */
|
||||
char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
|
||||
|
@ -2570,9 +2570,14 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
|
||||
SYSCTL_PROC(_kern, KERN_FILE, file, CTLTYPE_OPAQUE|CTLFLAG_RD,
|
||||
0, 0, sysctl_kern_file, "S,xfile", "Entire file table");
|
||||
|
||||
#ifdef KINFO_OFILE_SIZE
|
||||
CTASSERT(sizeof(struct kinfo_ofile) == KINFO_OFILE_SIZE);
|
||||
#endif
|
||||
|
||||
/* Compatability with early 7-stable */
|
||||
static int
|
||||
export_vnode_for_sysctl(struct vnode *vp, int type,
|
||||
struct kinfo_file *kif, struct filedesc *fdp, struct sysctl_req *req)
|
||||
export_vnode_for_osysctl(struct vnode *vp, int type,
|
||||
struct kinfo_ofile *kif, struct filedesc *fdp, struct sysctl_req *req)
|
||||
{
|
||||
int error;
|
||||
char *fullpath, *freepath;
|
||||
@ -2585,7 +2590,7 @@ export_vnode_for_sysctl(struct vnode *vp, int type,
|
||||
kif->kf_fd = type;
|
||||
kif->kf_type = KF_TYPE_VNODE;
|
||||
/* This function only handles directories. */
|
||||
KASSERT(vp->v_type == VDIR, ("export_vnode_for_sysctl: vnode not directory"));
|
||||
KASSERT(vp->v_type == VDIR, ("export_vnode_for_osysctl: vnode not directory"));
|
||||
kif->kf_vnode_type = KF_VTYPE_VDIR;
|
||||
|
||||
/*
|
||||
@ -2615,10 +2620,10 @@ export_vnode_for_sysctl(struct vnode *vp, int type,
|
||||
* Get per-process file descriptors for use by procstat(1), et al.
|
||||
*/
|
||||
static int
|
||||
sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
char *fullpath, *freepath;
|
||||
struct kinfo_file *kif;
|
||||
struct kinfo_ofile *kif;
|
||||
struct filedesc *fdp;
|
||||
int error, i, *name;
|
||||
struct socket *so;
|
||||
@ -2641,13 +2646,13 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
|
||||
FILEDESC_SLOCK(fdp);
|
||||
if (fdp->fd_cdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif,
|
||||
export_vnode_for_osysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif,
|
||||
fdp, req);
|
||||
if (fdp->fd_rdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif,
|
||||
export_vnode_for_osysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif,
|
||||
fdp, req);
|
||||
if (fdp->fd_jdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif,
|
||||
export_vnode_for_osysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif,
|
||||
fdp, req);
|
||||
for (i = 0; i < fdp->fd_nfiles; i++) {
|
||||
if ((fp = fdp->fd_ofiles[i]) == NULL)
|
||||
@ -2795,6 +2800,245 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static SYSCTL_NODE(_kern_proc, KERN_PROC_OFILEDESC, ofiledesc, CTLFLAG_RD,
|
||||
sysctl_kern_proc_ofiledesc, "Process ofiledesc entries");
|
||||
|
||||
#ifdef KINFO_FILE_SIZE
|
||||
CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE);
|
||||
#endif
|
||||
|
||||
static int
|
||||
export_vnode_for_sysctl(struct vnode *vp, int type,
|
||||
struct kinfo_file *kif, struct filedesc *fdp, struct sysctl_req *req)
|
||||
{
|
||||
int error;
|
||||
char *fullpath, *freepath;
|
||||
int vfslocked;
|
||||
|
||||
bzero(kif, sizeof(*kif));
|
||||
|
||||
vref(vp);
|
||||
kif->kf_fd = type;
|
||||
kif->kf_type = KF_TYPE_VNODE;
|
||||
/* This function only handles directories. */
|
||||
KASSERT(vp->v_type == VDIR, ("export_vnode_for_sysctl: vnode not directory"));
|
||||
kif->kf_vnode_type = KF_VTYPE_VDIR;
|
||||
|
||||
/*
|
||||
* This is not a true file descriptor, so we set a bogus refcount
|
||||
* and offset to indicate these fields should be ignored.
|
||||
*/
|
||||
kif->kf_ref_count = -1;
|
||||
kif->kf_offset = -1;
|
||||
|
||||
freepath = NULL;
|
||||
fullpath = "-";
|
||||
FILEDESC_SUNLOCK(fdp);
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
|
||||
vn_fullpath(curthread, vp, &fullpath, &freepath);
|
||||
vput(vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
strlcpy(kif->kf_path, fullpath, sizeof(kif->kf_path));
|
||||
if (freepath != NULL)
|
||||
free(freepath, M_TEMP);
|
||||
/* Pack record size down */
|
||||
kif->kf_structsize = offsetof(struct kinfo_file, kf_path) +
|
||||
strlen(kif->kf_path) + 1;
|
||||
kif->kf_structsize = roundup(kif->kf_structsize, sizeof(uint64_t));
|
||||
error = SYSCTL_OUT(req, kif, kif->kf_structsize);
|
||||
FILEDESC_SLOCK(fdp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get per-process file descriptors for use by procstat(1), et al.
|
||||
*/
|
||||
static int
|
||||
sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
char *fullpath, *freepath;
|
||||
struct kinfo_file *kif;
|
||||
struct filedesc *fdp;
|
||||
int error, i, *name;
|
||||
struct socket *so;
|
||||
struct vnode *vp;
|
||||
struct file *fp;
|
||||
struct proc *p;
|
||||
int vfslocked;
|
||||
|
||||
name = (int *)arg1;
|
||||
if ((p = pfind((pid_t)name[0])) == NULL)
|
||||
return (ESRCH);
|
||||
if ((error = p_candebug(curthread, p))) {
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
}
|
||||
fdp = fdhold(p);
|
||||
PROC_UNLOCK(p);
|
||||
if (fdp == NULL)
|
||||
return (ENOENT);
|
||||
kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
|
||||
FILEDESC_SLOCK(fdp);
|
||||
if (fdp->fd_cdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_cdir, KF_FD_TYPE_CWD, kif,
|
||||
fdp, req);
|
||||
if (fdp->fd_rdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_rdir, KF_FD_TYPE_ROOT, kif,
|
||||
fdp, req);
|
||||
if (fdp->fd_jdir != NULL)
|
||||
export_vnode_for_sysctl(fdp->fd_jdir, KF_FD_TYPE_JAIL, kif,
|
||||
fdp, req);
|
||||
for (i = 0; i < fdp->fd_nfiles; i++) {
|
||||
if ((fp = fdp->fd_ofiles[i]) == NULL)
|
||||
continue;
|
||||
bzero(kif, sizeof(*kif));
|
||||
FILE_LOCK(fp);
|
||||
vp = NULL;
|
||||
so = NULL;
|
||||
kif->kf_fd = i;
|
||||
switch (fp->f_type) {
|
||||
case DTYPE_VNODE:
|
||||
kif->kf_type = KF_TYPE_VNODE;
|
||||
vp = fp->f_vnode;
|
||||
vref(vp);
|
||||
break;
|
||||
|
||||
case DTYPE_SOCKET:
|
||||
kif->kf_type = KF_TYPE_SOCKET;
|
||||
so = fp->f_data;
|
||||
break;
|
||||
|
||||
case DTYPE_PIPE:
|
||||
kif->kf_type = KF_TYPE_PIPE;
|
||||
break;
|
||||
|
||||
case DTYPE_FIFO:
|
||||
kif->kf_type = KF_TYPE_FIFO;
|
||||
vp = fp->f_vnode;
|
||||
vref(vp);
|
||||
break;
|
||||
|
||||
case DTYPE_KQUEUE:
|
||||
kif->kf_type = KF_TYPE_KQUEUE;
|
||||
break;
|
||||
|
||||
case DTYPE_CRYPTO:
|
||||
kif->kf_type = KF_TYPE_CRYPTO;
|
||||
break;
|
||||
|
||||
case DTYPE_MQUEUE:
|
||||
kif->kf_type = KF_TYPE_MQUEUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
kif->kf_type = KF_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
kif->kf_ref_count = fp->f_count;
|
||||
if (fp->f_flag & FREAD)
|
||||
kif->kf_flags |= KF_FLAG_READ;
|
||||
if (fp->f_flag & FWRITE)
|
||||
kif->kf_flags |= KF_FLAG_WRITE;
|
||||
if (fp->f_flag & FAPPEND)
|
||||
kif->kf_flags |= KF_FLAG_APPEND;
|
||||
if (fp->f_flag & FASYNC)
|
||||
kif->kf_flags |= KF_FLAG_ASYNC;
|
||||
if (fp->f_flag & FFSYNC)
|
||||
kif->kf_flags |= KF_FLAG_FSYNC;
|
||||
if (fp->f_flag & FNONBLOCK)
|
||||
kif->kf_flags |= KF_FLAG_NONBLOCK;
|
||||
if (fp->f_flag & O_DIRECT)
|
||||
kif->kf_flags |= KF_FLAG_DIRECT;
|
||||
if (fp->f_flag & FHASLOCK)
|
||||
kif->kf_flags |= KF_FLAG_HASLOCK;
|
||||
kif->kf_offset = fp->f_offset;
|
||||
FILE_UNLOCK(fp);
|
||||
if (vp != NULL) {
|
||||
switch (vp->v_type) {
|
||||
case VNON:
|
||||
kif->kf_vnode_type = KF_VTYPE_VNON;
|
||||
break;
|
||||
case VREG:
|
||||
kif->kf_vnode_type = KF_VTYPE_VREG;
|
||||
break;
|
||||
case VDIR:
|
||||
kif->kf_vnode_type = KF_VTYPE_VDIR;
|
||||
break;
|
||||
case VBLK:
|
||||
kif->kf_vnode_type = KF_VTYPE_VBLK;
|
||||
break;
|
||||
case VCHR:
|
||||
kif->kf_vnode_type = KF_VTYPE_VCHR;
|
||||
break;
|
||||
case VLNK:
|
||||
kif->kf_vnode_type = KF_VTYPE_VLNK;
|
||||
break;
|
||||
case VSOCK:
|
||||
kif->kf_vnode_type = KF_VTYPE_VSOCK;
|
||||
break;
|
||||
case VFIFO:
|
||||
kif->kf_vnode_type = KF_VTYPE_VFIFO;
|
||||
break;
|
||||
case VBAD:
|
||||
kif->kf_vnode_type = KF_VTYPE_VBAD;
|
||||
break;
|
||||
default:
|
||||
kif->kf_vnode_type = KF_VTYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* It is OK to drop the filedesc lock here as we will
|
||||
* re-validate and re-evaluate its properties when
|
||||
* the loop continues.
|
||||
*/
|
||||
freepath = NULL;
|
||||
fullpath = "-";
|
||||
FILEDESC_SUNLOCK(fdp);
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
|
||||
vn_fullpath(curthread, vp, &fullpath, &freepath);
|
||||
vput(vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
strlcpy(kif->kf_path, fullpath,
|
||||
sizeof(kif->kf_path));
|
||||
if (freepath != NULL)
|
||||
free(freepath, M_TEMP);
|
||||
FILEDESC_SLOCK(fdp);
|
||||
}
|
||||
if (so != NULL) {
|
||||
struct sockaddr *sa;
|
||||
|
||||
if (so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa)
|
||||
== 0 && sa->sa_len <= sizeof(kif->kf_sa_local)) {
|
||||
bcopy(sa, &kif->kf_sa_local, sa->sa_len);
|
||||
free(sa, M_SONAME);
|
||||
}
|
||||
if (so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa)
|
||||
== 00 && sa->sa_len <= sizeof(kif->kf_sa_peer)) {
|
||||
bcopy(sa, &kif->kf_sa_peer, sa->sa_len);
|
||||
free(sa, M_SONAME);
|
||||
}
|
||||
kif->kf_sock_domain =
|
||||
so->so_proto->pr_domain->dom_family;
|
||||
kif->kf_sock_type = so->so_type;
|
||||
kif->kf_sock_protocol = so->so_proto->pr_protocol;
|
||||
}
|
||||
/* Pack record size down */
|
||||
kif->kf_structsize = offsetof(struct kinfo_file, kf_path) +
|
||||
strlen(kif->kf_path) + 1;
|
||||
kif->kf_structsize = roundup(kif->kf_structsize,
|
||||
sizeof(uint64_t));
|
||||
error = SYSCTL_OUT(req, kif, kif->kf_structsize);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
FILEDESC_SUNLOCK(fdp);
|
||||
fddrop(fdp);
|
||||
free(kif, M_TEMP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, CTLFLAG_RD,
|
||||
sysctl_kern_proc_filedesc, "Process filedesc entries");
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_compat.h"
|
||||
#include "opt_ddb.h"
|
||||
#include "opt_kdtrace.h"
|
||||
#include "opt_ktrace.h"
|
||||
@ -1339,13 +1340,18 @@ sysctl_kern_proc_sv_name(SYSCTL_HANDLER_ARGS)
|
||||
return (sysctl_handle_string(oidp, sv_name, 0, req));
|
||||
}
|
||||
|
||||
#ifdef KINFO_OVMENTRY_SIZE
|
||||
CTASSERT(sizeof(struct kinfo_ovmentry) == KINFO_OVMENTRY_SIZE);
|
||||
#endif
|
||||
|
||||
/* Compatability with early 7-stable */
|
||||
static int
|
||||
sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
|
||||
sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
vm_map_entry_t entry, tmp_entry;
|
||||
unsigned int last_timestamp;
|
||||
char *fullpath, *freepath;
|
||||
struct kinfo_vmentry *kve;
|
||||
struct kinfo_ovmentry *kve;
|
||||
struct vattr va;
|
||||
struct ucred *cred;
|
||||
int error, *name;
|
||||
@ -1501,6 +1507,176 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef KINFO_VMENTRY_SIZE
|
||||
CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE);
|
||||
#endif
|
||||
|
||||
static int
|
||||
sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
vm_map_entry_t entry, tmp_entry;
|
||||
unsigned int last_timestamp;
|
||||
char *fullpath, *freepath;
|
||||
struct kinfo_vmentry *kve;
|
||||
struct vattr va;
|
||||
struct ucred *cred;
|
||||
int error, *name;
|
||||
struct vnode *vp;
|
||||
struct proc *p;
|
||||
vm_map_t map;
|
||||
|
||||
name = (int *)arg1;
|
||||
if ((p = pfind((pid_t)name[0])) == NULL)
|
||||
return (ESRCH);
|
||||
if (p->p_flag & P_WEXIT) {
|
||||
PROC_UNLOCK(p);
|
||||
return (ESRCH);
|
||||
}
|
||||
if ((error = p_candebug(curthread, p))) {
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
}
|
||||
_PHOLD(p);
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
kve = malloc(sizeof(*kve), M_TEMP, M_WAITOK);
|
||||
|
||||
map = &p->p_vmspace->vm_map; /* XXXRW: More locking required? */
|
||||
vm_map_lock_read(map);
|
||||
for (entry = map->header.next; entry != &map->header;
|
||||
entry = entry->next) {
|
||||
vm_object_t obj, tobj, lobj;
|
||||
vm_offset_t addr;
|
||||
int vfslocked;
|
||||
|
||||
if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
|
||||
continue;
|
||||
|
||||
bzero(kve, sizeof(*kve));
|
||||
|
||||
kve->kve_private_resident = 0;
|
||||
obj = entry->object.vm_object;
|
||||
if (obj != NULL) {
|
||||
VM_OBJECT_LOCK(obj);
|
||||
if (obj->shadow_count == 1)
|
||||
kve->kve_private_resident =
|
||||
obj->resident_page_count;
|
||||
}
|
||||
kve->kve_resident = 0;
|
||||
addr = entry->start;
|
||||
while (addr < entry->end) {
|
||||
if (pmap_extract(map->pmap, addr))
|
||||
kve->kve_resident++;
|
||||
addr += PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
|
||||
if (tobj != obj)
|
||||
VM_OBJECT_LOCK(tobj);
|
||||
if (lobj != obj)
|
||||
VM_OBJECT_UNLOCK(lobj);
|
||||
lobj = tobj;
|
||||
}
|
||||
|
||||
kve->kve_fileid = 0;
|
||||
kve->kve_fsid = 0;
|
||||
freepath = NULL;
|
||||
fullpath = "";
|
||||
if (lobj) {
|
||||
vp = NULL;
|
||||
switch(lobj->type) {
|
||||
case OBJT_DEFAULT:
|
||||
kve->kve_type = KVME_TYPE_DEFAULT;
|
||||
break;
|
||||
case OBJT_VNODE:
|
||||
kve->kve_type = KVME_TYPE_VNODE;
|
||||
vp = lobj->handle;
|
||||
vref(vp);
|
||||
break;
|
||||
case OBJT_SWAP:
|
||||
kve->kve_type = KVME_TYPE_SWAP;
|
||||
break;
|
||||
case OBJT_DEVICE:
|
||||
kve->kve_type = KVME_TYPE_DEVICE;
|
||||
break;
|
||||
case OBJT_PHYS:
|
||||
kve->kve_type = KVME_TYPE_PHYS;
|
||||
break;
|
||||
case OBJT_DEAD:
|
||||
kve->kve_type = KVME_TYPE_DEAD;
|
||||
break;
|
||||
default:
|
||||
kve->kve_type = KVME_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (lobj != obj)
|
||||
VM_OBJECT_UNLOCK(lobj);
|
||||
|
||||
kve->kve_ref_count = obj->ref_count;
|
||||
kve->kve_shadow_count = obj->shadow_count;
|
||||
VM_OBJECT_UNLOCK(obj);
|
||||
if (vp != NULL) {
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY,
|
||||
curthread);
|
||||
vn_fullpath(curthread, vp, &fullpath,
|
||||
&freepath);
|
||||
cred = curthread->td_ucred;
|
||||
if (VOP_GETATTR(vp, &va, cred, curthread) == 0) {
|
||||
kve->kve_fileid = va.va_fileid;
|
||||
kve->kve_fsid = va.va_fsid;
|
||||
}
|
||||
vput(vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
}
|
||||
} else {
|
||||
kve->kve_type = KVME_TYPE_NONE;
|
||||
kve->kve_ref_count = 0;
|
||||
kve->kve_shadow_count = 0;
|
||||
}
|
||||
|
||||
kve->kve_start = entry->start;
|
||||
kve->kve_end = entry->end;
|
||||
kve->kve_offset = entry->offset;
|
||||
|
||||
if (entry->protection & VM_PROT_READ)
|
||||
kve->kve_protection |= KVME_PROT_READ;
|
||||
if (entry->protection & VM_PROT_WRITE)
|
||||
kve->kve_protection |= KVME_PROT_WRITE;
|
||||
if (entry->protection & VM_PROT_EXECUTE)
|
||||
kve->kve_protection |= KVME_PROT_EXEC;
|
||||
|
||||
if (entry->eflags & MAP_ENTRY_COW)
|
||||
kve->kve_flags |= KVME_FLAG_COW;
|
||||
if (entry->eflags & MAP_ENTRY_NEEDS_COPY)
|
||||
kve->kve_flags |= KVME_FLAG_NEEDS_COPY;
|
||||
|
||||
strlcpy(kve->kve_path, fullpath, sizeof(kve->kve_path));
|
||||
if (freepath != NULL)
|
||||
free(freepath, M_TEMP);
|
||||
|
||||
last_timestamp = map->timestamp;
|
||||
vm_map_unlock_read(map);
|
||||
/* Pack record size down */
|
||||
kve->kve_structsize = offsetof(struct kinfo_vmentry, kve_path) +
|
||||
strlen(kve->kve_path) + 1;
|
||||
kve->kve_structsize = roundup(kve->kve_structsize,
|
||||
sizeof(uint64_t));
|
||||
error = SYSCTL_OUT(req, kve, kve->kve_structsize);
|
||||
vm_map_lock_read(map);
|
||||
if (error)
|
||||
break;
|
||||
if (last_timestamp + 1 != map->timestamp) {
|
||||
vm_map_lookup_entry(map, addr - 1, &tmp_entry);
|
||||
entry = tmp_entry;
|
||||
}
|
||||
}
|
||||
vm_map_unlock_read(map);
|
||||
PRELE(p);
|
||||
free(kve, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(STACK) || defined(DDB)
|
||||
static int
|
||||
sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS)
|
||||
@ -1674,6 +1850,9 @@ static SYSCTL_NODE(_kern_proc, (KERN_PROC_PID | KERN_PROC_INC_THREAD), pid_td,
|
||||
static SYSCTL_NODE(_kern_proc, (KERN_PROC_PROC | KERN_PROC_INC_THREAD), proc_td,
|
||||
CTLFLAG_RD, sysctl_kern_proc, "Return process table, no threads");
|
||||
|
||||
static SYSCTL_NODE(_kern_proc, KERN_PROC_OVMMAP, ovmmap, CTLFLAG_RD,
|
||||
sysctl_kern_proc_ovmmap, "Old Process vm map entries");
|
||||
|
||||
static SYSCTL_NODE(_kern_proc, KERN_PROC_VMMAP, vmmap, CTLFLAG_RD,
|
||||
sysctl_kern_proc_vmmap, "Process vm map entries");
|
||||
|
||||
|
@ -463,13 +463,16 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
|
||||
#define KERN_PROC_RGID 10 /* by real group id */
|
||||
#define KERN_PROC_GID 11 /* by effective group id */
|
||||
#define KERN_PROC_PATHNAME 12 /* path to executable */
|
||||
#define KERN_PROC_VMMAP 13 /* VM map entries for process */
|
||||
#define KERN_PROC_FILEDESC 14 /* File descriptors for process */
|
||||
#define KERN_PROC_OVMMAP 13 /* Old VM map entries for process */
|
||||
#define KERN_PROC_OFILEDESC 14 /* Old file descriptors for process */
|
||||
#define KERN_PROC_KSTACK 15 /* Kernel stacks for process */
|
||||
#define KERN_PROC_INC_THREAD 0x10 /*
|
||||
* modifier for pid, pgrp, tty,
|
||||
* uid, ruid, gid, rgid and proc
|
||||
* This effectively uses 16-31
|
||||
*/
|
||||
#define KERN_PROC_VMMAP 32 /* VM map entries for process */
|
||||
#define KERN_PROC_FILEDESC 33 /* File descriptors for process */
|
||||
|
||||
/*
|
||||
* KERN_IPC identifiers
|
||||
|
@ -271,22 +271,57 @@ struct user {
|
||||
#define KF_FLAG_DIRECT 0x00000040
|
||||
#define KF_FLAG_HASLOCK 0x00000080
|
||||
|
||||
struct kinfo_file {
|
||||
/*
|
||||
* Old format. Has variable hidden padding due to alignment.
|
||||
* This is a compatability hack for pre-build 7.1 packages.
|
||||
*/
|
||||
#if defined(__amd64__)
|
||||
#define KINFO_OFILE_SIZE 1328
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
#define KINFO_OFILE_SIZE 1324
|
||||
#endif
|
||||
|
||||
struct kinfo_ofile {
|
||||
int kf_structsize; /* Size of kinfo_file. */
|
||||
int kf_type; /* Descriptor type. */
|
||||
int kf_fd; /* Array index. */
|
||||
int kf_ref_count; /* Reference count. */
|
||||
int kf_flags; /* Flags. */
|
||||
/* XXX Hidden alignment padding here on amd64 */
|
||||
off_t kf_offset; /* Seek location. */
|
||||
int kf_vnode_type; /* Vnode type. */
|
||||
int kf_sock_domain; /* Socket domain. */
|
||||
int kf_sock_type; /* Socket type. */
|
||||
int kf_sock_protocol; /* Socket protocol. */
|
||||
char kf_path[PATH_MAX]; /* Path to file, if any. */
|
||||
char kf_path[PATH_MAX]; /* Path to file, if any. */
|
||||
struct sockaddr_storage kf_sa_local; /* Socket address. */
|
||||
struct sockaddr_storage kf_sa_peer; /* Peer address. */
|
||||
};
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
#define KINFO_FILE_SIZE 1392
|
||||
#endif
|
||||
|
||||
struct kinfo_file {
|
||||
int kf_structsize; /* Variable size of record. */
|
||||
int kf_type; /* Descriptor type. */
|
||||
int kf_fd; /* Array index. */
|
||||
int kf_ref_count; /* Reference count. */
|
||||
int kf_flags; /* Flags. */
|
||||
int _kf_pad0; /* Round to 64 bit alignment */
|
||||
int64_t kf_offset; /* Seek location. */
|
||||
int kf_vnode_type; /* Vnode type. */
|
||||
int kf_sock_domain; /* Socket domain. */
|
||||
int kf_sock_type; /* Socket type. */
|
||||
int kf_sock_protocol; /* Socket protocol. */
|
||||
struct sockaddr_storage kf_sa_local; /* Socket address. */
|
||||
struct sockaddr_storage kf_sa_peer; /* Peer address. */
|
||||
int _kf_ispare[16]; /* Space for more stuff. */
|
||||
/* Truncated before copyout in sysctl */
|
||||
char kf_path[PATH_MAX]; /* Path to file, if any. */
|
||||
};
|
||||
|
||||
/*
|
||||
* The KERN_PROC_VMMAP sysctl allows a process to dump the VM layout of
|
||||
* another process as a series of entries.
|
||||
@ -307,11 +342,18 @@ struct kinfo_file {
|
||||
#define KVME_FLAG_COW 0x00000001
|
||||
#define KVME_FLAG_NEEDS_COPY 0x00000002
|
||||
|
||||
struct kinfo_vmentry {
|
||||
#if defined(__amd64__)
|
||||
#define KINFO_OVMENTRY_SIZE 1168
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
#define KINFO_OVMENTRY_SIZE 1128
|
||||
#endif
|
||||
|
||||
struct kinfo_ovmentry {
|
||||
int kve_structsize; /* Size of kinfo_vmmapentry. */
|
||||
int kve_type; /* Type of map entry. */
|
||||
void *kve_start; /* Starting pointer. */
|
||||
void *kve_end; /* Finishing pointer. */
|
||||
void *kve_start; /* Starting address. */
|
||||
void *kve_end; /* Finishing address. */
|
||||
int kve_flags; /* Flags on map entry. */
|
||||
int kve_resident; /* Number of resident pages. */
|
||||
int kve_private_resident; /* Number of private pages. */
|
||||
@ -321,11 +363,35 @@ struct kinfo_vmentry {
|
||||
char kve_path[PATH_MAX]; /* Path to VM obj, if any. */
|
||||
void *_kve_pspare[8]; /* Space for more stuff. */
|
||||
off_t kve_offset; /* Mapping offset in object */
|
||||
uint64_t kve_fileid; /* inode number of vnode */
|
||||
uint64_t kve_fileid; /* inode number if vnode */
|
||||
dev_t kve_fsid; /* dev_t of vnode location */
|
||||
int _kve_ispare[3]; /* Space for more stuff. */
|
||||
};
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
#define KINFO_VMENTRY_SIZE 1160
|
||||
#endif
|
||||
|
||||
struct kinfo_vmentry {
|
||||
int kve_structsize; /* Variable size of record. */
|
||||
int kve_type; /* Type of map entry. */
|
||||
uint64_t kve_start; /* Starting address. */
|
||||
uint64_t kve_end; /* Finishing address. */
|
||||
uint64_t kve_offset; /* Mapping offset in object */
|
||||
uint64_t kve_fileid; /* inode number if vnode */
|
||||
uint32_t kve_fsid; /* dev_t of vnode location */
|
||||
int kve_flags; /* Flags on map entry. */
|
||||
int kve_resident; /* Number of resident pages. */
|
||||
int kve_private_resident; /* Number of private pages. */
|
||||
int kve_protection; /* Protection bitmask. */
|
||||
int kve_ref_count; /* VM obj ref count. */
|
||||
int kve_shadow_count; /* VM obj shadow count. */
|
||||
int _kve_pad0; /* 64bit align next field */
|
||||
int _kve_ispare[16]; /* Space for more stuff. */
|
||||
/* Truncated before copyout in sysctl */
|
||||
char kve_path[PATH_MAX]; /* Path to VM obj, if any. */
|
||||
};
|
||||
|
||||
/*
|
||||
* The KERN_PROC_KSTACK sysctl allows a process to dump the kernel stacks of
|
||||
* another process as a series of entries. Each stack is represented by a
|
||||
@ -337,12 +403,15 @@ struct kinfo_vmentry {
|
||||
#define KKST_STATE_SWAPPED 1 /* Stack swapped out. */
|
||||
#define KKST_STATE_RUNNING 2 /* Stack ephemeral. */
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
#define KINFO_KSTACK_SIZE 1096
|
||||
#endif
|
||||
|
||||
struct kinfo_kstack {
|
||||
lwpid_t kkst_tid; /* ID of thread. */
|
||||
int kkst_state; /* Validity of stack. */
|
||||
char kkst_trace[KKST_MAXLEN]; /* String representing stack. */
|
||||
void *_kkst_pspare[8]; /* Space for more stuff. */
|
||||
int _kkst_ispare[8]; /* Space for more stuff. */
|
||||
int _kkst_ispare[16]; /* Space for more stuff. */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -12,4 +12,7 @@ SRCS= procstat.c \
|
||||
procstat_threads.c \
|
||||
procstat_vm.c
|
||||
|
||||
LDADD+= -lutil
|
||||
DPADD+= ${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#include "procstat.h"
|
||||
|
||||
@ -134,42 +135,18 @@ void
|
||||
procstat_files(pid_t pid, struct kinfo_proc *kipp)
|
||||
{
|
||||
struct kinfo_file *freep, *kif;
|
||||
int error, name[4];
|
||||
unsigned int i;
|
||||
int i, cnt;
|
||||
const char *str;
|
||||
size_t len;
|
||||
|
||||
if (!hflag)
|
||||
printf("%5s %-16s %4s %1s %1s %-8s %3s %7s %-3s %-12s\n",
|
||||
"PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET",
|
||||
"PRO", "NAME");
|
||||
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_PROC;
|
||||
name[2] = KERN_PROC_FILEDESC;
|
||||
name[3] = pid;
|
||||
|
||||
error = sysctl(name, 4, NULL, &len, NULL, 0);
|
||||
if (error < 0 && errno != ESRCH && errno != EPERM) {
|
||||
warn("sysctl: kern.proc.filedesc: %d", pid);
|
||||
return;
|
||||
}
|
||||
if (error < 0)
|
||||
return;
|
||||
|
||||
freep = kif = malloc(len);
|
||||
if (kif == NULL)
|
||||
err(-1, "malloc");
|
||||
|
||||
if (sysctl(name, 4, kif, &len, NULL, 0) < 0) {
|
||||
warn("sysctl: kern.proc.filedesc %d", pid);
|
||||
free(freep);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < len / sizeof(*kif); i++, kif++) {
|
||||
if (kif->kf_structsize != sizeof(*kif))
|
||||
errx(-1, "kinfo_file mismatch");
|
||||
freep = kinfo_getfile(pid, &cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
kif = &freep[i];
|
||||
|
||||
printf("%5d ", pid);
|
||||
printf("%-16s ", kipp->ki_comm);
|
||||
switch (kif->kf_fd) {
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#include "procstat.h"
|
||||
|
||||
@ -41,10 +43,9 @@ void
|
||||
procstat_vm(pid_t pid, struct kinfo_proc *kipp __unused)
|
||||
{
|
||||
struct kinfo_vmentry *freep, *kve;
|
||||
int error, name[4], ptrwidth;
|
||||
unsigned int i;
|
||||
int ptrwidth;
|
||||
int i, cnt;
|
||||
const char *str;
|
||||
size_t len;
|
||||
|
||||
ptrwidth = 2*sizeof(void *) + 2;
|
||||
if (!hflag)
|
||||
@ -52,41 +53,12 @@ procstat_vm(pid_t pid, struct kinfo_proc *kipp __unused)
|
||||
"PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
|
||||
"PRES", "REF", "SHD", "FL", "TP", "PATH");
|
||||
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_PROC;
|
||||
name[2] = KERN_PROC_VMMAP;
|
||||
name[3] = pid;
|
||||
|
||||
len = 0;
|
||||
error = sysctl(name, 4, NULL, &len, NULL, 0);
|
||||
if (error < 0 && errno != ESRCH && errno != EPERM) {
|
||||
warn("sysctl: kern.proc.vmmap: %d", pid);
|
||||
return;
|
||||
}
|
||||
if (error < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Especially if running procstat -sv, we may need room for more
|
||||
* mappings when printing than were present when we queried, so pad
|
||||
* out the allocation a bit.
|
||||
*/
|
||||
len += sizeof(*kve) * 3;
|
||||
freep = kve = malloc(len);
|
||||
if (kve == NULL)
|
||||
err(-1, "malloc");
|
||||
if (sysctl(name, 4, kve, &len, NULL, 0) < 0) {
|
||||
warn("sysctl: kern.proc.vmmap: %d", pid);
|
||||
free(freep);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (len / sizeof(*kve)); i++, kve++) {
|
||||
if (kve->kve_structsize != sizeof(*kve))
|
||||
errx(-1, "kinfo_vmentry structure mismatch");
|
||||
freep = kinfo_getvmmap(pid, &cnt);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
kve = &freep[i];
|
||||
printf("%5d ", pid);
|
||||
printf("%*p ", ptrwidth, kve->kve_start);
|
||||
printf("%*p ", ptrwidth, kve->kve_end);
|
||||
printf("%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
|
||||
printf("%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
|
||||
printf("%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
|
||||
printf("%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
|
||||
printf("%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
|
||||
|
Loading…
Reference in New Issue
Block a user