#! /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:  Make.fuser fuser.c
# Wrapped by brant@manta on Tue Feb 14 14:43:12 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Make.fuser' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Make.fuser'\"
else
echo shar: Extracting \"'Make.fuser'\" \(204 characters\)
sed "s/^X//" >'Make.fuser' <<'END_OF_FILE'
XSHELL=/bin/sh
XINSTALL=mv
XLBIN=/usr/local/bin
XCFLAGS=-c -O
Xinclude $(MAKEINC)/Makepre.h
X
Xfuser : fuser.o
X	ld $(SHAREDLIB) -s -o fuser fuser.o
X	chmod 4755 fuser
X	chown root fuser
X	$(INSTALL) fuser $(LBIN)
X
END_OF_FILE
if test 204 -ne `wc -c <'Make.fuser'`; then
    echo shar: \"'Make.fuser'\" unpacked with wrong size!
fi
# end of 'Make.fuser'
fi
if test -f 'fuser.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'fuser.c'\"
else
echo shar: Extracting \"'fuser.c'\" \(9081 characters\)
sed "s/^X//" >'fuser.c' <<'END_OF_FILE'
X/************************************************************
X *
X * This program was written by me, Mike "Ford" Ditto, and
X * I hereby release it into the public domain in the interest
X * of promoting the development of free, quality software
X * for the hackers and users of the world.
X *
X * Feel free to use, copy, modify, improve, and redistribute
X * this program, but keep in mind the spirit of this
X * contribution; always provide source, and always allow
X * free redistribution (shareware is fine with me).  If
X * you use a significant part of this code in a program of
X * yours, I would appreciate being given the appropriate
X * amount of credit.
X *				-=] Ford [=-
X *
X ************************************************************/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <ctype.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/sysmacros.h>
X#include <sys/stat.h>
X#include <sys/tune.h>
X#include <sys/inode.h>
X#include <sys/file.h>
X#include <sys/user.h>
X#include <sys/proc.h>
X#include <sys/signal.h>
X#include <a.out.h>
X
X/* get rid of meaningless NOFILE from param.h */
X#ifdef NOFILE
X#undef NOFILE
X#endif
X
Xextern char *sbrk();
Xextern long lseek();
Xextern void perror(), exit();
Xextern struct passwd *getpwuid();
X
X
Xchar *progname;
X
X#define tuhiaddr (mysyms[0].n_value)
X#define inodeaddr (mysyms[1].n_value)
X#define fileaddr (mysyms[2].n_value)
X#define procaddr (mysyms[3].n_value)
X#define nofileaddr (mysyms[4].n_value)
X
Xstruct nlist mysyms[] =
X{
X    { "tuhi", },
X    { "inode", },
X    { "file", },
X    { "proc", },
X    { "nofile", },
X    { (char *)0, },
X};
X
Xchar buf[BUFSIZ];
X
Xint kmem, mem, kflag, uflag;
Xint NINODE, NFILE, NPROC, NOFILE;
X
Xstruct inode *inode;
Xstruct file *file;
Xstruct proc *proc;
X
X
X/* main program for fuser(1M), a program which lists */
X/* processes that are using the given file(s) */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    int status=0;
X
X    progname = *argv;
X
X    setup();
X
X    while (++argv,--argc)
X	if ((*argv)[0]=='-')
X	{
X	    register char c, *i;
X
X	    kflag=uflag=0;
X
X	    i = *argv+1;
X	    while (c= *i++) switch(c)
X	    {
X	    case 'k':
X		++kflag;
X		break;
X	    case 'u':
X		++uflag;
X		break;
X	    default:
X		fprintf(stderr, "%s: bad flag `-%c'\n", progname, c);
X		fprintf(stderr,
X			"Usage: %s [-ku] files [[-] [-ku] files]\n",
X			progname);
X		return -1;
X	    }
X	}
X	else
X	    status += fuser(*argv);
X
X    return status;
X}
X
X
X/* a fast, zeroizing, memory allocator for things */
X/* that will never need to be freed */
Xchar *myalloc(nbytes)
Xlong nbytes;
X{
X    register char *ptr = sbrk((int)nbytes);
X
X    if ((long)ptr < 0L)
X    {
X	sprintf(buf, "%s: no memory!", progname);
X	perror(buf);
X	exit(1);
X    }
X
X    return ptr;
X}
X
X
X/* one-time setup of main data structures from the kernel */
Xsetup()
X{
X    struct tunable tune;
X
X    if ( (kmem=open("/dev/kmem", O_RDONLY)) < 0 )
X    {
X	sprintf(buf, "%s: can't open /dev/kmem", progname);
X	perror(buf);
X	exit(1);
X    }
X
X    if ( (mem=open("/dev/mem", O_RDONLY)) < 0 )
X    {
X	sprintf(buf, "%s: can't open /dev/mem", progname);
X	perror(buf);
X	exit(1);
X    }
X
X    if (nlist("/unix", mysyms))
X    {
X	sprintf(buf, "%s: can't nlist /unix", progname);
X	perror(buf);
X	exit(1);
X    }
X
X    setuid(getuid());
X
X    kcopy((char *)&NOFILE, nofileaddr, (long) sizeof NOFILE);
X
X#ifdef DEBUG
X    fprintf(stderr, "tuhi:	0x%08lx\n", tuhiaddr);
X#endif DEBUG
X    kcopy((char *)&tune, tuhiaddr, (long) sizeof tune);
X
X    /* do indirection on these addresses, since they */
X    /* are just pointers in the kernel */
X    kcopy((char *)&inodeaddr, inodeaddr, (long) sizeof inodeaddr);
X    kcopy((char *)&fileaddr, fileaddr, (long) sizeof fileaddr);
X    kcopy((char *)&procaddr, procaddr, (long) sizeof procaddr);
X
X#ifdef DEBUG
X    fprintf(stderr, "inode:	0x%08lx\n", inodeaddr);
X    fprintf(stderr, "file:	0x%08lx\n", fileaddr);
X    fprintf(stderr, "proc:	0x%08lx\n", procaddr);
X#endif DEBUG
X
X    NINODE = tune.ninode;
X    NFILE = tune.nfile;
X    NPROC = tune.nproc;
X
X#ifdef DEBUG
X    fprintf(stderr, "NOFILE:	%d\n", NOFILE);
X    fprintf(stderr, "NINODE:	%d\n", NINODE);
X    fprintf(stderr, "NFILE:	%d\n", NFILE);
X    fprintf(stderr, "NPROC:	%d\n", NPROC);
X#endif DEBUG
X
X    inode = (struct inode *)myalloc((long) sizeof (struct inode) * NINODE);
X    file = (struct file *)myalloc((long) sizeof (struct file) * NFILE);
X    proc = (struct proc *)myalloc((long) sizeof (struct proc) * NPROC);
X
X    kcopy((char *)inode, inodeaddr, (long) sizeof (struct inode) * NINODE);
X    kcopy((char *)file, fileaddr, (long) sizeof (struct file) * NFILE);
X    kcopy((char *)proc, procaddr, (long) sizeof (struct proc) * NPROC);
X}
X
X
X/* copy bytes from physical address space to this process */
Xpcopy(caddr, paddr, nbytes)
Xchar *caddr;
Xlong paddr;
Xlong nbytes;
X{
X    if ( lseek(mem, paddr, 0)<0L ||
X	read(mem, caddr, (unsigned)nbytes) != nbytes )
X    {
X	sprintf(buf, "%s: can't read /dev/mem", progname);
X	perror(buf);
X	exit(1);
X    }
X}
X
X
X/* copy bytes from kernel address space to this process */
Xkcopy(caddr, kaddr, nbytes)
Xchar *caddr;
Xlong kaddr;
Xlong nbytes;
X{
X    if ( lseek(kmem, kaddr, 0)<0L ||
X	read(kmem, caddr, (unsigned)nbytes) != nbytes )
X    {
X	sprintf(buf, "%s: can't read /dev/kmem", progname);
X	perror(buf);
X	exit(1);
X    }
X}
X
X
X/* Return a pointer to a local copy of the user structure */
X/* for process number `procidx'.  Returns NULL if procidx */
X/* refers to an invalid (not-in-use or otherwise) slot. */
Xstruct user *getuser(procidx)
Xint procidx;
X{
X    static struct user **users;
X    struct file **ofile;
X    long upage;
X
X    if (!proc[procidx].p_stat ||
X	proc[procidx].p_stat == SIDL ||
X	proc[procidx].p_stat == SZOMB)
X	return 0;
X
X    if (!(proc[procidx].p_flag & SLOAD))
X    {
X	/* can't handle swapped process yet */
X	fprintf(stderr, "%s: can't handle swapped process %d (flag=%05x)\n",
X		progname, proc[procidx].p_pid, proc[procidx].p_flag);
X	return 0;
X    }
X
X    if (!users)
X	users = (struct user **)myalloc((long) sizeof (struct user *) * NPROC);
X
X    if (!users[procidx])
X    {
X	upage = (long)ctob(proc[procidx].p_addr[0]);
X
X	/* allocate and copy in the user structure */
X	users[procidx] = (struct user *)myalloc((long) sizeof (struct user));
X	pcopy((char *)(users[procidx]),
X	      upage + U_OFFSET,
X	      (long) sizeof (struct user));
X
X	/* allocate and copy in the list of file pointers */
X	ofile = (struct file **)myalloc((long) sizeof (struct file *) * NOFILE);
X	pcopy((char *)ofile,
X	      upage+(long)(users[procidx]->u_ofile)-VPG_BASE,
X	      (long) sizeof (struct file *) * NOFILE);
X	users[procidx]->u_ofile = ofile;
X    }
X
X    return users[procidx];
X}
X
X
X/* find all users of the file `name' */
Xfuser(name)
Xchar *name;
X{
X    register i;
X    int filesys;
X    struct stat Stat;
X
X    if (stat(name, &Stat))
X    {
X	sprintf(buf, "%s: can't stat %s", progname, name);
X	perror(buf);
X	return 1;
X    }
X
X    /* see if we are looking for a whole filesystem */
X    filesys = ((Stat.st_mode&S_IFMT) == S_IFBLK);
X
X#ifdef DEBUG
X    if (filesys)
X	fprintf(stderr, "looking for files on dev=%d,%d\n",
X		bmajor(Stat.st_rdev), minor(Stat.st_rdev));
X    else
X	fprintf(stderr, "looking for dev=%d,%d, ino=%d\n",
X		bmajor(Stat.st_dev), minor(Stat.st_dev), Stat.st_ino);
X#endif DEBUG
X
X    for ( i=0 ; i<NINODE ; ++i )
X    {
X	if ( inode[i].i_count &&
X	     (filesys
X		 ? (brdev(inode[i].i_dev) == Stat.st_rdev)
X		 : (brdev(inode[i].i_dev) == Stat.st_dev &&
X		    inode[i].i_number == Stat.st_ino)) )
X	{
X#ifdef DEBUG
X	    fprintf(stderr, "Found it!  inode[%d], i_size is %ld\n",
X		   i, inode[i].i_size);
X#endif DEBUG
X
X	    iuser((struct inode *)inodeaddr + i);
X	}
X    }
X
X    putchar('\n');
X
X    return 0;
X}
X
X
X#define CHECK(kaddr, type) if (kaddr==kinode) { if (++flag==1) printf(" %d", proc[i].p_pid); if (type) putchar(type); }
X
X/* find all users of the inode at kernel address `kinode' */
Xiuser(kinode)
Xstruct inode *kinode;
X{
X    register int i, j;
X    int flag;
X    struct user *user;
X    struct passwd *pwd;
X
X#ifdef DEBUG
X    fprintf(stderr, "Looking for users of inode at kernel address 0x%08lx\n",
X	    kinode);
X#endif DEBUG
X
X    for ( i=0 ; i<NPROC ; ++i )
X	if (user = getuser(i))
X	{
X#ifdef DEBUG
X	    fprintf(stderr, "%03d: pid=%5d addr[0]=%05x addr[1]=%05x swaddr=%05x\n",
X		    i, proc[i].p_pid, proc[i].p_addr[0], proc[i].p_addr[1],
X		    proc[i].p_swaddr);
X#endif DEBUG
X
X#ifdef DEBUG
X	    fprintf(stderr, "	user = 0x%08lx\n", user);
X	    fprintf(stderr, "	user->u_ofile = 0x%08lx\n", user->u_ofile);
X#endif DEBUG
X
X	    fflush(stderr);
X	    flag=0;
X	    CHECK(user->u_cdir, 'c');
X	    CHECK(user->u_rdir, 'r');
X	    CHECK(user->u_pdir, 'p');
X	    for ( j=0 ; !flag && j<NOFILE ; ++j )
X		if (user->u_ofile[j])
X		    CHECK(file[user->u_ofile[j]-(struct file *)fileaddr].f_inode, 0);
X	    fflush(stdout);
X
X	    if (flag)
X	    {
X		if (uflag)
X		{
X		    if ( (pwd=getpwuid((int)proc[i].p_uid)) )
X			fprintf(stderr, "(%s)", pwd->pw_name);
X		    else
X			fprintf(stderr, "(%d)", proc[i].p_uid);
X		}
X		if (kflag && proc[i].p_pid)
X		    if (kill(proc[i].p_pid, SIGKILL))
X		    {
X			sprintf(buf, "%s: can't kill process %d",
X				progname, proc[i].p_pid);
X			perror(buf);
X		    }
X	    }
X	}
X}
END_OF_FILE
if test 9081 -ne `wc -c <'fuser.c'`; then
    echo shar: \"'fuser.c'\" unpacked with wrong size!
fi
# end of 'fuser.c'
fi
echo shar: End of shell archive.
exit 0

