Return to BSD News archive
Path: sserve!manuel.anu.edu.au!munnari.oz.au!spool.mu.edu!agate!doc.ic.ac.uk!uknet!mcsun!fuug!kiae!rdrel!guam.relcom.msk.su!vak From: vak@guam.relcom.msk.su (Serge V.Vakulenko) Newsgroups: comp.unix.bsd Subject: [386BSD] fs - print info about opened files Message-ID: <1992Nov16.210249.1609@rdrel.relcom.msk.su> Date: 16 Nov 92 21:02:49 GMT Sender: usenet@rdrel.relcom.msk.su (Usenet News Administrator) Organization: Relcom R&D Lines: 859 X-Newsreader: TIN [version 1.1 PL6] Here is simple utility, called `fs', which reads from the kernel and prints the information about files, opened by running processes. It also tries to convert dev/inode pairs to absolute file names. Share and enjoy! # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # Makefile # fs.1 # fs.c # fs.h # fsdumpdb.c # fsmakedb.1 # fsmakedb.c # echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X# Permission to use and distribute this software is permitted X# without fee, provided that this copyright notice is not changed. X XSHELL = /bin/sh XCFLAGS = -pipe -O XLDFLAGS = -pipe -O X XSRCS = fs.c fsdumpdb.c fsmakedb.c X Xall: fs fsmakedb fs.0 fsmakedb.0 X Xfs: fs.o X $(CC) $(LDFLAGS) fs.o -o fs -lutil X Xfsmakedb: fsmakedb.o X $(CC) $(LDFLAGS) fsmakedb.o -o fsmakedb X Xfsdumpdb: fsdumpdb.o X $(CC) $(LDFLAGS) fsdumpdb.o -o fsdumpdb X Xinstall: fs fsmakedb fs.0 fsmakedb.0 X install -c -s -o root -m 4755 fs /usr/bin/fs X install -c -s -o root -m 4755 fsmakedb /usr/sbin/fsmakedb X install -c fs.0 /usr/share/man/cat1/fs.0 X install -c fsmakedb.0 /usr/share/man/cat8/fsmakedb.0 X Xdepend: X mkdep $(SRCS) &&\ X sed '/^###$$/,$$d' Makefile > Makefile~ &&\ X echo '###' >> Makefile~ &&\ X cat .depend >> Makefile~ &&\ X rm .depend &&\ X mv Makefile~ Makefile X Xclean: X rm -f core.* .,* *.b *.o fs fsmakedb fsdumpdb .depend *.0 X X.SUFFIXES: .1 .0 X X.1.0: X nroff -man $< > $@ X X### Xfs.o : fs.c /usr/include/stdio.h /usr/include/sys/cdefs.h \ X /usr/include/machine/ansi.h /usr/include/nlist.h /usr/include/sys/types.h \ X /usr/include/machine/types.h /usr/include/db.h /usr/include/dirent.h \ X /usr/include/fcntl.h /usr/include/sys/param.h /usr/include/sys/syslimits.h \ X /usr/include/sys/errno.h /usr/include/sys/time.h \ X /usr/include/sys/resource.h /usr/include/sys/ucred.h /usr/include/sys/uio.h \ X /usr/include/sys/signal.h /usr/include/machine/trap.h \ X /usr/include/machine/param.h /usr/include/machine/endian.h \ X /usr/include/machine/limits.h /usr/include/sys/stat.h \ X /usr/include/ufs/quota.h /usr/include/sys/namei.h /usr/include/sys/file.h \ X /usr/include/sys/fcntl.h /usr/include/sys/unistd.h /usr/include/sys/vnode.h \ X /usr/include/ufs/inode.h /usr/include/ufs/../ufs/dinode.h \ X /usr/include/sys/proc.h /usr/include/machine/proc.h fs.h Xfsdumpdb.o : fsdumpdb.c /usr/include/stdio.h /usr/include/sys/cdefs.h \ X /usr/include/machine/ansi.h /usr/include/sys/types.h \ X /usr/include/machine/types.h /usr/include/db.h /usr/include/fcntl.h fs.h Xfsmakedb.o : fsmakedb.c /usr/include/stdio.h /usr/include/sys/cdefs.h \ X /usr/include/machine/ansi.h /usr/include/sys/types.h \ X /usr/include/machine/types.h /usr/include/db.h /usr/include/dirent.h \ X /usr/include/sys/stat.h /usr/include/fcntl.h fs.h END-of-Makefile echo x - fs.1 sed 's/^X//' >fs.1 << 'END-of-fs.1' X.\" Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X.\" Permission to use and distribute this software is permitted X.\" without fee, provided that this copyright notice is not changed. X.Dd November 16, 1992 X.Dt FS 1 X.Os BSD 3 X.Sh NAME X.Nm fs X.Nd print opened files X.Sh SYNOPSIS X.Nm fs X.Op Fl s X.Op Fl f Ar dbfile X.Sh DESCRIPTION XThe X.Nm fs Xutility prints information about files, which are currently opened by Xrunning processes. X.Pp XGiven the device and inode numbers of file, X.Nm fs Xtries to compute the full file name, using the database of Xall files in the filesystem. This database should be create by X.Xr fsmakedb 1 , Xand placed in X.Ql /var/db/fs.db . X.Pp XThe options are as follows: X.Bl -tag -width Ds X.It Fl s XShow opened sockets in addition to files. X.It Fl f XRead the file name info from the specified file. X.El X.Pp XIn order to have read access to /dev/kmem and other system files, the X.Nm fs Xutility should run setuid root. X.Sh SEE ALSO X.Xr fsmakedb 1 . END-of-fs.1 echo x - fs.c sed 's/^X//' >fs.c << 'END-of-fs.c' X/* X * fs.c - print files, opened by running processes. X * X * Version 1.0, Tue Nov 17 00:03:11 MSK 1992 X * X * Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X * Permission to use and distribute this software is permitted X * without fee, provided that this copyright notice is not changed. X */ X#include <stdio.h> X#include <nlist.h> X#include <sys/types.h> X#include <db.h> X#include <dirent.h> X#define KERNEL X#include <fcntl.h> X#include <sys/param.h> X#include <sys/time.h> X#include <sys/stat.h> X#include <ufs/quota.h> X#include <sys/namei.h> X#include <sys/uio.h> X#include <sys/file.h> X#include <sys/vnode.h> X#include <ufs/inode.h> X#include <sys/ucred.h> X#include <sys/proc.h> X#include "fs.h" X Xstruct devtab { X char *name; X int dev; X}; X Xstruct nlist symtab [] = { X { "_filehead", }, /* struct file * */ X#define FILEHEAD symtab[0] X { "_nfiles", }, /* int */ X#define NFILES symtab[1] X { 0, }, X}; X Xint nfiles; Xstruct file *filetab; Xstruct vnode *vnodetab; Xstruct devtab *cdev, *bdev; Xint cdevlen, bdevlen; Xint cdevcnt, bdevcnt; Xint initdevtab = 0; XDB *db; Xint sflag = 0; X Xchar *progname; X Xextern char *strrchr (), *strdup (), *malloc (), *calloc (); X X/* VARARGS1 */ Xvoid fatal (msg, a, b, c, d) Xchar *msg; Xlong a, b, c, d; X{ X fprintf (stderr, "%s: ", progname); X fprintf (stderr, msg, a, b, c, d); X fprintf (stderr, "\n"); X exit (-1); X} X Xvoid kread (off, addr, sz) Xlong off; Xvoid *addr; X{ X if (kvm_read (off, addr, sz) != sz) X fatal ("cannot read kernel memory"); X} X Xvoid readproc () X{ X struct file *f, *ptr; X struct vnode v; X X if (kvm_openfiles (0, 0, 0) < 0) X fatal ("cannot open kernel files"); X if (kvm_nlist (symtab) != 0) X fatal ("cannot read kernel symbols"); X kread (NFILES.n_value, &nfiles, sizeof (nfiles)); X X filetab = (struct file *) calloc (nfiles, sizeof (struct file)); X vnodetab = (struct vnode *) calloc (nfiles, sizeof (struct vnode)); X if (!filetab || !vnodetab) X fatal ("out of memory"); X X kread (FILEHEAD.n_value, &ptr, sizeof (ptr)); X for (f=filetab; ptr && f<filetab+nfiles; ++f) { X int i = f - filetab; X kread (ptr, f, sizeof (struct file)); X X if (f->f_type == DTYPE_VNODE) X kvm_read (f->f_data, vnodetab+i, sizeof (struct vnode)); X X ptr = f->f_filef; X } X} X Xchar *fileflag (int fl) X{ X static char buf [8]; X char *p; X X if (fl & ~(FREAD | FWRITE | O_APPEND | O_NONBLOCK | FHASLOCK)) { X sprintf (buf, "%o", fl); X return (buf); X } X p = buf + sizeof(buf); X *--p = 0; X *--p = (fl & FREAD) ? 'r' : '-'; X *--p = (fl & FWRITE) ? 'w' : '-'; X *--p = (fl & O_APPEND) ? 'a' : '-'; X *--p = (fl & O_NONBLOCK) ? 'n' : '-'; X *--p = (fl & FHASLOCK) ? 'l' : '-'; X return (p); X} X Xchar *filecount (cnt) X{ X static char buf [16]; X X if (cnt == 1) X return (""); X sprintf (buf, "(%d)", cnt); X return (buf); X} X Xchar *fileoffset (off) Xlong off; X{ X static char buf [24]; X X if (off == 0) X return (""); X sprintf (buf, "%x", off); X return (buf); X} X Xchar *vnodetype (typ) X{ X switch (typ) { X case VNON: return ("non"); X case VBAD: return ("bad"); X case VSOCK: return ("sock"); X case VFIFO: return ("fifo"); X case VLNK: return ("lnk"); X case VBLK: return ("blk"); X case VCHR: return ("chr"); X case VDIR: return ("dir"); X case VREG: return ("file"); X } X return ("?"); X} X Xvoid makedevtab () X{ X DIR *dird; X struct dirent *d; X struct stat st; X char afname [128]; X X cdevcnt = bdevcnt = 0; X cdevlen = bdevlen = 64; X bdev = (struct devtab *) malloc (bdevlen * sizeof (struct devtab)); X cdev = (struct devtab *) malloc (cdevlen * sizeof (struct devtab)); X if (! bdev || ! cdev) X fatal ("out of memory"); X strcpy (afname, "/dev/"); X dird = opendir (afname); X if (! dird) X fatal ("cannot read /dev directory"); X for (d=readdir(dird); d; d=readdir(dird)) { X strcpy (afname+5, d->d_name); X if (stat (afname, &st) < 0) X continue; X if ((st.st_mode & S_IFMT) == S_IFBLK) { X if (bdevcnt >= bdevlen) { X bdevlen += 64; X bdev = (struct devtab *) realloc ((char *) bdev, X bdevlen * sizeof (struct devtab)); X if (! bdev) X fatal ("out of memory"); X } X bdev[bdevcnt].dev = st.st_rdev; X bdev[bdevcnt].name = strdup (afname); X ++bdevcnt; X } else if ((st.st_mode & S_IFMT) == S_IFCHR) { X if (cdevcnt >= cdevlen) { X cdevlen += 64; X cdev = (struct devtab *) realloc ((char *) cdev, X cdevlen * sizeof (struct devtab)); X if (! cdev) X fatal ("out of memory"); X } X cdev[cdevcnt].dev = st.st_rdev; X cdev[cdevcnt].name = strdup (afname); X ++cdevcnt; X } X } X closedir (dird); X} X Xchar *devname (typ, dev) X{ X struct devtab *p; X int cnt, i; X static char buf [16]; X X if (! initdevtab) { X makedevtab (); X initdevtab = 1; X } X p = typ=='b' ? bdev : cdev; X cnt = typ=='b' ? bdevcnt : cdevcnt; X for (; --cnt>=0; ++p) X if (p->dev == dev) X return (p->name); X sprintf (buf, "%c %d/%d", typ, major (dev), minor (dev)); X return (buf); X} X Xchar *fetch (dev, inode, pdev, pinode) Xlong dev, inode, *pdev, *pinode; X{ X DBT key, val; X struct fskey keyrec; X struct fsrec *v; X X keyrec.dev = dev; X keyrec.inode = inode; X key.data = (char *) &keyrec; X key.size = sizeof (keyrec); X if ((*db->get) (db, &key, &val, 0) != 0) X return (0); X v = (struct fsrec *) val.data; X *pdev = v->pdev; X *pinode = v->pinode; X return (v->filename); X} X Xchar *strrcpy (to, from) Xchar *to, *from; X{ X int len = strlen (from); X X strncpy (to -= len, from, len); X return (to); X} X Xchar *filename (dev, inode) Xlong dev, inode; X{ X long pdev, pinode; X static char fullname [512]; X char *p, *name; X X if (! db) X return (0); X name = fetch (dev, inode, &pdev, &pinode); X if (! name) X return (0); X p = fullname + sizeof (fullname); X *--p = 0; X for (;;) { X p = strrcpy (p, name); X if (dev==pdev && inode==pinode) X break; X *--p = '/'; X name = fetch (dev = pdev, inode = pinode, &pdev, &pinode); X if (! name) X return (0); X } X return (p); X} X Xvoid printvnode (v) Xstruct vnode *v; X{ X struct inode *i; X char *name; X X switch (v->v_type) { X case VNON: case VBAD: case VSOCK: case VFIFO: case VLNK: X default: X printf (vnodetype (v->v_type)); X return; X case VBLK: case VCHR: case VDIR: case VREG: X break; X } X switch (v->v_tag) { X default: X printf ("%s on %d fs", vnodetype (v->v_type), v->v_tag); X return; X case VT_NON: X printf ("%s nowhere", vnodetype (v->v_type)); X return; X case VT_NFS: X printf ("%s on nfs", vnodetype (v->v_type)); X return; X case VT_MFS: X printf ("%s on mfs", vnodetype (v->v_type)); X return; X case VT_UFS: X break; X } X i = VTOI (v); X switch (v->v_type) { X case VBLK: X printf ("%s", devname ('b', i->i_rdev)); X return; X case VCHR: X printf ("%s", devname ('c', i->i_rdev)); X return; X } X name = filename (i->i_dev, i->i_number); X switch (v->v_type) { X case VDIR: X if (name) X printf ("%s/", name); X else X printf ("%s dir %d", devname ('b', i->i_dev), i->i_number); X break; X case VREG: X if (name) X printf ("%s", name); X else X printf ("%s file %d", devname ('b', i->i_dev), i->i_number); X break; X } X} X Xvoid printproc (f) Xstruct file *f; X{ X printf ("%6s %5s %8s ", X fileflag (f->f_flag), /* read/write etc. */ X filecount (f->f_count), /* reference count */ X fileoffset (f->f_offset) /* seek offset in file */ X ); X if (f->f_type == DTYPE_VNODE) X printvnode (vnodetab + (f - filetab)); X else if (f->f_type == DTYPE_SOCKET) X printf ("<socket>"); X printf ("\n"); X} X Xusage () X{ X fprintf (stderr, "Usage: %s [-s] [-f dbfile]\n", progname); X exit (-1); X} X Xint fsrechash (a, sz) Xstruct fskey *a; X{ X return (a->inode); X} X Xint main (argc, argv) Xchar **argv; X{ X struct file *f; X char *dbfile = FSDBFILE; X HASHINFO hi; X X /* Store the program name for message printing. */ X progname = strrchr (*argv, '/'); X if (! progname) X progname = *argv; X X /* Parse options. */ X for (++argv, --argc; *argv && **argv=='-'; ++argv, --argc) { X char *p; X X for (p=1+*argv; *p; ++p) { X switch (*p) { X case 's': X ++sflag; X continue; X case 'f': X dbfile = *++argv; X --argc; X if (! dbfile) X usage (); X break; X default: X fprintf (stderr, "%s: no such option: %c\n", X progname, *p); X usage (); X } X break; X } X } X if (*argv) X usage (); X X /* Read kernel info. */ X readproc (); X kvm_close (); X X /* Open dev/inode to file name conversion database */ X hi.bsize = 512; /* page size */ X hi.cachesize = 200*512; /* cache size */ X hi.hash = fsrechash; /* hash function */ X hi.lorder = 0; /* byte order */ X hi.ffactor = 64; /* fill factor */ X db = hash_open (dbfile, O_RDONLY, 0, &hi); X X /* Print processes information. */ X printf (" FLAGS REFCNT OFFSET FILENAME\n"); X X for (f=filetab; f->f_filef && f<filetab+nfiles; ++f) X if (sflag || f->f_type==DTYPE_VNODE) X printproc (f); X X return (0); X} END-of-fs.c echo x - fs.h sed 's/^X//' >fs.h << 'END-of-fs.h' X/* X * Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X * Permission to use and distribute this software is permitted X * without fee, provided that this copyright notice is not changed. X */ X#define FSDBFILE "/var/db/fs.db" X Xstruct fskey { X long dev; X long inode; X}; X Xstruct fsrec { X long pdev; X long pinode; X char filename [256]; X}; END-of-fs.h echo x - fsdumpdb.c sed 's/^X//' >fsdumpdb.c << 'END-of-fsdumpdb.c' X/* X * Dump the file info database. Used for debugging. X * X * Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X * Permission to use and distribute this software is permitted X * without fee, provided that this copyright notice is not changed. X */ X#include <stdio.h> X#include <sys/types.h> X#include <db.h> X#include <fcntl.h> X#include "fs.h" X XDB *db; Xchar *progname; Xint vflag = 0; X Xextern char *strrchr (); X Xvoid dump () X{ X DBT key, val; X struct fskey *k; X struct fsrec *v; X X for (;;) { X if ((*db->seq) (db, &key, &val, 0) != 0) { X perror ("seq"); X return; X } X k = (struct fskey *) key.data; X v = (struct fsrec *) val.data; X printf ("%d/%d -> %s\n", k->dev, k->inode, v->filename); X } X} X Xint fsrechash (a, sz) Xstruct fskey *a; X{ X return (a->inode); X} X Xusage () X{ X fprintf (stderr, "Usage: %s [dbfile]\n", progname); X exit (-1); X} X Xint main (argc, argv) Xchar **argv; X{ X char *dbname = FSDBFILE; X HASHINFO hi; X X /* Store the program name for message printing. */ X progname = strrchr (*argv, '/'); X if (! progname) X progname = *argv; X X /* Parse options. */ X for (++argv, --argc; *argv && **argv=='-'; ++argv, --argc) { X char *p; X X for (p=1+*argv; *p; ++p) { X switch (*p) { X case 'v': X ++vflag; X continue; X default: X fprintf (stderr, "%s: no such option: %c", X progname, *p); X usage (); X } X } X } X if (*argv) X dbname = *argv++; X if (*argv) X usage (); X X /* Open dev/inode to file name conversion database */ X hi.bsize = 512; /* page size */ X hi.cachesize = 200*512; /* cache size */ X hi.hash = fsrechash; /* hash function */ X hi.lorder = 0; /* byte order */ X hi.ffactor = 64; /* fill factor */ X db = hash_open (dbname, O_RDONLY, 0, &hi); X if (! db) { X fprintf (stderr, "%s: cannot read %s", progname, dbname); X exit (-1); X } X dump (); X X return (0); X} END-of-fsdumpdb.c echo x - fsmakedb.1 sed 's/^X//' >fsmakedb.1 << 'END-of-fsmakedb.1' X.\" Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X.\" Permission to use and distribute this software is permitted X.\" without fee, provided that this copyright notice is not changed. X.Dd November 16, 1992 X.Dt FSMAKEDB 8 X.Os BSD 3 X.Sh NAME X.Nm fsmakedb X.Nd create file name database for fs(1) utility X.Sh SYNOPSIS X.Nm fsmakedb X.Op Ar dbfile X.Sh DESCRIPTION XThe X.Nm fsmakedb Xutility creates the database of all files in the filesystem. X.Pp XThe X.Ar dbfile Xis the database name to create, default X.Ql /var/db/fs.db . X.Pp XIn order to have read/chdir access to all directories, the X.Nm fsmakedb Xutility should run setuid root. X.Sh SEE ALSO X.Xr fs 1 . END-of-fsmakedb.1 echo x - fsmakedb.c sed 's/^X//' >fsmakedb.c << 'END-of-fsmakedb.c' X/* X * Create the file info database for the fs(1) utility. X * X * Copyright (C) 1992 Sergey Vakulenko, <vak@kiae.su>. X * Permission to use and distribute this software is permitted X * without fee, provided that this copyright notice is not changed. X */ X#include <stdio.h> X#include <sys/types.h> X#include <db.h> X#include <dirent.h> X#include <sys/stat.h> X#include <fcntl.h> X#include "fs.h" X XDB *db; Xchar *progname; Xint vflag = 0; X Xextern char *strrchr (); X X/* VARARGS1 */ Xvoid fatal (msg, a, b, c, d) Xchar *msg; Xlong a, b, c, d; X{ X fprintf (stderr, "%s: ", progname); X fprintf (stderr, msg, a, b, c, d); X fprintf (stderr, "\n"); X exit (-1); X} X Xvoid store (dev, inode, name, pdev, pinode) Xchar *name; X{ X DBT key, val; X struct fskey keyrec; X struct fsrec valrec; X X keyrec.dev = dev; X keyrec.inode = inode; X key.data = (char *) &keyrec; X key.size = sizeof (keyrec); X X valrec.pdev = pdev; X valrec.pinode = pinode; X strcpy (valrec.filename, name); X val.data = (char *) &valrec; X val.size = (char *) &valrec.filename - (char *) &valrec + X strlen (name) + 1; X X if (vflag) X printf ("%d/%d -> %s\n", dev, inode, name); X if ((*db->put) (db, &key, &val, R_PUT) != 0) X fprintf (stderr, "error storing new record\n"); X} X Xvoid scan (dir, pst) Xchar *dir; Xstruct stat *pst; X{ X DIR *dird; X struct dirent *d; X struct stat st; X X if (chdir (dir) < 0) { X perror (dir); X return; X } X dird = opendir ("."); X if (! dird) { X perror (dir); X chdir (".."); X return; X } X for (d=readdir(dird); d; d=readdir(dird)) { X if (d->d_name[0] == '.' && (d->d_name[1] == 0 || X d->d_name[1] == '.' && d->d_name[2] == 0)) X continue; X if (lstat (d->d_name, &st) < 0) { X perror (d->d_name); X continue; X } X store (st.st_dev, st.st_ino, d->d_name, pst->st_dev, pst->st_ino); X if ((st.st_mode & S_IFMT) == S_IFDIR) X scan (d->d_name, &st); X } X closedir (dird); X chdir (".."); X} X Xint fsrechash (a, sz) Xstruct fskey *a; X{ X return (a->inode); X} X Xint main (argc, argv) Xchar **argv; X{ X char *dbname = FSDBFILE; X struct stat st; X HASHINFO hi; X X /* Store the program name for message printing. */ X progname = strrchr (*argv, '/'); X if (! progname) X progname = *argv; X X /* Parse options. */ X for (++argv, --argc; *argv && **argv=='-'; ++argv, --argc) { X char *p; X X for (p=1+*argv; *p; ++p) { X switch (*p) { X case 'v': X ++vflag; X break; X default: X fatal ("no such option: %c", *p); X } X } X } X if (*argv) X dbname = *argv++; X if (*argv) X fatal ("usage: %s [dbfile]", progname); X X /* Open dev/inode to file name conversion database */ X hi.bsize = 512; /* page size */ X hi.cachesize = 200*512; /* cache size */ X hi.hash = fsrechash; /* hash function */ X hi.lorder = 0; /* byte order */ X hi.ffactor = 64; /* fill factor */ X db = hash_open (dbname, O_RDWR|O_CREAT|O_TRUNC, 0644, &hi); X if (! db) X fatal ("cannot create %s", dbname); X X if (lstat ("/", &st) < 0) { X perror ("/"); X return (-1); X } X X /* Scan all files recursively beginning from the root. */ X store (st.st_dev, st.st_ino, "", st.st_dev, st.st_ino); X scan ("/", &st); X X dbm_close (db); X return (0); X} END-of-fsmakedb.c exit