Rapid Location of Mount Points
b.banerjee
bba at cbnewsj.ATT.COM
Tue Dec 12 12:14:06 AEST 1989
The following perl script is my implementation of the program
described in the article:
Rapid Location of Mount Points
Jonathan M. Smith
Computer Science Dept.
Columbia University, New York NY 10027
Software Practice and Experience Vol. 19(9), Sep. 1989.
This script (and the associated C program) will read the kernel
and print out the contents of the mount table given a Sys V
kernel. But, you say, /etc/mount does the same thing! Wrong!!
/etc/mount merely prints out the contents of /etc/mnttab. If
something munges this file -- you are SOL.
I make no claims on the code, nor any apologies. This is a quick
hack. I needed something quickly, as the /etc/mnttab on my system
was getting zorched on a semi-regular basis (still need to track
down the culprit).
It is easy enough to modify this to generate input to the
setmnt(1m) command or to use it in a variety of ways to
re-generate /etc/mnttab.
There are probably still bugs in it -- but it works well enough
for the time being. Some time when I don't have a zillion things
on my to-do list, I'll clean it up and rewrite it in C. It should
run about 2-3 times faster.
INSTALLATION:
------------
Install the dumpmnt shell script wherever convenient. Make sure
that the path to dumpmnt is specified in findmount.pl. Invoke
with:
perl findmount.pl
You'll need read access to /dev/kmem. You can either make dumpmnt
setgid to whichever group owns /dev/kmem (sys?) or run it as root.
I hope that you find this useful. If you make any
fixes/enhancements, I'd appreciate hearing about them.
Binayak Banerjee
bba at mtuxo.ATT.COM
AT&T Bell Labs
Middletown, NJ 07724.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of shell archive."
# Contents: README dumpmnt.c findmount.pl
# Wrapped by bba at mtuxo on Mon Dec 11 20:03:00 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1695 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThe following perl script is my implementation of the program
Xdescribed in the article:
X
X Rapid Location of Mount Points
X Jonathan M. Smith
X Computer Science Dept.
X Columbia University, New York NY 10027
X Software Practice and Experience Vol. 19(9), Sep. 1989.
X
XThis script (and the associated C program) will read the kernel
Xand print out the contents of the mount table given a Sys V
Xkernel. But, you say, /etc/mount does the same thing! Wrong!!
X/etc/mount merely prints out the contents of /etc/mnttab. If
Xsomething munges this file -- you are SOL.
X
XI make no claims on the code, nor any apologies. This is a quick
Xhack. I needed something quickly, as the /etc/mnttab on my system
Xwas getting zorched on a semi-regular basis (still need to track
Xdown the culprit).
X
XIt is easy enough to modify this to generate input to the
Xsetmnt(1m) command or to use it in a variety of ways to
Xre-generate /etc/mnttab.
X
XThere are probably still bugs in it -- but it works well enough
Xfor the time being. Some time when I don't have a zillion things
Xon my to-do list, I'll clean it up and rewrite it in C. It should
Xrun about 2-3 times faster.
X
XINSTALLATION:
X------------
X
XInstall the dumpmnt shell script wherever convenient. Make sure
Xthat the path to dumpmnt is specified in findmount.pl. Invoke
Xwith:
X
X perl findmount.pl
X
XYou'll need read access to /dev/kmem. You can either make dumpmnt
Xsetgid to whichever group owns /dev/kmem (sys?) or run it as root.
X
XI hope that you find this useful. If you make any
Xfixes/enhancements, I'd appreciate hearing about them.
X
X Binayak Banerjee
X bba at mtuxo.ATT.COM
X AT&T Bell Labs
X Middletown, NJ 07724.
END_OF_FILE
echo shar: NEWLINE appended to \"'README'\"
if test 1696 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'dumpmnt.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dumpmnt.c'\"
else
echo shar: Extracting \"'dumpmnt.c'\" \(6896 characters\)
sed "s/^X//" >'dumpmnt.c' <<'END_OF_FILE'
X/*
X * dumpmnt -c core -u executable
X *
X * Default value for core is /dev/kmem.
X * Default value for executable is /unix.
X *
X * This program will print out the following kernel information:
X *
X * mount-device (maj/min) parent-mount-device (maj/min) readonly-flag
X *
X * It is meant to be called from the ``findmount'' perl script.
X * (Appended to this file)
X *
X * Binayak Banerjee
X * bba at mtuxo.ATT.COM
X * AT&T Bell Labs
X * Middletown, NJ 07724
X * Mon Dec 11 19:53:39 EST 1989
X */
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/inode.h>
X#include <sys/sysmacros.h>
X#include <sys/buf.h>
X#include <sys/filsys.h>
X#include <sys/mount.h>
X#include <sys/var.h>
X#include <nlist.h>
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
Xlong lseek();
X
X# define UNIX "/unix" /* kernel */
X# define KMEM "/dev/kmem" /* kernel virtual memory */
X# define MEM "/dev/mem" /* kernel real memory */
X
Xstatic int kmem = -1; /* File Descriptor for /dev/kmem */
Xstatic int mem = -1; /* File Descriptor for /dev/mem */
X
Xstruct var Var;
Xstruct filsys SBlock;
Xstruct inode PInode;
Xstruct mount *mnttab;
Xstruct buf SbBuffer;
X
Xstatic struct nlist nlst[] = {
X# define MOUNT 0
X { "mount" },
X# define VAR 1
X { "v" },
X { NULL },
X};
X
Xinit_kernel(U_kmem,U_unix,U_nlst)
Xchar *U_kmem,*U_unix;
Xstruct nlist *U_nlst;
X{
X
X /* open kernel memory */
X if ((kmem = open(U_kmem, 0)) < 0)
X {
X perror(U_kmem);
X exit(20);
X }
X
X if (nlist(U_unix,U_nlst) == -1)
X {
X fprintf(stderr, "%s: can't nlist image\n",U_unix);
X exit(2);
X }
X
X return;
X}
X
X
Xgetkval(offset, ptr, size, refstr)
X
Xunsigned long offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{
X if (lseek(kmem, (long)offset, 0) == -1)
X {
X if (*refstr == '!')
X {
X refstr++;
X }
X fprintf(stderr, "%s: lseek to %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X exit(22);
X }
X if (read(kmem, (char *)ptr, size) == -1)
X {
X if (*refstr == '!')
X {
X /* we lost the race with the kernel, process isn't in memory */
X return(0);
X }
X else
X {
X fprintf(stderr, "%s: reading %s: %s\n",
X KMEM, refstr, sys_errlist[errno]);
X exit(23);
X }
X }
X return;
X}
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X int c;
X int MntSiz;
X int i;
X struct mount *mptr;
X char *core_file = KMEM;
X char *ex_file = UNIX;
X
X extern int optind, getopt();
X extern char *optarg;
X
X while ((c = getopt(argc,argv,"c:u:")) != EOF)
X switch (c)
X {
X case 'c': /* Specify core file */
X core_file = optarg;
X break;
X
X case 'u': /* Specify executable image */
X ex_file = optarg;
X break;
X
X default:
X break;
X }
X
X init_kernel(core_file,ex_file,&nlst[0]);
X
X /*
X * First Get var structure to find size of mount table.
X */
X (void) getkval(nlst[VAR].n_value,
X (int *)(&Var),
X sizeof(struct var),
X nlst[VAR].n_name);
X
X MntSiz = Var.v_mount;
X
X /*
X * Now, allocate space for the mount table and read it
X * all in -- in one shot.
X */
X
X mnttab = (struct mount *) malloc(sizeof(struct mount)*MntSiz);
X if (mnttab == (struct mount *)0) {
X fprintf(stderr,"%s: Couldn't allocate space\n",argv[0]);
X exit(2);
X }
X
X (void) getkval(nlst[MOUNT].n_value,
X (int *) mnttab,
X sizeof(struct mount)*MntSiz,
X nlst[MOUNT].n_name);
X
X /*
X * Now, we iterate through the entries in the mount table,
X * printing out the relevant information.
X */
X
X for (i = 0; i < MntSiz; i++) {
X mptr = &mnttab[i];
X if (! (mptr->m_flags & MINUSE)) continue;
X
X /* Now grab the parent device inode */
X
X (void) getkval(mptr->m_inodp,
X (int *) &PInode,
X sizeof(struct inode),
X "inode");
X
X /*
X * Also grab the boot block for readonly-ness
X * But first must grab the buffer for the superblock.
X */
X
X (void) getkval(mptr->m_bufp,
X (int *) &SbBuffer,
X sizeof(struct buf),
X "super block buffer");
X
X
X /* Now grab the superblock */
X (void) getkval(SbBuffer.b_un.b_filsys,
X (int *) &SBlock,
X sizeof(struct filsys),
X "superblock");
X
X
X /* Now print it all out */
X
X printf ("%d (%d/%d) %d (%d/%d) %d\n",
X mptr->m_dev,
X bmajor(mptr->m_dev),
X minor(mptr->m_dev),
X PInode.i_dev,
X bmajor(PInode.i_dev),
X minor(PInode.i_dev),
X SBlock.s_ronly);
X }
X}
X/* Here is findmount.pl */
X# ifdef notdef
X#! /usr/bin/perl
X
X# This routine will walk through a directory (/dev) and create a
X# map between device numbers and their names. It does a
X# depth first search through the directory.
X
X# Binayak Banerjee
X# bba at mtuxo.ATT.COM
X# AT&T Bell Labs
X# Middletown, NJ 07724
X# Mon Dec 11 19:53:39 EST 1989
X
Xsub devmap {
X local($thisdir,$item,$dev,$ino,$mode);
X local($nlink,$uid,$gid,$devno, at junk);
X
X push(dlist, at _[0]);
X
X while ($thisdir=pop(dlist)) {
X opendir(DH,$thisdir);
X while ($item = readdir(DH)) {
X if ($item =~ /^\.$|^\.\.$/) { next;}
X $item = join('/',$thisdir,$item);
X if (-d $item) {
X push(dlist,$item);
X next;
X }
X if (-b _) {
X ($dev,$ino,$mode,$nlink,
X $uid,$gid,$devno, at junk) = stat(_);
X @devname[$devno] = $item;
X }
X }
X closedir(DH);
X }
X}
X
X# We want to find out certain information about the mounted
X# file systems in order to cut down on the search. We do this
X# by opening a pipe to an external program "dumpmnt" which prints
X# out 3 date items of interest. These are:
X#
X# 1. The mounted device.
X# 2. The parent of the mounted device.
X# 3. A boolean value specifying if the device is
X# mounted readonly.
X
X$INTERIOR = 100;
X$LEAF = 200;
X
Xsub GetDevInfo {
X open(inp_pipe,'./dumpmnt |');
X
X while (<inp_pipe>) {
X ($tdev,$pdev,$rflg) =
X /^(\d+)\s+\(.*\)\s+(\d+)\s+\(.*\)\s+([01])$/;
X # Now set up the leaf and interior node bit.
X $devtyp[$pdev] = $INTERIOR;
X if ($devtyp[$tdev] != $INTERIOR) {
X $devtyp[$tdev] = $LEAF;
X }
X # Now readonly flags
X $readonly[$tdev] = $rflg? "read only":"read/write";
X }
X close(inp_pipe);
X}
X
X# Read some information about the devices (other than names).
X
X# Make the map of device numbers to names.
Xdo devmap("/dev");
X
X# Do map of device number types.
X
Xdo GetDevInfo();
X
X# Now here is the meat of the whole thing.
X
X# prime the pump.
X
X$thisdir = '/';
X($dev, at junk) = stat($thisdir);
Xprint "/ on $devname[$dev] $readonly[$dev]\n";
Xpush(dirlist,$dev);
Xpush(dirlist,"/");
Xwhile ($thisdir=pop(dirlist)) {
X $dirdev = pop(dirlist);
X # if ($thisdir =~ m'^/dev$') { next; }
X opendir(DH,$thisdir);
X # Skip over '.' and '..'
X $item = readdir(DH); $item = readdir(DH);
X while ($item = readdir(DH)) {
X $item = join('/',$thisdir,$item);
X if (! -d $item) { next; }
X
X ($dev,$ino,$mode,$nlink, at junk) = stat(_);
X
X # Mount point if dev is not the same as that
X # of it's parent.
X if ($dev != $dirdev) {
X $item =~ s'^//'/';
X print "$item on $devname[$dev] $readonly[$dev]\n";
X }
X
X # The directory has no subdirectories if it has
X # only 2 links.
X if ($nlink == 2 || $devtyp[$dev] == $LEAF){
X # print STDERR "$item is skipped\n";
X next;
X }
X # print "pushing $item\n";
X push(dirlist,$dev);
X push(dirlist,$item);
X }
X closedir(DH);
X}
X# endif
X
END_OF_FILE
echo shar: NEWLINE appended to \"'dumpmnt.c'\"
if test 6897 -ne `wc -c <'dumpmnt.c'`; then
echo shar: \"'dumpmnt.c'\" unpacked with wrong size!
fi
# end of 'dumpmnt.c'
fi
if test -f 'findmount.pl' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'findmount.pl'\"
else
echo shar: Extracting \"'findmount.pl'\" \(2718 characters\)
sed "s/^X//" >'findmount.pl' <<'END_OF_FILE'
X#! /usr/bin/perl
X
X# This routine will walk through a directory (/dev) and create a
X# map between device numbers and their names. It does a
X# depth first search through the directory.
X
X# Binayak Banerjee
X# bba at mtuxo.ATT.COM
X# AT&T Bell Labs
X# Middletown, NJ 07724
X# Mon Dec 11 19:53:39 EST 1989
X
Xsub devmap {
X local($thisdir,$item,$dev,$ino,$mode);
X local($nlink,$uid,$gid,$devno, at junk);
X
X push(dlist, at _[0]);
X
X while ($thisdir=pop(dlist)) {
X opendir(DH,$thisdir);
X while ($item = readdir(DH)) {
X if ($item =~ /^\.$|^\.\.$/) { next;}
X $item = join('/',$thisdir,$item);
X if (-d $item) {
X push(dlist,$item);
X next;
X }
X if (-b _) {
X ($dev,$ino,$mode,$nlink,
X $uid,$gid,$devno, at junk) = stat(_);
X @devname[$devno] = $item;
X }
X }
X closedir(DH);
X }
X}
X
X# We want to find out certain information about the mounted
X# file systems in order to cut down on the search. We do this
X# by opening a pipe to an external program "dumpmnt" which prints
X# out 3 date items of interest. These are:
X#
X# 1. The mounted device.
X# 2. The parent of the mounted device.
X# 3. A boolean value specifying if the device is
X# mounted readonly.
X
X$INTERIOR = 100;
X$LEAF = 200;
X
Xsub GetDevInfo {
X open(inp_pipe,'./dumpmnt |');
X
X while (<inp_pipe>) {
X ($tdev,$pdev,$rflg) =
X /^(\d+)\s+\(.*\)\s+(\d+)\s+\(.*\)\s+([01])$/;
X # Now set up the leaf and interior node bit.
X $devtyp[$pdev] = $INTERIOR;
X if ($devtyp[$tdev] != $INTERIOR) {
X $devtyp[$tdev] = $LEAF;
X }
X # Now readonly flags
X $readonly[$tdev] = $rflg? "read only":"read/write";
X }
X close(inp_pipe);
X}
X
X# Read some information about the devices (other than names).
X
X# Make the map of device numbers to names.
Xdo devmap("/dev");
X
X# Do map of device number types.
X
Xdo GetDevInfo();
X
X# Now here is the meat of the whole thing.
X
X# prime the pump.
X
X$thisdir = '/';
X($dev, at junk) = stat($thisdir);
Xprint "/ on $devname[$dev] $readonly[$dev]\n";
Xpush(dirlist,$dev);
Xpush(dirlist,"/");
Xwhile ($thisdir=pop(dirlist)) {
X $dirdev = pop(dirlist);
X # if ($thisdir =~ m'^/dev$') { next; }
X opendir(DH,$thisdir);
X # Skip over '.' and '..'
X $item = readdir(DH); $item = readdir(DH);
X while ($item = readdir(DH)) {
X $item = join('/',$thisdir,$item);
X if (! -d $item) { next; }
X
X ($dev,$ino,$mode,$nlink, at junk) = stat(_);
X
X # Mount point if dev is not the same as that
X # of it's parent.
X if ($dev != $dirdev) {
X $item =~ s'^//'/';
X print "$item on $devname[$dev] $readonly[$dev]\n";
X }
X
X # The directory has no subdirectories if it has
X # only 2 links.
X if ($nlink == 2 || $devtyp[$dev] == $LEAF){
X # print STDERR "$item is skipped\n";
X next;
X }
X # print "pushing $item\n";
X push(dirlist,$dev);
X push(dirlist,$item);
X }
X closedir(DH);
X}
X
END_OF_FILE
echo shar: NEWLINE appended to \"'findmount.pl'\"
if test 2719 -ne `wc -c <'findmount.pl'`; then
echo shar: \"'findmount.pl'\" unpacked with wrong size!
fi
# end of 'findmount.pl'
fi
echo shar: End of shell archive.
exit 0
More information about the Alt.sources
mailing list