Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Jun 2003 16:14:27 +0200 (CEST)
From:      Lukas Ertl <l.ertl@univie.ac.at>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/53682: [PATCH] add fuser(1) utitity
Message-ID:  <200306241414.h5OEER3v016291@leelou.in.tern>
Resent-Message-ID: <200306241420.h5OEK7Pr085771@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         53682
>Category:       bin
>Synopsis:       [PATCH] add fuser(1) utitity
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun 24 07:20:07 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Lukas Ertl
>Release:        FreeBSD 5.1-CURRENT i386
>Organization:
Vienna University Computer Center
>Environment:
System: FreeBSD leelou 5.1-CURRENT FreeBSD 5.1-CURRENT #1: Sun Jun 22 12:56:44 CEST 2003 le@leelou:/usr/obj/usr/src/sys/LEELOU i386


	
>Description:

Although our fstat(1) provides the same functionality, POSIX requires an 
fuser(1) utility, which is still missing on FreeBSD.

>How-To-Repeat:
	
>Fix:

This patch was sent to me from tjr@ who has received it from Peter Werner
<peterw@ifost.org.au>.

I had to hack a bit to make it compile and run on FreeBSD.

--- fuser.diff begins here ---
diff -ruN /usr/src/usr.bin/fuser/Makefile usr.bin/fuser/Makefile
--- /usr/src/usr.bin/fuser/Makefile	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/Makefile	Tue Jun 24 15:52:01 2003
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+PROG= fuser
+SRCS= isofs.c filestat.c fuser.c 
+LDADD= -lkvm
+DPADD= ${LIBKVM}
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff -ruN /usr/src/usr.bin/fuser/filestat.c usr.bin/fuser/filestat.c
--- /usr/src/usr.bin/fuser/filestat.c	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/filestat.c	Tue Jun 24 16:01:49 2003
@@ -0,0 +1,201 @@
+/*-
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/vnode.h>
+#define	_KERNEL
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <fs/nullfs/null.h>
+#undef _KERNEL
+#include <nfs/nfsproto.h>
+#include <nfs/rpcv2.h>
+#include <nfsclient/nfs.h>
+#include <nfsclient/nfsnode.h>
+
+#include <kvm.h>
+#include <string.h>
+
+#include "fuser.h"
+
+udev_t dev2udev(struct cdev *dev);
+
+extern kvm_t *kd;
+
+int
+ufs_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+	struct inode inode;
+
+	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) 
+		return 0;
+
+	fi->fi_dev = dev2udev(inode.i_dev) & 0xffff;
+	fi->fi_inode = (long)inode.i_number;
+
+	return 1;
+}
+
+int
+ext2fs_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+	struct inode inode;
+
+	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) 
+		return 0;
+	
+	fi->fi_dev = dev2udev(inode.i_dev) & 0xffff;
+	fi->fi_inode = (long)inode.i_number;
+
+	return 1;
+}
+
+int
+msdos_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+#if 0
+	struct inode inode;
+
+	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) 
+		return 0;
+	
+	fi->fi_dev = inode.i_dev & 0xffff;
+	fi->fi_inode = (long)inode.i_number;
+#endif
+
+	return 1;
+}
+
+int
+nfs_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+	struct nfsnode nfsnode;
+	mode_t mode;
+
+	if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) 
+		return 0;
+	
+	
+	fi->fi_dev = nfsnode.n_vattr.va_fsid;
+	fi->fi_inode = nfsnode.n_vattr.va_fileid;
+
+	return 1;
+}
+
+int
+null_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+	struct null_node node;
+	struct fileinfo fis;
+	struct vnode vn;
+	char tagstr[12], *tagptr;
+	int fail = 1;
+
+	memset(&fis, 0, sizeof fis);
+
+	if (!KVM_READ(VTONULL(vp), &node, sizeof (node))) 
+		return 0;
+	
+
+	/*
+	 * Attempt to find information that might be useful.
+	 */
+	if (node.null_lowervp) {
+		if (!KVM_READ(node.null_lowervp, &vn, sizeof (vn))) 
+			return 0;
+		if (!KVM_READ(&node.null_lowervp->v_tag, &tagptr, sizeof tagptr))
+			return 0;
+		if (!KVM_READ(tagptr, tagstr, sizeof tagstr))
+			return 0;
+
+		tagstr[sizeof(tagstr) - 1] = '\0';
+		
+		fail = 0;
+		if (vn.v_type == VNON || vn.v_type == VBAD)
+			fail = 1;
+		else {
+			if (!strcmp("ufs", tagstr) || !strcmp("mfs", tagstr)) {
+				if (!ufs_filestat(&vn, &fis))
+					fail = 1;
+			} else if (!strcmp("nfs", tagstr)) {
+				if (!nfs_filestat(&vn, &fis))
+					fail = 1;
+			} else if (!strcmp("ext2fs", tagstr)) {
+				if (!ext2fs_filestat(&vn, &fis))
+					fail = 1;
+			} else if (!strcmp("isofs", tagstr)) {
+				if (!isofs_filestat(&vn, &fis))
+					fail = 1;
+			} else if (!strcmp("msdosfs", tagstr)) {
+				if (!msdos_filestat(&vn, &fis))
+					fail = 1;
+			}
+		}
+	}
+
+	fi->fi_dev = (long)node.null_vnode;
+	if (fail)
+		fi->fi_inode = (long)node.null_lowervp;
+	else
+		fi->fi_inode = fis.fi_inode;
+
+	return 1;
+}
+
+/*
+ * Read the cdev structure in the kernel
+ * in order to work out the associated udev_t
+ */
+udev_t
+dev2udev(struct cdev *dev)
+{
+	struct cdev si;
+	
+	if (KVM_READ(dev, &si, sizeof si)) {
+		return si.si_udev;
+	} else {
+		errx("can't convert dev_t %x to a udev_t\n", dev);
+		return -1;
+	}
+}
diff -ruN /usr/src/usr.bin/fuser/fuser.1 usr.bin/fuser/fuser.1
--- /usr/src/usr.bin/fuser/fuser.1	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/fuser.1	Wed Jun  4 19:24:41 2003
@@ -0,0 +1,124 @@
+.\" Copyright (c) 2002 Peter Werner <peterw@ifost.org.au>
+.\" 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. The name of the author may not be used to endorse or promote products
+.\"    derived from this software without specific prior written permission. 
+.\" 
+.\" THIS SOFTWARE IS PROVIDED ``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. 
+.Dd June 4, 2003
+.Dt FUSER 1
+.Os
+.Sh NAME
+.Nm fuser
+.Nd list process IDs holding specific files open 
+.Sh SYNOPSIS
+.Nm 
+.Op Fl cfu
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ar
+.Sh DESCRIPTION
+.Nm
+will write to standard output the process IDs of processes running on the 
+local system that have one or more of the named files open. 
+If
+.Ar file
+is a block device, and it has an equivalent
+.Xr fstab 5
+entry, the output will show all processes having files opened on that file
+system. 
+.Pp
+The options are as follows:
+.Bl -tag -width Ds 
+.It Fl c
+The file is treated as a mount point and 
+.Nm
+will report on any files open in the file system.
+.It Fl f
+The report shall be only for the named file(s).
+.It Fl u
+The username associated with each process ID using the file will be printed 
+in parentheses to standard error.
+If the username is unable to be determined, the real user id will be printed
+instead. 
+.It Fl M Ar core
+Extract values associated with the name list from the specified core
+instead of the running kernel.
+.It Fl N Ar system
+Extract the name list from the specified system instead of the running kernel.
+.El
+.Pp
+The
+.Fl c
+and
+.Fl f
+options are mutually exclusive.
+.Pp
+The name of the file followed by a colon
+.Pq Sq \&:
+will be printed to standard error.
+The following characters may be printed to standard error after the process id
+if the described conditions are true:
+.Bl -tag -width Ds
+.It r
+The file is the processes root directory.
+.It c
+The file is the processes current working directory.
+.El
+.Pp
+.Sh EXAMPLES
+.Cm $ fuser -c /mnt
+.Pp
+This will print the process id's of any processes holding files open under the
+.Ar /mnt
+filesystem. 
+.Pp
+.Cm # fuser -c /mnt 2> /dev/null \&| xargs kill 
+.Sy -TERM
+.Pp
+This will result in any process holding a file open under the
+.Ar /mnt
+filesystem being sent SIGTERM (unless a process releases the file in the time
+it takes
+.Nm
+to exit and
+.Xr kill 1
+to run).
+.Pp
+.Cm $ fuser /dev/ad0s1a
+.Pp
+.Nm
+will report on all files opened under the filesystem on which
+.Ar /dev/ad0s1a
+is mounted on.
+.Pp
+.Cm $ fuser -f /dev/ad0s1a
+.Pp
+.Nm
+will report on all processes currently holding
+.Ar /dev/ad0s1a
+open.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits 0 on success or >0 if an error occured.
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr kill 1 ,
+.Xr signal 3 ,
+.Xr fstab 5
diff -ruN /usr/src/usr.bin/fuser/fuser.c usr.bin/fuser/fuser.c
--- /usr/src/usr.bin/fuser/fuser.c	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/fuser.c	Tue Jun 24 16:01:35 2003
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2002 Peter Werner <peterw@ifost.org.au>
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <sys/param.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/filedesc.h>
+#define _KERNEL
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#undef _KERNEL
+#include <err.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <kvm.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fuser.h"
+
+struct f_file {
+	SLIST_ENTRY(f_file) f_next;
+	dev_t f_dev;
+	ino_t f_file;
+	char *f_name;
+	uid_t *f_uids;
+	pid_t *f_pids;
+	int   *f_flags;
+#define F_ROOT 0x01 	/* is procs root directory */
+#define F_CWD  0x02	/* is procs cwd */
+#define F_OPEN 0x04	/* just has it open */
+	int f_nuids;
+};
+
+struct fproc {
+	uid_t fp_uid;
+	pid_t fp_pid;
+	struct file **fp_fvec;
+	int fp_nfiles;
+	struct vnode *fp_cdir;
+	struct vnode *fp_rdir;
+};
+
+int 		 getprocfdtable(struct kinfo_proc *kp, struct fproc *);
+int 		 filecwd(struct f_file *ff, struct fproc *);
+int 		 fileroot(struct f_file *ff, struct fproc *);
+int 		 fileopened(struct f_file *ff, struct fproc *);
+int 		 match(struct f_file *ff, struct fileinfo *fi);
+struct f_file	*alloc_file(char *);
+void 		 check(struct kinfo_proc *);
+struct fileinfo *getfileinfo(struct vnode *);
+void 		 print(void);
+void 		 printff(struct f_file *, int);
+void		 usage(void);
+
+kvm_t *kd;
+SLIST_HEAD(, f_file) filelist;
+int nprocs = 0; /* # of processes given to us by kvm_getprocs() */ 
+int uflag = 0; /* print usernames to stderr */
+int cflag = 0; /* find all files open under this device */
+int fflag = 0; /* mainly for show */
+int error = 0; /* exit > 0 on error */
+extern char *__progname;
+
+/*
+ * list process IDs of all processes that have one or more files open
+ */ 
+int
+main(int argc, char **argv)
+{
+	char errbuf[_POSIX2_LINE_MAX];
+	char *memf, *nlistf;
+	struct kinfo_proc *kp;
+	int i, ch; 
+	struct f_file *ff;
+
+	memf = nlistf = NULL;
+	SLIST_INIT(&filelist);
+
+	while ((ch = getopt(argc, argv, "cufN:M:")) != -1)
+		switch(ch) {
+		case 'c':
+			cflag = 1;
+			break;
+		case 'u':
+			uflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			break;
+		case 'M':
+			memf = optarg;
+			break;
+		case 'N':
+			nlistf = optarg;
+			break;
+		default:
+			usage();
+		}
+
+	if (fflag && cflag) {
+		fprintf(stderr, "%s: 'f' and 'c' cannot be used together\n", 
+		    __progname);
+		usage();
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	if (argc == 0)
+		usage();
+
+	if (nlistf != NULL || memf != NULL) {
+		setegid(getgid());
+		setgid(getgid());
+	}
+
+	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+	if (kd == NULL)
+		errx(1, "%s", errbuf);
+
+	setgid(getgid());
+	
+	kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nprocs);
+	if (kp == NULL)
+		errx(1, "%s", kvm_geterr(kd));
+
+	for (i = 0; argv[i] != NULL && i < argc; i++) {
+		ff = alloc_file(argv[i]);
+		if (ff == NULL) {
+			error++;
+			warn("%s", argv[i]);
+			continue;
+		}
+		SLIST_INSERT_HEAD(&filelist, ff, f_next);
+	}
+		
+	for (i = 0; i < nprocs; ++kp, i++) {
+		if (kp->ki_stat == SZOMB)
+			continue;
+		
+		check(kp);
+	}
+
+	kvm_close(kd);
+	
+	print();
+
+	return(error);
+}
+
+/*
+ * print out all the information we have gathered
+ */
+void
+print(void)
+{
+	struct f_file *ff;
+	int i;
+
+	SLIST_FOREACH(ff, &filelist, f_next) {
+		fprintf(stderr, "%s: ", ff->f_name);
+		for (i = 0; i < ff->f_nuids; i++) 
+			if (ff->f_flags[i] != 0) 
+				printff(ff, i);	
+		
+		fflush(stdout);
+		fprintf(stderr, "\n");
+	}
+
+	return;
+}
+
+/*
+ * print out the specfics for a given file/filesystem
+ */
+void
+printff(struct f_file *ff, int i)
+{
+	struct passwd *pwd;
+
+	printf("%d", ff->f_pids[i]);	
+	fflush(stdout);
+
+	if (ff->f_flags[i] & F_CWD)
+		fprintf(stderr, "c");
+
+	if (ff->f_flags[i] & F_ROOT)
+		fprintf(stderr, "r");
+
+	if (uflag) {
+		pwd = getpwuid(ff->f_uids[i]);
+		if (pwd != NULL)
+			fprintf(stderr, "(%s)", pwd->pw_name);
+		else
+			fprintf(stderr, "(%d)", ff->f_uids[i]);
+	}
+
+	putchar(' ');
+}
+	
+struct fproc *
+alloc_fproc(struct kinfo_proc *kp)
+{
+	struct fproc *fp;
+
+	fp = malloc(sizeof(struct fproc));
+	if (fp == NULL)
+		return(NULL);
+
+	memset(fp, 0, sizeof(struct fproc));
+	fp->fp_pid = kp->ki_pid;
+	fp->fp_uid = kp->ki_ruid;
+
+	return(fp);
+}
+
+/*
+ * return 1 if the file watched (ff) is
+ * equivalent to a file held by a process (fi)
+ */
+int 
+match(struct f_file *ff, struct fileinfo *fi)
+{
+	if (fi->fi_dev == ff->f_dev) {
+		if (cflag)
+			return(1);
+		if (fi->fi_inode == ff->f_file)
+			return(1);			
+	}
+
+	return(0);
+}
+	
+/*
+ * examine all files held open by a process and record the details if they 
+ * are of interest to us.
+ */
+void 
+check(struct kinfo_proc *kp)
+{
+	struct f_file *ff;
+	struct fproc *fp;
+
+	fp = alloc_fproc(kp);
+	if (fp == NULL) {
+		error++;
+		warn("alloc fp");
+		return;
+	}
+
+	if (!getprocfdtable(kp, fp))
+		return;
+
+	SLIST_FOREACH(ff, &filelist, f_next) {
+		
+		ff->f_uids[ff->f_nuids] = fp->fp_uid;
+		ff->f_pids[ff->f_nuids] = fp->fp_pid;
+
+		if (fileopened(ff, fp)) 
+			ff->f_flags[ff->f_nuids] |= F_OPEN;
+
+		if (fileroot(ff, fp))
+			ff->f_flags[ff->f_nuids] |= F_ROOT;
+
+		if (filecwd(ff, fp))
+			ff->f_flags[ff->f_nuids] |= F_CWD;
+
+		ff->f_nuids++;
+	}
+
+}
+
+/*
+ * see if the process (fp) has a specific file (ff) opened
+ */
+int
+fileopened(struct f_file *ff, struct fproc *fp)
+{
+	struct file f;
+	struct fileinfo *fi;
+	int i;
+
+	for (i = 0; i < fp->fp_nfiles; i++) {
+			
+		if (fp->fp_fvec[i] == NULL)
+			continue;
+
+		if (!KVM_READ(fp->fp_fvec[i], &f, sizeof(f))) 
+			continue;
+
+		if (f.f_type != DTYPE_VNODE)
+			continue;
+
+		fi = getfileinfo((struct vnode *)f.f_data);
+		if (fi == NULL) 
+			continue;
+
+		if (match(ff, fi))
+			return(1);
+
+	}
+
+	return(0);
+}
+			
+/*
+ * see if a processes (fp) root directory is a file we're interested in (ff)
+ */
+int
+fileroot(struct f_file *ff, struct fproc *fp)
+{
+	struct fileinfo *fi;
+	
+	if (fp->fp_rdir == NULL)
+		return(0);
+
+	fi = getfileinfo(fp->fp_rdir);
+	if (fi == NULL) 
+		return(0);
+
+	return(match(ff, fi));
+}
+
+/*
+ * see if a processes current working directory is a file we're interested in
+ */
+int
+filecwd(struct f_file *ff, struct fproc *fp)
+{
+	struct fileinfo *fi;
+
+	if (fp->fp_cdir == NULL)
+		return(0);
+
+	fi = getfileinfo(fp->fp_cdir);
+	if (fi == NULL) 
+		return(0);
+
+	return(match(ff, fi));
+}
+
+/*
+ * read in a processes filedesc table
+ */
+int
+getprocfdtable(struct kinfo_proc *kp, struct fproc *fp)
+{
+	struct filedesc0 filed0;
+	int nfiles;
+	struct file **fvec;
+#define filed	filed0.fd_fd
+
+	if (kp->ki_fd == NULL)
+		return;
+
+	if (!KVM_READ(kp->ki_fd, &filed0, sizeof(filed0))) 
+		return(0);
+
+	nfiles = filed.fd_lastfile + 1;
+	fvec = calloc(nfiles, sizeof(struct file *));
+	if (fvec == NULL)
+		return(0);
+	
+	memset(fvec, 0, nfiles * sizeof(struct file *));
+
+	if (filed.fd_nfiles < 0 || filed.fd_lastfile >= filed.fd_nfiles ||
+			filed.fd_freefile > filed.fd_lastfile + 1) {
+		fprintf(stderr, "filedesc corrupted for pid %d", kp->ki_pid);
+		return(0);
+	}
+
+	/*
+	 * since we dont bother with filedesc0, just read from kvm
+	 */
+	if (!KVM_READ(filed.fd_ofiles, fvec, nfiles * sizeof(struct file *)))
+		return(0);
+
+	fp->fp_rdir = filed.fd_rdir;
+	fp->fp_cdir = filed.fd_cdir;
+	fp->fp_fvec = fvec;
+	fp->fp_nfiles = nfiles;
+
+	return(1);
+} 
+	
+/*
+ * return pertinent information for the vnode located in kmem at address v
+ */
+struct fileinfo *
+getfileinfo(struct vnode *vp)
+{
+	struct fileinfo *fi;
+	struct vnode vn;
+	char tagstr[12], *tagptr;
+	
+	fi = malloc(sizeof(struct fileinfo));
+	if (fi == NULL) {
+		error++;
+		warn("malloc failed");
+		return(NULL);
+	}
+
+	if (!KVM_READ(vp, &vn, sizeof(struct vnode))) {
+		error++;
+		warnx("rd vnode %s", kvm_geterr(kd));
+		return(NULL);
+	}
+	if (!KVM_READ(&vp->v_tag, &tagptr, sizeof tagptr)) {
+		error++;
+		warnx("rd vtag %s", kvm_geterr(kd));
+		return(NULL);
+	}
+	if (!KVM_READ(tagptr, tagstr, sizeof tagstr)) {
+		error++;
+		warnx("rd tagptr %s", kvm_geterr(kd));
+		return(NULL);
+	}
+
+	tagstr[sizeof(tagstr) - 1] = '\0';
+	
+	if (vn.v_type == VBAD || vn.v_type == VNON)
+		return(NULL);
+
+	if (!strcmp("ufs", tagstr) || !strcmp("mfs", tagstr)) {
+		if (!ufs_filestat(&vn, fi))
+			return (NULL);
+	} else if (!strcmp("nfs", tagstr)) {
+		if (!nfs_filestat(&vn, fi))
+			return (NULL);
+	} else if (!strcmp("ext2fs", tagstr)) {
+		if (!ext2fs_filestat(&vn, fi))
+			return (NULL);
+	} else if (!strcmp("isofs", tagstr)) {
+		if (!isofs_filestat(&vn, fi))
+			return (NULL);
+	} else if (!strcmp("msdosfs", tagstr)) {
+		if (!msdos_filestat(&vn, fi))
+			return (NULL);
+	} else if (!strcmp("nullfs", tagstr)) {
+		if (!null_filestat(&vn, fi))
+			return(NULL);
+	}
+
+	return(fi);
+}
+
+struct f_file *
+alloc_file(char *fname)
+{
+	int i;
+	struct f_file *ff;
+	struct stat sb;
+	struct fstab *fstp;
+
+	ff = malloc(sizeof(struct f_file));
+	if (ff == NULL)
+		return(NULL);
+	
+	memset(ff, 0, sizeof(struct f_file));
+
+	i = stat(fname, &sb); 
+	if (i == -1) {
+		free(ff);
+		return(NULL);
+	}
+
+	/*
+	 * not too sure what to do here, the spec states 'For block special
+	 * devices, all processes using any file on that device are listed' and
+	 * then on the -f option 'The report shall be only for the named
+	 * files.' so what happens if you do 'fuser -f <blk dev>'? currently -f 
+	 * will be only for the block device, while 'fuser <blk dev>' will show
+	 * all processes under that filesystem (if its in /etc/fstab).
+	 */ 
+	if (sb.st_mode & S_IFBLK && fflag == 0) {
+		fstp = getfsspec(fname);
+		if (fstp != NULL) { 
+			i = stat(fstp->fs_file, &sb);
+			if (i == -1) {
+				free(ff);
+				return(NULL);
+			}
+			cflag = 1;
+		}
+	}
+
+	ff->f_file = sb.st_ino;
+	ff->f_dev = sb.st_dev & 0xffff;
+		
+	/*
+	 * calloc will memset for us regardless of /etc/malloc.conf
+	 */
+	ff->f_uids = calloc(nprocs + 1, sizeof(uid_t));
+	if (ff->f_uids == NULL) {
+		free(ff);
+		return(NULL);
+	}
+
+	ff->f_pids = calloc(nprocs + 1, sizeof(pid_t));	
+	if (ff->f_pids == NULL) {
+		free(ff->f_uids);
+		free(ff);
+		return(NULL);
+	}
+
+	ff->f_flags = calloc(nprocs + 1, sizeof(int));
+	if (ff->f_flags == NULL) {
+		free(ff->f_pids);
+		free(ff->f_uids);
+		free(ff);
+		return(NULL);
+	}
+
+	ff->f_name = strdup(fname);
+	if (ff->f_name == NULL) {
+		free(ff->f_flags);
+		free(ff->f_pids);
+		free(ff->f_uids);
+		free(ff);
+		return(NULL);
+	}	
+
+	ff->f_nuids = 0;
+	
+	return(ff);
+}
+
+void
+usage(void)
+{
+	fprintf(stderr, "%s: [ -cfu ] [ -M core ] [ -N system ] file ...\n", 
+	    __progname);
+	exit(1);
+}
diff -ruN /usr/src/usr.bin/fuser/fuser.h usr.bin/fuser/fuser.h
--- /usr/src/usr.bin/fuser/fuser.h	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/fuser.h	Wed Jun  4 18:50:39 2003
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2002 Peter Werner <peterw@ifost.org.au>
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED ``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. 
+ */
+#ifndef __fuser_h
+#define __fuser_h
+
+#include <sys/types.h>
+
+struct fileinfo {
+	dev_t fi_dev;
+	ino_t fi_inode;
+};
+
+/*
+ * functions from fstat
+ */
+int ufs_filestat(struct vnode *, struct fileinfo *);
+int ext2fs_filestat(struct vnode *, struct fileinfo *);
+int isofs_filestat(struct vnode *, struct fileinfo *);
+int msdos_filestat(struct vnode *, struct fileinfo *);
+int nfs_filestat(struct vnode *, struct fileinfo *);
+int null_filestat(struct vnode *, struct fileinfo *);
+
+/*
+ * a kvm_read that returns true if everything is read
+ */
+#define KVM_READ(kaddr, paddr, len) \
+	(kvm_read(kd, (u_long)(kaddr), (void *)(paddr), (len)) == (len))
+
+#endif /* ! __fuser_h */
diff -ruN /usr/src/usr.bin/fuser/isofs.c usr.bin/fuser/isofs.c
--- /usr/src/usr.bin/fuser/isofs.c	Thu Jan  1 01:00:00 1970
+++ usr.bin/fuser/isofs.c	Tue Jun 24 16:02:23 2003
@@ -0,0 +1,64 @@
+/*-
+ * 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/vnode.h>
+#include <sys/sysctl.h>
+#define	_KERNEL
+#include <sys/mount.h>
+#undef _KERNEL
+
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/cd9660_node.h>
+
+#include <kvm.h>
+
+#include "fuser.h"
+
+extern kvm_t *kd;
+
+int
+isofs_filestat(struct vnode *vp, struct fileinfo *fi)
+{
+	struct iso_node inode;
+
+	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) 
+		return 0;
+	
+	fi->fi_dev = inode.i_dev & 0xffff;
+	fi->fi_inode = (long)inode.i_number;
+	return 1;
+}
--- fuser.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200306241414.h5OEER3v016291>