From owner-svn-src-projects@FreeBSD.ORG Sun Jul 19 23:11:10 2009 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3E530106566C; Sun, 19 Jul 2009 23:11:10 +0000 (UTC) (envelope-from stas@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2B6D48FC25; Sun, 19 Jul 2009 23:11:10 +0000 (UTC) (envelope-from stas@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n6JNBA92059857; Sun, 19 Jul 2009 23:11:10 GMT (envelope-from stas@svn.freebsd.org) Received: (from stas@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n6JNB9K8059851; Sun, 19 Jul 2009 23:11:09 GMT (envelope-from stas@svn.freebsd.org) Message-Id: <200907192311.n6JNB9K8059851@svn.freebsd.org> From: Stanislav Sedov Date: Sun, 19 Jul 2009 23:11:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r195775 - projects/libprocstat/usr.bin/fstat X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 19 Jul 2009 23:11:10 -0000 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 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 + * Copyright (c) 2005-2009 Stanislav Sedov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,729 +27,339 @@ #include __FBSDID("$FreeBSD$"); -#include -#include -#include -#include +#include +#include +#include +#include + +#include #include #include -#include #include #include #include #include #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define _WANT_FILE -#include -#include -#define _KERNEL -#include -#include -#undef _KERNEL - -#include -#include -#include +#include +#include +#include +#include +#include -#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 ***