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, ®ion, 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-%