ofiles: list processes that have files open (ported from BSD)

Lenny Tropiano lenny at icus.islp.ny.us
Wed Mar 29 14:54:48 AEST 1989


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 at 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 at kenobi.cts.com
X- The Unix Programmer's Manual,		...!sdcsvax!crash!elgar!ford
X  2nd Edition, June, 1972.		ditto at 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 at 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 at 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



More information about the Unix-pc.sources mailing list