summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Makefile1
-rw-r--r--lib/libprocstat/Makefile36
-rw-r--r--lib/libprocstat/cd9660.c (renamed from usr.bin/fstat/cd9660.c)43
-rw-r--r--lib/libprocstat/common_kvm.c207
-rw-r--r--lib/libprocstat/common_kvm.h (renamed from usr.bin/fstat/fstat.h)71
-rw-r--r--lib/libprocstat/libprocstat.c1306
-rw-r--r--lib/libprocstat/libprocstat.h160
-rw-r--r--lib/libprocstat/libprocstat_internal.h39
-rw-r--r--lib/libprocstat/msdosfs.c (renamed from usr.bin/fstat/msdosfs.c)51
-rw-r--r--lib/libprocstat/ntfs.c71
-rw-r--r--lib/libprocstat/nwfs.c76
-rw-r--r--lib/libprocstat/smbfs.c77
-rw-r--r--lib/libprocstat/udf.c102
-rw-r--r--lib/libprocstat/zfs.c (renamed from usr.bin/fstat/zfs.c)48
-rw-r--r--lib/libprocstat/zfs/Makefile (renamed from usr.bin/fstat/zfs/Makefile)0
-rw-r--r--lib/libutil/Makefile6
-rw-r--r--lib/libutil/kinfo_getallproc.374
-rw-r--r--lib/libutil/kinfo_getallproc.c98
-rw-r--r--lib/libutil/kinfo_getproc.373
-rw-r--r--lib/libutil/kinfo_getproc.c71
-rw-r--r--lib/libutil/libutil.h5
-rw-r--r--sys/kern/kern_descrip.c480
-rw-r--r--sys/kern/kern_proc.c12
-rw-r--r--sys/sys/user.h99
-rw-r--r--usr.bin/fstat/Makefile20
-rw-r--r--usr.bin/fstat/fstat.c986
-rw-r--r--usr.bin/fstat/functions.h34
-rw-r--r--usr.bin/fstat/fuser.1148
-rw-r--r--usr.bin/fstat/fuser.c369
-rw-r--r--usr.bin/fstat/main.c49
-rw-r--r--usr.bin/procstat/Makefile2
-rw-r--r--usr.bin/procstat/procstat.c117
-rw-r--r--usr.bin/procstat/procstat.h20
-rw-r--r--usr.bin/procstat/procstat_args.c9
-rw-r--r--usr.bin/procstat/procstat_basic.c3
-rw-r--r--usr.bin/procstat/procstat_bin.c9
-rw-r--r--usr.bin/procstat/procstat_cred.c9
-rw-r--r--usr.bin/procstat/procstat_files.c156
-rw-r--r--usr.bin/procstat/procstat_kstack.c17
-rw-r--r--usr.bin/procstat/procstat_sigs.c9
-rw-r--r--usr.bin/procstat/procstat_threads.c11
-rw-r--r--usr.bin/procstat/procstat_vm.c7
42 files changed, 3931 insertions, 1250 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 4fef1bb..7be186f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -92,6 +92,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libpkg} \
${_libpmc} \
${_libproc} \
+ libprocstat \
librt \
${_librtld_db} \
${_libsdp} \
diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile
new file mode 100644
index 0000000..dc3dd58
--- /dev/null
+++ b/lib/libprocstat/Makefile
@@ -0,0 +1,36 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+LIB= procstat
+
+SRCS= cd9660.c \
+ common_kvm.c \
+ libprocstat.c \
+ msdosfs.c \
+ ntfs.c \
+ nwfs.c \
+ smbfs.c \
+ udf.c
+
+INCS= libprocstat.h
+CFLAGS+= -I. -I${.CURDIR} -D_KVM_VNODE
+SHLIB_MAJOR= 1
+WITHOUT_MAN= yes
+
+# XXX This is a hack.
+.if ${MK_CDDL} != "no"
+CFLAGS+= -DZFS
+OBJS+= zfs/zfs.o
+SOBJS+= zfs/zfs.So
+POBJS+= zfs/zfs.po
+SUBDIR= zfs
+zfs/zfs.o: .PHONY
+ @cd ${.CURDIR}/zfs && ${MAKE} zfs.o
+zfs/zfs.So: .PHONY
+ @cd ${.CURDIR}/zfs && ${MAKE} zfs.So
+zfs/zfs.po: .PHONY
+ @cd ${.CURDIR}/zfs && ${MAKE} zfs.po
+.endif
+
+.include <bsd.lib.mk>
diff --git a/usr.bin/fstat/cd9660.c b/lib/libprocstat/cd9660.c
index 1c26e8d..95882be 100644
--- a/usr.bin/fstat/cd9660.c
+++ b/lib/libprocstat/cd9660.c
@@ -49,31 +49,42 @@ __FBSDID("$FreeBSD$");
#include <sys/vnode.h>
#include <sys/mount.h>
+#include <netinet/in.h>
+
+#include <err.h>
+
#include <isofs/cd9660/cd9660_node.h>
+#define _KERNEL
+#include <isofs/cd9660/iso.h>
+#undef _KERNEL
#include <kvm.h>
#include <stdio.h>
-#include "fstat.h"
+#include "libprocstat.h"
+#include "common_kvm.h"
int
-isofs_filestat(struct vnode *vp, struct filestat *fsp)
+isofs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
{
struct iso_node isonode;
+ struct iso_mnt mnt;
- if (!KVM_READ(VTOI(vp), &isonode, sizeof (isonode))) {
- dprintf(stderr, "can't read iso_node at %p for pid %d\n",
- (void *)VTOI(vp), Pid);
- return 0;
+ if (!kvm_read_all(kd, (unsigned long)VTOI(vp), &isonode,
+ sizeof(isonode))) {
+ warnx("can't read iso_node at %p",
+ (void *)VTOI(vp));
+ return (1);
}
-#if 0
- fsp->fsid = dev2udev(isonode.i_dev);
-#endif
- fsp->mode = (mode_t)isonode.inode.iso_mode;
- fsp->rdev = isonode.inode.iso_rdev;
-
- fsp->fileid = (long)isonode.i_number;
- fsp->size = (u_long)isonode.i_size;
- return 1;
+ if (!kvm_read_all(kd, (unsigned long)isonode.i_mnt, &mnt,
+ sizeof(mnt))) {
+ warnx("can't read iso_mnt at %p",
+ (void *)VTOI(vp));
+ return (1);
+ }
+ vn->vn_fsid = dev2udev(kd, mnt.im_dev);
+ vn->vn_mode = (mode_t)isonode.inode.iso_mode;
+ vn->vn_fileid = (long)isonode.i_number;
+ vn->vn_size = (u_long)isonode.i_size;
+ return (0);
}
-
diff --git a/lib/libprocstat/common_kvm.c b/lib/libprocstat/common_kvm.c
new file mode 100644
index 0000000..1ff181c
--- /dev/null
+++ b/lib/libprocstat/common_kvm.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#define _KERNEL
+#include <sys/pipe.h>
+#include <sys/mount.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+#undef _KERNEL
+#include <nfs/nfsproto.h>
+#include <nfsclient/nfs.h>
+#include <nfsclient/nfsnode.h>
+
+#include <assert.h>
+#include <err.h>
+#include <kvm.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <libprocstat.h>
+#include "common_kvm.h"
+
+int
+kvm_read_all(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes)
+{
+ ssize_t error;
+
+ if (nbytes >= SSIZE_MAX)
+ return (0);
+ error = kvm_read(kd, addr, buf, nbytes);
+ return (error == (ssize_t)(nbytes));
+}
+
+int
+kdevtoname(kvm_t *kd, struct cdev *dev, char *buf)
+{
+ struct cdev si;
+
+ assert(buf);
+ if (!kvm_read_all(kd, (unsigned long)dev, &si, sizeof(si)))
+ return (1);
+ strlcpy(buf, si.__si_namebuf, SPECNAMELEN + 1);
+ return (0);
+}
+
+int
+ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct inode inode;
+
+ if (!kvm_read_all(kd, (unsigned long)VTOI(vp), &inode, sizeof(inode))) {
+ warnx("can't read inode at %p", (void *)VTOI(vp));
+ return (1);
+ }
+ /*
+ * The st_dev from stat(2) is a dev_t. These kernel structures
+ * contain cdev pointers. We need to convert to dev_t to make
+ * comparisons
+ */
+ vn->vn_fsid = dev2udev(kd, inode.i_dev);
+ vn->vn_fileid = (long)inode.i_number;
+ vn->vn_mode = (mode_t)inode.i_mode;
+ vn->vn_size = (u_long)inode.i_size;
+ return (0);
+}
+
+int
+devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct devfs_dirent devfs_dirent;
+ struct mount mount;
+
+ if (!kvm_read_all(kd, (unsigned long)getvnodedata(vp), &devfs_dirent,
+ sizeof(devfs_dirent))) {
+ warnx("can't read devfs_dirent at %p",
+ (void *)vp->v_data);
+ return (1);
+ }
+ if (!kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mount,
+ sizeof(mount))) {
+ warnx("can't read mount at %p",
+ (void *)getvnodemount(vp));
+ return (1);
+ }
+ vn->vn_fsid = mount.mnt_stat.f_fsid.val[0];
+ vn->vn_fileid = devfs_dirent.de_inode;
+ vn->vn_mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR;
+ vn->vn_size = 0;
+ return (0);
+}
+
+int
+nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct nfsnode nfsnode;
+ mode_t mode;
+
+ if (!kvm_read_all(kd, (unsigned long)VTONFS(vp), &nfsnode,
+ sizeof(nfsnode))) {
+ warnx("can't read nfsnode at %p",
+ (void *)VTONFS(vp));
+ return (1);
+ }
+ vn->vn_fsid = nfsnode.n_vattr.va_fsid;
+ vn->vn_fileid = nfsnode.n_vattr.va_fileid;
+ vn->vn_size = nfsnode.n_size;
+ mode = (mode_t)nfsnode.n_vattr.va_mode;
+ switch (vp->v_type) {
+ case VREG:
+ mode |= S_IFREG;
+ break;
+ case VDIR:
+ mode |= S_IFDIR;
+ break;
+ case VBLK:
+ mode |= S_IFBLK;
+ break;
+ case VCHR:
+ mode |= S_IFCHR;
+ break;
+ case VLNK:
+ mode |= S_IFLNK;
+ break;
+ case VSOCK:
+ mode |= S_IFSOCK;
+ break;
+ case VFIFO:
+ mode |= S_IFIFO;
+ break;
+ default:
+ break;
+ };
+ vn->vn_mode = mode;
+ return (0);
+}
+
+/*
+ * Read the cdev structure in the kernel in order to work out the
+ * associated dev_t
+ */
+dev_t
+dev2udev(kvm_t *kd, struct cdev *dev)
+{
+ struct cdev_priv priv;
+
+ assert(kd);
+ if (kvm_read_all(kd, (unsigned long)cdev2priv(dev), &priv,
+ sizeof(priv))) {
+ return ((dev_t)priv.cdp_inode);
+ } else {
+ warnx("can't convert cdev *%p to a dev_t\n", dev);
+ return (-1);
+ }
+}
+
+void *
+getvnodedata(struct vnode *vp)
+{
+ return (vp->v_data);
+}
+
+struct mount *
+getvnodemount(struct vnode *vp)
+{
+ return (vp->v_mount);
+}
diff --git a/usr.bin/fstat/fstat.h b/lib/libprocstat/common_kvm.h
index 3533a60..d0b5307 100644
--- a/usr.bin/fstat/fstat.h
+++ b/lib/libprocstat/common_kvm.h
@@ -1,6 +1,6 @@
/*-
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -29,48 +26,28 @@
* $FreeBSD$
*/
-#ifndef __FSTAT_H__
-#define __FSTAT_H__
+#ifndef _COMMON_KVM_H_
+#define _COMMON_KVM_H_
+
+dev_t dev2udev(kvm_t *kd, struct cdev *dev);
+int kdevtoname(kvm_t *kd, struct cdev *dev, char *);
+int kvm_read_all(kvm_t *kd, unsigned long addr, void *buf,
+ size_t nbytes);
/*
- * a kvm_read that returns true if everything is read
+ * Filesystems specific access routines.
*/
-#define KVM_READ(kaddr, paddr, len) \
- ((len) < SSIZE_MAX && \
- kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (ssize_t)(len))
-
-#define dprintf if (vflg) fprintf
-
-typedef struct devs {
- struct devs *next;
- long fsid;
- long ino;
- const char *name;
-} DEVS;
-
-struct filestat {
- long fsid;
- long fileid;
- mode_t mode;
- u_long size;
- dev_t rdev;
-};
-
-/* Ugh */
-extern kvm_t *kd;
-extern int vflg;
-extern int Pid;
-
-dev_t dev2udev(struct cdev *dev);
-
-/* Additional filesystem types */
-int isofs_filestat(struct vnode *vp, struct filestat *fsp);
-int msdosfs_filestat(struct vnode *vp, struct filestat *fsp);
-
-#ifdef ZFS
-int zfs_filestat(struct vnode *vp, struct filestat *fsp);
-void *getvnodedata(struct vnode *vp);
-struct mount *getvnodemount(struct vnode *vp);
-#endif
-
-#endif /* __FSTAT_H__ */
+int devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int isofs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int msdosfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int ntfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int nwfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int smbfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int udf_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+int zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn);
+void *getvnodedata(struct vnode *vp);
+struct mount *getvnodemount(struct vnode *vp);
+
+#endif /* _COMMON_KVM_H_ */
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
new file mode 100644
index 0000000..cfe81a2
--- /dev/null
+++ b/lib/libprocstat/libprocstat.c
@@ -0,0 +1,1306 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/sysctl.h>
+#include <sys/tty.h>
+#include <sys/filedesc.h>
+#include <sys/queue.h>
+#define _WANT_FILE
+#include <sys/file.h>
+#include <sys/conf.h>
+#define _KERNEL
+#include <sys/mount.h>
+#include <sys/pipe.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+#undef _KERNEL
+#include <nfs/nfsproto.h>
+#include <nfsclient/nfs.h>
+#include <nfsclient/nfsnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <libutil.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <libprocstat.h>
+#include "libprocstat_internal.h"
+#include "common_kvm.h"
+
+int statfs(const char *, struct statfs *); /* XXX */
+
+#define PROCSTAT_KVM 1
+#define PROCSTAT_SYSCTL 2
+
+static char *getmnton(kvm_t *kd, struct mount *m);
+static struct filestat_list *procstat_getfiles_kvm(
+ struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
+static struct filestat_list *procstat_getfiles_sysctl(
+ struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
+static int procstat_get_pipe_info_sysctl(struct filestat *fst,
+ struct pipestat *pipe, char *errbuf);
+static int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct pipestat *pipe, char *errbuf);
+static int procstat_get_pts_info_sysctl(struct filestat *fst,
+ struct ptsstat *pts, char *errbuf);
+static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct ptsstat *pts, char *errbuf);
+static int procstat_get_socket_info_sysctl(struct filestat *fst,
+ struct sockstat *sock, char *errbuf);
+static int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct sockstat *sock, char *errbuf);
+static int to_filestat_flags(int flags);
+static int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct vnstat *vn, char *errbuf);
+static int procstat_get_vnode_info_sysctl(struct filestat *fst,
+ struct vnstat *vn, char *errbuf);
+static int vntype2psfsttype(int type);
+
+void
+procstat_close(struct procstat *procstat)
+{
+
+ assert(procstat);
+ if (procstat->type == PROCSTAT_KVM)
+ kvm_close(procstat->kd);
+}
+
+struct procstat *
+procstat_open_sysctl(void)
+{
+ struct procstat *procstat;
+
+ procstat = calloc(1, sizeof(*procstat));
+ if (procstat == NULL) {
+ warn("malloc()");
+ return (NULL);
+ }
+ procstat->type = PROCSTAT_SYSCTL;
+ return (procstat);
+}
+
+struct procstat *
+procstat_open_kvm(const char *nlistf, const char *memf)
+{
+ struct procstat *procstat;
+ kvm_t *kd;
+ char buf[_POSIX2_LINE_MAX];
+
+ procstat = calloc(1, sizeof(*procstat));
+ if (procstat == NULL) {
+ warn("malloc()");
+ return (NULL);
+ }
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
+ if (kd == NULL) {
+ warnx("kvm_openfiles(): %s", buf);
+ free(procstat);
+ return (NULL);
+ }
+ procstat->type = PROCSTAT_KVM;
+ procstat->kd = kd;
+ return (procstat);
+}
+
+struct kinfo_proc *
+procstat_getprocs(struct procstat *procstat, int what, int arg,
+ unsigned int *count)
+{
+ struct kinfo_proc *p0, *p;
+ size_t len;
+ int name[4];
+ int error;
+
+ assert(procstat);
+ assert(count);
+ p = NULL;
+ if (procstat->type == PROCSTAT_KVM) {
+ p0 = kvm_getprocs(procstat->kd, what, arg, count);
+ if (p0 == NULL || count == 0)
+ return (NULL);
+ len = *count * sizeof(*p);
+ p = malloc(len);
+ if (p == NULL) {
+ warnx("malloc(%zd)", len);
+ goto fail;
+ }
+ bcopy(p0, p, len);
+ return (p);
+ } else if (procstat->type == PROCSTAT_SYSCTL) {
+ len = 0;
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = what;
+ name[3] = arg;
+ error = sysctl(name, 4, NULL, &len, NULL, 0);
+ if (error < 0 && errno != EPERM) {
+ warn("sysctl(kern.proc)");
+ goto fail;
+ }
+ if (len == 0) {
+ warnx("no processes?");
+ goto fail;
+ }
+ p = malloc(len);
+ if (p == NULL) {
+ warnx("malloc(%zd)", len);
+ goto fail;
+ }
+ error = sysctl(name, 4, p, &len, NULL, 0);
+ if (error < 0 && errno != EPERM) {
+ warn("sysctl(kern.proc)");
+ goto fail;
+ }
+ /* Perform simple consistency checks. */
+ if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
+ warnx("kinfo_proc structure size mismatch");
+ goto fail;
+ }
+ *count = len / sizeof(*p);
+ return (p);
+ } else {
+ warnx("unknown access method");
+ return (NULL);
+ }
+fail:
+ if (p)
+ free(p);
+ return (NULL);
+}
+
+void
+procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
+{
+
+ if (p != NULL)
+ free(p);
+ p = NULL;
+}
+
+struct filestat_list *
+procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+{
+
+ if (procstat->type == PROCSTAT_SYSCTL)
+ return (procstat_getfiles_sysctl(procstat, kp, mmapped));
+ else if (procstat->type == PROCSTAT_KVM)
+ return (procstat_getfiles_kvm(procstat, kp, mmapped));
+ else
+ return (NULL);
+}
+
+void
+procstat_freefiles(struct procstat *procstat, struct filestat_list *head)
+{
+ struct filestat *fst, *tmp;
+
+ STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
+ if (fst->fs_path != NULL)
+ free(fst->fs_path);
+ free(fst);
+ }
+ free(head);
+ if (procstat->vmentries != NULL) {
+ free (procstat->vmentries);
+ procstat->vmentries = NULL;
+ }
+ if (procstat->files != NULL) {
+ free (procstat->files);
+ procstat->files = NULL;
+ }
+}
+
+static struct filestat *
+filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
+ int refcount, off_t offset, char *path)
+{
+ struct filestat *entry;
+
+ entry = calloc(1, sizeof(*entry));
+ if (entry == NULL) {
+ warn("malloc()");
+ return (NULL);
+ }
+ entry->fs_typedep = typedep;
+ entry->fs_fflags = fflags;
+ entry->fs_uflags = uflags;
+ entry->fs_fd = fd;
+ entry->fs_type = type;
+ entry->fs_ref_count = refcount;
+ entry->fs_offset = offset;
+ entry->fs_path = path;
+ return (entry);
+}
+
+static struct vnode *
+getctty(kvm_t *kd, struct kinfo_proc *kp)
+{
+ struct pgrp pgrp;
+ struct proc proc;
+ struct session sess;
+ int error;
+
+ assert(kp);
+ error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
+ sizeof(proc));
+ if (error == 0) {
+ warnx("can't read proc struct at %p for pid %d",
+ kp->ki_paddr, kp->ki_pid);
+ return (NULL);
+ }
+ if (proc.p_pgrp == NULL)
+ return (NULL);
+ error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
+ sizeof(pgrp));
+ if (error == 0) {
+ warnx("can't read pgrp struct at %p for pid %d",
+ proc.p_pgrp, kp->ki_pid);
+ return (NULL);
+ }
+ error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
+ sizeof(sess));
+ if (error == 0) {
+ warnx("can't read session struct at %p for pid %d",
+ pgrp.pg_session, kp->ki_pid);
+ return (NULL);
+ }
+ return (sess.s_ttyvp);
+}
+
+static struct filestat_list *
+procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+{
+ struct file file;
+ struct filedesc filed;
+ struct vm_map_entry vmentry;
+ struct vm_object object;
+ struct vmspace vmspace;
+ vm_map_entry_t entryp;
+ vm_map_t map;
+ vm_object_t objp;
+ struct vnode *vp;
+ struct file **ofiles;
+ struct filestat *entry;
+ struct filestat_list *head;
+ kvm_t *kd;
+ void *data;
+ int i, fflags;
+ int prot, type;
+ unsigned int nfiles;
+
+ assert(procstat);
+ kd = procstat->kd;
+ if (kd == NULL)
+ return (NULL);
+ if (kp->ki_fd == NULL)
+ return (NULL);
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
+ sizeof(filed))) {
+ warnx("can't read filedesc at %p", (void *)kp->ki_fd);
+ return (NULL);
+ }
+
+ /*
+ * Allocate list head.
+ */
+ head = malloc(sizeof(*head));
+ if (head == NULL)
+ return (NULL);
+ STAILQ_INIT(head);
+
+ /* root directory vnode, if one. */
+ if (filed.fd_rdir) {
+ entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* current working directory vnode. */
+ if (filed.fd_cdir) {
+ entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* jail root, if any. */
+ if (filed.fd_jdir) {
+ entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* ktrace vnode, if one */
+ if (kp->ki_tracep) {
+ entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
+ PS_FST_UFLAG_TRACE, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* text vnode, if one */
+ if (kp->ki_textvp) {
+ entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ /* Controlling terminal. */
+ if ((vp = getctty(kd, kp)) != NULL) {
+ entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
+ PS_FST_UFLAG_CTTY, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+
+ nfiles = filed.fd_lastfile + 1;
+ ofiles = malloc(nfiles * sizeof(struct file *));
+ if (ofiles == NULL) {
+ warn("malloc(%zd)", nfiles * sizeof(struct file *));
+ goto do_mmapped;
+ }
+ if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles,
+ nfiles * sizeof(struct file *))) {
+ warnx("cannot read file structures at %p",
+ (void *)filed.fd_ofiles);
+ free(ofiles);
+ goto do_mmapped;
+ }
+ for (i = 0; i <= filed.fd_lastfile; i++) {
+ if (ofiles[i] == NULL)
+ continue;
+ if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
+ sizeof(struct file))) {
+ warnx("can't read file %d at %p", i,
+ (void *)ofiles[i]);
+ continue;
+ }
+ switch (file.f_type) {
+ case DTYPE_VNODE:
+ type = PS_FST_TYPE_VNODE;
+ data = file.f_vnode;
+ break;
+ case DTYPE_SOCKET:
+ type = PS_FST_TYPE_SOCKET;
+ data = file.f_data;
+ break;
+ case DTYPE_PIPE:
+ type = PS_FST_TYPE_PIPE;
+ data = file.f_data;
+ break;
+ case DTYPE_FIFO:
+ type = PS_FST_TYPE_FIFO;
+ data = file.f_vnode;
+ break;
+#ifdef DTYPE_PTS
+ case DTYPE_PTS:
+ type = PS_FST_TYPE_PTS;
+ data = file.f_data;
+ break;
+#endif
+ default:
+ continue;
+ }
+ entry = filestat_new_entry(data, type, i,
+ to_filestat_flags(file.f_flag), 0, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ free(ofiles);
+
+do_mmapped:
+
+ /*
+ * Process mmapped files if requested.
+ */
+ if (mmapped) {
+ if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
+ sizeof(vmspace))) {
+ warnx("can't read vmspace at %p",
+ (void *)kp->ki_vmspace);
+ goto exit;
+ }
+ map = &vmspace.vm_map;
+
+ for (entryp = map->header.next;
+ entryp != &kp->ki_vmspace->vm_map.header;
+ entryp = vmentry.next) {
+ if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry,
+ sizeof(vmentry))) {
+ warnx("can't read vm_map_entry at %p",
+ (void *)entryp);
+ continue;
+ }
+ if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
+ continue;
+ if ((objp = vmentry.object.vm_object) == NULL)
+ continue;
+ for (; objp; objp = object.backing_object) {
+ if (!kvm_read_all(kd, (unsigned long)objp,
+ &object, sizeof(object))) {
+ warnx("can't read vm_object at %p",
+ (void *)objp);
+ break;
+ }
+ }
+
+ /* We want only vnode objects. */
+ if (object.type != OBJT_VNODE)
+ continue;
+
+ prot = vmentry.protection;
+ fflags = 0;
+ if (prot & VM_PROT_READ)
+ fflags = PS_FST_FFLAG_READ;
+ if (prot & VM_PROT_WRITE)
+ fflags |= PS_FST_FFLAG_WRITE;
+
+ /*
+ * Create filestat entry.
+ */
+ entry = filestat_new_entry(object.handle,
+ PS_FST_TYPE_VNODE, -1, fflags,
+ PS_FST_UFLAG_MMAP, 0, 0, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ }
+exit:
+ return (head);
+}
+
+/*
+ * kinfo types to filestat translation.
+ */
+static int
+kinfo_type2fst(int kftype)
+{
+ static struct {
+ int kf_type;
+ int fst_type;
+ } kftypes2fst[] = {
+ { KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO },
+ { KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
+ { KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
+ { KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
+ { KF_TYPE_NONE, PS_FST_TYPE_NONE },
+ { KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
+ { KF_TYPE_PTS, PS_FST_TYPE_PTS },
+ { KF_TYPE_SEM, PS_FST_TYPE_SEM },
+ { KF_TYPE_SHM, PS_FST_TYPE_SHM },
+ { KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
+ { KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
+ { KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
+ };
+#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst))
+ unsigned int i;
+
+ for (i = 0; i < NKFTYPES; i++)
+ if (kftypes2fst[i].kf_type == kftype)
+ break;
+ if (i == NKFTYPES)
+ return (PS_FST_TYPE_UNKNOWN);
+ return (kftypes2fst[i].fst_type);
+}
+
+/*
+ * kinfo flags to filestat translation.
+ */
+static int
+kinfo_fflags2fst(int kfflags)
+{
+ static struct {
+ int kf_flag;
+ int fst_flag;
+ } kfflags2fst[] = {
+ { KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
+ { KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
+ { KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
+ { KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
+ { KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
+ { KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
+ { KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
+ { KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
+ { KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
+ { KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
+ { KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
+ { KF_FLAG_READ, PS_FST_FFLAG_READ },
+ { KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
+ { KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
+ { KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
+ };
+#define NKFFLAGS (sizeof(kfflags2fst) / sizeof(*kfflags2fst))
+ unsigned int i;
+ int flags;
+
+ flags = 0;
+ for (i = 0; i < NKFFLAGS; i++)
+ if ((kfflags & kfflags2fst[i].kf_flag) != 0)
+ flags |= kfflags2fst[i].fst_flag;
+ return (flags);
+}
+
+static int
+kinfo_uflags2fst(int fd)
+{
+
+ switch (fd) {
+ case KF_FD_TYPE_CTTY:
+ return (PS_FST_UFLAG_CTTY);
+ case KF_FD_TYPE_CWD:
+ return (PS_FST_UFLAG_CDIR);
+ case KF_FD_TYPE_JAIL:
+ return (PS_FST_UFLAG_JAIL);
+ case KF_FD_TYPE_TEXT:
+ return (PS_FST_UFLAG_TEXT);
+ case KF_FD_TYPE_TRACE:
+ return (PS_FST_UFLAG_TRACE);
+ case KF_FD_TYPE_ROOT:
+ return (PS_FST_UFLAG_RDIR);
+ }
+ return (0);
+}
+
+static struct filestat_list *
+procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
+{
+ struct kinfo_file *kif, *files;
+ struct kinfo_vmentry *kve, *vmentries;
+ struct filestat_list *head;
+ struct filestat *entry;
+ char *path;
+ off_t offset;
+ int cnt, fd, fflags;
+ int i, type, uflags;
+ int refcount;
+
+ assert(kp);
+ if (kp->ki_fd == NULL)
+ return (NULL);
+
+ files = kinfo_getfile(kp->ki_pid, &cnt);
+ if (files == NULL && errno != EPERM) {
+ warn("kinfo_getfile()");
+ return (NULL);
+ }
+ procstat->files = files;
+
+ /*
+ * Allocate list head.
+ */
+ head = malloc(sizeof(*head));
+ if (head == NULL)
+ return (NULL);
+ STAILQ_INIT(head);
+ for (i = 0; i < cnt; i++) {
+ kif = &files[i];
+
+ type = kinfo_type2fst(kif->kf_type);
+ fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
+ fflags = kinfo_fflags2fst(kif->kf_flags);
+ uflags = kinfo_uflags2fst(kif->kf_fd);
+ refcount = kif->kf_ref_count;
+ offset = kif->kf_offset;
+ if (*kif->kf_path != '\0')
+ path = strdup(kif->kf_path);
+ else
+ path = NULL;
+
+ /*
+ * Create filestat entry.
+ */
+ entry = filestat_new_entry(kif, type, fd, fflags, uflags,
+ refcount, offset, path);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ if (mmapped != 0) {
+ vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
+ procstat->vmentries = vmentries;
+ if (vmentries == NULL || cnt == 0)
+ goto fail;
+ for (i = 0; i < cnt; i++) {
+ kve = &vmentries[i];
+ if (kve->kve_type != KVME_TYPE_VNODE)
+ continue;
+ fflags = 0;
+ if (kve->kve_protection & KVME_PROT_READ)
+ fflags = PS_FST_FFLAG_READ;
+ if (kve->kve_protection & KVME_PROT_WRITE)
+ fflags |= PS_FST_FFLAG_WRITE;
+ offset = kve->kve_offset;
+ refcount = kve->kve_ref_count;
+ if (*kve->kve_path != '\0')
+ path = strdup(kve->kve_path);
+ else
+ path = NULL;
+ entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
+ fflags, PS_FST_UFLAG_MMAP, refcount, offset, path);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
+ }
+fail:
+ return (head);
+}
+
+int
+procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
+ struct pipestat *ps, char *errbuf)
+{
+
+ assert(ps);
+ if (procstat->type == PROCSTAT_KVM) {
+ return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
+ errbuf));
+ } else if (procstat->type == PROCSTAT_SYSCTL) {
+ return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
+ } else {
+ warnx("unknow access method: %d", procstat->type);
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+ }
+}
+
+static int
+procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct pipestat *ps, char *errbuf)
+{
+ struct pipe pi;
+ void *pipep;
+
+ assert(kd);
+ assert(ps);
+ assert(fst);
+ bzero(ps, sizeof(*ps));
+ pipep = fst->fs_typedep;
+ if (pipep == NULL)
+ goto fail;
+ if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
+ warnx("can't read pipe at %p", (void *)pipep);
+ goto fail;
+ }
+ ps->addr = (uintptr_t)pipep;
+ ps->peer = (uintptr_t)pi.pipe_peer;
+ ps->buffer_cnt = pi.pipe_buffer.cnt;
+ return (0);
+
+fail:
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+}
+
+static int
+procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
+ char *errbuf __unused)
+{
+ struct kinfo_file *kif;
+
+ assert(ps);
+ assert(fst);
+ bzero(ps, sizeof(*ps));
+ kif = fst->fs_typedep;
+ if (kif == NULL)
+ return (1);
+ ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
+ ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
+ ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
+ return (0);
+}
+
+int
+procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
+ struct ptsstat *pts, char *errbuf)
+{
+
+ assert(pts);
+ if (procstat->type == PROCSTAT_KVM) {
+ return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
+ errbuf));
+ } else if (procstat->type == PROCSTAT_SYSCTL) {
+ return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
+ } else {
+ warnx("unknow access method: %d", procstat->type);
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+ }
+}
+
+static int
+procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct ptsstat *pts, char *errbuf)
+{
+ struct tty tty;
+ void *ttyp;
+
+ assert(kd);
+ assert(pts);
+ assert(fst);
+ bzero(pts, sizeof(*pts));
+ ttyp = fst->fs_typedep;
+ if (ttyp == NULL)
+ goto fail;
+ if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
+ warnx("can't read tty at %p", (void *)ttyp);
+ goto fail;
+ }
+ pts->dev = dev2udev(kd, tty.t_dev);
+ (void)kdevtoname(kd, tty.t_dev, pts->devname);
+ return (0);
+
+fail:
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+}
+
+static int
+procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
+ char *errbuf __unused)
+{
+ struct kinfo_file *kif;
+
+ assert(pts);
+ assert(fst);
+ bzero(pts, sizeof(*pts));
+ kif = fst->fs_typedep;
+ if (kif == NULL)
+ return (0);
+ pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
+ strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
+ return (0);
+}
+
+int
+procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
+ struct vnstat *vn, char *errbuf)
+{
+
+ assert(vn);
+ if (procstat->type == PROCSTAT_KVM) {
+ return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
+ errbuf));
+ } else if (procstat->type == PROCSTAT_SYSCTL) {
+ return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
+ } else {
+ warnx("unknow access method: %d", procstat->type);
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+ }
+}
+
+static int
+procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct vnstat *vn, char *errbuf)
+{
+ /* Filesystem specific handlers. */
+ #define FSTYPE(fst) {#fst, fst##_filestat}
+ struct {
+ const char *tag;
+ int (*handler)(kvm_t *kd, struct vnode *vp,
+ struct vnstat *vn);
+ } fstypes[] = {
+ FSTYPE(devfs),
+ FSTYPE(isofs),
+ FSTYPE(msdosfs),
+ FSTYPE(nfs),
+ FSTYPE(ntfs),
+ FSTYPE(nwfs),
+ FSTYPE(smbfs),
+ FSTYPE(udf),
+ FSTYPE(ufs),
+#ifdef ZFS
+ FSTYPE(zfs),
+#endif
+ };
+#define NTYPES (sizeof(fstypes) / sizeof(*fstypes))
+ struct vnode vnode;
+ char tagstr[12];
+ void *vp;
+ int error, found;
+ unsigned int i;
+
+ assert(kd);
+ assert(vn);
+ assert(fst);
+ vp = fst->fs_typedep;
+ if (vp == NULL)
+ goto fail;
+ error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
+ if (error == 0) {
+ warnx("can't read vnode at %p", (void *)vp);
+ goto fail;
+ }
+ bzero(vn, sizeof(*vn));
+ vn->vn_type = vntype2psfsttype(vnode.v_type);
+ if (vnode.v_type == VNON || vnode.v_type == VBAD)
+ return (0);
+ error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
+ sizeof(tagstr));
+ if (error == 0) {
+ warnx("can't read v_tag at %p", (void *)vp);
+ goto fail;
+ }
+ tagstr[sizeof(tagstr) - 1] = '\0';
+
+ /*
+ * Find appropriate handler.
+ */
+ for (i = 0, found = 0; i < NTYPES; i++)
+ if (!strcmp(fstypes[i].tag, tagstr)) {
+ if (fstypes[i].handler(kd, &vnode, vn) != 0) {
+ goto fail;
+ }
+ break;
+ }
+ if (i == NTYPES) {
+ snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
+ return (1);
+ }
+ vn->vn_mntdir = getmnton(kd, vnode.v_mount);
+ if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
+ vnode.v_rdev != NULL){
+ vn->vn_dev = dev2udev(kd, vnode.v_rdev);
+ (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
+ } else {
+ vn->vn_dev = -1;
+ }
+ return (0);
+
+fail:
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+}
+
+/*
+ * kinfo vnode type to filestat translation.
+ */
+static int
+kinfo_vtype2fst(int kfvtype)
+{
+ static struct {
+ int kf_vtype;
+ int fst_vtype;
+ } kfvtypes2fst[] = {
+ { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
+ { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
+ { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
+ { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
+ { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
+ { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
+ { KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
+ { KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
+ { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
+ };
+#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
+ unsigned int i;
+
+ for (i = 0; i < NKFVTYPES; i++)
+ if (kfvtypes2fst[i].kf_vtype == kfvtype)
+ break;
+ if (i == NKFVTYPES)
+ return (PS_FST_VTYPE_UNKNOWN);
+ return (kfvtypes2fst[i].fst_vtype);
+}
+
+static int
+procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
+ char *errbuf)
+{
+ struct statfs stbuf;
+ struct kinfo_file *kif;
+ struct kinfo_vmentry *kve;
+ uint64_t fileid;
+ uint64_t size;
+ char *name, *path;
+ uint32_t fsid;
+ uint16_t mode;
+ uint32_t rdev;
+ int vntype;
+ int status;
+
+ assert(fst);
+ assert(vn);
+ bzero(vn, sizeof(*vn));
+ if (fst->fs_typedep == NULL)
+ return (1);
+ if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
+ kve = fst->fs_typedep;
+ fileid = kve->kve_vn_fileid;
+ fsid = kve->kve_vn_fsid;
+ mode = kve->kve_vn_mode;
+ path = kve->kve_path;
+ rdev = kve->kve_vn_rdev;
+ size = kve->kve_vn_size;
+ vntype = kinfo_vtype2fst(kve->kve_vn_type);
+ status = kve->kve_status;
+ } else {
+ kif = fst->fs_typedep;
+ fileid = kif->kf_un.kf_file.kf_file_fileid;
+ fsid = kif->kf_un.kf_file.kf_file_fsid;
+ mode = kif->kf_un.kf_file.kf_file_mode;
+ path = kif->kf_path;
+ rdev = kif->kf_un.kf_file.kf_file_rdev;
+ size = kif->kf_un.kf_file.kf_file_size;
+ vntype = kinfo_vtype2fst(kif->kf_vnode_type);
+ status = kif->kf_status;
+ }
+ vn->vn_type = vntype;
+ if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
+ return (0);
+ if ((status & KF_ATTR_VALID) == 0) {
+ snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
+ return (1);
+ }
+ if (path && *path) {
+ statfs(path, &stbuf);
+ vn->vn_mntdir = strdup(stbuf.f_mntonname);
+ } else
+ vn->vn_mntdir = strdup("-");
+ vn->vn_dev = rdev;
+ if (vntype == PS_FST_VTYPE_VBLK) {
+ name = devname(rdev, S_IFBLK);
+ if (name != NULL)
+ strlcpy(vn->vn_devname, name,
+ sizeof(vn->vn_devname));
+ } else if (vntype == PS_FST_VTYPE_VCHR) {
+ name = devname(vn->vn_dev, S_IFCHR);
+ if (name != NULL)
+ strlcpy(vn->vn_devname, name,
+ sizeof(vn->vn_devname));
+ }
+ vn->vn_fsid = fsid;
+ vn->vn_fileid = fileid;
+ vn->vn_size = size;
+ vn->vn_mode = mode;
+ return (0);
+}
+
+int
+procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
+ struct sockstat *sock, char *errbuf)
+{
+
+ assert(sock);
+ if (procstat->type == PROCSTAT_KVM) {
+ return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
+ errbuf));
+ } else if (procstat->type == PROCSTAT_SYSCTL) {
+ return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
+ } else {
+ warnx("unknow access method: %d", procstat->type);
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+ }
+}
+
+static int
+procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
+ struct sockstat *sock, char *errbuf)
+{
+ struct domain dom;
+ struct inpcb inpcb;
+ struct protosw proto;
+ struct socket s;
+ struct unpcb unpcb;
+ ssize_t len;
+ void *so;
+
+ assert(kd);
+ assert(sock);
+ assert(fst);
+ bzero(sock, sizeof(*sock));
+ so = fst->fs_typedep;
+ if (so == NULL)
+ goto fail;
+ sock->so_addr = (uintptr_t)so;
+ /* fill in socket */
+ if (!kvm_read_all(kd, (unsigned long)so, &s,
+ sizeof(struct socket))) {
+ warnx("can't read sock at %p", (void *)so);
+ goto fail;
+ }
+ /* fill in protosw entry */
+ if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
+ sizeof(struct protosw))) {
+ warnx("can't read protosw at %p", (void *)s.so_proto);
+ goto fail;
+ }
+ /* fill in domain */
+ if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
+ sizeof(struct domain))) {
+ warnx("can't read domain at %p",
+ (void *)proto.pr_domain);
+ goto fail;
+ }
+ if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
+ sizeof(sock->dname) - 1)) < 0) {
+ warnx("can't read domain name at %p", (void *)dom.dom_name);
+ sock->dname[0] = '\0';
+ }
+ else
+ sock->dname[len] = '\0';
+
+ /*
+ * Fill in known data.
+ */
+ sock->type = s.so_type;
+ sock->proto = proto.pr_protocol;
+ sock->dom_family = dom.dom_family;
+ sock->so_pcb = (uintptr_t)s.so_pcb;
+
+ /*
+ * Protocol specific data.
+ */
+ switch(dom.dom_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (proto.pr_protocol == IPPROTO_TCP) {
+ if (s.so_pcb) {
+ if (kvm_read(kd, (u_long)s.so_pcb,
+ (char *)&inpcb, sizeof(struct inpcb))
+ != sizeof(struct inpcb)) {
+ warnx("can't read inpcb at %p",
+ (void *)s.so_pcb);
+ } else
+ sock->inp_ppcb =
+ (uintptr_t)inpcb.inp_ppcb;
+ }
+ }
+ break;
+ case AF_UNIX:
+ if (s.so_pcb) {
+ if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
+ sizeof(struct unpcb)) != sizeof(struct unpcb)){
+ warnx("can't read unpcb at %p",
+ (void *)s.so_pcb);
+ } else if (unpcb.unp_conn) {
+ sock->so_rcv_sb_state = s.so_rcv.sb_state;
+ sock->so_snd_sb_state = s.so_snd.sb_state;
+ sock->unp_conn = (uintptr_t)unpcb.unp_conn;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+
+fail:
+ snprintf(errbuf, _POSIX2_LINE_MAX, "error");
+ return (1);
+}
+
+static int
+procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
+ char *errbuf __unused)
+{
+ struct kinfo_file *kif;
+
+ assert(sock);
+ assert(fst);
+ bzero(sock, sizeof(*sock));
+ kif = fst->fs_typedep;
+ if (kif == NULL)
+ return (0);
+
+ /*
+ * Fill in known data.
+ */
+ sock->type = kif->kf_sock_type;
+ sock->proto = kif->kf_sock_protocol;
+ sock->dom_family = kif->kf_sock_domain;
+ sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
+ strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
+ bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
+ bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
+
+ /*
+ * Protocol specific data.
+ */
+ switch(sock->dom_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (sock->proto == IPPROTO_TCP)
+ sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
+ break;
+ case AF_UNIX:
+ if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
+ sock->so_rcv_sb_state =
+ kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
+ sock->so_snd_sb_state =
+ kif->kf_un.kf_sock.kf_sock_snd_sb_state;
+ sock->unp_conn =
+ kif->kf_un.kf_sock.kf_sock_unpconn;
+ }
+ break;
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Descriptor flags to filestat translation.
+ */
+static int
+to_filestat_flags(int flags)
+{
+ static struct {
+ int flag;
+ int fst_flag;
+ } fstflags[] = {
+ { FREAD, PS_FST_FFLAG_READ },
+ { FWRITE, PS_FST_FFLAG_WRITE },
+ { O_APPEND, PS_FST_FFLAG_APPEND },
+ { O_ASYNC, PS_FST_FFLAG_ASYNC },
+ { O_CREAT, PS_FST_FFLAG_CREAT },
+ { O_DIRECT, PS_FST_FFLAG_DIRECT },
+ { O_EXCL, PS_FST_FFLAG_EXCL },
+ { O_EXEC, PS_FST_FFLAG_EXEC },
+ { O_EXLOCK, PS_FST_FFLAG_EXLOCK },
+ { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
+ { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
+ { O_SHLOCK, PS_FST_FFLAG_SHLOCK },
+ { O_SYNC, PS_FST_FFLAG_SYNC },
+ { O_TRUNC, PS_FST_FFLAG_TRUNC }
+ };
+#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags))
+ int fst_flags;
+ unsigned int i;
+
+ fst_flags = 0;
+ for (i = 0; i < NFSTFLAGS; i++)
+ if (flags & fstflags[i].flag)
+ fst_flags |= fstflags[i].fst_flag;
+ return (fst_flags);
+}
+
+/*
+ * Vnode type to filestate translation.
+ */
+static int
+vntype2psfsttype(int type)
+{
+ static struct {
+ int vtype;
+ int fst_vtype;
+ } vt2fst[] = {
+ { VBAD, PS_FST_VTYPE_VBAD },
+ { VBLK, PS_FST_VTYPE_VBLK },
+ { VCHR, PS_FST_VTYPE_VCHR },
+ { VDIR, PS_FST_VTYPE_VDIR },
+ { VFIFO, PS_FST_VTYPE_VFIFO },
+ { VLNK, PS_FST_VTYPE_VLNK },
+ { VNON, PS_FST_VTYPE_VNON },
+ { VREG, PS_FST_VTYPE_VREG },
+ { VSOCK, PS_FST_VTYPE_VSOCK }
+ };
+#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst))
+ unsigned int i, fst_type;
+
+ fst_type = PS_FST_VTYPE_UNKNOWN;
+ for (i = 0; i < NVFTYPES; i++) {
+ if (type == vt2fst[i].vtype) {
+ fst_type = vt2fst[i].fst_vtype;
+ break;
+ }
+ }
+ return (fst_type);
+}
+
+static char *
+getmnton(kvm_t *kd, struct mount *m)
+{
+ static struct mount mnt;
+ static struct mtab {
+ struct mtab *next;
+ struct mount *m;
+ char mntonname[MNAMELEN + 1];
+ } *mhead = NULL;
+ struct mtab *mt;
+
+ for (mt = mhead; mt != NULL; mt = mt->next)
+ if (m == mt->m)
+ return (mt->mntonname);
+ if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
+ warnx("can't read mount table at %p", (void *)m);
+ return (NULL);
+ }
+ if ((mt = malloc(sizeof (struct mtab))) == NULL)
+ err(1, NULL);
+ mt->m = m;
+ bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
+ mnt.mnt_stat.f_mntonname[MNAMELEN] = '\0';
+ mt->next = mhead;
+ mhead = mt;
+ return (mt->mntonname);
+}
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
new file mode 100644
index 0000000..62b1bd5
--- /dev/null
+++ b/lib/libprocstat/libprocstat.h
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBPROCSTAT_H_
+#define _LIBPROCSTAT_H_
+
+/*
+ * Vnode types.
+ */
+#define PS_FST_VTYPE_VNON 1
+#define PS_FST_VTYPE_VREG 2
+#define PS_FST_VTYPE_VDIR 3
+#define PS_FST_VTYPE_VBLK 4
+#define PS_FST_VTYPE_VCHR 5
+#define PS_FST_VTYPE_VLNK 6
+#define PS_FST_VTYPE_VSOCK 7
+#define PS_FST_VTYPE_VFIFO 8
+#define PS_FST_VTYPE_VBAD 9
+#define PS_FST_VTYPE_UNKNOWN 255
+
+/*
+ * Descriptor types.
+ */
+#define PS_FST_TYPE_VNODE 1
+#define PS_FST_TYPE_FIFO 2
+#define PS_FST_TYPE_SOCKET 3
+#define PS_FST_TYPE_PIPE 4
+#define PS_FST_TYPE_PTS 5
+#define PS_FST_TYPE_KQUEUE 6
+#define PS_FST_TYPE_CRYPTO 7
+#define PS_FST_TYPE_MQUEUE 8
+#define PS_FST_TYPE_SHM 9
+#define PS_FST_TYPE_SEM 10
+#define PS_FST_TYPE_UNKNOWN 11
+#define PS_FST_TYPE_NONE 12
+
+/*
+ * Special descriptor numbers.
+ */
+#define PS_FST_UFLAG_RDIR 0x0001
+#define PS_FST_UFLAG_CDIR 0x0002
+#define PS_FST_UFLAG_JAIL 0x0004
+#define PS_FST_UFLAG_TRACE 0x0008
+#define PS_FST_UFLAG_TEXT 0x0010
+#define PS_FST_UFLAG_MMAP 0x0020
+#define PS_FST_UFLAG_CTTY 0x0040
+
+/*
+ * Descriptor flags.
+ */
+#define PS_FST_FFLAG_READ 0x0001
+#define PS_FST_FFLAG_WRITE 0x0002
+#define PS_FST_FFLAG_NONBLOCK 0x0004
+#define PS_FST_FFLAG_APPEND 0x0008
+#define PS_FST_FFLAG_SHLOCK 0x0010
+#define PS_FST_FFLAG_EXLOCK 0x0020
+#define PS_FST_FFLAG_ASYNC 0x0040
+#define PS_FST_FFLAG_SYNC 0x0080
+#define PS_FST_FFLAG_NOFOLLOW 0x0100
+#define PS_FST_FFLAG_CREAT 0x0200
+#define PS_FST_FFLAG_TRUNC 0x0400
+#define PS_FST_FFLAG_EXCL 0x0800
+#define PS_FST_FFLAG_DIRECT 0x1000
+#define PS_FST_FFLAG_EXEC 0x2000
+#define PS_FST_FFLAG_HASLOCK 0x4000
+
+struct procstat;
+struct filestat {
+ int fs_type; /* Descriptor type. */
+ int fs_flags; /* filestat specific flags. */
+ int fs_fflags; /* Descriptor access flags. */
+ int fs_uflags; /* How this file is used. */
+ int fs_fd; /* File descriptor number. */
+ int fs_ref_count; /* Reference count. */
+ off_t fs_offset; /* Seek location. */
+ void *fs_typedep; /* Type dependent data. */
+ char *fs_path;
+ STAILQ_ENTRY(filestat) next;
+};
+struct vnstat {
+ uint64_t vn_fileid;
+ uint64_t vn_size;
+ char *vn_mntdir;
+ uint32_t vn_dev;
+ uint32_t vn_fsid;
+ int vn_type;
+ uint16_t vn_mode;
+ char vn_devname[SPECNAMELEN + 1];
+};
+struct ptsstat {
+ uint32_t dev;
+ char devname[SPECNAMELEN + 1];
+};
+struct pipestat {
+ size_t buffer_cnt;
+ uint64_t addr;
+ uint64_t peer;
+};
+struct sockstat {
+ uint64_t inp_ppcb;
+ uint64_t so_addr;
+ uint64_t so_pcb;
+ uint64_t unp_conn;
+ int dom_family;
+ int proto;
+ int so_rcv_sb_state;
+ int so_snd_sb_state;
+ struct sockaddr_storage sa_local; /* Socket address. */
+ struct sockaddr_storage sa_peer; /* Peer address. */
+ int type;
+ char dname[32];
+};
+
+STAILQ_HEAD(filestat_list, filestat);
+
+void procstat_close(struct procstat *procstat);
+void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p);
+void procstat_freefiles(struct procstat *procstat,
+ struct filestat_list *head);
+struct filestat_list *procstat_getfiles(struct procstat *procstat,
+ struct kinfo_proc *kp, int mmapped);
+struct kinfo_proc *procstat_getprocs(struct procstat *procstat,
+ int what, int arg, unsigned int *count);
+int procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
+ struct pipestat *pipe, char *errbuf);
+int procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
+ struct ptsstat *pts, char *errbuf);
+int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
+ struct sockstat *sock, char *errbuf);
+int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
+ struct vnstat *vn, char *errbuf);
+struct procstat *procstat_open_sysctl(void);
+struct procstat *procstat_open_kvm(const char *nlistf, const char *memf);
+
+#endif /* !_LIBPROCSTAT_H_ */
diff --git a/lib/libprocstat/libprocstat_internal.h b/lib/libprocstat/libprocstat_internal.h
new file mode 100644
index 0000000..1c1d842
--- /dev/null
+++ b/lib/libprocstat/libprocstat_internal.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LIBPROCSTAT_INTERNAL_H_
+#define _LIBPROCSTAT_INTERNAL_H_
+
+struct procstat {
+ int type;
+ kvm_t *kd;
+ void *vmentries;
+ void *files;
+};
+
+#endif /* !_LIBPROCSTAT_INTERNAL_H_ */
diff --git a/usr.bin/fstat/msdosfs.c b/lib/libprocstat/msdosfs.c
index 7f80499..84b437e 100644
--- a/usr.bin/fstat/msdosfs.c
+++ b/lib/libprocstat/msdosfs.c
@@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/vnode.h>
+#include <netinet/in.h>
+
#define _KERNEL
#include <sys/mount.h>
#include <fs/msdosfs/bpb.h>
@@ -62,9 +64,10 @@ __FBSDID("$FreeBSD$");
* VTODE is defined in denode.h only if _KERNEL is defined, but that leads to
* header explosion
*/
-#define VTODE(vp) ((struct denode *)(vp)->v_data)
+#define VTODE(vp) ((struct denode *)getvnodedata(vp))
-#include "fstat.h"
+#include "libprocstat.h"
+#include "common_kvm.h"
struct dosmount {
struct dosmount *next;
@@ -73,7 +76,7 @@ struct dosmount {
};
int
-msdosfs_filestat(struct vnode *vp, struct filestat *fsp)
+msdosfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
{
struct denode denode;
static struct dosmount *mounts;
@@ -81,10 +84,10 @@ msdosfs_filestat(struct vnode *vp, struct filestat *fsp)
u_long dirsperblk;
int fileid;
- if (!KVM_READ(VTODE(vp), &denode, sizeof (denode))) {
- dprintf(stderr, "can't read denode at %p for pid %d\n",
- (void *)VTODE(vp), Pid);
- return 0;
+ if (!kvm_read_all(kd, (unsigned long)VTODE(vp), &denode,
+ sizeof(denode))) {
+ warnx("can't read denode at %p", (void *)VTODE(vp));
+ return (1);
}
/*
@@ -96,30 +99,30 @@ msdosfs_filestat(struct vnode *vp, struct filestat *fsp)
break;
if (!mnt) {
- if ((mnt = malloc(sizeof(struct dosmount))) == NULL)
- err(1, NULL);
- if (!KVM_READ(denode.de_pmp, &mnt->data, sizeof mnt->data)) {
+ if ((mnt = malloc(sizeof(struct dosmount))) == NULL) {
+ warn("malloc()");
+ return (1);
+ }
+ if (!kvm_read_all(kd, (unsigned long)denode.de_pmp,
+ &mnt->data, sizeof(mnt->data))) {
free(mnt);
- dprintf(stderr,
- "can't read mount info at %p for pid %d\n",
- (void *)denode.de_pmp, Pid);
- return 0;
+ warnx("can't read mount info at %p",
+ (void *)denode.de_pmp);
+ return (1);
}
mnt->next = mounts;
mounts = mnt;
mnt->kptr = denode.de_pmp;
}
- fsp->fsid = dev2udev(mnt->data.pm_dev);
- fsp->mode = 0555;
- fsp->mode |= denode.de_Attributes & ATTR_READONLY ? 0 : 0222;
- fsp->mode &= mnt->data.pm_mask;
+ vn->vn_fsid = dev2udev(kd, mnt->data.pm_dev);
+ vn->vn_mode = 0555;
+ vn->vn_mode |= denode.de_Attributes & ATTR_READONLY ? 0 : 0222;
+ vn->vn_mode &= mnt->data.pm_mask;
/* Distinguish directories and files. No "special" files in FAT. */
- fsp->mode |= denode.de_Attributes & ATTR_DIRECTORY ? S_IFDIR : S_IFREG;
-
- fsp->size = denode.de_FileSize;
- fsp->rdev = 0;
+ vn->vn_mode |= denode.de_Attributes & ATTR_DIRECTORY ? S_IFDIR : S_IFREG;
+ vn->vn_size = denode.de_FileSize;
/*
* XXX -
@@ -145,6 +148,6 @@ msdosfs_filestat(struct vnode *vp, struct filestat *fsp)
fileid += denode.de_diroffset / sizeof(struct direntry);
}
- fsp->fileid = fileid;
- return 1;
+ vn->vn_fileid = fileid;
+ return (0);
}
diff --git a/lib/libprocstat/ntfs.c b/lib/libprocstat/ntfs.c
new file mode 100644
index 0000000..888e6cd
--- /dev/null
+++ b/lib/libprocstat/ntfs.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include <fs/ntfs/ntfs.h>
+#include <fs/ntfs/ntfs_inode.h>
+
+#include "libprocstat.h"
+#include "common_kvm.h"
+
+int
+ntfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct fnode fnod;
+ struct ntnode node;
+ int error;
+
+ assert(kd);
+ assert(vn);
+ error = kvm_read_all(kd, (unsigned long)VTOF(vp), &fnod, sizeof(fnod));
+ if (error != 0) {
+ warnx("can't read ntfs fnode at %p", (void *)VTOF(vp));
+ return (1);
+ }
+ error = kvm_read_all(kd, (unsigned long)FTONT(&fnod), &node,
+ sizeof(node));
+ if (error != 0) {
+ warnx("can't read ntfs node at %p", (void *)FTONT(&fnod));
+ return (1);
+ }
+ vn->vn_fileid = node.i_number;
+ vn->vn_fsid = dev2udev(kd, node.i_dev);
+ return (0);
+}
diff --git a/lib/libprocstat/nwfs.c b/lib/libprocstat/nwfs.c
new file mode 100644
index 0000000..006f9aa
--- /dev/null
+++ b/lib/libprocstat/nwfs.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#define _KERNEL
+#include <sys/mount.h>
+#undef _KERNEL
+
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include <fs/nwfs/nwfs.h>
+#include <fs/nwfs/nwfs_node.h>
+
+#include "libprocstat.h"
+#include "common_kvm.h"
+
+int
+nwfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct mount mnt;
+ struct nwnode node;
+ int error;
+
+ assert(kd);
+ assert(vn);
+ error = kvm_read_all(kd, (unsigned long)VTONW(vp), &node, sizeof(node));
+ if (error != 0) {
+ warnx("can't read nwfs fnode at %p", (void *)VTONW(vp));
+ return (1);
+ }
+ error = kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mnt,
+ sizeof(mnt));
+ if (error != 0) {
+ warnx("can't read mount at %p for vnode %p",
+ (void *)getvnodemount(vp), vp);
+ return (1);
+ }
+ vn->vn_fileid = node.n_fid.f_id;
+ if (vn->vn_fileid == 0)
+ vn->vn_fileid = NWFS_ROOT_INO;
+ vn->vn_fsid = mnt.mnt_stat.f_fsid.val[0];
+ return (0);
+}
diff --git a/lib/libprocstat/smbfs.c b/lib/libprocstat/smbfs.c
new file mode 100644
index 0000000..24d8acd
--- /dev/null
+++ b/lib/libprocstat/smbfs.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#define _KERNEL
+#include <sys/mount.h>
+#undef _KERNEL
+
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+
+#include "libprocstat.h"
+#include "common_kvm.h"
+
+int
+smbfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct smbnode node;
+ struct mount mnt;
+ int error;
+
+ assert(kd);
+ assert(vn);
+ error = kvm_read_all(kd, (unsigned long)VTOSMB(vp), &node,
+ sizeof(node));
+ if (error != 0) {
+ warnx("can't read smbfs fnode at %p", (void *)VTOSMB(vp));
+ return (1);
+ }
+ error = kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mnt,
+ sizeof(mnt));
+ if (error != 0) {
+ warnx("can't read mount at %p for vnode %p",
+ (void *)getvnodemount(vp), vp);
+ return (1);
+ }
+ vn->vn_fileid = node.n_ino;
+ if (vn->vn_fileid == 0)
+ vn->vn_fileid = 2;
+ vn->vn_fsid = mnt.mnt_stat.f_fsid.val[0];
+ return (0);
+}
diff --git a/lib/libprocstat/udf.c b/lib/libprocstat/udf.c
new file mode 100644
index 0000000..5d9310e
--- /dev/null
+++ b/lib/libprocstat/udf.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#define _KERNEL
+#include <sys/mount.h>
+#undef _KERNEL
+
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <kvm.h>
+#include <stdlib.h>
+
+#include <fs/udf/ecma167-udf.h>
+
+#include "libprocstat.h"
+#include "common_kvm.h"
+
+/* XXX */
+struct udf_mnt {
+ int im_flags;
+ struct mount *im_mountp;
+ struct g_consumer *im_cp;
+ struct bufobj *im_bo;
+ struct cdev *im_dev;
+ struct vnode *im_devvp;
+ int bsize;
+ int bshift;
+ int bmask;
+ uint32_t part_start;
+ uint32_t part_len;
+ uint64_t root_id;
+ struct long_ad root_icb;
+ int p_sectors;
+ int s_table_entries;
+ void *s_table;
+ void *im_d2l;
+};
+struct udf_node {
+ struct vnode *i_vnode;
+ struct udf_mnt *udfmp;
+ ino_t hash_id;
+ long diroff;
+ struct file_entry *fentry;
+};
+#define VTON(vp) ((struct udf_node *)((vp)->v_data))
+
+int
+udf_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
+{
+ struct udf_node node;
+ struct udf_mnt mnt;
+ int error;
+
+ assert(kd);
+ assert(vn);
+ error = kvm_read_all(kd, (unsigned long)VTON(vp), &node, sizeof(node));
+ if (error != 0) {
+ warnx("can't read udf fnode at %p", (void *)VTON(vp));
+ return (1);
+ }
+ error = kvm_read_all(kd, (unsigned long)node.udfmp, &mnt, sizeof(mnt));
+ if (error != 0) {
+ warnx("can't read udf_mnt at %p for vnode %p",
+ (void *)node.udfmp, vp);
+ return (1);
+ }
+ vn->vn_fileid = node.hash_id;
+ vn->vn_fsid = dev2udev(kd, mnt.im_dev);
+ return (0);
+}
diff --git a/usr.bin/fstat/zfs.c b/lib/libprocstat/zfs.c
index cdca41f..aa6d78e 100644
--- a/usr.bin/fstat/zfs.c
+++ b/lib/libprocstat/zfs.c
@@ -45,14 +45,16 @@
#include <sys/zfs_znode.h>
#include <sys/zfs_sa.h>
+#include <netinet/in.h>
+
#include <err.h>
#include <kvm.h>
#include <stdio.h>
#include <stdlib.h>
#define ZFS
-#undef dprintf
-#include <fstat.h>
+#include "libprocstat.h"
+#include "common_kvm.h"
/*
* Offset calculations that are used to get data from znode without having the
@@ -62,7 +64,7 @@
#define LOCATION_ZPHYS(zsize) ((zsize) - (2 * sizeof(void *) + sizeof(struct task)))
int
-zfs_filestat(struct vnode *vp, struct filestat *fsp)
+zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
{
znode_phys_t zphys;
@@ -76,20 +78,19 @@ zfs_filestat(struct vnode *vp, struct filestat *fsp)
len = sizeof(size);
if (sysctlbyname("debug.sizeof.znode", &size, &len, NULL, 0) == -1) {
- dprintf(stderr, "error getting sysctl\n");
- return (0);
+ warnx("error getting sysctl");
+ return (1);
}
znodeptr = malloc(size);
if (znodeptr == NULL) {
- dprintf(stderr, "error allocating memory for znode storage\n");
- return (0);
+ warnx("error allocating memory for znode storage");
+ return (1);
}
-
/* Since we have problems including vnode.h, we'll use the wrappers. */
vnodeptr = getvnodedata(vp);
- if (!KVM_READ(vnodeptr, znodeptr, (size_t)size)) {
- dprintf(stderr, "can't read znode at %p for pid %d\n",
- (void *)vnodeptr, Pid);
+ if (!kvm_read_all(kd, (unsigned long)vnodeptr, znodeptr,
+ (size_t)size)) {
+ warnx("can't read znode at %p", (void *)vnodeptr);
goto bad;
}
@@ -104,33 +105,30 @@ zfs_filestat(struct vnode *vp, struct filestat *fsp)
zid = (uint64_t *)(dataptr + LOCATION_ZID);
zphys_addr = *(void **)(dataptr + LOCATION_ZPHYS(size));
- if (!KVM_READ(zphys_addr, &zphys, sizeof(zphys))) {
- dprintf(stderr, "can't read znode_phys at %p for pid %d\n",
- zphys_addr, Pid);
+ if (!kvm_read_all(kd, (unsigned long)zphys_addr, &zphys,
+ sizeof(zphys))) {
+ warnx("can't read znode_phys at %p", zphys_addr);
goto bad;
}
/* Get the mount pointer, and read from the address. */
mountptr = getvnodemount(vp);
- if (!KVM_READ(mountptr, &mount, sizeof(mount))) {
- dprintf(stderr, "can't read mount at %p for pid %d\n",
- (void *)mountptr, Pid);
+ if (!kvm_read_all(kd, (unsigned long)mountptr, &mount, sizeof(mount))) {
+ warnx("can't read mount at %p", (void *)mountptr);
goto bad;
}
-
- fsp->fsid = (long)(uint32_t)mount.mnt_stat.f_fsid.val[0];
- fsp->fileid = *zid;
+ vn->vn_fsid = mount.mnt_stat.f_fsid.val[0];
+ vn->vn_fileid = *zid;
/*
* XXX: Shows up wrong in output, but UFS has this error too. Could
* be that we're casting mode-variables from 64-bit to 8-bit or simply
* error in the mode-to-string function.
*/
- fsp->mode = (mode_t)zphys.zp_mode;
- fsp->size = (u_long)zphys.zp_size;
- fsp->rdev = (dev_t)zphys.zp_rdev;
+ vn->vn_mode = (mode_t)zphys.zp_mode;
+ vn->vn_size = (u_long)zphys.zp_size;
free(znodeptr);
- return (1);
+ return (0);
bad:
free(znodeptr);
- return (0);
+ return (1);
}
diff --git a/usr.bin/fstat/zfs/Makefile b/lib/libprocstat/zfs/Makefile
index 7ecfc85..7ecfc85 100644
--- a/usr.bin/fstat/zfs/Makefile
+++ b/lib/libprocstat/zfs/Makefile
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 9dc35c0..b2378ad 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -9,7 +9,8 @@ LIB= util
SHLIB_MAJOR= 9
SRCS= _secure_path.c auth.c expand_number.c flopen.c fparseln.c gr_util.c \
- hexdump.c humanize_number.c kinfo_getfile.c kinfo_getvmmap.c kld.c \
+ hexdump.c humanize_number.c kinfo_getfile.c kinfo_getfile.c \
+ kinfo_getallproc.c kinfo_getproc.c kinfo_getvmmap.c kld.c \
login_auth.c login_cap.c \
login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \
pidfile.c property.c pty.c pw_util.c quotafile.c realhostname.c \
@@ -29,7 +30,8 @@ MAN+= kld.3 login_auth.3 login_tty.3 pty.3 \
_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
realhostname_sa.3 trimdomain.3 fparseln.3 humanize_number.3 \
pidfile.3 flopen.3 expand_number.3 hexdump.3 \
- kinfo_getfile.3 kinfo_getvmmap.3 quotafile.3
+ kinfo_getfile.3 kinfo_getallproc.3 kinfo_getproc.3 \
+ kinfo_getvmmap.3 quotafile.3
MAN+= login.conf.5 auth.conf.5
MLINKS+= kld.3 kld_isloaded.3 kld.3 kld_load.3
MLINKS+= property.3 properties_read.3 property.3 properties_free.3
diff --git a/lib/libutil/kinfo_getallproc.3 b/lib/libutil/kinfo_getallproc.3
new file mode 100644
index 0000000..73981ae
--- /dev/null
+++ b/lib/libutil/kinfo_getallproc.3
@@ -0,0 +1,74 @@
+.\"
+.\" Copyright (c) 2009 Ulf Lilleengen
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 9, 2009
+.Os
+.Dt KINFO_GETALLPROC 3
+.Sh NAME
+.Nm kinfo_getallproc
+.Nd function for getting process information of all processes from kernel
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft struct kinfo_proc *
+.Fn kinfo_getallproc "int *cntp"
+.Sh DESCRIPTION
+This function is used for obtaining process information of all processes from
+the kernel.
+.Pp
+The
+.Ar cntp
+field is a pointer containing the number of process structures returned.
+This function is a wrapper around
+.Xr sysctl 3
+with the
+.Dv KERN_PROC_PROC
+mib.
+While the kernel returns a packed structure, this function expands the
+data into a fixed record format.
+.Sh RETURN VALUES
+On success the
+.Fn kinfo_getallproc
+function returns a pointer to
+.Ar cntp
+.Vt struct kinfo_proc
+structures as defined by
+.In sys/user.h .
+The pointer was obtained by an internal call to
+.Xr malloc 3
+and must be freed by the caller with a call to
+.Xr free 3 .
+On failure the
+.Fn kinfo_getallproc
+function returns
+.Dv NULL .
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr sysctl 3
diff --git a/lib/libutil/kinfo_getallproc.c b/lib/libutil/kinfo_getallproc.c
new file mode 100644
index 0000000..0f43ce2
--- /dev/null
+++ b/lib/libutil/kinfo_getallproc.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2007 Robert N. M. Watson
+ * Copyright (c) 2009 Ulf Lilleengen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libutil.h"
+
+
+/*
+ * Sort processes first by pid and then tid.
+ */
+static int
+kinfo_proc_compare(const void *a, const void *b)
+{
+ int i;
+
+ i = ((const struct kinfo_proc *)a)->ki_pid -
+ ((const struct kinfo_proc *)b)->ki_pid;
+ if (i != 0)
+ return (i);
+ i = ((const struct kinfo_proc *)a)->ki_tid -
+ ((const struct kinfo_proc *)b)->ki_tid;
+ return (i);
+}
+
+static void
+kinfo_proc_sort(struct kinfo_proc *kipp, int count)
+{
+
+ qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare);
+}
+
+struct kinfo_proc *
+kinfo_getallproc(int *cntp)
+{
+ struct kinfo_proc *kipp;
+ size_t len;
+ int mib[3];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PROC;
+
+ len = 0;
+ if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0)
+ return (NULL);
+
+ kipp = malloc(len);
+ if (kipp == NULL)
+ return (NULL);
+
+ if (sysctl(mib, 3, kipp, &len, NULL, 0) < 0)
+ goto bad;
+ if (len % sizeof(*kipp) != 0)
+ goto bad;
+ if (kipp->ki_structsize != sizeof(*kipp))
+ goto bad;
+ *cntp = len / sizeof(*kipp);
+ kinfo_proc_sort(kipp, len / sizeof(*kipp));
+ return (kipp);
+bad:
+ *cntp = 0;
+ free(kipp);
+ return (NULL);
+}
diff --git a/lib/libutil/kinfo_getproc.3 b/lib/libutil/kinfo_getproc.3
new file mode 100644
index 0000000..2778ad1
--- /dev/null
+++ b/lib/libutil/kinfo_getproc.3
@@ -0,0 +1,73 @@
+.\"
+.\" Copyright (c) 2009 Ulf Lilleengen
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 9, 2009
+.Os
+.Dt KINFO_GETPROC 3
+.Sh NAME
+.Nm kinfo_getproc
+.Nd function for getting process information from kernel
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In sys/types.h
+.In libutil.h
+.Ft struct kinfo_proc *
+.Fn kinfo_getproc "pid_t pid" "int *cntp"
+.Sh DESCRIPTION
+This function is used for obtaining process information from the kernel.
+.Pp
+The
+.Ar pid
+field contains the process identifier.
+This should be the a process that you have privilige to access.
+This function is a wrapper around
+.Xr sysctl 3
+with the
+.Dv KERN_PROC_PID
+mib.
+While the kernel returns a packed structure, this function expands the
+data into a fixed record format.
+.Sh RETURN VALUES
+On success the
+.Fn kinfo_getproc
+function returns a pointer to a
+.Vt struct kinfo_proc
+structure as defined by
+.In sys/user.h .
+The pointer was obtained by an internal call to
+.Xr malloc 3
+and must be freed by the caller with a call to
+.Xr free 3 .
+On failure the
+.Fn kinfo_getproc
+function returns
+.Dv NULL .
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3 ,
+.Xr sysctl 3
diff --git a/lib/libutil/kinfo_getproc.c b/lib/libutil/kinfo_getproc.c
new file mode 100644
index 0000000..2ae6b57
--- /dev/null
+++ b/lib/libutil/kinfo_getproc.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2009 Ulf Lilleengen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libutil.h"
+
+struct kinfo_proc *
+kinfo_getproc(pid_t pid)
+{
+ struct kinfo_proc *kipp;
+ int mib[4];
+ size_t len;
+
+ len = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+ if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0)
+ return (NULL);
+
+ kipp = malloc(len);
+ if (kipp == NULL)
+ return (NULL);
+
+ if (sysctl(mib, 4, kipp, &len, NULL, 0) < 0)
+ goto bad;
+ if (len != sizeof(*kipp))
+ goto bad;
+ if (kipp->ki_structsize != sizeof(*kipp))
+ goto bad;
+ if (kipp->ki_pid != pid)
+ goto bad;
+ return (kipp);
+bad:
+ free(kipp);
+ return (NULL);
+}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index f39e4f5..fc6d3bb 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -88,6 +88,7 @@ struct termios;
struct winsize;
struct in_addr;
struct kinfo_file;
+struct kinfo_proc;
struct kinfo_vmentry;
__BEGIN_DECLS
@@ -126,6 +127,10 @@ struct kinfo_file *
kinfo_getfile(pid_t _pid, int *_cntp);
struct kinfo_vmentry *
kinfo_getvmmap(pid_t _pid, int *_cntp);
+struct kinfo_proc *
+ kinfo_getallproc(int *_cntp);
+struct kinfo_proc *
+ kinfo_getproc(pid_t _pid);
#ifdef _STDIO_H_ /* avoid adding new includes */
char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 3f40f2b..bf75db0 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$");
#include <sys/mqueue.h>
#include <sys/mutex.h>
#include <sys/namei.h>
+#include <sys/selinfo.h>
+#include <sys/pipe.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/protosw.h>
@@ -73,6 +75,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sysproto.h>
#include <sys/tty.h>
#include <sys/unistd.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
#include <sys/user.h>
#include <sys/vnode.h>
#ifdef KTRACE
@@ -81,6 +85,9 @@ __FBSDID("$FreeBSD$");
#include <net/vnet.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+
#include <security/audit/audit.h>
#include <vm/uma.h>
@@ -106,6 +113,10 @@ static int fd_last_used(struct filedesc *, int, int);
static void fdgrowtable(struct filedesc *, int);
static void fdunused(struct filedesc *fdp, int fd);
static void fdused(struct filedesc *fdp, int fd);
+static int fill_vnode_info(struct vnode *vp, struct kinfo_file *kif);
+static int fill_socket_info(struct socket *so, struct kinfo_file *kif);
+static int fill_pts_info(struct tty *tp, struct kinfo_file *kif);
+static int fill_pipe_info(struct pipe *pi, struct kinfo_file *kif);
/*
* A process is initially started out with NDFILE descriptors stored within
@@ -2972,48 +2983,74 @@ 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;
+export_fd_for_sysctl(void *data, int type, int fd, int fflags, int refcnt,
+ int64_t offset, struct kinfo_file *kif, struct sysctl_req *req)
+{
+ struct {
+ int fflag;
+ int kf_fflag;
+ } fflags_table[] = {
+ { FAPPEND, KF_FLAG_APPEND },
+ { FASYNC, KF_FLAG_ASYNC },
+ { FFSYNC, KF_FLAG_FSYNC },
+ { FHASLOCK, KF_FLAG_HASLOCK },
+ { FNONBLOCK, KF_FLAG_NONBLOCK },
+ { FREAD, KF_FLAG_READ },
+ { FWRITE, KF_FLAG_WRITE },
+ { O_CREAT, KF_FLAG_CREAT },
+ { O_DIRECT, KF_FLAG_DIRECT },
+ { O_EXCL, KF_FLAG_EXCL },
+ { O_EXEC, KF_FLAG_EXEC },
+ { O_EXLOCK, KF_FLAG_EXLOCK },
+ { O_NOFOLLOW, KF_FLAG_NOFOLLOW },
+ { O_SHLOCK, KF_FLAG_SHLOCK },
+ { O_TRUNC, KF_FLAG_TRUNC }
+ };
+#define NFFLAGS (sizeof(fflags_table) / sizeof(*fflags_table))
+ struct vnode *vp;
+ int error, vfslocked;
+ unsigned int i;
bzero(kif, sizeof(*kif));
-
- vref(vp);
- kif->kf_fd = type;
- kif->kf_type = KF_TYPE_VNODE;
- /* This function only handles directories. */
- if (vp->v_type != VDIR) {
+ switch (type) {
+ case KF_TYPE_FIFO:
+ case KF_TYPE_VNODE:
+ vp = (struct vnode *)data;
+ error = fill_vnode_info(vp, kif);
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
vrele(vp);
- return (ENOTDIR);
+ VFS_UNLOCK_GIANT(vfslocked);
+ break;
+ case KF_TYPE_SOCKET:
+ error = fill_socket_info((struct socket *)data, kif);
+ break;
+ case KF_TYPE_PIPE:
+ error = fill_pipe_info((struct pipe *)data, kif);
+ break;
+ case KF_TYPE_PTS:
+ error = fill_pts_info((struct tty *)data, kif);
+ break;
+ default:
+ error = 0;
}
- kif->kf_vnode_type = KF_VTYPE_VDIR;
+ if (error == 0)
+ kif->kf_status |= KF_ATTR_VALID;
/*
- * This is not a true file descriptor, so we set a bogus refcount
- * and offset to indicate these fields should be ignored.
+ * Translate file access flags.
*/
- kif->kf_ref_count = -1;
- kif->kf_offset = -1;
-
- freepath = NULL;
- fullpath = "-";
- FILEDESC_SUNLOCK(fdp);
- vn_fullpath(curthread, vp, &fullpath, &freepath);
- vfslocked = VFS_LOCK_GIANT(vp->v_mount);
- vrele(vp);
- VFS_UNLOCK_GIANT(vfslocked);
- strlcpy(kif->kf_path, fullpath, sizeof(kif->kf_path));
- if (freepath != NULL)
- free(freepath, M_TEMP);
+ for (i = 0; i < NFFLAGS; i++)
+ if (fflags & fflags_table[i].fflag)
+ kif->kf_flags |= fflags_table[i].kf_fflag;
+ kif->kf_fd = fd;
+ kif->kf_type = type;
+ kif->kf_ref_count = refcnt;
+ kif->kf_offset = offset;
/* 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);
}
@@ -3023,17 +3060,16 @@ export_vnode_for_sysctl(struct vnode *vp, int type,
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 filedesc *fdp;
+ struct kinfo_file *kif;
struct proc *p;
- struct tty *tp;
- int vfslocked;
+ struct vnode *cttyvp, *textvp, *tracevp;
size_t oldidx;
+ int64_t offset;
+ void *data;
+ int error, i, *name;
+ int type, refcnt, fflags;
name = (int *)arg1;
if ((p = pfind((pid_t)name[0])) == NULL)
@@ -3042,177 +3078,136 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
PROC_UNLOCK(p);
return (error);
}
+ /* ktrace vnode */
+ tracevp = p->p_tracevp;
+ if (tracevp != NULL)
+ vref(tracevp);
+ /* text vnode */
+ textvp = p->p_textvp;
+ if (textvp != NULL)
+ vref(textvp);
+ /* Controlling tty. */
+ cttyvp = NULL;
+ if (p->p_pgrp != NULL && p->p_pgrp->pg_session != NULL) {
+ cttyvp = p->p_pgrp->pg_session->s_ttyvp;
+ if (cttyvp != NULL)
+ vref(cttyvp);
+ }
fdp = fdhold(p);
PROC_UNLOCK(p);
- if (fdp == NULL)
- return (ENOENT);
kif = malloc(sizeof(*kif), M_TEMP, M_WAITOK);
+ if (tracevp != NULL)
+ export_fd_for_sysctl(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE,
+ FREAD | FWRITE, -1, -1, kif, req);
+ if (textvp != NULL)
+ export_fd_for_sysctl(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
+ FREAD, -1, -1, kif, req);
+ if (cttyvp != NULL)
+ export_fd_for_sysctl(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
+ FREAD | FWRITE, -1, -1, kif, req);
+ if (fdp == NULL)
+ goto fail;
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);
+ /* working directory */
+ if (fdp->fd_cdir != NULL) {
+ vref(fdp->fd_cdir);
+ data = fdp->fd_cdir;
+ FILEDESC_SUNLOCK(fdp);
+ export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD,
+ FREAD, -1, -1, kif, req);
+ FILEDESC_SLOCK(fdp);
+ }
+ /* root directory */
+ if (fdp->fd_rdir != NULL) {
+ vref(fdp->fd_rdir);
+ data = fdp->fd_rdir;
+ FILEDESC_SUNLOCK(fdp);
+ export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT,
+ FREAD, -1, -1, kif, req);
+ FILEDESC_SLOCK(fdp);
+ }
+ /* jail directory */
+ if (fdp->fd_jdir != NULL) {
+ vref(fdp->fd_jdir);
+ data = fdp->fd_jdir;
+ FILEDESC_SUNLOCK(fdp);
+ export_fd_for_sysctl(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL,
+ FREAD, -1, -1, kif, req);
+ FILEDESC_SLOCK(fdp);
+ }
for (i = 0; i < fdp->fd_nfiles; i++) {
if ((fp = fdp->fd_ofiles[i]) == NULL)
continue;
- bzero(kif, sizeof(*kif));
- vp = NULL;
- so = NULL;
- tp = NULL;
- kif->kf_fd = i;
+ data = NULL;
switch (fp->f_type) {
case DTYPE_VNODE:
- kif->kf_type = KF_TYPE_VNODE;
- vp = fp->f_vnode;
+ type = KF_TYPE_VNODE;
+ vref(fp->f_vnode);
+ data = fp->f_vnode;
break;
case DTYPE_SOCKET:
- kif->kf_type = KF_TYPE_SOCKET;
- so = fp->f_data;
+ type = KF_TYPE_SOCKET;
+ data = fp->f_data;
break;
case DTYPE_PIPE:
- kif->kf_type = KF_TYPE_PIPE;
+ type = KF_TYPE_PIPE;
+ data = fp->f_data;
break;
case DTYPE_FIFO:
- kif->kf_type = KF_TYPE_FIFO;
- vp = fp->f_vnode;
+ type = KF_TYPE_FIFO;
+ vref(fp->f_vnode);
+ data = fp->f_vnode;
break;
case DTYPE_KQUEUE:
- kif->kf_type = KF_TYPE_KQUEUE;
+ type = KF_TYPE_KQUEUE;
break;
case DTYPE_CRYPTO:
- kif->kf_type = KF_TYPE_CRYPTO;
+ type = KF_TYPE_CRYPTO;
break;
case DTYPE_MQUEUE:
- kif->kf_type = KF_TYPE_MQUEUE;
+ type = KF_TYPE_MQUEUE;
break;
case DTYPE_SHM:
- kif->kf_type = KF_TYPE_SHM;
+ type = KF_TYPE_SHM;
break;
case DTYPE_SEM:
- kif->kf_type = KF_TYPE_SEM;
+ type = KF_TYPE_SEM;
break;
case DTYPE_PTS:
- kif->kf_type = KF_TYPE_PTS;
- tp = fp->f_data;
+ type = KF_TYPE_PTS;
+ data = fp->f_data;
break;
default:
- kif->kf_type = KF_TYPE_UNKNOWN;
+ 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;
- if (vp != NULL) {
- vref(vp);
- 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);
- vn_fullpath(curthread, vp, &fullpath, &freepath);
- vfslocked = VFS_LOCK_GIANT(vp->v_mount);
- vrele(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;
+ refcnt = fp->f_count;
+ fflags = fp->f_flag;
+ offset = fp->f_offset;
- 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)
- == 0 && 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;
- }
- if (tp != NULL) {
- strlcpy(kif->kf_path, tty_devname(tp),
- sizeof(kif->kf_path));
- }
- /* 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));
+ /*
+ * Create sysctl entry.
+ * It is OK to drop the filedesc lock here as we will
+ * re-validate and re-evaluate its properties when
+ * the loop continues.
+ */
oldidx = req->oldidx;
- error = SYSCTL_OUT(req, kif, kif->kf_structsize);
+ if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO)
+ FILEDESC_SUNLOCK(fdp);
+ error = export_fd_for_sysctl(data, type, i,
+ fflags, refcnt, offset, kif, req);
+ if (type == KF_TYPE_VNODE || type == KF_TYPE_FIFO)
+ FILEDESC_SLOCK(fdp);
if (error) {
if (error == ENOMEM) {
/*
@@ -3228,11 +3223,164 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS)
}
}
FILEDESC_SUNLOCK(fdp);
+fail:
fddrop(fdp);
free(kif, M_TEMP);
return (error);
}
+int
+vntype_to_kinfo(int vtype)
+{
+ struct {
+ int vtype;
+ int kf_vtype;
+ } vtypes_table[] = {
+ { VBAD, KF_VTYPE_VBAD },
+ { VBLK, KF_VTYPE_VBLK },
+ { VCHR, KF_VTYPE_VCHR },
+ { VDIR, KF_VTYPE_VDIR },
+ { VFIFO, KF_VTYPE_VFIFO },
+ { VLNK, KF_VTYPE_VLNK },
+ { VNON, KF_VTYPE_VNON },
+ { VREG, KF_VTYPE_VREG },
+ { VSOCK, KF_VTYPE_VSOCK }
+ };
+#define NVTYPES (sizeof(vtypes_table) / sizeof(*vtypes_table))
+ unsigned int i;
+
+ /*
+ * Perform vtype translation.
+ */
+ for (i = 0; i < NVTYPES; i++)
+ if (vtypes_table[i].vtype == vtype)
+ break;
+ if (i < NVTYPES)
+ return (vtypes_table[i].kf_vtype);
+
+ return (KF_VTYPE_UNKNOWN);
+}
+
+static int
+fill_vnode_info(struct vnode *vp, struct kinfo_file *kif)
+{
+ struct vattr va;
+ char *fullpath, *freepath;
+ int error, vfslocked;
+
+ if (vp == NULL)
+ return (1);
+ kif->kf_vnode_type = vntype_to_kinfo(vp->v_type);
+ freepath = NULL;
+ fullpath = "-";
+ error = vn_fullpath(curthread, vp, &fullpath, &freepath);
+ if (error == 0) {
+ strlcpy(kif->kf_path, fullpath, sizeof(kif->kf_path));
+ }
+ if (freepath != NULL)
+ free(freepath, M_TEMP);
+
+ /*
+ * Retrieve vnode attributes.
+ */
+ va.va_fsid = VNOVAL;
+ va.va_rdev = NODEV;
+ vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_GETATTR(vp, &va, curthread->td_ucred);
+ VOP_UNLOCK(vp, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error != 0)
+ return (error);
+ if (va.va_fsid != VNOVAL)
+ kif->kf_un.kf_file.kf_file_fsid = va.va_fsid;
+ else
+ kif->kf_un.kf_file.kf_file_fsid =
+ vp->v_mount->mnt_stat.f_fsid.val[0];
+ kif->kf_un.kf_file.kf_file_fileid = va.va_fileid;
+ kif->kf_un.kf_file.kf_file_mode = MAKEIMODE(va.va_type, va.va_mode);
+ kif->kf_un.kf_file.kf_file_size = va.va_size;
+ kif->kf_un.kf_file.kf_file_rdev = va.va_rdev;
+ return (0);
+}
+
+static int
+fill_socket_info(struct socket *so, struct kinfo_file *kif)
+{
+ struct sockaddr *sa;
+ struct inpcb *inpcb;
+ struct unpcb *unpcb;
+ int error;
+
+ if (so == NULL)
+ return (1);
+ 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;
+ kif->kf_un.kf_sock.kf_sock_pcb = (uintptr_t)so->so_pcb;
+ switch(kif->kf_sock_domain) {
+ case AF_INET:
+ case AF_INET6:
+ if (kif->kf_sock_protocol == IPPROTO_TCP) {
+ if (so->so_pcb != NULL) {
+ inpcb = (struct inpcb *)(so->so_pcb);
+ kif->kf_un.kf_sock.kf_sock_inpcb =
+ (uintptr_t)inpcb->inp_ppcb;
+ }
+ }
+ break;
+ case AF_UNIX:
+ if (so->so_pcb != NULL) {
+ unpcb = (struct unpcb *)(so->so_pcb);
+ if (unpcb->unp_conn) {
+ kif->kf_un.kf_sock.kf_sock_unpconn =
+ (uintptr_t)unpcb->unp_conn;
+ kif->kf_un.kf_sock.kf_sock_rcv_sb_state =
+ so->so_rcv.sb_state;
+ kif->kf_un.kf_sock.kf_sock_snd_sb_state =
+ so->so_snd.sb_state;
+ }
+ }
+ break;
+ }
+ error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+ if (error == 0 && sa->sa_len <= sizeof(kif->kf_sa_local)) {
+ bcopy(sa, &kif->kf_sa_local, sa->sa_len);
+ free(sa, M_SONAME);
+ }
+ error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
+ if (error == 0 && sa->sa_len <= sizeof(kif->kf_sa_peer)) {
+ bcopy(sa, &kif->kf_sa_peer, sa->sa_len);
+ free(sa, M_SONAME);
+ }
+ strncpy(kif->kf_path, so->so_proto->pr_domain->dom_name,
+ sizeof(kif->kf_path));
+ return (0);
+}
+
+static int
+fill_pts_info(struct tty *tp, struct kinfo_file *kif)
+{
+
+ if (tp == NULL)
+ return (1);
+ kif->kf_un.kf_pts.kf_pts_dev = tty_udev(tp);
+ strlcpy(kif->kf_path, tty_devname(tp), sizeof(kif->kf_path));
+ return (0);
+}
+
+static int
+fill_pipe_info(struct pipe *pi, struct kinfo_file *kif)
+{
+
+ if (pi == NULL)
+ return (1);
+ kif->kf_un.kf_pipe.kf_pipe_addr = (uintptr_t)pi;
+ kif->kf_un.kf_pipe.kf_pipe_peer = (uintptr_t)pi->pipe_peer;
+ kif->kf_un.kf_pipe.kf_pipe_buffer_cnt = pi->pipe_buffer.cnt;
+ return (0);
+}
+
static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc, CTLFLAG_RD,
sysctl_kern_proc_filedesc, "Process filedesc entries");
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 34cc570..4f1dc45 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -1757,8 +1757,6 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
last_timestamp = map->timestamp;
vm_map_unlock_read(map);
- kve->kve_fileid = 0;
- kve->kve_fsid = 0;
freepath = NULL;
fullpath = "";
if (lobj) {
@@ -1800,12 +1798,18 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_ARGS)
if (vp != NULL) {
vn_fullpath(curthread, vp, &fullpath,
&freepath);
+ kve->kve_vn_type = vntype_to_kinfo(vp->v_type);
cred = curthread->td_ucred;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
vn_lock(vp, LK_SHARED | LK_RETRY);
if (VOP_GETATTR(vp, &va, cred) == 0) {
- kve->kve_fileid = va.va_fileid;
- kve->kve_fsid = va.va_fsid;
+ kve->kve_vn_fileid = va.va_fileid;
+ kve->kve_vn_fsid = va.va_fsid;
+ kve->kve_vn_mode =
+ MAKEIMODE(va.va_type, va.va_mode);
+ kve->kve_vn_size = va.va_size;
+ kve->kve_vn_rdev = va.va_rdev;
+ kve->kve_status = KF_ATTR_VALID;
}
vput(vp);
VFS_UNLOCK_GIANT(vfslocked);
diff --git a/sys/sys/user.h b/sys/sys/user.h
index 5c5cbd4..644f911 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -233,6 +233,8 @@ struct user {
* The KERN_PROC_FILE sysctl allows a process to dump the file descriptor
* array of another process.
*/
+#define KF_ATTR_VALID 0x0001
+
#define KF_TYPE_NONE 0
#define KF_TYPE_VNODE 1
#define KF_TYPE_SOCKET 2
@@ -260,6 +262,9 @@ struct user {
#define KF_FD_TYPE_CWD -1 /* Current working directory */
#define KF_FD_TYPE_ROOT -2 /* Root directory */
#define KF_FD_TYPE_JAIL -3 /* Jail directory */
+#define KF_FD_TYPE_TRACE -4 /* ptrace vnode */
+#define KF_FD_TYPE_TEXT -5 /* Text vnode */
+#define KF_FD_TYPE_CTTY -6 /* Controlling terminal */
#define KF_FLAG_READ 0x00000001
#define KF_FLAG_WRITE 0x00000002
@@ -269,6 +274,13 @@ struct user {
#define KF_FLAG_NONBLOCK 0x00000020
#define KF_FLAG_DIRECT 0x00000040
#define KF_FLAG_HASLOCK 0x00000080
+#define KF_FLAG_SHLOCK 0x00000100
+#define KF_FLAG_EXLOCK 0x00000200
+#define KF_FLAG_NOFOLLOW 0x00000400
+#define KF_FLAG_CREAT 0x00000800
+#define KF_FLAG_TRUNC 0x00001000
+#define KF_FLAG_EXCL 0x00002000
+#define KF_FLAG_EXEC 0x00004000
/*
* Old format. Has variable hidden padding due to alignment.
@@ -303,22 +315,67 @@ struct kinfo_ofile {
#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. */
+ 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. */
+ union {
+ struct {
+ /* Address of so_pcb. */
+ uint64_t kf_sock_pcb;
+ /* Address of inp_ppcb. */
+ uint64_t kf_sock_inpcb;
+ /* Address of unp_conn. */
+ uint64_t kf_sock_unpconn;
+ /* Send buffer state. */
+ uint16_t kf_sock_snd_sb_state;
+ /* Receive buffer state. */
+ uint16_t kf_sock_rcv_sb_state;
+ /* Round to 64 bit alignment. */
+ uint32_t kf_sock_pad0;
+ } kf_sock;
+ struct {
+ /* Global file id. */
+ uint64_t kf_file_fileid;
+ /* File size. */
+ uint64_t kf_file_size;
+ /* Vnode filesystem id. */
+ uint32_t kf_file_fsid;
+ /* File device. */
+ uint32_t kf_file_rdev;
+ /* File mode. */
+ uint16_t kf_file_mode;
+ /* Round to 64 bit alignment. */
+ uint16_t kf_file_pad0;
+ uint32_t kf_file_pad1;
+ } kf_file;
+ struct {
+ uint64_t kf_pipe_addr;
+ uint64_t kf_pipe_peer;
+ uint32_t kf_pipe_buffer_cnt;
+ /* Round to 64 bit alignment. */
+ uint32_t kf_pipe_pad0[3];
+ } kf_pipe;
+ struct {
+ uint32_t kf_pts_dev;
+ /* Round to 64 bit alignment. */
+ uint32_t kf_pts_pad0[7];
+ } kf_pts;
+ } kf_un;
+ uint16_t kf_status; /* Status flags. */
+ uint16_t kf_pad1; /* Round to 32 bit alignment. */
+ int _kf_ispare[7]; /* Space for more stuff. */
/* Truncated before copyout in sysctl */
- char kf_path[PATH_MAX]; /* Path to file, if any. */
+ char kf_path[PATH_MAX]; /* Path to file, if any. */
};
/*
@@ -379,16 +436,20 @@ struct kinfo_vmentry {
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 */
+ uint64_t kve_vn_fileid; /* inode number if vnode */
+ uint32_t kve_vn_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. */
+ int kve_vn_type; /* Vnode type. */
+ uint64_t kve_vn_size; /* File size. */
+ uint32_t kve_vn_rdev; /* Device id if device. */
+ uint16_t kve_vn_mode; /* File mode. */
+ uint16_t kve_status; /* Status flags. */
+ int _kve_ispare[12]; /* Space for more stuff. */
/* Truncated before copyout in sysctl */
char kve_path[PATH_MAX]; /* Path to VM obj, if any. */
};
@@ -415,4 +476,8 @@ struct kinfo_kstack {
int _kkst_ispare[16]; /* Space for more stuff. */
};
+#ifdef _KERNEL
+int vntype_to_kinfo(int vtype);
+#endif /* !_KERNEL */
+
#endif
diff --git a/usr.bin/fstat/Makefile b/usr.bin/fstat/Makefile
index 23e907b..c59e123 100644
--- a/usr.bin/fstat/Makefile
+++ b/usr.bin/fstat/Makefile
@@ -1,24 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
-.include <bsd.own.mk>
-
PROG= fstat
-SRCS= cd9660.c fstat.c msdosfs.c
+SRCS= fstat.c fuser.c main.c
+LINKS= ${BINDIR}/fstat ${BINDIR}/fuser
DPADD= ${LIBKVM}
-LDADD= -lkvm
-BINGRP= kmem
-BINMODE=2555
-
-CFLAGS+=-D_KVM_VNODE
+LDADD= -lkvm -lutil -lprocstat
-# XXX This is a hack.
-.if ${MK_CDDL} != "no"
-CFLAGS+= -DZFS
-OBJS+= zfs/zfs.o
-SUBDIR= zfs
-zfs/zfs.o: .PHONY
- @cd ${.CURDIR}/zfs && ${MAKE} zfs.o
-.endif
+MAN1= fuser.1 fstat.1
.include <bsd.prog.mk>
diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c
index 7725c88..9d057e5 100644
--- a/usr.bin/fstat/fstat.c
+++ b/usr.bin/fstat/fstat.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -27,69 +28,24 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
-#endif
-#endif /* not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/proc.h>
#include <sys/user.h>
#include <sys/stat.h>
-#include <sys/vnode.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
-#include <sys/domain.h>
-#include <sys/protosw.h>
-#include <sys/un.h>
-#include <sys/unpcb.h>
#include <sys/sysctl.h>
-#include <sys/tty.h>
-#include <sys/filedesc.h>
#include <sys/queue.h>
-#define _WANT_FILE
-#include <sys/file.h>
-#include <sys/conf.h>
-#define _KERNEL
-#include <sys/pipe.h>
-#include <sys/mount.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <fs/devfs/devfs.h>
-#include <fs/devfs/devfs_int.h>
-#undef _KERNEL
-#include <nfs/nfsproto.h>
-#include <nfsclient/nfs.h>
-#include <nfsclient/nfsnode.h>
-
-
-#include <vm/vm.h>
-#include <vm/vm_map.h>
-#include <vm/vm_object.h>
-
-#include <net/route.h>
+
#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/in_pcb.h>
+#include <assert.h>
#include <ctype.h>
#include <err.h>
-#include <fcntl.h>
-#include <kvm.h>
+#include <libprocstat.h>
#include <limits.h>
-#include <nlist.h>
-#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -98,69 +54,49 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <netdb.h>
-#include "fstat.h"
-
-#define TEXT -1
-#define CDIR -2
-#define RDIR -3
-#define TRACE -4
-#define MMAP -5
-#define JDIR -6
-
-DEVS *devs;
-
-#ifdef notdef
-struct nlist nl[] = {
- { "" },
-};
-#endif
+#include "functions.h"
int fsflg, /* show files on same filesystem as file(s) argument */
pflg, /* show files open by a particular pid */
uflg; /* show files open by a particular (effective) user */
int checkfile; /* true if restricting to particular files or filesystems */
int nflg; /* (numerical) display f.s. and rdev as dev_t */
-int vflg; /* display errors in locating kernel data objects etc... */
int mflg; /* include memory-mapped files */
+int vflg; /* be verbose */
+typedef struct devs {
+ struct devs *next;
+ uint32_t fsid;
+ uint64_t ino;
+ const char *name;
+} DEVS;
-struct file **ofiles; /* buffer of pointers to file structures */
-int maxfiles;
-#define ALLOC_OFILES(d) \
- if ((d) > maxfiles) { \
- free(ofiles); \
- ofiles = malloc((d) * sizeof(struct file *)); \
- if (ofiles == NULL) { \
- err(1, NULL); \
- } \
- maxfiles = (d); \
- }
-
+DEVS *devs;
char *memf, *nlistf;
-kvm_t *kd;
-
-static void fstat_kvm(int, int);
-static void fstat_sysctl(int, int);
-void dofiles(struct kinfo_proc *kp);
-void dommap(struct kinfo_proc *kp);
-void vtrans(struct vnode *vp, int i, int flag);
-int ufs_filestat(struct vnode *vp, struct filestat *fsp);
-int nfs_filestat(struct vnode *vp, struct filestat *fsp);
-int devfs_filestat(struct vnode *vp, struct filestat *fsp);
-char *getmnton(struct mount *m);
-void pipetrans(struct pipe *pi, int i, int flag);
-void socktrans(struct socket *sock, int i);
-void ptstrans(struct tty *tp, int i, int flag);
-void getinetproto(int number);
-int getfname(const char *filename);
-void usage(void);
-char *kdevtoname(struct cdev *dev);
+
+static int getfname(const char *filename);
+static void dofiles(struct procstat *procstat, struct kinfo_proc *p);
+static void print_access_flags(int flags);
+static void print_file_info(struct procstat *procstat,
+ struct filestat *fst, const char *uname, const char *cmd, int pid);
+static void print_pipe_info(struct procstat *procstat,
+ struct filestat *fst);
+static void print_pts_info(struct procstat *procstat,
+ struct filestat *fst);
+static void print_socket_info(struct procstat *procstat,
+ struct filestat *fst);
+static void print_vnode_info(struct procstat *procstat,
+ struct filestat *fst);
+static void usage(void) __dead2;
int
-main(int argc, char **argv)
+do_fstat(int argc, char **argv)
{
+ struct kinfo_proc *p;
struct passwd *passwd;
+ struct procstat *procstat;
int arg, ch, what;
+ int cnt, i;
arg = 0;
what = KERN_PROC_PROC;
@@ -225,16 +161,18 @@ main(int argc, char **argv)
}
if (memf != NULL)
- fstat_kvm(what, arg);
+ procstat = procstat_open_kvm(nlistf, memf);
else
- fstat_sysctl(what, arg);
- exit(0);
-}
-
-static void
-print_header(void)
-{
+ procstat = procstat_open_sysctl();
+ if (procstat == NULL)
+ errx(1, "procstat_open()");
+ p = procstat_getprocs(procstat, what, arg, &cnt);
+ if (p == NULL)
+ errx(1, "procstat_getprocs()");
+ /*
+ * Print header.
+ */
if (nflg)
printf("%s",
"USER CMD PID FD DEV INUM MODE SZ|DV R/W");
@@ -245,312 +183,65 @@ print_header(void)
printf(" NAME\n");
else
putchar('\n');
-}
-
-static void
-fstat_kvm(int what, int arg)
-{
- struct kinfo_proc *p, *plast;
- char buf[_POSIX2_LINE_MAX];
- int cnt;
-
- ALLOC_OFILES(256); /* reserve space for file pointers */
/*
- * Discard setgid privileges if not the running kernel so that bad
- * guys can't print interesting stuff from kernel memory.
+ * Go through the process list.
*/
- if (nlistf != NULL || memf != NULL)
- setgid(getgid());
-
- if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
- errx(1, "%s", buf);
- setgid(getgid());
-#ifdef notdef
- if (kvm_nlist(kd, nl) != 0)
- errx(1, "no namelist: %s", kvm_geterr(kd));
-#endif
- if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
- errx(1, "%s", kvm_geterr(kd));
- print_header();
- for (plast = &p[cnt]; p < plast; ++p) {
- if (p->ki_stat == SZOMB)
+ for (i = 0; i < cnt; i++) {
+ if (p[i].ki_stat == SZOMB)
continue;
- dofiles(p);
- if (mflg)
- dommap(p);
+ dofiles(procstat, &p[i]);
}
+ procstat_freeprocs(procstat, p);
+ procstat_close(procstat);
+ return (0);
}
static void
-fstat_sysctl(int what, int arg)
-{
-
- /* not yet implemented */
- fstat_kvm(what, arg);
-}
-
-const char *Uname, *Comm;
-int Pid;
-
-#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
- switch(i) { \
- case TEXT: \
- printf(" text"); \
- break; \
- case CDIR: \
- printf(" wd"); \
- break; \
- case RDIR: \
- printf(" root"); \
- break; \
- case TRACE: \
- printf(" tr"); \
- break; \
- case MMAP: \
- printf(" mmap"); \
- break; \
- case JDIR: \
- printf(" jail"); \
- break; \
- default: \
- printf(" %4d", i); \
- break; \
- }
-
-/*
- * print open files attributed to this process
- */
-void
-dofiles(struct kinfo_proc *kp)
+dofiles(struct procstat *procstat, struct kinfo_proc *kp)
{
- int i;
- struct file file;
- struct filedesc filed;
-
- Uname = user_from_uid(kp->ki_uid, 0);
- Pid = kp->ki_pid;
- Comm = kp->ki_comm;
-
- if (kp->ki_fd == NULL)
+ const char *cmd;
+ const char *uname;
+ struct filestat *fst;
+ struct filestat_list *head;
+ int pid;
+
+ uname = user_from_uid(kp->ki_uid, 0);
+ pid = kp->ki_pid;
+ cmd = kp->ki_comm;
+
+ head = procstat_getfiles(procstat, kp, mflg);
+ if (head == NULL)
return;
- if (!KVM_READ(kp->ki_fd, &filed, sizeof (filed))) {
- dprintf(stderr, "can't read filedesc at %p for pid %d\n",
- (void *)kp->ki_fd, Pid);
- return;
- }
- /*
- * root directory vnode, if one
- */
- if (filed.fd_rdir)
- vtrans(filed.fd_rdir, RDIR, FREAD);
- /*
- * current working directory vnode
- */
- if (filed.fd_cdir)
- vtrans(filed.fd_cdir, CDIR, FREAD);
- /*
- * jail root, if any.
- */
- if (filed.fd_jdir)
- vtrans(filed.fd_jdir, JDIR, FREAD);
- /*
- * ktrace vnode, if one
- */
- if (kp->ki_tracep)
- vtrans(kp->ki_tracep, TRACE, FREAD|FWRITE);
- /*
- * text vnode, if one
- */
- if (kp->ki_textvp)
- vtrans(kp->ki_textvp, TEXT, FREAD);
- /*
- * open files
- */
-#define FPSIZE (sizeof (struct file *))
-#define MAX_LASTFILE (0x1000000)
-
- /* Sanity check on filed.fd_lastfile */
- if (filed.fd_lastfile <= -1 || filed.fd_lastfile > MAX_LASTFILE)
- return;
-
- ALLOC_OFILES(filed.fd_lastfile+1);
- if (!KVM_READ(filed.fd_ofiles, ofiles,
- (filed.fd_lastfile+1) * FPSIZE)) {
- dprintf(stderr,
- "can't read file structures at %p for pid %d\n",
- (void *)filed.fd_ofiles, Pid);
- return;
- }
- for (i = 0; i <= filed.fd_lastfile; i++) {
- if (ofiles[i] == NULL)
- continue;
- if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
- dprintf(stderr, "can't read file %d at %p for pid %d\n",
- i, (void *)ofiles[i], Pid);
- continue;
- }
- if (file.f_type == DTYPE_VNODE)
- vtrans(file.f_vnode, i, file.f_flag);
- else if (file.f_type == DTYPE_SOCKET) {
- if (checkfile == 0)
- socktrans(file.f_data, i);
- }
-#ifdef DTYPE_PIPE
- else if (file.f_type == DTYPE_PIPE) {
- if (checkfile == 0)
- pipetrans(file.f_data, i, file.f_flag);
- }
-#endif
-#ifdef DTYPE_FIFO
- else if (file.f_type == DTYPE_FIFO) {
- if (checkfile == 0)
- vtrans(file.f_vnode, i, file.f_flag);
- }
-#endif
-#ifdef DTYPE_PTS
- else if (file.f_type == DTYPE_PTS) {
- if (checkfile == 0)
- ptstrans(file.f_data, i, file.f_flag);
- }
-#endif
- else {
- dprintf(stderr,
- "unknown file type %d for file %d of pid %d\n",
- file.f_type, i, Pid);
- }
- }
-}
-
-void
-dommap(struct kinfo_proc *kp)
-{
- vm_map_t map;
- struct vmspace vmspace;
- struct vm_map_entry entry;
- vm_map_entry_t entryp;
- struct vm_object object;
- vm_object_t objp;
- int prot, fflags;
-
- if (!KVM_READ(kp->ki_vmspace, &vmspace, sizeof(vmspace))) {
- dprintf(stderr,
- "can't read vmspace at %p for pid %d\n",
- (void *)kp->ki_vmspace, Pid);
- return;
- }
- map = &vmspace.vm_map;
-
- for (entryp = map->header.next;
- entryp != &kp->ki_vmspace->vm_map.header; entryp = entry.next) {
- if (!KVM_READ(entryp, &entry, sizeof(entry))) {
- dprintf(stderr,
- "can't read vm_map_entry at %p for pid %d\n",
- (void *)entryp, Pid);
- return;
- }
-
- if (entry.eflags & MAP_ENTRY_IS_SUB_MAP)
- continue;
-
- if ((objp = entry.object.vm_object) == NULL)
- continue;
-
- for (; objp; objp = object.backing_object) {
- if (!KVM_READ(objp, &object, sizeof(object))) {
- dprintf(stderr,
- "can't read vm_object at %p for pid %d\n",
- (void *)objp, Pid);
- return;
- }
- }
-
- prot = entry.protection;
- fflags = (prot & VM_PROT_READ ? FREAD : 0) |
- (prot & VM_PROT_WRITE ? FWRITE : 0);
-
- switch (object.type) {
- case OBJT_VNODE:
- vtrans((struct vnode *)object.handle, MMAP, fflags);
- break;
- default:
- break;
- }
- }
+ STAILQ_FOREACH(fst, head, next)
+ print_file_info(procstat, fst, uname, cmd, pid);
+ procstat_freefiles(procstat, head);
}
-char *
-kdevtoname(struct cdev *dev)
-{
- struct cdev si;
- if (!KVM_READ(dev, &si, sizeof si))
- return (NULL);
- return (strdup(si.__si_namebuf));
-}
-
-void
-vtrans(struct vnode *vp, int i, int flag)
+static void
+print_file_info(struct procstat *procstat, struct filestat *fst,
+ const char *uname, const char *cmd, int pid)
{
- struct vnode vn;
- struct filestat fst;
- char rw[3], mode[15], tagstr[12], *tagptr;
- const char *badtype, *filename;
-
- filename = badtype = NULL;
- if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
- dprintf(stderr, "can't read vnode at %p for pid %d\n",
- (void *)vp, Pid);
- return;
- }
- if (!KVM_READ(&vp->v_tag, &tagptr, sizeof tagptr) ||
- !KVM_READ(tagptr, tagstr, sizeof tagstr)) {
- dprintf(stderr, "can't read v_tag at %p for pid %d\n",
- (void *)vp, Pid);
- return;
- }
- tagstr[sizeof(tagstr) - 1] = '\0';
- if (vn.v_type == VNON)
- badtype = "none";
- else if (vn.v_type == VBAD)
- badtype = "bad";
- else {
- if (!strcmp("ufs", tagstr)) {
- if (!ufs_filestat(&vn, &fst))
- badtype = "error";
- } else if (!strcmp("devfs", tagstr)) {
- if (!devfs_filestat(&vn, &fst))
- badtype = "error";
- } else if (!strcmp("nfs", tagstr)) {
- if (!nfs_filestat(&vn, &fst))
- badtype = "error";
- } else if (!strcmp("msdosfs", tagstr)) {
- if (!msdosfs_filestat(&vn, &fst))
- badtype = "error";
- } else if (!strcmp("isofs", tagstr)) {
- if (!isofs_filestat(&vn, &fst))
- badtype = "error";
-#ifdef ZFS
- } else if (!strcmp("zfs", tagstr)) {
- if (!zfs_filestat(&vn, &fst))
- badtype = "error";
-#endif
- } else {
- static char unknown[32];
- snprintf(unknown, sizeof unknown, "?(%s)", tagstr);
- badtype = unknown;
- }
- }
- if (checkfile) {
- int fsmatch = 0;
- DEVS *d;
-
- if (badtype)
+ struct vnstat vn;
+ DEVS *d;
+ const char *filename;
+ int error, fsmatch = 0;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ filename = NULL;
+ if (checkfile != 0) {
+ if (fst->fs_type != PS_FST_TYPE_VNODE &&
+ fst->fs_type != PS_FST_TYPE_FIFO)
return;
+ error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
+ if (error != 0)
+ return;
+
for (d = devs; d != NULL; d = d->next)
- if (d->fsid == fst.fsid) {
+ if (d->fsid == vn.vn_fsid) {
fsmatch = 1;
- if (d->ino == fst.fileid) {
+ if ((unsigned)d->ino == vn.vn_fileid) {
filename = d->name;
break;
}
@@ -558,271 +249,83 @@ vtrans(struct vnode *vp, int i, int flag)
if (fsmatch == 0 || (filename == NULL && fsflg == 0))
return;
}
- PREFIX(i);
- if (badtype) {
- (void)printf(" - - %10s -\n", badtype);
- return;
- }
- if (nflg)
- (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
- else
- (void)printf(" %-8s", getmnton(vn.v_mount));
- if (nflg)
- (void)sprintf(mode, "%o", fst.mode);
- else
- strmode(fst.mode, mode);
- (void)printf(" %6ld %10s", fst.fileid, mode);
- switch (vn.v_type) {
- case VBLK:
- case VCHR: {
- char *name;
-
- name = kdevtoname(vn.v_rdev);
- if (nflg || !name)
- printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
- else {
- printf(" %6s", name);
- free(name);
- }
- break;
- }
- default:
- printf(" %6lu", fst.size);
- }
- rw[0] = '\0';
- if (flag & FREAD)
- strcat(rw, "r");
- if (flag & FWRITE)
- strcat(rw, "w");
- printf(" %2s", rw);
- if (filename && !fsflg)
- printf(" %s", filename);
- putchar('\n');
-}
-
-int
-ufs_filestat(struct vnode *vp, struct filestat *fsp)
-{
- struct inode inode;
- if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
- dprintf(stderr, "can't read inode at %p for pid %d\n",
- (void *)VTOI(vp), Pid);
- return 0;
- }
/*
- * The st_dev from stat(2) is a dev_t. These kernel structures
- * contain cdev pointers. We need to convert to dev_t to make
- * comparisons
+ * Print entry prefix.
*/
- fsp->fsid = dev2udev(inode.i_dev);
- fsp->fileid = (long)inode.i_number;
- fsp->mode = (mode_t)inode.i_mode;
- fsp->size = (u_long)inode.i_size;
-#if should_be_but_is_hard
- /* XXX - need to load i_ump and i_din[12] from kernel memory */
- if (inode.i_ump->um_fstype == UFS1)
- fsp->rdev = inode.i_din1->di_rdev;
+ printf("%-8.8s %-10s %5d", uname, cmd, pid);
+ if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
+ printf(" text");
+ else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
+ printf(" wd");
+ else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
+ printf(" root");
+ else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
+ printf(" tr");
+ else if (fst->fs_uflags & PS_FST_UFLAG_MMAP)
+ printf(" mmap");
+ else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
+ printf(" jail");
+ else if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
+ printf(" ctty");
else
- fsp->rdev = inode.i_din2->di_rdev;
-#else
- fsp->rdev = 0;
-#endif
-
- return 1;
-}
-
-int
-devfs_filestat(struct vnode *vp, struct filestat *fsp)
-{
- struct devfs_dirent devfs_dirent;
- struct mount mount;
- struct vnode vnode;
-
- if (!KVM_READ(vp->v_data, &devfs_dirent, sizeof (devfs_dirent))) {
- dprintf(stderr, "can't read devfs_dirent at %p for pid %d\n",
- (void *)vp->v_data, Pid);
- return 0;
- }
- if (!KVM_READ(vp->v_mount, &mount, sizeof (mount))) {
- dprintf(stderr, "can't read mount at %p for pid %d\n",
- (void *)vp->v_mount, Pid);
- return 0;
- }
- if (!KVM_READ(devfs_dirent.de_vnode, &vnode, sizeof (vnode))) {
- dprintf(stderr, "can't read vnode at %p for pid %d\n",
- (void *)devfs_dirent.de_vnode, Pid);
- return 0;
- }
- fsp->fsid = (long)(uint32_t)mount.mnt_stat.f_fsid.val[0];
- fsp->fileid = devfs_dirent.de_inode;
- fsp->mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR;
- fsp->size = 0;
- fsp->rdev = dev2udev(vnode.v_rdev);
+ printf(" %4d", fst->fs_fd);
- return 1;
-}
-
-int
-nfs_filestat(struct vnode *vp, struct filestat *fsp)
-{
- struct nfsnode nfsnode;
- mode_t mode;
-
- if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
- dprintf(stderr, "can't read nfsnode at %p for pid %d\n",
- (void *)VTONFS(vp), Pid);
- return 0;
- }
- fsp->fsid = nfsnode.n_vattr.va_fsid;
- fsp->fileid = nfsnode.n_vattr.va_fileid;
- fsp->size = nfsnode.n_size;
- fsp->rdev = nfsnode.n_vattr.va_rdev;
- mode = (mode_t)nfsnode.n_vattr.va_mode;
- switch (vp->v_type) {
- case VREG:
- mode |= S_IFREG;
- break;
- case VDIR:
- mode |= S_IFDIR;
- break;
- case VBLK:
- mode |= S_IFBLK;
- break;
- case VCHR:
- mode |= S_IFCHR;
+ /*
+ * Print type-specific data.
+ */
+ switch (fst->fs_type) {
+ case PS_FST_TYPE_FIFO:
+ case PS_FST_TYPE_VNODE:
+ print_vnode_info(procstat, fst);
break;
- case VLNK:
- mode |= S_IFLNK;
+ case PS_FST_TYPE_SOCKET:
+ print_socket_info(procstat, fst);
break;
- case VSOCK:
- mode |= S_IFSOCK;
+ case PS_FST_TYPE_PIPE:
+ print_pipe_info(procstat, fst);
break;
- case VFIFO:
- mode |= S_IFIFO;
+ case PS_FST_TYPE_PTS:
+ print_pts_info(procstat, fst);
break;
- case VNON:
- case VBAD:
- case VMARKER:
- return 0;
- };
- fsp->mode = mode;
-
- return 1;
-}
-
-
-char *
-getmnton(struct mount *m)
-{
- static struct mount mount;
- static struct mtab {
- struct mtab *next;
- struct mount *m;
- char mntonname[MNAMELEN];
- } *mhead = NULL;
- struct mtab *mt;
-
- for (mt = mhead; mt != NULL; mt = mt->next)
- if (m == mt->m)
- return (mt->mntonname);
- if (!KVM_READ(m, &mount, sizeof(struct mount))) {
- warnx("can't read mount table at %p", (void *)m);
- return (NULL);
- }
- if ((mt = malloc(sizeof (struct mtab))) == NULL)
- err(1, NULL);
- mt->m = m;
- bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
- mt->next = mhead;
- mhead = mt;
- return (mt->mntonname);
-}
-
-void
-pipetrans(struct pipe *pi, int i, int flag)
-{
- struct pipe pip;
- char rw[3];
-
- PREFIX(i);
-
- /* fill in socket */
- if (!KVM_READ(pi, &pip, sizeof(struct pipe))) {
- dprintf(stderr, "can't read pipe at %p\n", (void *)pi);
- goto bad;
+ default:
+ if (vflg)
+ fprintf(stderr,
+ "unknown file type %d for file %d of pid %d\n",
+ fst->fs_type, fst->fs_fd, pid);
}
-
- printf("* pipe %8lx <-> %8lx", (u_long)pi, (u_long)pip.pipe_peer);
- printf(" %6d", (int)pip.pipe_buffer.cnt);
- rw[0] = '\0';
- if (flag & FREAD)
- strcat(rw, "r");
- if (flag & FWRITE)
- strcat(rw, "w");
- printf(" %2s", rw);
+ if (filename && !fsflg)
+ printf(" %s", filename);
putchar('\n');
- return;
-
-bad:
- printf("* error\n");
}
-void
-socktrans(struct socket *sock, int i)
+static void
+print_socket_info(struct procstat *procstat, struct filestat *fst)
{
static const char *stypename[] = {
"unused", /* 0 */
- "stream", /* 1 */
+ "stream", /* 1 */
"dgram", /* 2 */
"raw", /* 3 */
"rdm", /* 4 */
"seqpak" /* 5 */
};
-#define STYPEMAX 5
- struct socket so;
- struct protosw proto;
- struct domain dom;
- struct inpcb inpcb;
- struct unpcb unpcb;
- int len;
- char dname[32];
-
- PREFIX(i);
-
- /* fill in socket */
- if (!KVM_READ(sock, &so, sizeof(struct socket))) {
- dprintf(stderr, "can't read sock at %p\n", (void *)sock);
- goto bad;
- }
-
- /* fill in protosw entry */
- if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
- dprintf(stderr, "can't read protosw at %p",
- (void *)so.so_proto);
- goto bad;
- }
-
- /* fill in domain */
- if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
- dprintf(stderr, "can't read domain at %p\n",
- (void *)proto.pr_domain);
- goto bad;
- }
+#define STYPEMAX 5
+ struct sockstat sock;
+ struct protoent *pe;
+ char errbuf[_POSIX2_LINE_MAX];
+ int error;
+ static int isopen;
- if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
- sizeof(dname) - 1)) < 0) {
- dprintf(stderr, "can't read domain name at %p\n",
- (void *)dom.dom_name);
- dname[0] = '\0';
+ error = procstat_get_socket_info(procstat, fst, &sock, errbuf);
+ if (error != 0) {
+ printf("* error");
+ return;
}
+ if (sock.type > STYPEMAX)
+ printf("* %s ?%d", sock.dname, sock.type);
else
- dname[len] = '\0';
-
- if ((u_short)so.so_type > STYPEMAX)
- printf("* %s ?%d", dname, so.so_type);
- else
- printf("* %s %s", dname, stypename[so.so_type]);
+ printf("* %s %s", sock.dname, stypename[sock.type]);
/*
* protocol specific formatting
@@ -835,139 +338,144 @@ socktrans(struct socket *sock, int i)
* The idea is not to duplicate netstat, but to make available enough
* information for further analysis.
*/
- switch(dom.dom_family) {
+ switch (sock.dom_family) {
case AF_INET:
case AF_INET6:
- getinetproto(proto.pr_protocol);
- if (proto.pr_protocol == IPPROTO_TCP ) {
- if (so.so_pcb) {
- if (kvm_read(kd, (u_long)so.so_pcb,
- (char *)&inpcb, sizeof(struct inpcb))
- != sizeof(struct inpcb)) {
- dprintf(stderr,
- "can't read inpcb at %p\n",
- (void *)so.so_pcb);
- goto bad;
- }
- printf(" %lx", (u_long)inpcb.inp_ppcb);
- }
+ if (!isopen)
+ setprotoent(++isopen);
+ if ((pe = getprotobynumber(sock.proto)) != NULL)
+ printf(" %s", pe->p_name);
+ else
+ printf(" %d", sock.proto);
+ if (sock.proto == IPPROTO_TCP ) {
+ if (sock.inp_ppcb != 0)
+ printf(" %lx", (u_long)sock.inp_ppcb);
}
- else if (so.so_pcb)
- printf(" %lx", (u_long)so.so_pcb);
+ else if (sock.so_pcb != 0)
+ printf(" %lx", (u_long)sock.so_pcb);
break;
case AF_UNIX:
/* print address of pcb and connected pcb */
- if (so.so_pcb) {
- printf(" %lx", (u_long)so.so_pcb);
- if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
- sizeof(struct unpcb)) != sizeof(struct unpcb)){
- dprintf(stderr, "can't read unpcb at %p\n",
- (void *)so.so_pcb);
- goto bad;
- }
- if (unpcb.unp_conn) {
+ if (sock.so_pcb != 0) {
+ printf(" %lx", (u_long)sock.so_pcb);
+ if (sock.unp_conn) {
char shoconn[4], *cp;
cp = shoconn;
- if (!(so.so_rcv.sb_state & SBS_CANTRCVMORE))
+ if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE))
*cp++ = '<';
*cp++ = '-';
- if (!(so.so_snd.sb_state & SBS_CANTSENDMORE))
+ if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE))
*cp++ = '>';
*cp = '\0';
printf(" %s %lx", shoconn,
- (u_long)unpcb.unp_conn);
- }
+ (u_long)sock.unp_conn);
+ }
}
break;
default:
/* print protocol number and socket address */
- printf(" %d %lx", proto.pr_protocol, (u_long)sock);
+ printf(" %d %lx", sock.proto, (u_long)sock.so_addr);
}
- printf("\n");
- return;
-bad:
- printf("* error\n");
}
-void
-ptstrans(struct tty *tp, int i, int flag)
+static void
+print_pipe_info(struct procstat *procstat, struct filestat *fst)
{
- struct tty tty;
- char *name;
- char rw[3];
- dev_t rdev;
+ struct pipestat ps;
+ char errbuf[_POSIX2_LINE_MAX];
+ int error;
- PREFIX(i);
-
- /* Obtain struct tty. */
- if (!KVM_READ(tp, &tty, sizeof(struct tty))) {
- dprintf(stderr, "can't read tty at %p\n", (void *)tp);
- goto bad;
- }
-
- /* Figure out the device name. */
- name = kdevtoname(tty.t_dev);
- if (name == NULL) {
- dprintf(stderr, "can't determine tty name at %p\n", (void *)tp);
- goto bad;
+ error = procstat_get_pipe_info(procstat, fst, &ps, errbuf);
+ if (error != 0) {
+ printf("* error");
+ return;
}
+ printf("* pipe %8lx <-> %8lx", (u_long)ps.addr, (u_long)ps.peer);
+ printf(" %6zd", ps.buffer_cnt);
+ print_access_flags(fst->fs_fflags);
+}
- rw[0] = '\0';
- if (flag & FREAD)
- strcat(rw, "r");
- if (flag & FWRITE)
- strcat(rw, "w");
+static void
+print_pts_info(struct procstat *procstat, struct filestat *fst)
+{
+ struct ptsstat pts;
+ char errbuf[_POSIX2_LINE_MAX];
+ int error;
+ error = procstat_get_pts_info(procstat, fst, &pts, errbuf);
+ if (error != 0) {
+ printf("* error");
+ return;
+ }
printf("* pseudo-terminal master ");
- if (nflg || !name) {
- rdev = dev2udev(tty.t_dev);
- printf("%10d,%-2d", major(rdev), minor(rdev));
+ if (nflg || !*pts.devname) {
+ printf("%10d,%-2d", major(pts.dev), minor(pts.dev));
} else {
- printf("%10s", name);
+ printf("%10s", pts.devname);
}
- printf(" %2s\n", rw);
-
- free(name);
-
- return;
-bad:
- printf("* error\n");
+ print_access_flags(fst->fs_fflags);
}
-/*
- * Read the cdev structure in the kernel in order to work out the
- * associated dev_t
- */
-dev_t
-dev2udev(struct cdev *dev)
+static void
+print_vnode_info(struct procstat *procstat, struct filestat *fst)
{
- struct cdev_priv priv;
+ struct vnstat vn;
+ char errbuf[_POSIX2_LINE_MAX];
+ char mode[15];
+ const char *badtype;
+ int error;
+
+ badtype = NULL;
+ error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
+ if (error != 0)
+ badtype = errbuf;
+ else if (vn.vn_type == PS_FST_VTYPE_VBAD)
+ badtype = "bad";
+ else if (vn.vn_type == PS_FST_VTYPE_VNON)
+ badtype = "none";
+ if (badtype != NULL) {
+ printf(" - - %10s -", badtype);
+ return;
+ }
- if (KVM_READ(cdev2priv(dev), &priv, sizeof priv)) {
- return ((dev_t)priv.cdp_inode);
- } else {
- dprintf(stderr, "can't convert cdev *%p to a dev_t\n", dev);
- return -1;
+ if (nflg)
+ printf(" %2d,%-2d", major(vn.vn_fsid), minor(vn.vn_fsid));
+ else if (vn.vn_mntdir != NULL)
+ (void)printf(" %-8s", vn.vn_mntdir);
+
+ /*
+ * Print access mode.
+ */
+ if (nflg)
+ (void)snprintf(mode, sizeof(mode), "%o", vn.vn_mode);
+ else {
+ strmode(vn.vn_mode, mode);
}
+ (void)printf(" %6ld %10s", vn.vn_fileid, mode);
+
+ if (vn.vn_type == PS_FST_VTYPE_VBLK || vn.vn_type == PS_FST_VTYPE_VCHR) {
+ if (nflg || !*vn.vn_devname)
+ printf(" %2d,%-2d", major(vn.vn_dev), minor(vn.vn_dev));
+ else {
+ printf(" %6s", vn.vn_devname);
+ }
+ } else
+ printf(" %6lu", vn.vn_size);
+ print_access_flags(fst->fs_fflags);
}
-/*
- * getinetproto --
- * print name of protocol number
- */
-void
-getinetproto(int number)
+static void
+print_access_flags(int flags)
{
- static int isopen;
- struct protoent *pe;
+ char rw[3];
- if (!isopen)
- setprotoent(++isopen);
- if ((pe = getprotobynumber(number)) != NULL)
- printf(" %s", pe->p_name);
- else
- printf(" %d", number);
+ rw[0] = '\0';
+ if (flags & PS_FST_FFLAG_READ)
+ strcat(rw, "r");
+ if (flags & PS_FST_FFLAG_WRITE)
+ strcat(rw, "w");
+ printf(" %2s", rw);
}
int
@@ -978,7 +486,7 @@ getfname(const char *filename)
if (stat(filename, &statbuf)) {
warn("%s", filename);
- return(0);
+ return (0);
}
if ((cur = malloc(sizeof(DEVS))) == NULL)
err(1, NULL);
@@ -988,24 +496,10 @@ getfname(const char *filename)
cur->ino = statbuf.st_ino;
cur->fsid = statbuf.st_dev;
cur->name = filename;
- return(1);
+ return (1);
}
-#ifdef ZFS
-void *
-getvnodedata(struct vnode *vp)
-{
- return (vp->v_data);
-}
-
-struct mount *
-getvnodemount(struct vnode *vp)
-{
- return (vp->v_mount);
-}
-#endif
-
-void
+static void
usage(void)
{
(void)fprintf(stderr,
diff --git a/usr.bin/fstat/functions.h b/usr.bin/fstat/functions.h
new file mode 100644
index 0000000..a23d27e
--- /dev/null
+++ b/usr.bin/fstat/functions.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef __FUNCTIONS_H__
+#define __FUNCTIONS_H__
+
+int do_fstat(int argc, char *argv[]);
+int do_fuser(int argc, char *argv[]);
+
+#endif /* !__FUNCTIONS_H__ */
diff --git a/usr.bin/fstat/fuser.1 b/usr.bin/fstat/fuser.1
new file mode 100644
index 0000000..999a72d
--- /dev/null
+++ b/usr.bin/fstat/fuser.1
@@ -0,0 +1,148 @@
+.\" Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 31, 2009
+.Dt FUSER 1
+.Os
+.Sh NAME
+.Nm fuser
+.Nd list IDs of all processes that have one or more files open
+.Sh SYNOPSIS
+.Nm
+.Op Fl cfkmu
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Op Fl s Ar signal
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility writes to stdout the PIDs of processes that have one or
+more named files open.
+For block and character special devices, all processes using files
+on that device are listed.
+A file is considered open by a process if it was explicitly opened,
+is the working directory, root directory, jail root directory,
+active executable text, kernel trace file or the controlling terminal
+of the process.
+If
+.Fl m
+option is specified, the
+.Nm
+utility will also look through mmapped files.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Treat files as mount point and report on any files open in the file system.
+.It Fl f
+The report must be only for named files.
+.It Fl k
+Send signal to reported processes
+.Pq SIGKILL by default .
+.It Fl m
+Search through mmapped files too.
+.It Fl u
+Write the user name associated with each process to stdout.
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default
+.Pa /dev/kmem .
+.It Fl N
+Extract the name list from the specified system instead of the default,
+which is the kernel image the system has booted from.
+.It Fl s
+Use given signal name instead of default SIGKILL.
+.El
+.Pp
+The following symbols, written to stderr will indicate how files is used:
+.Bl -tag -width MOUNT
+.It Cm r
+The file is the root directory of the process.
+.It Cm c
+The file is the current workdir directory of the process.
+.It Cm j
+The file is the jail-root of the process.
+.It Cm t
+The file is the kernel tracing file for the process.
+.It Cm x
+The file is executable text of the process.
+.It Cm y
+The process use this file as its controlling tty.
+.It Cm m
+The file is mmapped.
+.It Cm w
+The file is open for writing.
+.It Cm a
+The file is open as append only
+.Pq O_APPEND was specified .
+.It Cm d
+The process bypasses fs cache while writing to this file
+.Pq O_DIRECT was specified .
+.It Cm s
+Shared lock is hold.
+.It Cm e
+Exclusive lock is hold.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility returns 0 on successful completion and >0 otherwise.
+.Sh EXAMPLES
+The command:
+.Dq Li "fuser -fu ."
+writes to standart output the process IDs of processes that are using the
+current directory and writes to stderr an indication of how those processes are
+using the direcory and user names associated with the processes that are using
+this directory.
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr ps 1 ,
+.Xr systat 1 ,
+.Xr iostat 8 ,
+.Xr pstat 8 ,
+.Xr vmstat 8
+.Sh STANDARTS
+The
+.Nm
+utility is expected to conform to
+.St -p1003.1-2004 .
+.Sh BUGS
+Since
+.Nm
+takes a snapshot of the system, it is only correct for a very short period
+of time.
+When working via
+.Xr kvm 3
+interface the report will be limited to filesystems the
+.Nm
+utility knows about (currently only cd9660, devfs, nfs, ntfs, nwfs, udf,
+ufs and zfs).
+.Sh AUTHORS
+The
+.Nm
+utility and this manual page was written by
+.An Stanislav Sedov Aq stas@FreeBSD.org .
diff --git a/usr.bin/fstat/fuser.c b/usr.bin/fstat/fuser.c
new file mode 100644
index 0000000..02975b3
--- /dev/null
+++ b/usr.bin/fstat/fuser.c
@@ -0,0 +1,369 @@
+/*-
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <libprocstat.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "functions.h"
+
+/*
+ * File access mode flags table.
+ */
+struct {
+ int flag;
+ char ch;
+} fflags[] = {
+ {PS_FST_FFLAG_WRITE, 'w'},
+ {PS_FST_FFLAG_APPEND, 'a'},
+ {PS_FST_FFLAG_DIRECT, 'd'},
+ {PS_FST_FFLAG_SHLOCK, 's'},
+ {PS_FST_FFLAG_EXLOCK, 'e'}
+};
+#define NFFLAGS (sizeof(fflags) / sizeof(*fflags))
+
+/*
+ * Usage flags translation table.
+ */
+struct {
+ int flag;
+ char ch;
+} uflags[] = {
+ {PS_FST_UFLAG_RDIR, 'r'},
+ {PS_FST_UFLAG_CDIR, 'c'},
+ {PS_FST_UFLAG_JAIL, 'j'},
+ {PS_FST_UFLAG_TRACE, 't'},
+ {PS_FST_UFLAG_TEXT, 'x'},
+ {PS_FST_UFLAG_MMAP, 'm'},
+ {PS_FST_UFLAG_CTTY, 'y'}
+};
+#define NUFLAGS (sizeof(uflags) / sizeof(*uflags))
+
+struct consumer {
+ pid_t pid;
+ uid_t uid;
+ int fd;
+ int flags;
+ int uflags;
+ STAILQ_ENTRY(consumer) next;
+};
+struct reqfile {
+ uint32_t fsid;
+ uint64_t fileid;
+ const char *name;
+ STAILQ_HEAD(, consumer) consumers;
+};
+
+/*
+ * Option flags.
+ */
+#define UFLAG 0x01 /* -u flag: show users */
+#define FFLAG 0x02 /* -f flag: specified files only */
+#define CFLAG 0x04 /* -c flag: treat as mpoints */
+#define MFLAG 0x10 /* -m flag: mmapped files too */
+#define KFLAG 0x20 /* -k flag: send signal (SIGKILL by default) */
+
+static int flags = 0; /* Option flags. */
+
+static void printflags(struct consumer *consumer);
+static int str2sig(const char *str);
+static void usage(void) __dead2;
+static int addfile(const char *path, struct reqfile *reqfile);
+static void dofiles(struct procstat *procstat, struct kinfo_proc *kp,
+ struct reqfile *reqfiles, size_t nfiles);
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: fuser [-cfhkmu] [-M core] [-N system] [-s signal] file ...\n");
+ exit(EX_USAGE);
+}
+
+static void
+printflags(struct consumer *cons)
+{
+ unsigned int i;
+
+ assert(cons);
+ for (i = 0; i < NUFLAGS; i++)
+ if ((cons->uflags & uflags[i].flag) != 0)
+ fputc(uflags[i].ch, stderr);
+ for (i = 0; i < NFFLAGS; i++)
+ if ((cons->flags & fflags[i].flag) != 0)
+ fputc(fflags[i].ch, stderr);
+}
+
+/*
+ * Add file to the list.
+ */
+static int
+addfile(const char *path, struct reqfile *reqfile)
+{
+ struct stat sb;
+
+ assert(path);
+ if (stat(path, &sb) != 0) {
+ warn("%s", path);
+ return (1);
+ }
+ reqfile->fileid = sb.st_ino;
+ reqfile->fsid = sb.st_dev;
+ reqfile->name = path;
+ STAILQ_INIT(&reqfile->consumers);
+ return (0);
+}
+
+int
+do_fuser(int argc, char *argv[])
+{
+ struct consumer *consumer;
+ struct kinfo_proc *p, *procs;
+ struct procstat *procstat;
+ struct reqfile *reqfiles;
+ char *ep, *nlistf, *memf;
+ int ch, cnt, sig;
+ unsigned int i, nfiles;
+
+ sig = SIGKILL; /* Default to kill. */
+ nlistf = NULL;
+ memf = NULL;
+ while ((ch = getopt(argc, argv, "M:N:cfhkms:u")) != -1)
+ switch(ch) {
+ case 'f':
+ if ((flags & CFLAG) != 0)
+ usage();
+ flags |= FFLAG;
+ break;
+ case 'c':
+ if ((flags & FFLAG) != 0)
+ usage();
+ flags |= CFLAG;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'u':
+ flags |= UFLAG;
+ break;
+ case 'm':
+ flags |= MFLAG;
+ break;
+ case 'k':
+ flags |= KFLAG;
+ break;
+ case 's':
+ if (isdigit(*optarg)) {
+ sig = strtol(optarg, &ep, 10);
+ if (*ep != '\0' || sig < 0 || sig >= sys_nsig)
+ errx(EX_USAGE, "illegal signal number" ": %s",
+ optarg);
+ } else {
+ sig = str2sig(optarg);
+ if (sig < 0)
+ errx(EX_USAGE, "illegal signal name: "
+ "%s", optarg);
+ }
+ break;
+ case 'h':
+ /* PASSTHROUGH */
+ default:
+ usage();
+ /* NORETURN */
+ }
+ argv += optind;
+ argc -= optind;
+
+ assert(argc >= 0);
+ if (argc == 0)
+ usage();
+ /* NORETURN */
+
+ /*
+ * Process named files.
+ */
+ reqfiles = malloc(argc * sizeof(struct reqfile));
+ if (reqfiles == NULL)
+ err(EX_OSERR, "malloc()");
+ nfiles = 0;
+ while (argc--)
+ if (!addfile(*(argv++), &reqfiles[nfiles]))
+ nfiles++;
+ if (nfiles == 0)
+ errx(EX_IOERR, "files not accessible");
+
+ if (memf != NULL)
+ procstat = procstat_open_kvm(nlistf, memf);
+ else
+ procstat = procstat_open_sysctl();
+ if (procstat == NULL)
+ errx(1, "procstat_open()");
+ procs = procstat_getprocs(procstat, KERN_PROC_PROC, 0, &cnt);
+ if (procs == NULL)
+ errx(1, "procstat_getprocs()");
+
+ /*
+ * Walk through process table and look for matching files.
+ */
+ p = procs;
+ while(cnt--)
+ if (p->ki_stat != SZOMB)
+ dofiles(procstat, p++, reqfiles, nfiles);
+
+ for (i = 0; i < nfiles; i++) {
+ fprintf(stderr, "%s:", reqfiles[i].name);
+ fflush(stderr);
+ STAILQ_FOREACH(consumer, &reqfiles[i].consumers, next) {
+ if (consumer->flags != 0) {
+ fprintf(stdout, "%6d", consumer->pid);
+ fflush(stdout);
+ printflags(consumer);
+ if ((flags & UFLAG) != 0)
+ fprintf(stderr, "(%s)",
+ user_from_uid(consumer->uid, 0));
+ if ((flags & KFLAG) != 0)
+ kill(consumer->pid, sig);
+ fflush(stderr);
+ }
+ }
+ (void)fprintf(stderr, "\n");
+ }
+ procstat_freeprocs(procstat, procs);
+ procstat_close(procstat);
+ free(reqfiles);
+ return (0);
+}
+
+static void
+dofiles(struct procstat *procstat, struct kinfo_proc *kp,
+ struct reqfile *reqfiles, size_t nfiles)
+{
+ struct vnstat vn;
+ struct consumer *cons;
+ struct filestat *fst;
+ struct filestat_list *head;
+ int error, match;
+ unsigned int i;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ head = procstat_getfiles(procstat, kp, flags & MFLAG);
+ if (head == NULL)
+ return;
+ STAILQ_FOREACH(fst, head, next) {
+ if (fst->fs_type != PS_FST_TYPE_VNODE)
+ continue;
+ error = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
+ if (error != 0)
+ continue;
+ for (i = 0; i < nfiles; i++) {
+ if (flags & CFLAG && reqfiles[i].fsid == vn.vn_fsid) {
+ break;
+ }
+ else if (reqfiles[i].fsid == vn.vn_fsid &&
+ reqfiles[i].fileid == vn.vn_fileid) {
+ break;
+ }
+ else if (!(flags & FFLAG) &&
+ (vn.vn_type == PS_FST_VTYPE_VCHR ||
+ vn.vn_type == PS_FST_VTYPE_VBLK) &&
+ vn.vn_fsid == reqfiles[i].fileid) {
+ break;
+ }
+ }
+ if (i == nfiles)
+ continue; /* No match. */
+
+ /*
+ * Look for existing entries.
+ */
+ match = 0;
+ STAILQ_FOREACH(cons, &reqfiles[i].consumers, next)
+ if (cons->pid == kp->ki_pid) {
+ match = 1;
+ break;
+ }
+ if (match == 1) { /* Use old entry. */
+ cons->flags |= fst->fs_fflags;
+ cons->uflags |= fst->fs_uflags;
+ } else {
+ /*
+ * Create new entry in the consumer chain.
+ */
+ cons = calloc(1, sizeof(struct consumer));
+ if (cons == NULL) {
+ warn("malloc()");
+ continue;
+ }
+ cons->uid = kp->ki_uid;
+ cons->pid = kp->ki_pid;
+ cons->uflags = fst->fs_uflags;
+ cons->flags = fst->fs_fflags;
+ STAILQ_INSERT_TAIL(&reqfiles[i].consumers, cons, next);
+ }
+ }
+ procstat_freefiles(procstat, head);
+}
+
+/*
+ * Returns signal number for it's string representation.
+ */
+static int
+str2sig(const char *str)
+{
+ int i;
+
+#define SIGPREFIX "sig"
+ if (!strncasecmp(str, SIGPREFIX, sizeof(SIGPREFIX)))
+ str += sizeof(SIGPREFIX);
+ for (i = 1; i < sys_nsig; i++) {
+ if (!strcasecmp(sys_signame[i], str))
+ return (i);
+ }
+ return (-1);
+}
diff --git a/usr.bin/fstat/main.c b/usr.bin/fstat/main.c
new file mode 100644
index 0000000..4123e64
--- /dev/null
+++ b/usr.bin/fstat/main.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "functions.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *p;
+
+ p = basename(argv[0]);
+ if (p == NULL)
+ err(1, "basename(%s)", argv[0]);
+ if (!strcmp(p, "fuser"))
+ return (do_fuser(argc, argv));
+ else
+ return (do_fstat(argc, argv));
+}
diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile
index fa1c3b4..e8e35ed 100644
--- a/usr.bin/procstat/Makefile
+++ b/usr.bin/procstat/Makefile
@@ -13,7 +13,7 @@ SRCS= procstat.c \
procstat_threads.c \
procstat_vm.c
-LDADD+= -lutil
+LDADD+= -lutil -lprocstat -lkvm
DPADD+= ${LIBUTIL}
.include <bsd.prog.mk>
diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c
index ee95ae2..69648fd 100644
--- a/usr.bin/procstat/procstat.c
+++ b/usr.bin/procstat/procstat.c
@@ -31,6 +31,7 @@
#include <sys/user.h>
#include <err.h>
+#include <libprocstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
@@ -45,36 +46,36 @@ static void
usage(void)
{
- fprintf(stderr, "usage: procstat [-h] [-n] [-w interval] [-b | -c | -f | "
- "-i | -j | -k | -s | -t | -v]\n");
+ fprintf(stderr, "usage: procstat [-h] [-M core] [-N system] "
+ "[-w interval] [-b | -c | -f | -i | -j | -k | -s | -t | -v]\n");
fprintf(stderr, " [-a | pid ...]\n");
exit(EX_USAGE);
}
static void
-procstat(pid_t pid, struct kinfo_proc *kipp)
+procstat(struct procstat *prstat, struct kinfo_proc *kipp)
{
if (bflag)
- procstat_bin(pid, kipp);
+ procstat_bin(kipp);
else if (cflag)
- procstat_args(pid, kipp);
+ procstat_args(kipp);
else if (fflag)
- procstat_files(pid, kipp);
+ procstat_files(prstat, kipp);
else if (iflag)
- procstat_sigs(pid, kipp);
+ procstat_sigs(prstat, kipp);
else if (jflag)
- procstat_threads_sigs(pid, kipp);
+ procstat_threads_sigs(prstat, kipp);
else if (kflag)
- procstat_kstack(pid, kipp, kflag);
+ procstat_kstack(kipp, kflag);
else if (sflag)
- procstat_cred(pid, kipp);
+ procstat_cred(kipp);
else if (tflag)
- procstat_threads(pid, kipp);
+ procstat_threads(kipp);
else if (vflag)
- procstat_vm(pid, kipp);
+ procstat_vm(kipp);
else
- procstat_basic(pid, kipp);
+ procstat_basic(kipp);
}
/*
@@ -104,17 +105,26 @@ kinfo_proc_sort(struct kinfo_proc *kipp, int count)
int
main(int argc, char *argv[])
{
- int ch, interval, name[4], tmp;
- unsigned int i;
- struct kinfo_proc *kipp;
- size_t len;
+ int ch, interval, tmp;
+ int i;
+ struct kinfo_proc *p;
+ struct procstat *prstat;
long l;
pid_t pid;
char *dummy;
+ char *nlistf, *memf;
+ int cnt;
interval = 0;
- while ((ch = getopt(argc, argv, "abcfijknhstvw:")) != -1) {
+ memf = nlistf = NULL;
+ while ((ch = getopt(argc, argv, "N:M:abcfijkhstvw:")) != -1) {
switch (ch) {
+ case 'M':
+ memf = optarg;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
case 'a':
aflag++;
break;
@@ -194,38 +204,27 @@ main(int argc, char *argv[])
if (!(aflag == 1 && argc == 0) && !(aflag == 0 && argc > 0))
usage();
+ if (memf != NULL)
+ prstat = procstat_open_kvm(nlistf, memf);
+ else
+ prstat = procstat_open_sysctl();
+ if (prstat == NULL)
+ errx(1, "procstat_open()");
do {
if (aflag) {
- name[0] = CTL_KERN;
- name[1] = KERN_PROC;
- name[2] = KERN_PROC_PROC;
-
- len = 0;
- if (sysctl(name, 3, NULL, &len, NULL, 0) < 0)
- err(-1, "sysctl: kern.proc.all");
-
- kipp = malloc(len);
- if (kipp == NULL)
- err(-1, "malloc");
-
- if (sysctl(name, 3, kipp, &len, NULL, 0) < 0) {
- free(kipp);
- err(-1, "sysctl: kern.proc.all");
- }
- if (len % sizeof(*kipp) != 0)
- err(-1, "kinfo_proc mismatch");
- if (kipp->ki_structsize != sizeof(*kipp))
- err(-1, "kinfo_proc structure mismatch");
- kinfo_proc_sort(kipp, len / sizeof(*kipp));
- for (i = 0; i < len / sizeof(*kipp); i++) {
- procstat(kipp[i].ki_pid, &kipp[i]);
+ p = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt);
+ if (p == NULL)
+ errx(1, "procstat_getprocs()");
+ kinfo_proc_sort(p, cnt);
+ for (i = 0; i < cnt; i++) {
+ procstat(prstat, &p[i]);
/* Suppress header after first process. */
hflag = 1;
}
- free(kipp);
+ procstat_freeprocs(prstat, p);
}
- for (i = 0; i < (unsigned int)argc; i++) {
+ for (i = 0; i < argc; i++) {
l = strtol(argv[i], &dummy, 10);
if (*dummy != '\0')
usage();
@@ -233,31 +232,12 @@ main(int argc, char *argv[])
usage();
pid = l;
- name[0] = CTL_KERN;
- name[1] = KERN_PROC;
- name[2] = KERN_PROC_PID;
- name[3] = pid;
-
- len = 0;
- if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
- err(-1, "sysctl: kern.proc.pid: %d", pid);
-
- kipp = malloc(len);
- if (kipp == NULL)
- err(-1, "malloc");
-
- if (sysctl(name, 4, kipp, &len, NULL, 0) < 0) {
- free(kipp);
- err(-1, "sysctl: kern.proc.pid: %d", pid);
- }
- if (len != sizeof(*kipp))
- err(-1, "kinfo_proc mismatch");
- if (kipp->ki_structsize != sizeof(*kipp))
- errx(-1, "kinfo_proc structure mismatch");
- if (kipp->ki_pid != pid)
- errx(-1, "kinfo_proc pid mismatch");
- procstat(pid, kipp);
- free(kipp);
+ p = procstat_getprocs(prstat, KERN_PROC_PID, pid, &cnt);
+ if (p == NULL)
+ errx(1, "procstat_getprocs()");
+ if (cnt != 0)
+ procstat(prstat, p);
+ procstat_freeprocs(prstat, p);
/* Suppress header after first process. */
hflag = 1;
@@ -265,5 +245,6 @@ main(int argc, char *argv[])
if (interval)
sleep(interval);
} while (interval);
+ procstat_close(prstat);
exit(0);
}
diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h
index d73a203..ad425f3 100644
--- a/usr.bin/procstat/procstat.h
+++ b/usr.bin/procstat/procstat.h
@@ -34,15 +34,15 @@ extern int hflag, nflag;
struct kinfo_proc;
void kinfo_proc_sort(struct kinfo_proc *kipp, int count);
-void procstat_args(pid_t pid, struct kinfo_proc *kipp);
-void procstat_basic(pid_t pid, struct kinfo_proc *kipp);
-void procstat_bin(pid_t pid, struct kinfo_proc *kipp);
-void procstat_cred(pid_t pid, struct kinfo_proc *kipp);
-void procstat_files(pid_t pid, struct kinfo_proc *kipp);
-void procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag);
-void procstat_sigs(pid_t pid, struct kinfo_proc *kipp);
-void procstat_threads(pid_t pid, struct kinfo_proc *kipp);
-void procstat_threads_sigs(pid_t pid, struct kinfo_proc *kipp);
-void procstat_vm(pid_t pid, struct kinfo_proc *kipp);
+void procstat_args(struct kinfo_proc *kipp);
+void procstat_basic(struct kinfo_proc *kipp);
+void procstat_bin(struct kinfo_proc *kipp);
+void procstat_cred(struct kinfo_proc *kipp);
+void procstat_files(struct procstat *prstat, struct kinfo_proc *kipp);
+void procstat_kstack(struct kinfo_proc *kipp, int kflag);
+void procstat_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
+void procstat_threads(struct kinfo_proc *kipp);
+void procstat_threads_sigs(struct procstat *prstat, struct kinfo_proc *kipp);
+void procstat_vm(struct kinfo_proc *kipp);
#endif /* !PROCSTAT_H */
diff --git a/usr.bin/procstat/procstat_args.c b/usr.bin/procstat/procstat_args.c
index e5a7acd..e8e6b94 100644
--- a/usr.bin/procstat/procstat_args.c
+++ b/usr.bin/procstat/procstat_args.c
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
+#include <libprocstat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -42,7 +43,7 @@
static char args[ARG_MAX];
void
-procstat_args(pid_t pid, struct kinfo_proc *kipp)
+procstat_args(struct kinfo_proc *kipp)
{
int error, name[4];
size_t len;
@@ -54,11 +55,11 @@ procstat_args(pid_t pid, struct kinfo_proc *kipp)
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_ARGS;
- name[3] = pid;
+ name[3] = kipp->ki_pid;
len = sizeof(args);
error = sysctl(name, 4, args, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
- warn("sysctl: kern.proc.args: %d", pid);
+ warn("sysctl: kern.proc.args: %d", kipp->ki_pid);
return;
}
if (error < 0)
@@ -68,7 +69,7 @@ procstat_args(pid_t pid, struct kinfo_proc *kipp)
len = strlen(args) + 1;
}
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
printf("%-16s ", kipp->ki_comm);
for (cp = args; cp < args + len; cp += strlen(cp) + 1)
printf("%s%s", cp != args ? " " : "", cp);
diff --git a/usr.bin/procstat/procstat_basic.c b/usr.bin/procstat/procstat_basic.c
index 2775172..af43fd1 100644
--- a/usr.bin/procstat/procstat_basic.c
+++ b/usr.bin/procstat/procstat_basic.c
@@ -31,13 +31,14 @@
#include <sys/user.h>
#include <err.h>
+#include <libprocstat.h>
#include <stdio.h>
#include <string.h>
#include "procstat.h"
void
-procstat_basic(pid_t pid __unused, struct kinfo_proc *kipp)
+procstat_basic(struct kinfo_proc *kipp)
{
if (!hflag)
diff --git a/usr.bin/procstat/procstat_bin.c b/usr.bin/procstat/procstat_bin.c
index 8ed5efe..cf4ca5b 100644
--- a/usr.bin/procstat/procstat_bin.c
+++ b/usr.bin/procstat/procstat_bin.c
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
+#include <libprocstat.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
@@ -39,7 +40,7 @@
#include "procstat.h"
void
-procstat_bin(pid_t pid, struct kinfo_proc *kipp)
+procstat_bin(struct kinfo_proc *kipp)
{
char pathname[PATH_MAX];
int error, name[4];
@@ -51,12 +52,12 @@ procstat_bin(pid_t pid, struct kinfo_proc *kipp)
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PATHNAME;
- name[3] = pid;
+ name[3] = kipp->ki_pid;
len = sizeof(pathname);
error = sysctl(name, 4, pathname, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
- warn("sysctl: kern.proc.pathname: %d", pid);
+ warn("sysctl: kern.proc.pathname: %d", kipp->ki_pid);
return;
}
if (error < 0)
@@ -64,7 +65,7 @@ procstat_bin(pid_t pid, struct kinfo_proc *kipp)
if (len == 0 || strlen(pathname) == 0)
strcpy(pathname, "-");
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
printf("%-16s ", kipp->ki_comm);
printf("%s\n", pathname);
}
diff --git a/usr.bin/procstat/procstat_cred.c b/usr.bin/procstat/procstat_cred.c
index 1e91a94..ea8fdfd 100644
--- a/usr.bin/procstat/procstat_cred.c
+++ b/usr.bin/procstat/procstat_cred.c
@@ -31,6 +31,7 @@
#include <sys/user.h>
#include <err.h>
+#include <libprocstat.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -38,7 +39,7 @@
#include "procstat.h"
void
-procstat_cred(pid_t pid, struct kinfo_proc *kipp)
+procstat_cred(struct kinfo_proc *kipp)
{
int i;
int mib[4];
@@ -51,7 +52,7 @@ procstat_cred(pid_t pid, struct kinfo_proc *kipp)
"COMM", "EUID", "RUID", "SVUID", "EGID", "RGID", "SVGID",
"GROUPS");
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
printf("%-16s ", kipp->ki_comm);
printf("%5d ", kipp->ki_uid);
printf("%5d ", kipp->ki_ruid);
@@ -69,7 +70,7 @@ procstat_cred(pid_t pid, struct kinfo_proc *kipp)
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_GROUPS;
- mib[3] = pid;
+ mib[3] = kipp->ki_pid;
ngroups = sysconf(_SC_NGROUPS_MAX) + 1;
len = ngroups * sizeof(gid_t);
@@ -78,7 +79,7 @@ procstat_cred(pid_t pid, struct kinfo_proc *kipp)
if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) {
warn("sysctl: kern.proc.groups: %d "
- "group list truncated", pid);
+ "group list truncated", kipp->ki_pid);
free(groups);
groups = NULL;
}
diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c
index debb0e4..f7d91a4 100644
--- a/usr.bin/procstat/procstat_files.c
+++ b/usr.bin/procstat/procstat_files.c
@@ -37,11 +37,11 @@
#include <arpa/inet.h>
#include <err.h>
+#include <libprocstat.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <libutil.h>
#include "procstat.h"
@@ -132,162 +132,165 @@ print_address(struct sockaddr_storage *ss)
}
void
-procstat_files(pid_t pid, struct kinfo_proc *kipp)
-{
- struct kinfo_file *freep, *kif;
- int i, cnt;
+procstat_files(struct procstat *procstat, struct kinfo_proc *kipp)
+{
+ struct sockstat sock;
+ struct filestat_list *head;
+ struct filestat *fst;
const char *str;
+ struct vnstat vn;
+ int error;
if (!hflag)
printf("%5s %-16s %4s %1s %1s %-8s %3s %7s %-3s %-12s\n",
"PID", "COMM", "FD", "T", "V", "FLAGS", "REF", "OFFSET",
"PRO", "NAME");
- freep = kinfo_getfile(pid, &cnt);
- if (freep == NULL)
+ head = procstat_getfiles(procstat, kipp, 0);
+ if (head == NULL)
return;
- for (i = 0; i < cnt; i++) {
- kif = &freep[i];
-
- printf("%5d ", pid);
+ STAILQ_FOREACH(fst, head, next) {
+ printf("%5d ", kipp->ki_pid);
printf("%-16s ", kipp->ki_comm);
- switch (kif->kf_fd) {
- case KF_FD_TYPE_CWD:
+ if (fst->fs_uflags & PS_FST_UFLAG_CTTY)
+ printf("ctty ");
+ else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
printf(" cwd ");
- break;
-
- case KF_FD_TYPE_ROOT:
- printf("root ");
- break;
-
- case KF_FD_TYPE_JAIL:
+ else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
printf("jail ");
- break;
+ else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
+ printf("root ");
+ else if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
+ printf("text ");
+ else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
+ printf("trace ");
+ else
+ printf("%4d ", fst->fs_fd);
- default:
- printf("%4d ", kif->kf_fd);
- break;
- }
- switch (kif->kf_type) {
- case KF_TYPE_VNODE:
+ switch (fst->fs_type) {
+ case PS_FST_TYPE_VNODE:
str = "v";
break;
- case KF_TYPE_SOCKET:
+ case PS_FST_TYPE_SOCKET:
str = "s";
break;
- case KF_TYPE_PIPE:
+ case PS_FST_TYPE_PIPE:
str = "p";
break;
- case KF_TYPE_FIFO:
+ case PS_FST_TYPE_FIFO:
str = "f";
break;
- case KF_TYPE_KQUEUE:
+ case PS_FST_TYPE_KQUEUE:
str = "k";
break;
- case KF_TYPE_CRYPTO:
+ case PS_FST_TYPE_CRYPTO:
str = "c";
break;
- case KF_TYPE_MQUEUE:
+ case PS_FST_TYPE_MQUEUE:
str = "m";
break;
- case KF_TYPE_SHM:
+ case PS_FST_TYPE_SHM:
str = "h";
break;
- case KF_TYPE_PTS:
+ case PS_FST_TYPE_PTS:
str = "t";
break;
- case KF_TYPE_SEM:
+ case PS_FST_TYPE_SEM:
str = "e";
break;
- case KF_TYPE_NONE:
- case KF_TYPE_UNKNOWN:
+ case PS_FST_TYPE_NONE:
+ case PS_FST_TYPE_UNKNOWN:
default:
str = "?";
break;
}
printf("%1s ", str);
str = "-";
- if (kif->kf_type == KF_TYPE_VNODE) {
- switch (kif->kf_vnode_type) {
- case KF_VTYPE_VREG:
+ if (fst->fs_type == PS_FST_TYPE_VNODE) {
+ error = procstat_get_vnode_info(procstat, fst, &vn, NULL);
+ switch (vn.vn_type) {
+ case PS_FST_VTYPE_VREG:
str = "r";
break;
- case KF_VTYPE_VDIR:
+ case PS_FST_VTYPE_VDIR:
str = "d";
break;
- case KF_VTYPE_VBLK:
+ case PS_FST_VTYPE_VBLK:
str = "b";
break;
- case KF_VTYPE_VCHR:
+ case PS_FST_VTYPE_VCHR:
str = "c";
break;
- case KF_VTYPE_VLNK:
+ case PS_FST_VTYPE_VLNK:
str = "l";
break;
- case KF_VTYPE_VSOCK:
+ case PS_FST_VTYPE_VSOCK:
str = "s";
break;
- case KF_VTYPE_VFIFO:
+ case PS_FST_VTYPE_VFIFO:
str = "f";
break;
- case KF_VTYPE_VBAD:
+ case PS_FST_VTYPE_VBAD:
str = "x";
break;
- case KF_VTYPE_VNON:
- case KF_VTYPE_UNKNOWN:
+ case PS_FST_VTYPE_VNON:
+ case PS_FST_VTYPE_UNKNOWN:
default:
str = "?";
break;
}
}
printf("%1s ", str);
- printf("%s", kif->kf_flags & KF_FLAG_READ ? "r" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_WRITE ? "w" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_APPEND ? "a" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_ASYNC ? "s" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_FSYNC ? "f" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_NONBLOCK ? "n" : "-");
- printf("%s", kif->kf_flags & KF_FLAG_DIRECT ? "d" : "-");
- printf("%s ", kif->kf_flags & KF_FLAG_HASLOCK ? "l" : "-");
- if (kif->kf_ref_count > -1)
- printf("%3d ", kif->kf_ref_count);
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_READ ? "r" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_WRITE ? "w" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_APPEND ? "a" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_ASYNC ? "s" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_SYNC ? "f" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_NONBLOCK ? "n" : "-");
+ printf("%s", fst->fs_fflags & PS_FST_FFLAG_DIRECT ? "d" : "-");
+ printf("%s ", fst->fs_fflags & PS_FST_FFLAG_HASLOCK ? "l" : "-");
+ if (fst->fs_ref_count > -1)
+ printf("%3d ", fst->fs_ref_count);
else
printf("%3c ", '-');
- if (kif->kf_offset > -1)
- printf("%7jd ", (intmax_t)kif->kf_offset);
+ if (fst->fs_offset > -1)
+ printf("%7jd ", (intmax_t)fst->fs_offset);
else
printf("%7c ", '-');
- switch (kif->kf_type) {
- case KF_TYPE_VNODE:
- case KF_TYPE_FIFO:
- case KF_TYPE_PTS:
+ switch (fst->fs_type) {
+ case PS_FST_TYPE_VNODE:
+ case PS_FST_TYPE_FIFO:
+ case PS_FST_TYPE_PTS:
printf("%-3s ", "-");
- printf("%-18s", kif->kf_path);
+ printf("%-18s", fst->fs_path != NULL ? fst->fs_path : "-");
break;
- case KF_TYPE_SOCKET:
+ case PS_FST_TYPE_SOCKET:
+ error = procstat_get_socket_info(procstat, fst, &sock, NULL);
+ if (error != 0)
+ break;
printf("%-3s ",
- protocol_to_string(kif->kf_sock_domain,
- kif->kf_sock_type, kif->kf_sock_protocol));
+ protocol_to_string(sock.dom_family,
+ sock.type, sock.proto));
/*
* While generally we like to print two addresses,
* local and peer, for sockets, it turns out to be
@@ -295,18 +298,18 @@ procstat_files(pid_t pid, struct kinfo_proc *kipp)
* local sockets, as typically they aren't bound and
* connected, and the path strings can get long.
*/
- if (kif->kf_sock_domain == AF_LOCAL) {
+ if (sock.dom_family == AF_LOCAL) {
struct sockaddr_un *sun =
- (struct sockaddr_un *)&kif->kf_sa_local;
+ (struct sockaddr_un *)&sock.sa_local;
if (sun->sun_path[0] != 0)
- print_address(&kif->kf_sa_local);
+ print_address(&sock.sa_local);
else
- print_address(&kif->kf_sa_peer);
+ print_address(&sock.sa_peer);
} else {
- print_address(&kif->kf_sa_local);
+ print_address(&sock.sa_local);
printf(" ");
- print_address(&kif->kf_sa_peer);
+ print_address(&sock.sa_peer);
}
break;
@@ -317,5 +320,4 @@ procstat_files(pid_t pid, struct kinfo_proc *kipp)
printf("\n");
}
- free(freep);
}
diff --git a/usr.bin/procstat/procstat_kstack.c b/usr.bin/procstat/procstat_kstack.c
index 9d5f71e..fd2b9ab 100644
--- a/usr.bin/procstat/procstat_kstack.c
+++ b/usr.bin/procstat/procstat_kstack.c
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
+#include <libprocstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -124,7 +125,7 @@ kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count)
void
-procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
+procstat_kstack(struct kinfo_proc *kipp, int kflag)
{
struct kinfo_kstack *kkstp, *kkstp_free;
struct kinfo_proc *kip, *kip_free;
@@ -140,12 +141,12 @@ procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_KSTACK;
- name[3] = pid;
+ name[3] = kipp->ki_pid;
kstk_len = 0;
error = sysctl(name, 4, NULL, &kstk_len, NULL, 0);
if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
- warn("sysctl: kern.proc.kstack: %d", pid);
+ warn("sysctl: kern.proc.kstack: %d", kipp->ki_pid);
return;
}
if (error < 0 && errno == ENOENT) {
@@ -160,7 +161,7 @@ procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
err(-1, "malloc");
if (sysctl(name, 4, kkstp, &kstk_len, NULL, 0) < 0) {
- warn("sysctl: kern.proc.pid: %d", pid);
+ warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
free(kkstp);
return;
}
@@ -171,12 +172,12 @@ procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
- name[3] = pid;
+ name[3] = kipp->ki_pid;
kip_len = 0;
error = sysctl(name, 4, NULL, &kip_len, NULL, 0);
if (error < 0 && errno != ESRCH) {
- warn("sysctl: kern.proc.pid: %d", pid);
+ warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
return;
}
if (error < 0)
@@ -187,7 +188,7 @@ procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
err(-1, "malloc");
if (sysctl(name, 4, kip, &kip_len, NULL, 0) < 0) {
- warn("sysctl: kern.proc.pid: %d", pid);
+ warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
free(kip);
return;
}
@@ -209,7 +210,7 @@ procstat_kstack(pid_t pid, struct kinfo_proc *kipp, int kflag)
if (kipp == NULL)
continue;
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
printf("%6d ", kkstp->kkst_tid);
printf("%-16s ", kipp->ki_comm);
printf("%-16s ", (strlen(kipp->ki_ocomm) &&
diff --git a/usr.bin/procstat/procstat_sigs.c b/usr.bin/procstat/procstat_sigs.c
index b1f5e35..70df250 100644
--- a/usr.bin/procstat/procstat_sigs.c
+++ b/usr.bin/procstat/procstat_sigs.c
@@ -37,6 +37,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <libprocstat.h>
#include "procstat.h"
@@ -63,10 +64,12 @@ procstat_print_sig(const sigset_t *set, int sig, char flag)
}
void
-procstat_sigs(pid_t pid, struct kinfo_proc *kipp)
+procstat_sigs(struct procstat *prstat __unused, struct kinfo_proc *kipp)
{
int j;
+ pid_t pid;
+ pid = kipp->ki_pid;
if (!hflag)
printf("%5s %-16s %-7s %4s\n", "PID", "COMM", "SIG", "FLAGS");
@@ -83,13 +86,15 @@ procstat_sigs(pid_t pid, struct kinfo_proc *kipp)
}
void
-procstat_threads_sigs(pid_t pid, struct kinfo_proc *kipp)
+procstat_threads_sigs(struct procstat *prstat __unused, struct kinfo_proc *kipp)
{
struct kinfo_proc *kip;
+ pid_t pid;
int error, name[4], j;
unsigned int i;
size_t len;
+ pid = kipp->ki_pid;
if (!hflag)
printf("%5s %6s %-16s %-7s %4s\n", "PID", "TID", "COMM",
"SIG", "FLAGS");
diff --git a/usr.bin/procstat/procstat_threads.c b/usr.bin/procstat/procstat_threads.c
index 64e0a36..7633608 100644
--- a/usr.bin/procstat/procstat_threads.c
+++ b/usr.bin/procstat/procstat_threads.c
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
+#include <libprocstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,7 +40,7 @@
#include "procstat.h"
void
-procstat_threads(pid_t pid, struct kinfo_proc *kipp)
+procstat_threads(struct kinfo_proc *kipp)
{
struct kinfo_proc *kip;
int error, name[4];
@@ -57,12 +58,12 @@ procstat_threads(pid_t pid, struct kinfo_proc *kipp)
name[0] = CTL_KERN;
name[1] = KERN_PROC;
name[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
- name[3] = pid;
+ name[3] = kipp->ki_pid;
len = 0;
error = sysctl(name, 4, NULL, &len, NULL, 0);
if (error < 0 && errno != ESRCH) {
- warn("sysctl: kern.proc.pid: %d", pid);
+ warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
return;
}
if (error < 0)
@@ -73,7 +74,7 @@ procstat_threads(pid_t pid, struct kinfo_proc *kipp)
err(-1, "malloc");
if (sysctl(name, 4, kip, &len, NULL, 0) < 0) {
- warn("sysctl: kern.proc.pid: %d", pid);
+ warn("sysctl: kern.proc.pid: %d", kipp->ki_pid);
free(kip);
return;
}
@@ -81,7 +82,7 @@ procstat_threads(pid_t pid, struct kinfo_proc *kipp)
kinfo_proc_sort(kip, len / sizeof(*kipp));
for (i = 0; i < len / sizeof(*kipp); i++) {
kipp = &kip[i];
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
printf("%6d ", kipp->ki_tid);
printf("%-16s ", strlen(kipp->ki_comm) ?
kipp->ki_comm : "-");
diff --git a/usr.bin/procstat/procstat_vm.c b/usr.bin/procstat/procstat_vm.c
index 5c965a9..2eada92 100644
--- a/usr.bin/procstat/procstat_vm.c
+++ b/usr.bin/procstat/procstat_vm.c
@@ -32,6 +32,7 @@
#include <err.h>
#include <errno.h>
+#include <libprocstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -40,7 +41,7 @@
#include "procstat.h"
void
-procstat_vm(pid_t pid, struct kinfo_proc *kipp __unused)
+procstat_vm(struct kinfo_proc *kipp)
{
struct kinfo_vmentry *freep, *kve;
int ptrwidth;
@@ -53,12 +54,12 @@ procstat_vm(pid_t pid, struct kinfo_proc *kipp __unused)
"PID", ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
"PRES", "REF", "SHD", "FL", "TP", "PATH");
- freep = kinfo_getvmmap(pid, &cnt);
+ freep = kinfo_getvmmap(kipp->ki_pid, &cnt);
if (freep == NULL)
return;
for (i = 0; i < cnt; i++) {
kve = &freep[i];
- printf("%5d ", pid);
+ printf("%5d ", kipp->ki_pid);
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" : "-");
OpenPOWER on IntegriCloud