lenny@icus.islp.ny.us (Lenny Tropiano) (03/29/89)
Mike -=]Ford[=- Ditto sent this to me a while back, I figured it was something that would be useful to the UNIX PC community. It basically is an enchanced "fuser-type" program that will list the processes that have a particular file open. The program (using the "make install") will be installed setuid "root" into /usr/lbin, if you don't want this, please modify the Makefile, or install by hand. This was ported from the BSD ofiles, that was recently posted to comp.sources.unix. $ ofiles /dev/kmem /dev/kmem User PID Type Command root 192 f ttydaemon root 193 f loadavgd root 277 f sysinfo root 546 f ofiles $ ofiles /u/lenny/Filecabinet /u/lenny/Filecabinet User PID Type Command lenny 252 p ksh lenny 521 p postnews lenny 522 p vi root 550 p ofiles $ ofiles /dev/fp011 /dev/fp011 User PID Type Command lenny 252 f ksh lenny 522 f vi root 558 f ofiles Enjoy, Lenny -- cut here -- -- cut here -- -- cut here -- -- cut here -- -- cut here -- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Makefile README ofiles.c # Wrapped by lenny@icus on Tue Mar 28 23:48:17 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(736 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# X# Makefile to compile ofiles.c (Open Files) X# Port from BSD ofiles done by Mike -=]Ford[=- Ditto X# Makefile contributed by Lenny Tropiano X# X# NOTE: If you don't want this program installed setuid, so anyone can use it, X# modify the "make install" dependency with the permission you want to X# grant. X# XCFLAGS=-v -O XLDFLAGS=-s XLIBS=/lib/crt0s.o /lib/shlib.ifile XDEST=/usr/lbin/ XCC=cc XLD=ld X# Xofiles: ofiles.o X @echo "Loading ..." X $(LD) $(LDFLAGS) -o ofiles ofiles.o $(LIBS) X# X# You need to be super-user to do this. X# X$(DEST): X mkdir $(DEST) X chown bin $(DEST) X chgrp bin $(DEST) X chmod 755 $(DEST) X# Xinstall: ofiles $(DEST) X cp ofiles $(DEST) X chown root $(DEST)/ofiles X chgrp sys $(DEST)/ofiles X chmod 4755 $(DEST)/ofiles END_OF_Makefile if test 736 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(750 characters\) sed "s/^X//" >README <<'END_OF_README' X[.. in reply to a letter to Mike about "ofiles" ..] X XWell, I recently ran across a posting of something called "ofiles" for XBSD, and remembering your message, I decided to see if it ported Xeasily to the Unix PC. It did, and here it is, although it doesn't Xseem to exactly fit your description. It seems to be just a "fuser" Xprogram with slightly fancier output. X XHere's the BSD version and the Unix PC version. If you can track down Xthe program you were talking about, I'd like to see it. X X -=] Ford [=- X X"The number of Unix installations (In Real Life: Mike Ditto) Xhas grown to 10, with more expected." ford@kenobi.cts.com X- The Unix Programmer's Manual, ...!sdcsvax!crash!elgar!ford X 2nd Edition, June, 1972. ditto@cbmvax.commodore.com X END_OF_README if test 750 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f ofiles.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"ofiles.c\" else echo shar: Extracting \"ofiles.c\" \(6440 characters\) sed "s/^X//" >ofiles.c <<'END_OF_ofiles.c' X/* X * UNIX PC Port programmed by Mike -=]Ford[=- Ditto (ditto@cbmvax.commodore.com) X */ X X#ifndef lint Xstatic char rcsid[]="$Header: ofiles.c,v 1.1 85/05/03 06:49:19 cspencer Exp $"; X#endif lint X#include <sys/param.h> X#include <sys/dir.h> X#define KERNEL X#include <sys/file.h> X#undef KERNEL X#include <sys/inode.h> X#include <sys/user.h> X#include <sys/pte.h> X#include <sys/proc.h> X#include <nlist.h> X#include <sys/stat.h> X#include <pwd.h> X#include <sys/vmmac.h> X#include <sys/var.h> X#include <stdio.h> X X X#define CDIR 01 X#define OFILE 02 X#define RDIR 04 X X Xlong eseek(); X X#undef NOFILE Xint NOFILE; Xint nproc; /* number of entries in proc table */ Xint mem; /* fd for /dev/mem */ Xint kmem; Xint swap; /* fd for /dev/swap */ Xlong procbase; X Xint pids_only = 0; /* if non-zero, only output process ids */ X Xchar *progname; Xstruct nlist unix_nl[] = { X#define X_PROC 0 X {"proc"}, X#define X_VAR 1 X {"v"}, X#define X_NOFILE 2 X {"nofile"}, X {0} X}; X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X X struct inode *i,*getinode(); X struct stat s; X struct user *u, *getuser(); X struct proc p; X register int filen, flags, procn; X register char *filename, *fsname; X X progname = argv[0]; X X if(argc == 1) { X fprintf(stderr,"usage: %s [-p] files\n", progname); X exit(1); X } X X /* check for -p flag */ X if(strcmp(argv[1],"-p") == 0) { X pids_only++; X --argc; X ++argv; X } X X if((mem = open("/dev/mem", 0)) < 0) X error("can't open /dev/mem. "); X if((kmem = open("/dev/kmem", 0)) < 0) X error("can't open /dev/kmem. "); X if((swap = open("/dev/swap", 0)) < 0) X error("can't open /dev/swap. "); X getsyms(); X X while(--argc) { X filename = *++argv; X fsname = ""; X X if(stat(filename, &s)) { X fprintf(stderr,"can't stat %s. ",filename); X perror(""); X continue; X } X if(! pids_only) { X printf("%s\t%s\n", filename,fsname); X printf("%-8.8s\tPID\tType\tCommand\n", "User"); X } X for(procn = 0; procn < nproc; procn++){ X procslot(procn, &p); X flags = 0; X if(p.p_stat == 0 || p.p_stat == SZOMB) X continue; X u = getuser(&p); X if ( u == (struct user *)NULL) X continue; X i = getinode(u->u_rdir, "rdir"); X if(check(&s,i)) X flags |= RDIR; X X i = getinode(u->u_cdir, "cdir"); X if(check(&s,i)) X flags |= CDIR; X X for(filen = 0; filen < NOFILE; filen++) { X struct file f; X X if(u->u_ofile[filen] == NULL) X continue; X X eseek(kmem,(long)u->u_ofile[filen],0,"file"); X eread(kmem,(char *)&f, sizeof(f), "file"); X X if(f.f_count > 0) { X i = getinode((char *)f.f_inode, "file"); X if(check(&s,i)) X flags |= OFILE; X } X } X if(flags) gotone(u,&p,flags); X } X if(! pids_only) X printf("\n"); X } X} X X/* X * print the name of the user owning process "p" and the pid of that process X */ Xgotone(u,p,f) Xstruct user *u; Xstruct proc *p; Xint f; X{ X register struct passwd *pw; X struct passwd *getpwuid(); X X /* only print pids and return */ X if(pids_only) { X printf("%d ",p->p_pid); X fflush(stdout); X return; X } X pw = getpwuid(u->u_uid); X if(pw) X printf("%-8.8s\t", pw->pw_name ); X else X printf("(%d)\t", u->u_uid); X printf("%d\t", p->p_pid); X if(f & OFILE) putchar('f'); /* proc has a file */ X if(f & CDIR) putchar('p'); /* proc's current dir is on device */ X if(f & RDIR) putchar('r'); /* proc's root dir is on device */ X printf("\t"); X printf("%-14.14s", u->u_comm); X printf("\n"); X} X X/* X * is inode "i" on device "s"? returns TRUE or FALSE X */ Xcheck(s, i) Xstruct stat *s; Xstruct inode *i; X{ X if ((s->st_mode & S_IFMT) == S_IFBLK && s->st_rdev == brdev(i->i_dev)) X return 1; X else if((s->st_dev == brdev(i->i_dev)) && (s->st_ino == i->i_number)) X return 1; X else return 0; X} X X X/* X * getinode - read an inode from from mem at address "addr" X * return pointer to inode struct. X */ Xstruct inode *getinode(ip,s) Xstruct inode *ip; Xchar *s; X{ X static struct inode i; X X eseek(kmem, (long)ip, 0, "inode"); X eread(kmem, (char *)&i, sizeof(i), "inode"); X return &i; X} X X X X/* X * get user page for proc "p" from core or swap X * return pointer to user struct X */ Xstruct user *getuser(p) Xstruct proc *p; X{ X char buf[NBPC]; X long upage; X#define up ((struct user *)(buf + U_OFFSET)) X X if (!p->p_stat || X p->p_stat == SIDL || X p->p_stat == SZOMB) X return 0; X X if (p->p_flag & SLOAD) X { X lseek(mem, (long)ctob(p->p_addr[0]), 0); X read(mem, buf, sizeof buf); X } X else X { X lseek(swap, (long)dbtob((long)p->p_swaddr), 0); X read(swap, buf, sizeof buf); X } X X if (/* (up->u_procp != ((struct proc *)procbase)+procidx) || */ X (up->u_ruid != p->p_uid) || X ((long)(up->u_ofile) < (long)VPG_BASE) || X ((long)(up->u_ofile) >= X (long)VPG_BASE+sizeof (buf)-(sizeof (struct file *) * NOFILE))) X { X#ifdef DEBUG X fprintf(stderr, "Warning: got bogus user area; skipping.\n"); X#endif DEBUG X p->p_stat = 0; X return 0; X } X X /* Adjust the ofile pointer */ X up->u_ofile = (struct file **) X ((char *)up->u_ofile + ((long)buf-VPG_BASE)); X X return up; X#undef up X} X X/* X * read with error checking X */ Xeread( fd, p, size, s) Xint fd; Xchar *p; Xint size; Xchar *s; X{ X int n; X char buf[100]; X if(( n = read(fd, p, size)) != size){ X sprintf(buf, "read error for %s. ", s); X error(buf); X } X return n; X} X X/* X * seek with error checking X */ Xlong eseek(fd, off, whence, s) Xint fd; Xlong off; Xint whence; Xchar *s; X{ X long lseek(); X long ret; X char buf[100]; X X if(( ret = lseek(fd, off, whence)) != off) { X sprintf(buf, "seek for %s failed, wanted %o, got %o. ", X s, off, ret); X error(buf); X } X return ret; X} X X/* X * print mesg "s" followed by system erro msg. exit. X */ Xerror(s) Xchar *s; X{ X if (s) X fprintf(stderr,s); X perror(""); X exit(1); X} X X/* X * get some symbols form the kernel X */ Xgetsyms() X{ X register i; X struct var v; X X nlist("/unix", unix_nl); X X for(i = 0; i < (sizeof(unix_nl)/sizeof(unix_nl[0]))-1; i++) X if(unix_nl[i].n_value == 0) { X fprintf(stderr,"%s: can't nlist for %s.\n", X progname, unix_nl[i].n_name); X exit(1); X } X eseek(kmem, (long)unix_nl[X_NOFILE].n_value, 0); X eread(kmem, &NOFILE, sizeof(NOFILE), "NOFILE"); X eseek(kmem, (long)unix_nl[X_PROC].n_value, 0); X eread(kmem, &procbase, sizeof(procbase), "procbase 1"); X eseek(kmem, (long)unix_nl[X_VAR].n_value, 0); X eread(kmem, &v, sizeof(v), "var"); X nproc = v.v_proc; X return; X} X X X/* X * read proc table entry "n" into buffer "p" X */ Xprocslot(n, p) Xint n; Xstruct proc *p; X{ X eseek(kmem, procbase + (long)(n * sizeof(struct proc)), 0); X eread(kmem, (char *)p, sizeof(struct proc), "proc"); X return; X} END_OF_ofiles.c if test 6440 -ne `wc -c <ofiles.c`; then echo shar: \"ofiles.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0 -- Lenny Tropiano ICUS Software Systems [w] +1 (516) 582-5525 lenny@icus.islp.ny.us Telex; 154232428 ICUS [h] +1 (516) 968-8576 {talcott,decuac,boulder,hombre,pacbell,sbcs}!icus!lenny attmail!icus!lenny ICUS Software Systems -- PO Box 1; Islip Terrace, NY 11752