Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jul 2009 23:11:09 +0000 (UTC)
From:      Stanislav Sedov <stas@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r195775 - projects/libprocstat/usr.bin/fstat
Message-ID:  <200907192311.n6JNB9K8059851@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: stas
Date: Sun Jul 19 23:11:08 2009
New Revision: 195775
URL: http://svn.freebsd.org/changeset/base/195775

Log:
  - Fix fuser to use libprocstat instead of relying on its own kvm-only
    functionality.
  - Add new 'fs_uflags' field to filestat struct to indicate how the
    file is used by the process (root dir, cwd, etc).  Previously these
    flags have been encoded as the 'special' descriptor numbers and
    it was impossible to indicate multiple usage cases (e.g. root dir
    and cwd simultaneously) which is important to fuser(8).

Modified:
  projects/libprocstat/usr.bin/fstat/Makefile
  projects/libprocstat/usr.bin/fstat/fstat.c
  projects/libprocstat/usr.bin/fstat/fuser.1
  projects/libprocstat/usr.bin/fstat/fuser.c
  projects/libprocstat/usr.bin/fstat/libprocstat.c
  projects/libprocstat/usr.bin/fstat/libprocstat.h
  projects/libprocstat/usr.bin/fstat/main.c

Modified: projects/libprocstat/usr.bin/fstat/Makefile
==============================================================================
--- projects/libprocstat/usr.bin/fstat/Makefile	Sun Jul 19 21:40:19 2009	(r195774)
+++ projects/libprocstat/usr.bin/fstat/Makefile	Sun Jul 19 23:11:08 2009	(r195775)
@@ -4,7 +4,7 @@
 .include <bsd.own.mk>
 
 PROG=	fstat
-SRCS=	cd9660.c common_kvm.c fstat.c libprocstat.c main.c msdosfs.c
+SRCS=	cd9660.c common_kvm.c fstat.c fuser.c libprocstat.c main.c msdosfs.c
 LINKS=	${BINDIR}/fstat ${BINDIR}/fuser
 DPADD=	${LIBKVM}
 LDADD=	-lkvm -lutil

Modified: projects/libprocstat/usr.bin/fstat/fstat.c
==============================================================================
--- projects/libprocstat/usr.bin/fstat/fstat.c	Sun Jul 19 21:40:19 2009	(r195774)
+++ projects/libprocstat/usr.bin/fstat/fstat.c	Sun Jul 19 23:11:08 2009	(r195775)
@@ -255,29 +255,20 @@ print_file_info(struct procstat *procsta
 	 * Print entry prefix.
 	 */
 	printf("%-8.8s %-10s %5d", uname, cmd, pid);
-	switch(fst->fs_fd) {
-	case PS_FST_FD_TEXT:
+	if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
 		printf(" text");
-		break;
-	case PS_FST_FD_CDIR:
+	else if (fst->fs_uflags & PS_FST_UFLAG_CDIR)
 		printf("   wd");
-		break;
-	case PS_FST_FD_RDIR:
+	else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
 		printf(" root");
-		break;
-	case PS_FST_FD_TRACE:
+	else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
 		printf("   tr");
-		break;
-	case PS_FST_FD_MMAP:
+	else if (fst->fs_uflags & PS_FST_UFLAG_MMAP)
 		printf(" mmap");
-		break;
-	case PS_FST_FD_JAIL:
+	else if (fst->fs_uflags & PS_FST_UFLAG_JAIL)
 		printf(" jail");
-		break;
-	default:
+	else
 		printf(" %4d", fst->fs_fd);
-		break;
-	}
 
 	/*
 	 * Print type-specific data.

Modified: projects/libprocstat/usr.bin/fstat/fuser.1
==============================================================================
--- projects/libprocstat/usr.bin/fstat/fuser.1	Sun Jul 19 21:40:19 2009	(r195774)
+++ projects/libprocstat/usr.bin/fstat/fuser.1	Sun Jul 19 23:11:08 2009	(r195775)
@@ -33,8 +33,8 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl cfkmu
-.Op Fl C Ar core
-.Op Fl K Ar kernel
+.Op Fl M Ar core
+.Op Fl N Ar system
 .Op Fl s Ar signal
 .Op Ar
 .Sh DESCRIPTION
@@ -66,12 +66,13 @@ Send signal to reported processes
 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
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the 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 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

Modified: projects/libprocstat/usr.bin/fstat/fuser.c
==============================================================================
--- projects/libprocstat/usr.bin/fstat/fuser.c	Sun Jul 19 21:40:19 2009	(r195774)
+++ projects/libprocstat/usr.bin/fstat/fuser.c	Sun Jul 19 23:11:08 2009	(r195775)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2005,2009 Stanislav Sedov <stas@FreeBSD.org>
+ * Copyright (c) 2005-2009 Stanislav Sedov <stas@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,729 +27,339 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
+#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 <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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
 
-#include "common.h"
 #include "functions.h"
+#include "libprocstat.h"
 
 /*
- * Local types
+ * File access mode flags table.
  */
-
-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;
+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))
 
 /*
- * Local definitions
+ * Usage flags translation table.
  */
-
-/* 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;
+	int	flag;
 	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'},
+	{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'}
 };
-#define NUFLAGS (sizeof(uflags) / sizeof(*uflags))
-	
-/* Filesystem-specific handlers */
-#define FSTYPE(fst) {#fst, fst##_filestat}
-static 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	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 {
+	long		fsid;
+	long		fileid;
+	const char	*name;
+	STAILQ_HEAD(, consumer) consumers;
 };
-#define NTYPES (sizeof(fstypes) / sizeof(*fstypes))
 
 /*
- * Global vars
+ * 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)	*/
 
-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);
+static int flags = 0;	/* Option flags. */
 
-/*
- * 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	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)
 {
 
-	(void)fprintf(stderr, "usage: %s [-cfkmu] [-C core] [-K kernel]" \
-	    " [-s signal] file ...\n", getprogname());
-
+	fprintf(stderr,
+"usage: fuser [-cfhkmu] [-M core] [-N system] [-s signal] file ...\n");
 	exit(EX_USAGE);
 }
 
-void
-print_file_info(pid, uid, ufl)
-	pid_t		pid;
-	uid_t		uid;
-	int		ufl;
+static void
+printflags(struct consumer *cons)
 {
-	uint	i;
-
-	(void)fprintf(stdout, "%6d", pid);
-	(void)fflush(stdout);
+	unsigned int i;
 
+	assert(cons);
 	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);
+		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);
+	/* XXX: add controlling tty support. */
 }
 
 /*
  * Add file to the list.
  */
 static int
-addfile(path)
-	const char	*path;
+addfile(const char *path, struct reqfile *reqfile)
 {
-	struct stat	sb;
-	int		type;
-	reqfile_t	*rfile;
+	struct stat sb;
 
 	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 (1);
 	}
-
-	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);
+	reqfile->fileid = sb.st_ino;
+	reqfile->fsid = sb.st_dev;
+	reqfile->name = path;
+	STAILQ_INIT(&reqfile->consumers);
+	return (0);	
+/* XXX: devs? */
 }
 
 int
-do_fuser(argc, argv)
-	int	argc;
-	char	*argv[];	
+do_fuser(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)
+	struct consumer *consumer;
+	struct kinfo_proc *p;
+	struct procstat *procstat;
+	struct reqfile *reqfiles;
+	int ch, cnt, sig;
+	unsigned int i, nfiles;
+	char *ep, *kernimg, *mcore;
+
+	sig = SIGKILL;	/* Default to kill. */
+	kernimg = NULL;
+	mcore = 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 'K':
+		case 'N':
 			kernimg = optarg;
 			break;
-
-		case 'C':
+		case 'M':
 			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 {
+					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--)
-		(void)addfile(argv[argc]);
-
-	if (SLIST_EMPTY(&rfiles))
+		if (!addfile(*(argv++), &reqfiles[nfiles]))
+			nfiles++;
+	if (nfiles == 0)
 		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);
-
+	procstat = procstat_open(kernimg, mcore);
+	if (procstat == NULL)
+		errx(1, "procstat_open()");
+	p = procstat_getprocs(procstat, KERN_PROC_ALL, 0, &cnt);
+	if (p == NULL)
+		 errx(1, "procstat_getprocs()");
+
+	/*
+	 * Walk through process table and look for matching files.
+	 */
 	while(cnt--)
-		(void)gather_pinfo(procs++);
+		if (p->ki_stat != SZOMB)
+			dofiles(procstat, p++, reqfiles, nfiles);
 
-	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);
+	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)
-					(void)kill(pinfo->pid, sig);
+					kill(consumer->pid, sig);
+				fflush(stderr);
 			}
 		}
 		(void)fprintf(stderr, "\n");
 	}
-
-	SLIST_FREE(&rfiles, next, free);
-	SLIST_FREE(&prclist, next, pinfo_free);
-	(void)kvm_close(kd);
-
-	return 0;
-		
+	procstat_close(procstat);
+	/* XXX: free resoucres .*/
+	return (0);
 }
 
-int
-add_mmapped(p, head)
-	const struct kinfo_proc	*p;
-	fds_head_t		*head;
+static void
+dofiles(struct procstat *procstat, struct kinfo_proc *kp,
+    struct reqfile *reqfiles, size_t nfiles)
 {
-	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)
+	struct consumer *cons;
+	struct filestat *fst;
+	struct filestat_list *head;
+	struct vnstat vn;
+	int error, match;
+	unsigned int i;
+	
+	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;
-
-		if ((objp = entry.object.vm_object) == NULL)
+		error = procstat_get_vnode_info(procstat, fst, &vn, NULL);
+		if (error != 0)
 			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;
+		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. */
 
-		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);
+		/*
+		 * 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);
+		}
 	}
-
-	return 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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