svn commit: r195488 - projects/libprocstat/usr.bin/fstat
Stanislav Sedov
stas at FreeBSD.org
Thu Jul 9 09:46:35 UTC 2009
Author: stas
Date: Thu Jul 9 09:46:34 2009
New Revision: 195488
URL: http://svn.freebsd.org/changeset/base/195488
Log:
- Add files forgotten in yesterday commit.
Added:
projects/libprocstat/usr.bin/fstat/fuser.1
projects/libprocstat/usr.bin/fstat/fuser.c
Added: projects/libprocstat/usr.bin/fstat/fuser.1
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/libprocstat/usr.bin/fstat/fuser.1 Thu Jul 9 09:46:34 2009 (r195488)
@@ -0,0 +1,141 @@
+.\" Copyright (c) 2005 Stanislav Sedov <ssedov at mbsd.msk.ru>
+.\" 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.
+.\"
+.\" $Id: fuser.1,v 1.3 2005/08/29 12:07:19 stas Exp $
+.\"
+.Dd August 24, 2005
+.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 C Ar core
+.Op Fl K Ar kernel
+.Op Fl s Ar signal
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility shall write to stdout the process IDs 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 for that process or controlling tty
+of the process.
+If
+.Fl m
+option is specified, the
+.Nm
+utility will search through mmapped files also.
+.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
+Report on mmapped files too.
+.It Fl u
+Write the user name, associated with each process, to stdout.
+.It Fl C
+Use given kernel core file instead of default
+.Pa /dev/kmem .
+.It Fl K
+Use specified kernel image instead of the default one,
+which is the 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.
+Currently, not all filesystems are supported.
+.Sh AUTHORS
+The
+.Nm
+utility and this manual page was contributed by
+.An Stanislav Sedov Aq ssedov at mbsd.msk.ru .
Added: projects/libprocstat/usr.bin/fstat/fuser.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/libprocstat/usr.bin/fstat/fuser.c Thu Jul 9 09:46:34 2009 (r195488)
@@ -0,0 +1,755 @@
+/*-
+ * Copyright (c) 2005,2009 Stanislav Sedov <stas at 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+#include <sysexits.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <assert.h>
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+#include <sys/filedesc.h>
+#include <sys/queue.h>
+#include <sys/tty.h>
+#define _WANT_FILE
+#include <sys/conf.h>
+#include <sys/file.h>
+#define _KERNEL
+#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+#undef _KERNEL
+
+#include <vm/vm.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+
+#include "common.h"
+#include "functions.h"
+
+/*
+ * Local types
+ */
+
+enum {REQFILE, REQDEV, REQMNT}; /* Type of requested file */
+typedef struct reqfile {
+ ino_t ino;
+ dev_t dev;
+ const char *fname;
+ int type;
+ SLIST_ENTRY(reqfile) next;
+} reqfile_t;
+typedef SLIST_HEAD(, finfo) fds_head_t; /* List of opened files */
+
+typedef struct pinfo {
+ pid_t pid;
+ uid_t uid;
+ fds_head_t fds;
+ SLIST_ENTRY(pinfo) next;
+} pinfo_t;
+
+typedef struct finfo{
+ struct filestat stat;
+ int uflags; /* How this file is used */
+ SLIST_ENTRY(finfo) next;
+} finfo_t;
+
+/*
+ * Local definitions
+ */
+
+/* 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) */
+
+/* Macros for freeing SLISTs, probably must be in /sys/queue.h */
+#define SLIST_FREE(head, field, freef) do { \
+ typeof(SLIST_FIRST(head)) __elm0; \
+ typeof(SLIST_FIRST(head)) __elm; \
+ SLIST_FOREACH_SAFE(__elm, (head), field, __elm0) \
+ (void)(freef)(__elm); \
+} while(0);
+
+/* File's usage flags */
+#define UFL_RDIR 0x0001 /* root dir */
+#define UFL_CDIR 0x0002 /* cwd */
+#define UFL_JDIR 0x0004 /* jail root */
+#define UFL_TRACEP 0x0008 /* trace vnode */
+#define UFL_TEXTVP 0x0010 /* text(executable) file */
+#define UFL_CTTY 0x0020 /* contolling tty */
+#define UFL_MMAP 0x0040 /* file is mmapped */
+#define UFL_FREAD 0x0080 /* file opened for reading */
+#define UFL_FWRITE 0x0100 /* file opened for writing */
+#define UFL_FAPPEND 0x0200 /* file opened as append-only */
+#define UFL_FDIRECT 0x0400 /* file bypasses fs cache */
+#define UFL_FSHLOCK 0x0800 /* shared lock is obtained */
+#define UFL_FEXLOCK 0x1000 /* exclusive lock is obtained */
+
+struct {
+ int val;
+ char ch;
+} uflags[] = {
+ {UFL_RDIR, 'r'},
+ {UFL_JDIR, 'j'},
+ {UFL_CDIR, 'c'},
+ {UFL_TRACEP, 't'},
+ {UFL_TEXTVP, 'x'},
+ {UFL_CTTY, 'y'},
+ {UFL_MMAP, 'm'},
+ {UFL_FWRITE, 'w'},
+ {UFL_FAPPEND, 'a'},
+ {UFL_FDIRECT, 'd'},
+ {UFL_FSHLOCK, 's'},
+ {UFL_FEXLOCK, 'e'},
+};
+#define NUFLAGS (sizeof(uflags) / sizeof(*uflags))
+
+/* Filesystem-specific handlers */
+#define FSTYPE(fst) {#fst, fst##_filestat}
+struct {
+ const char *tag;
+ int (*handler)(kvm_t *kd, struct vnode *vp, struct filestat *fsp);
+} fstypes[] = {
+ FSTYPE(ufs),
+ FSTYPE(devfs),
+ FSTYPE(nfs),
+ FSTYPE(msdosfs),
+ FSTYPE(isofs),
+/*
+ FSTYPE(ntfs),
+ FSTYPE(nwfs),
+ FSTYPE(smbfs),
+ FSTYPE(udf),
+*/
+};
+#define NTYPES (sizeof(fstypes) / sizeof(*fstypes))
+
+/*
+ * Global vars
+ */
+
+kvm_t *kd; /* KVM descriptors */
+static int flags = 0; /* Option flags */
+
+/* List of requested files */
+static SLIST_HEAD(, reqfile) rfiles = SLIST_HEAD_INITIALIZER(&rfiles);
+
+/* List of current processes */
+static SLIST_HEAD(, pinfo) prclist = SLIST_HEAD_INITIALIZER(&prclist);
+
+/*
+ * Prototypes
+ */
+static const struct vnode *get_ctty \
+ __P((const struct kinfo_proc *p));
+static int vp2finfo \
+ __P((const struct vnode *vp, fds_head_t *h, int fl));
+static void print_file_info \
+ __P((pid_t pid, uid_t uid, int ufl));
+static int add_mmapped \
+ __P((const struct kinfo_proc *p, fds_head_t *head));
+static int str2sig \
+ __P((const char *str));
+static void usage \
+ __P((void)) __dead2;
+static int gather_pinfo \
+ __P((const struct kinfo_proc *p));
+static int addfile \
+ __P((const char *path));
+static int add_ofiles \
+ __P((const struct filedesc *fd, fds_head_t *head));
+static int get_uflags \
+ __P((const reqfile_t *rfile, const pinfo_t *pinfo));
+static void pinfo_free \
+ __P((pinfo_t *pinfo));
+int main \
+ __P((int argc, char *argv[]));
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: %s [-cfkmu] [-C core] [-K kernel]" \
+ " [-s signal] file ...\n", getprogname());
+
+ exit(EX_USAGE);
+}
+
+void
+print_file_info(pid, uid, ufl)
+ pid_t pid;
+ uid_t uid;
+ int ufl;
+{
+ uint i;
+
+ (void)fprintf(stdout, "%6d", pid);
+ (void)fflush(stdout);
+
+ for (i = 0; i < NUFLAGS; i++)
+ if ((ufl & uflags[i].val) != 0)
+ (void)fprintf(stderr, "%c", uflags[i].ch);
+
+ if ((flags & UFLAG) != 0)
+ (void)fprintf(stderr,"(%s)", user_from_uid(uid, 0));
+
+ (void)fflush(stderr);
+}
+
+/*
+ * Add file to the list.
+ */
+static int
+addfile(path)
+ const char *path;
+{
+ struct stat sb;
+ int type;
+ reqfile_t *rfile;
+
+ assert(path);
+
+ if (stat(path, &sb) != 0) {
+ warn("%s", path);
+ return 1;
+ }
+
+ rfile = (reqfile_t *)malloc(sizeof(reqfile_t));
+ if (rfile == NULL)
+ err(EX_OSERR, "malloc()");
+
+ type = sb.st_mode & S_IFMT;
+
+ rfile->ino = sb.st_ino;
+ rfile->dev = sb.st_dev;
+ rfile->fname = path;
+
+ if ((flags & CFLAG) != 0)
+ rfile->type = REQMNT;
+ else if ((type == S_IFCHR || type == S_IFBLK) && ((flags & FFLAG) == 0))
+ rfile->type = REQDEV;
+ else
+ rfile->type = REQFILE;
+
+ SLIST_INSERT_HEAD(&rfiles, rfile, next);
+
+ return 0;
+}
+
+/*
+ * The purpose of this routine is to walk through list of fds, opened
+ * by a given process and add suitable entries to list.
+ */
+static int
+add_ofiles(fd, head)
+ const struct filedesc *fd;
+ fds_head_t *head;
+{
+ struct file **ofiles;
+ struct file file;
+ int nfiles;
+ int ufl;
+ uint i;
+
+ assert(head);
+ assert(fd);
+
+ nfiles = (fd->fd_lastfile + 1);
+ if (nfiles <= 0) {
+ return 1;
+ }
+
+#define OFSIZE (nfiles * sizeof(*ofiles))
+ ofiles = (struct file **)malloc(OFSIZE);
+ if (ofiles == NULL)
+ err(EX_OSERR, "malloc()");
+
+ if (!kvm_read_all(kd, (unsigned long)fd->fd_ofiles, ofiles, OFSIZE)) {
+ warnx("can't read file structures at %p", fd->fd_ofiles);
+
+ free(ofiles);
+ return 1;
+ }
+#undef OFSIZE
+
+ for (i = 0; i < (unsigned)nfiles; i++) {
+ if (ofiles[i] == 0)
+ continue;
+
+ if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
+ sizeof(file))) {
+ warnx("can't read file structure at %p", ofiles[i]);
+ continue;
+ }
+
+ ufl = 0;
+ if ((file.f_flag & FREAD) != 0)
+ ufl |= UFL_FREAD;
+ if ((file.f_flag & FWRITE) != 0)
+ ufl |= UFL_FWRITE;
+ if ((file.f_flag & O_APPEND) != 0)
+ ufl |= UFL_FAPPEND;
+ if ((file.f_flag & O_DIRECT) != 0)
+ ufl |= UFL_FDIRECT;
+ if ((file.f_flag & O_SHLOCK) != 0)
+ ufl |= UFL_FSHLOCK;
+ if ((file.f_flag & O_EXLOCK) != 0)
+ ufl |= UFL_FEXLOCK;
+
+ switch (file.f_type) {
+ case DTYPE_VNODE:
+ case DTYPE_FIFO:
+ (void)vp2finfo(file.f_vnode, head, ufl);
+
+ default:
+ continue;
+ }
+ }
+
+ free(ofiles);
+
+ return 0;
+}
+
+/*
+ * This routine returns controlling tty of the process, if exist.
+ */
+const struct vnode *
+get_ctty(p)
+ const struct kinfo_proc *p;
+{
+ struct proc proc;
+ struct pgrp pgrp;
+ struct session sess;
+
+ assert(p);
+ if (!kvm_read_all(kd, (unsigned long)p->ki_paddr, &proc,
+ sizeof(proc))) {
+ warnx("can't read proc struct at %p for pid %d", \
+ p->ki_paddr, p->ki_pid);
+ return NULL;
+ }
+
+ if (proc.p_pgrp == NULL)
+ return NULL;
+
+ if (!kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp, sizeof(pgrp))) {
+ warnx("can't read pgrp struct at %p for pid %d", \
+ proc.p_pgrp, p->ki_pid);
+ return NULL;
+ }
+
+ if (!kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
+ sizeof(sess))) {
+ warnx("can't read session struct at %p for pid %d", \
+ pgrp.pg_session, p->ki_pid);
+ return NULL;
+ }
+
+ return sess.s_ttyvp;
+}
+
+/*
+ * The purpose of this routine is to build the entire pinfo structure for
+ * given process. The structure's pointer will be inserted in the list.
+ */
+int
+gather_pinfo(p)
+ const struct kinfo_proc *p;
+{
+ struct filedesc fd_info;
+ pinfo_t *pinfo;
+
+ assert(p);
+ if (p->ki_stat == SZOMB || p->ki_fd == NULL)
+ return 1;
+
+ if (!kvm_read_all(kd, (unsigned long)p->ki_fd, &fd_info,
+ sizeof(fd_info))) {
+ warnx("can't read open file's info at %p for pid %d", \
+ p->ki_fd, p->ki_pid);
+ return 1;
+ }
+
+ pinfo = (pinfo_t *)malloc(sizeof(pinfo_t));
+ if (pinfo == NULL)
+ err(EX_OSERR, "malloc()");
+
+ pinfo->pid = p->ki_pid;
+ pinfo->uid = p->ki_uid;
+ SLIST_INIT(&pinfo->fds);
+
+ /* Add files from process's open fds list */
+ (void)add_ofiles(&fd_info, &pinfo->fds);
+
+ if ((flags & MFLAG) != 0)
+ (void)add_mmapped(p, &pinfo->fds);
+
+ (void)vp2finfo(p->ki_tracep, &pinfo->fds, \
+ UFL_FREAD|UFL_FWRITE|UFL_TRACEP);
+
+ (void)vp2finfo(p->ki_textvp, &pinfo->fds, UFL_FREAD|UFL_TEXTVP);
+
+ (void)vp2finfo(get_ctty(p), &pinfo->fds, UFL_CTTY);
+
+ (void)vp2finfo(fd_info.fd_rdir, &pinfo->fds, UFL_FREAD|UFL_RDIR);
+
+ (void)vp2finfo(fd_info.fd_cdir, &pinfo->fds, UFL_FREAD|UFL_CDIR);
+
+ (void)vp2finfo(fd_info.fd_jdir, &pinfo->fds, UFL_FREAD|UFL_JDIR);
+
+ SLIST_INSERT_HEAD(&prclist, pinfo, next);
+
+ return 0;
+}
+
+/*
+ * Insert finfo structure for given vnode into the list
+ */
+static int
+vp2finfo(vp, head, ufl)
+ const struct vnode *vp;
+ fds_head_t *head;
+ int ufl;
+{
+ struct vnode vn;
+ finfo_t *finfo;
+ char tag[8]; /* Max expected fs name length */
+ uint found, i;
+
+ assert(head);
+ if (vp == NULL)
+ return 1;
+
+ finfo = (finfo_t *)malloc(sizeof(finfo_t));
+ if (finfo == NULL)
+ err(EX_OSERR, "malloc()");
+
+ if (!kvm_read_all(kd, (unsigned long)vp, &vn, sizeof(vn))) {
+ warnx("can't read vnode at %p", vp);
+ return 1;
+ }
+
+ if (!kvm_read_all(kd, (unsigned long)vn.v_tag, &tag, sizeof(tag))) {
+ warnx("can't read v_tag at %p", vp);
+ return 1;
+ }
+ tag[sizeof(tag) - 1] = 0;
+
+ if (vn.v_type == VNON || vn.v_type == VBAD)
+ return 1;
+
+ for (i = 0, found = 0; i < NTYPES; i++)
+ if (!strcmp(fstypes[i].tag, tag)) {
+ if (fstypes[i].handler(kd, &vn, &(finfo->stat)) != 0)
+ return 1;
+ found = 1;
+ break;
+ }
+ if (found == 0)
+ return 1;
+
+ finfo->uflags = ufl;
+ SLIST_INSERT_HEAD(head, finfo, next);
+
+ return 0;
+}
+
+/*
+ * This routine walks through linked list of opened files and gathers
+ * informations how given file is used.
+ */
+static int
+get_uflags(rfile, pinfo)
+ const reqfile_t *rfile;
+ const pinfo_t *pinfo;
+{
+ finfo_t *fd;
+ int ufl = 0;
+
+ assert(rfile);
+ assert(pinfo);
+
+ switch (rfile->type) {
+ case REQFILE:
+ SLIST_FOREACH(fd, &pinfo->fds, next)
+ if (fd->stat.fileid == rfile->ino && \
+ fd->stat.fsid == rfile->dev)
+ ufl |= fd->uflags;
+
+ return ufl;
+
+ case REQMNT:
+ SLIST_FOREACH(fd, &pinfo->fds, next)
+ if (fd->stat.fsid == rfile->dev)
+ ufl |= fd->uflags;
+
+ return ufl;
+
+ case REQDEV:
+ SLIST_FOREACH(fd, &pinfo->fds, next)
+ if ((fd->stat.fileid == rfile->ino && \
+ fd->stat.fsid == rfile->dev) || \
+ fd->stat.fsid == rfile->ino)
+ ufl |= fd->uflags;
+
+ return ufl;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Helper routine to free pinfo structure
+ */
+static void
+pinfo_free(pinfo)
+ pinfo_t *pinfo;
+{
+
+ assert(pinfo);
+ SLIST_FREE(&pinfo->fds, next, free);
+ free(pinfo);
+}
+
+int
+do_fuser(argc, argv)
+ int argc;
+ char *argv[];
+{
+ reqfile_t *rfile;
+ pinfo_t *pinfo;
+ struct kinfo_proc *procs;
+ char buf[_POSIX2_LINE_MAX]; /* KVM mandatory */
+ char ch;
+ int ufl, cnt;
+ int sig = SIGKILL; /* Default to kill */
+ char *ep;
+ char *kernimg = NULL; /* We are using curr. sys by default */
+ char *mcore = NULL;
+
+ while ((ch = getopt(argc, argv, "C:K:cfkms: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 'K':
+ kernimg = optarg;
+ break;
+
+ case 'C':
+ mcore = 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;
+
+ default:
+ usage();
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ assert(argc >= 0);
+ if (argc == 0)
+ usage();
+
+ while (argc--)
+ (void)addfile(argv[argc]);
+
+ if (SLIST_EMPTY(&rfiles))
+ errx(EX_IOERR, "files not accessible");
+
+ kd = kvm_openfiles(kernimg, mcore, NULL, O_RDONLY, buf);
+ if (kd == NULL)
+ errx(EX_OSERR, "kvm_openfiles(): %s", buf);
+
+ procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &cnt);
+ if (procs == NULL)
+ errx(EX_OSERR, "kvm_getproc(): %s", buf);
+
+ while(cnt--)
+ (void)gather_pinfo(procs++);
+
+ SLIST_FOREACH(rfile, &rfiles, next) {
+ (void)fprintf(stderr, "%s:", rfile->fname);
+ (void)fflush(stderr);
+
+ SLIST_FOREACH(pinfo, &prclist, next) {
+ ufl = get_uflags(rfile, pinfo);
+
+ if (ufl != 0) {
+ print_file_info(pinfo->pid, \
+ pinfo->uid, ufl);
+ if ((flags & KFLAG) != 0)
+ (void)kill(pinfo->pid, sig);
+ }
+ }
+ (void)fprintf(stderr, "\n");
+ }
+
+ SLIST_FREE(&rfiles, next, free);
+ SLIST_FREE(&prclist, next, pinfo_free);
+ (void)kvm_close(kd);
+
+ return 0;
+
+}
+
+int
+add_mmapped(p, head)
+ const struct kinfo_proc *p;
+ fds_head_t *head;
+{
+ 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 ufl;
+
+ assert(p);
+ if (!kvm_read_all(kd, (unsigned long)p->ki_vmspace, &vmspace,
+ sizeof(vmspace))) {
+ warnx("can't read vmspace at %p for pid %d\n",
+ (void *)p->ki_vmspace, p->ki_pid);
+ return 1;
+ }
+
+ map = &vmspace.vm_map;
+
+ for (entryp = map->header.next;
+ entryp != &p->ki_vmspace->vm_map.header; entryp = entry.next) {
+ if (!kvm_read_all(kd, (unsigned long)entryp, &entry,
+ sizeof(entry))) {
+ warnx("can't read vm_map_entry at %p for pid %d\n",
+ (void *)entryp, p->ki_pid);
+ return 1;
+ }
+
+ 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_all(kd, (unsigned long)objp, &object,
+ sizeof(object))) {
+ warnx("can't read vm_object at %p for pid %d\n",
+ (void *)objp, p->ki_pid);
+ return 1;
+ }
+ }
+
+ ufl = (entry.protection & VM_PROT_READ ? UFL_FREAD : 0);
+ ufl |= (entry.protection & VM_PROT_WRITE ? UFL_FWRITE : 0);
+ ufl |= UFL_MMAP;
+
+ if (object.type == OBJT_VNODE)
+ (void)vp2finfo((struct vnode *)object.handle, head, \
+ ufl);
+ }
+
+ return 0;
+}
+
+/*
+ * Returns signal number for it's string representation
+ */
+static int
+str2sig(str)
+ const char *str;
+{
+ int n;
+
+ if (!strncasecmp(str, "sig", (size_t)3))
+ str += 3;
+
+ for (n = 1; n < sys_nsig; n++) {
+ if (!strcasecmp(sys_signame[n], str))
+ return (n);
+ }
+
+ return -1;
+}
More information about the svn-src-projects
mailing list