summaryrefslogtreecommitdiffstats
path: root/usr.bin/fstat
diff options
context:
space:
mode:
authorstas <stas@FreeBSD.org>2011-05-12 10:11:39 +0000
committerstas <stas@FreeBSD.org>2011-05-12 10:11:39 +0000
commit5f9f79547658271f3f469b6423a176831fef7683 (patch)
tree9f873599b157e2ba06c3088d82cad8a221b42d18 /usr.bin/fstat
parentf47d00001ad33e13ec3b6fc74732b959cd485dc7 (diff)
downloadFreeBSD-src-5f9f79547658271f3f469b6423a176831fef7683.zip
FreeBSD-src-5f9f79547658271f3f469b6423a176831fef7683.tar.gz
- Commit work from libprocstat project. These patches add support for runtime
file and processes information retrieval from the running kernel via sysctl in the form of new library, libprocstat. The library also supports KVM backend for analyzing memory crash dumps. Both procstat(1) and fstat(1) utilities have been modified to take advantage of the library (as the bonus point the fstat(1) utility no longer need superuser privileges to operate), and the procstat(1) utility is now able to display information from memory dumps as well. The newly introduced fuser(1) utility also uses this library and able to operate via sysctl and kvm backends. The library is by no means complete (e.g. KVM backend is missing vnode name resolution routines, and there're no manpages for the library itself) so I plan to improve it further. I'm commiting it so it will get wider exposure and review. We won't be able to MFC this work as it relies on changes in HEAD, which was introduced some time ago, that break kernel ABI. OTOH we may be able to merge the library with KVM backend if we really need it there. Discussed with: rwatson
Diffstat (limited to 'usr.bin/fstat')
-rw-r--r--usr.bin/fstat/Makefile20
-rw-r--r--usr.bin/fstat/cd9660.c79
-rw-r--r--usr.bin/fstat/fstat.c986
-rw-r--r--usr.bin/fstat/functions.h (renamed from usr.bin/fstat/fstat.h)56
-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/fstat/msdosfs.c150
-rw-r--r--usr.bin/fstat/zfs.c136
-rw-r--r--usr.bin/fstat/zfs/Makefile23
10 files changed, 817 insertions, 1199 deletions
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/cd9660.c b/usr.bin/fstat/cd9660.c
deleted file mode 100644
index 1c26e8d..0000000
--- a/usr.bin/fstat/cd9660.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2000 Peter Edwards
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by Peter Edwards
- *
- * 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.
- */
-
-/*
- * XXX -
- * This had to be separated from fstat.c because cd9660s has namespace
- * conflicts with UFS.
- */
-
-#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 <isofs/cd9660/cd9660_node.h>
-
-#include <kvm.h>
-#include <stdio.h>
-
-#include "fstat.h"
-
-int
-isofs_filestat(struct vnode *vp, struct filestat *fsp)
-{
- struct iso_node isonode;
-
- 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 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;
-}
-
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/fstat.h b/usr.bin/fstat/functions.h
index 3533a60..a23d27e 100644
--- a/usr.bin/fstat/fstat.h
+++ b/usr.bin/fstat/functions.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
@@ -28,49 +25,10 @@
*
* $FreeBSD$
*/
+#ifndef __FUNCTIONS_H__
+#define __FUNCTIONS_H__
-#ifndef __FSTAT_H__
-#define __FSTAT_H__
+int do_fstat(int argc, char *argv[]);
+int do_fuser(int argc, char *argv[]);
-/*
- * a kvm_read that returns true if everything is read
- */
-#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__ */
+#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/fstat/msdosfs.c b/usr.bin/fstat/msdosfs.c
deleted file mode 100644
index 7f80499..0000000
--- a/usr.bin/fstat/msdosfs.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (c) 2000 Peter Edwards
- * Copyright (c) 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by Peter Edwards
- *
- * 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/stat.h>
-#include <sys/vnode.h>
-
-#define _KERNEL
-#include <sys/mount.h>
-#include <fs/msdosfs/bpb.h>
-#include <fs/msdosfs/msdosfsmount.h>
-#undef _KERNEL
-
-#include <fs/msdosfs/denode.h>
-#include <fs/msdosfs/direntry.h>
-#include <fs/msdosfs/fat.h>
-
-#include <err.h>
-#include <kvm.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/*
- * XXX -
- * 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)
-
-#include "fstat.h"
-
-struct dosmount {
- struct dosmount *next;
- struct msdosfsmount *kptr; /* Pointer in kernel space */
- struct msdosfsmount data; /* User space copy of structure */
-};
-
-int
-msdosfs_filestat(struct vnode *vp, struct filestat *fsp)
-{
- struct denode denode;
- static struct dosmount *mounts;
- struct dosmount *mnt;
- 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;
- }
-
- /*
- * Find msdosfsmount structure for the vnode's filesystem. Needed
- * for some filesystem parameters
- */
- for (mnt = mounts; mnt; mnt = mnt->next)
- if (mnt->kptr == denode.de_pmp)
- break;
-
- if (!mnt) {
- if ((mnt = malloc(sizeof(struct dosmount))) == NULL)
- err(1, NULL);
- if (!KVM_READ(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;
- }
- 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;
-
- /* 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;
-
- /*
- * XXX -
- * Culled from msdosfs_vnops.c. There appears to be a problem
- * here, in that a directory has the same inode number as the first
- * file in the directory. stat(2) suffers from this problem also, so
- * I won't try to fix it here.
- *
- * The following computation of the fileid must be the same as that
- * used in msdosfs_readdir() to compute d_fileno. If not, pwd
- * doesn't work.
- */
- dirsperblk = mnt->data.pm_BytesPerSec / sizeof(struct direntry);
- if (denode.de_Attributes & ATTR_DIRECTORY) {
- fileid = cntobn(&mnt->data, denode.de_StartCluster)
- * dirsperblk;
- if (denode.de_StartCluster == MSDOSFSROOT)
- fileid = 1;
- } else {
- fileid = cntobn(&mnt->data, denode.de_dirclust) * dirsperblk;
- if (denode.de_dirclust == MSDOSFSROOT)
- fileid = roottobn(&mnt->data, 0) * dirsperblk;
- fileid += denode.de_diroffset / sizeof(struct direntry);
- }
-
- fsp->fileid = fileid;
- return 1;
-}
diff --git a/usr.bin/fstat/zfs.c b/usr.bin/fstat/zfs.c
deleted file mode 100644
index cdca41f..0000000
--- a/usr.bin/fstat/zfs.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*-
- * Copyright (c) 2007 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/param.h>
-#define _KERNEL
-#include <sys/mount.h>
-#include <sys/taskqueue.h>
-#undef _KERNEL
-#include <sys/sysctl.h>
-
-#undef lbolt
-#undef lbolt64
-#undef gethrestime_sec
-#include <sys/zfs_context.h>
-#include <sys/spa.h>
-#include <sys/spa_impl.h>
-#include <sys/dmu.h>
-#include <sys/zap.h>
-#include <sys/fs/zfs.h>
-#include <sys/zfs_znode.h>
-#include <sys/zfs_sa.h>
-
-#include <err.h>
-#include <kvm.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define ZFS
-#undef dprintf
-#include <fstat.h>
-
-/*
- * Offset calculations that are used to get data from znode without having the
- * definition.
- */
-#define LOCATION_ZID (2 * sizeof(void *))
-#define LOCATION_ZPHYS(zsize) ((zsize) - (2 * sizeof(void *) + sizeof(struct task)))
-
-int
-zfs_filestat(struct vnode *vp, struct filestat *fsp)
-{
-
- znode_phys_t zphys;
- struct mount mount, *mountptr;
- uint64_t *zid;
- void *znodeptr, *vnodeptr;
- char *dataptr;
- void *zphys_addr;
- size_t len;
- int size;
-
- len = sizeof(size);
- if (sysctlbyname("debug.sizeof.znode", &size, &len, NULL, 0) == -1) {
- dprintf(stderr, "error getting sysctl\n");
- return (0);
- }
- znodeptr = malloc(size);
- if (znodeptr == NULL) {
- dprintf(stderr, "error allocating memory for znode storage\n");
- return (0);
- }
-
- /* 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);
- goto bad;
- }
-
- /*
- * z_id field is stored in the third pointer. We therefore skip the two
- * first bytes.
- *
- * Pointer to the z_phys structure is the next last pointer. Therefore
- * go back two bytes from the end.
- */
- dataptr = znodeptr;
- 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);
- 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);
- goto bad;
- }
-
- fsp->fsid = (long)(uint32_t)mount.mnt_stat.f_fsid.val[0];
- fsp->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;
- free(znodeptr);
- return (1);
-bad:
- free(znodeptr);
- return (0);
-}
diff --git a/usr.bin/fstat/zfs/Makefile b/usr.bin/fstat/zfs/Makefile
deleted file mode 100644
index 7ecfc85..0000000
--- a/usr.bin/fstat/zfs/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/..
-
-SRCS= zfs.c
-OBJS= zfs.o
-WARNS?= 1
-
-CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
-CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
-CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
-CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
-CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
-CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
-CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
-CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
-CFLAGS+= -I${.CURDIR}/..
-CFLAGS+= -DNEED_SOLARIS_BOOLEAN
-
-all: ${OBJS}
-CLEANFILES= ${OBJS}
-
-.include <bsd.lib.mk>
OpenPOWER on IntegriCloud