[comp.sys.pyramid] Pyramid version of ``find-fs''

romain@pyrnj.uucp (Romain Kang) (02/22/89)

This is a variation on the theme of /etc/fuser, even though only finds
open files on the same filesystem.  However, it will work on NFS file
systems as well as local UNIX filesystems.

: shell archive -- use sh, not csh
: this archive contains:
:	Makefile
:	ffs.c
:
echo x - Makefile
cat > Makefile << '%-End-of-Makefile-%'
# uncomment these if you have snode.h
#INC	= -I/usr/include -I/usr/src/osx
#SNODE	= -DSNODE

# uncomment if you have OSx5.0
#OSX	= -DOSx5_0

CC	= ucb cc
CFLAGS	= -OG $(INC) $(SNODE) $(OSX)

ffs:	ffs.o
	$(CC) -o ffs $?

ffs.o:	Makefile

clean:
	rm -f *.o core

clobber:
	rm -f ffs *.o core
%-End-of-Makefile-%
echo x - ffs.c
cat > ffs.c << '%-End-of-ffs.c-%'
/*
 * find-fs filesystem
 *
 * Finds processes accessing an nfs file system.
 * Compile by cc -I/sys/h -o find-fs find-fs.c
 *
 * Copyright Richard Tobin, AIAI 1988 (R.Tobin@uk.ac.ed)
 * May be freely redistributed if this notice remains intact.
 *
 * Modified by Valdis Kletnieks, Clarkson University
 * to print out the inode-number as well.  Run 'ncheck' to find
 * what THAT points at.
 *
 * Pyramid version, Romain Kang (romain@pyrnj.UUCP)
 * Added -q argument for quieter/quicker output.
 * Support for remote NFS files (rnodes) and NFSSRC3.2 snodes.
 * To get inode of device special files, you currently need kernel source.
 *	If you have snode.h, #define SNODE
 */

#define KERNEL	1		/* so we get the stuff we need */
/*#define SNODE			/* if you have snode.h */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <ufs/inode.h>		/* V. Kletnieks */
#include <rpc/rpc.h>
#include <nfs/nfs.h>
#include <nfs/rnode.h>
#include <stdio.h>		/* must be after vfs - sigh */
#include <mntent.h>
#ifdef	OSx5_0
# include <a.out.h>
# include <sys/immu.h>
# undef r_lock
# include <sys/region.h>
# define N_NAME	n_un.n_name
#else
# include <nlist.h>
# include <sys/pte.h>
# include <sys/text.h>
# define N_NAME	n_name
#endif
#ifdef	SNODE
# include <specfs/snode.h>
#endif

#undef	NOFILE
#define	NOFILE	(u->u_rlimit[RLIMIT_FDMAX].rlim_cur)
#undef KERNEL

struct	user *get_user();
int	check();
void	name(), get_names(), kread(), error(), xperror();
fsid_t	*fsid();
int	kfd;
int	qflag;

#ifndef	OSx5_0
int	mfd, sfd;
void	mread();
#endif

#define	Check(v,id,format,arg1,arg2)	\
	if (check(v,id,format,arg1,arg2)&&qflag) continue

main(argc, argv)
    int argc;
    char **argv;
{
    int f;
    int rc;
    int k_proc, k_procNPROC;
    struct proc *proc, *procNPROC, *paddr, p;
#undef u			/* where is this??? */
    struct user *u;
    struct file file;
    struct file **ofile;
#ifndef	OSx5_0
    struct text *p_text, text;
#else
    reg_t *regp, region;
    preg_t pregion;
#endif
    fsid_t *id;

    if (argc > 2 && strcmp(argv[1],"-q") == 0)
    {
	qflag++;
	argv++;
	argc--;
    }

    if (argc != 2)
	error("usage: ffs filesystem");

    id = fsid(argv[1]);
    fprintf(stderr, "looking for id %x %x\n", id->val[0], id->val[1]);

    kfd = open("/dev/kmem", O_RDONLY);
    if(kfd < 0)
	xperror("open: /dev/kmem");

#ifndef	OSx5_0
    mfd = open("/dev/mem", O_RDONLY);
    if(mfd < 0)
	xperror("open: /dev/mem");

    sfd = open("/dev/drum", O_RDONLY);
    if(sfd < 0)
	xperror("open: /dev/drum");
#endif

    name("_proc", &k_proc);
    name("_procNPROC", &k_procNPROC);
    get_names("/vmunix");

    kread(k_proc, &proc, sizeof(proc));
    kread(k_procNPROC, &procNPROC, sizeof(procNPROC));

    for(paddr = proc; paddr < procNPROC; ++paddr)
    {
	kread(paddr, &p, sizeof(p));
	if(p.p_pid <= 2)	/* 1 and 2 cause problems */
	    continue;

#if OSx5_0
	if (p.p_region)
	{
	    kread(p.p_region, &pregion, sizeof(pregion));
	    if (regp = pregion.p_reg)
	    {
		kread(regp, &region, sizeof(region));
		Check(region.r_vptr, id, "process %d inode %d text\n", p.p_pid, 0);
	    }
	}
#else
	if (p.p_textp)
	{
	    kread(p.p_textp, &text, sizeof(text));
	    Check(text.x_vptr, id, "process %d inode %d text\n", p.p_pid, 0);
	}
#endif

	if(p.p_stat == SZOMB) continue;

	u = get_user(&p);
	if(!u)
	{
	    printf("warning: couldn't read u area for process %d\n", p.p_pid);
	    continue;
	}

	Check(u->u_cdir, id, "process %d inode %d current directory\n", p.p_pid, 0);
	Check(u->u_rdir, id, "process %d inode %d root directory\n", p.p_pid, 0);

	if (NOFILE > NFD_DEF)
	{
	    int ofile_size = (NOFILE) * sizeof(struct file *);

	    printf("NOFILE = %d\n", NOFILE);
	    ofile = (struct file **)malloc(ofile_size);
	    kread(u->u_ofile, ofile, ofile_size);
	}
	else	{
	    ofile = u->u_ofile_arr;
	}

	for (f = 0; f <= u->u_maxofile; f++)
	{
	    if (ofile[f])
	    {
		kread(ofile[f], &file, sizeof(file));
		if (file.f_count > 0 && file.f_type == DTYPE_VNODE)
		    if (check(file.f_data, id, "process %d inode %d descriptor %d\n",
			p.p_pid, f) && qflag)
				break;
	    }
	}

	if (NOFILE > NFD_DEF)
		free(ofile);
    }
    if (qflag>1)
	putchar('\n');
    exit(0);
}

check(v, id, format, arg1, arg2)
    struct vnode *v;
    fsid_t id[];
    char *format;
    int arg1, arg2;
{
    struct vnode vnode;
    struct inode inode;
    struct rnode rnode;
    struct vfs vfs;

    if(!v)
	return 0;

    kread(v, &vnode, sizeof(vnode));
    kread(vnode.v_vfsp, &vfs, sizeof(vfs));

    if(bcmp(&vfs.vfs_fsid, id, sizeof(fsid_t)) == 0)
    {
	if (qflag)
	{
	    printf((qflag>1) ? " %d" : "%d", arg1);
	    qflag++;
	    return 1;
	}
#ifdef	SNODE
	/* Yes, the SNODE #ifdef is ugly... */
	if (vnode.v_type == VCHR || vnode.v_type == VBLK)
	{
	    struct snode snode;
	    kread(vnode.v_data, &snode, sizeof(snode));
	    kread(snode.s_realvp, &vnode, sizeof(vnode));
	}
#else
	if (vnode.v_type == VCHR || vnode.v_type == VBLK)
	    inode.i_number = -2;
	else
#endif	SNODE
	if (vnode.v_flag&VREMOTE)
	{
	    kread(vnode.v_data, &rnode, sizeof(rnode));
	    inode.i_number = rnode.r_nfsattr.na_nodeid;
	}
	else
	    kread(vnode.v_data, &inode, sizeof(inode));
	printf(format, arg1, (int)inode.i_number, arg2);
	return 1;
    }
    return 0;
}

#define MAXAD 50
struct nlist nl[MAXAD];
int *ad[MAXAD], nad=0;

void
name(nm, addr)
    char *nm;
    int *addr;
{
    if(nad == MAXAD)
	error("too many names");

    nl[nad].N_NAME = nm;
    ad[nad++] = addr;
}

void
get_names(file)
    char *file;
{
    char buf[100];

    if(nlist(file, nl) < 0)
	error("can't nlist /vmunix");

    do
    {
	if(nl[--nad].n_type == N_UNDF)
	{
	    sprintf(buf, "can't find symbol %s", nl[nad].N_NAME);
	    error(buf);
	}

	*ad[nad] = nl[nad].n_value;
    }
    while(nad > 0);
}

void
kread(address, buffer, size)
    caddr_t address;
    caddr_t buffer;
    int size;
{
    extern int errno;

    if(lseek(kfd, (long)address, L_SET) == -1)
	xperror("kmem seek");
    errno = 0;
    if(read(kfd, buffer, size) != size)
    {
	fprintf(stderr, "kaddr = 0x%x: ", address);
	perror("kmem read");
	abort();
    }
}

#ifndef	OSx5_0
void
mread(address, buffer, size)
    int size;
    char *address, *buffer;
{
    extern int errno;

    if(lseek(mfd, (long)address, L_SET) == -1)
	xperror("mem seek");
    errno = 0;
    if(read(mfd, buffer, size) != size)
	xperror("mem read");
}
#endif

void
error(message)
    char *message;
{
    fprintf(stderr, "%s\n", message);
    exit(1);
}

void
xperror(message)
    char *message;
{
    perror(message);
    exit(1);
}

struct user *
get_user(p)
    struct proc *p;
{
    static union {
	struct user u;
	char buf[UPAGES * PAGSIZ];
    } ubuf;
    struct user *u = &ubuf.u;

#ifdef	OSx5_0
    if (readublk(p->p_pid, u) == -1)
	u = 0;
#else
    struct pte ptes[UPAGES], *pte;
    char *buf;
    int bytes;

    if(p->p_flag & SLOAD)
    {
	/* it's in memory */
	kread(p->p_addr, ptes, sizeof(ptes));

	for(bytes = sizeof(*u), pte = ptes, buf = (char *)u;
	    bytes > 0;
	    bytes -= NBPG, pte++, buf += NBPG)
	    mread(pte->pg_pfnum * NBPG, buf, bytes > NBPG ? NBPG : bytes);
    }
    else
    {
	/* read from swap */
	if(lseek(sfd, (long)dtob(p->p_swaddr), L_SET) == -1)
	    xperror("swap seek");
	if(read(sfd, u, sizeof(*u)) < sizeof(*u))
	    return (struct user *)0;
    }
#endif

    return u;
}

fsid_t *
fsid(name)
    char *name;
{
    static struct statfs fsbuf;
    struct stat statbuf;

    if(stat(name, &statbuf) < 0)
	xperror("stat");

    if(statbuf.st_dev < 0)	/* seems to mean nfs */
    {
	if(statfs(name, &fsbuf) < 0)
	    xperror("statfs");
    }
    else
    {
	/* local UNIX file system */
	fsbuf.f_fsid.val[0] = statbuf.st_dev;
	fsbuf.f_fsid.val[1] = 0;	/* MOUNT_UFS */
    }

    return &fsbuf.f_fsid;
}
%-End-of-ffs.c-%