summaryrefslogtreecommitdiff
path: root/usr.bin/fstat/fuser.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2009-07-08 16:04:01 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2009-07-08 16:04:01 +0000
commitdb88960d516b2c5ac6c28f48ad6f552239017182 (patch)
tree2eb62c4b472e6eab4b3b59c0b4c498be8772e383 /usr.bin/fstat/fuser.c
parentadaaa9d9490a77fc421f46a2b0f652b6d9c9199e (diff)
Add POSIX-compliant fuser mode to fstat. Originally based on
a diff from Peter Werner but largely rewritten to use kinfo_file2. OK deraadt@ with man fixes from jmc@ and sobrado@
Diffstat (limited to 'usr.bin/fstat/fuser.c')
-rw-r--r--usr.bin/fstat/fuser.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/usr.bin/fstat/fuser.c b/usr.bin/fstat/fuser.c
new file mode 100644
index 00000000000..3f146373d72
--- /dev/null
+++ b/usr.bin/fstat/fuser.c
@@ -0,0 +1,177 @@
+/* $OpenBSD: fuser.c,v 1.1 2009/07/08 16:04:00 millert Exp $ */
+
+/*
+ * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * 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/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#define _KERNEL /* for DTYPE_VNODE */
+#include <sys/file.h>
+#undef _KERNEL
+
+#include <err.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fstat.h"
+
+/*
+ * Returns 1 if the file watched (fa) is equivalent
+ * to a file held by a process (kf), else 0.
+ */
+static int
+match(struct filearg *fa, struct kinfo_file2 *kf)
+{
+ if (fa->dev == kf->va_fsid) {
+ if (cflg)
+ return (1);
+ if (fa->ino == kf->va_fileid)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Examine kinfo_file2 struct and record the details if they
+ * match a watched file.
+ */
+void
+fuser_check(struct kinfo_file2 *kf)
+{
+ struct filearg *fa;
+ struct fuser *fu;
+
+ if (kf->f_type != DTYPE_VNODE)
+ return;
+
+ SLIST_FOREACH(fa, &fileargs, next) {
+ if (!match(fa, kf))
+ continue;
+
+ /*
+ * This assumes that kinfo_files2 returns all files
+ * associated with a process in a contiguous block.
+ */
+ if (TAILQ_EMPTY(&fa->fusers) || kf->p_pid !=
+ (fu = TAILQ_LAST(&fa->fusers, fuserhead))->pid) {
+ fu = malloc(sizeof(*fu));
+ if (fu == NULL)
+ err(1, NULL);
+ fu->pid = kf->p_pid;
+ fu->uid = kf->p_uid;
+ fu->flags = 0;
+ TAILQ_INSERT_TAIL(&fa->fusers, fu, tq);
+ }
+ switch (kf->fd_fd) {
+ case KERN_FILE_CDIR:
+ fu->flags |= F_CWD;
+ break;
+ case KERN_FILE_RDIR:
+ fu->flags |= F_ROOT;
+ break;
+ case KERN_FILE_TRACE:
+ case KERN_FILE_TEXT:
+ /* ignore */
+ break;
+ default:
+ fu->flags |= F_OPEN;
+ break;
+ }
+ }
+}
+
+/*
+ * Print out the specfics for a given file/filesystem
+ */
+static void
+printfu(struct fuser *fu)
+{
+ struct passwd *pwd;
+
+ printf("%d", fu->pid);
+ fflush(stdout);
+
+ if (fu->flags & F_CWD)
+ fprintf(stderr, "c");
+
+ if (fu->flags & F_ROOT)
+ fprintf(stderr, "r");
+
+ if (uflg) {
+ pwd = getpwuid(fu->uid);
+ if (pwd != NULL)
+ fprintf(stderr, "(%s)", pwd->pw_name);
+ else
+ fprintf(stderr, "(%d)", fu->uid);
+ }
+
+ putchar(' ');
+}
+
+/*
+ * For each file, print matching process info and optionally send a signal.
+ */
+void
+fuser_run(void)
+{
+ struct filearg *fa;
+ struct fuser *fu;
+ pid_t mypid = getpid();
+
+ SLIST_FOREACH(fa, &fileargs, next) {
+ fprintf(stderr, "%s: ", fa->name);
+ TAILQ_FOREACH(fu, &fa->fusers, tq) {
+ printfu(fu);
+ if (sflg && fu->pid != mypid) {
+ kill(fu->pid, signo);
+ }
+ }
+ fflush(stdout);
+ fprintf(stderr, "\n");
+ }
+}