[comp.unix.shell] finding the filesystem of a file

dt@mathcs.emory.edu (Dave Taylor {guest}) (11/06/90)

Curious to know if anyone can tell me the fastest way to find out which
filesystem a given file is on if the entire pathname is given.  I have only
5 filesystems  but I'm stumped as to on how to make sure that I always match
the file with the appropriate filesystem.  i.e. if the files are /u/foo/bar/new
and maybe /u/foobar/new AND the filesystems are /u, /u/foo, and /u/foo/bar.

for the file /u/foo/bar/new, the output should be "/u/foo/bar"
for the file /u/foobar/new, the output should be "/u"

The reason for this is because I backup several filesystems on one tape and I
need to know which filesystem to look in as I search through my log files.

Thanks in advance for all your help.



--david

-- 
-------                                                                 -------
David E. Taylor, OMSS UNIX Development // Operation Mobilization USA
AT&T: (404) 631-0432  +====+  UUCP:    {decvax, sun!sunatl, gatech}!emory!om!dt
FAX:  (404) 631-0439  +====+  Internet: dt%om.uucp@mathcs.emory.edu

dt@mathcs.emory.edu (Dave Taylor {guest}) (11/06/90)

> Curious to know if anyone can tell me the fastest way to find out which
> filesystem a given file is on if the entire pathname is given.  I have only
> 5 filesystems  but I'm stumped as to on how to make sure that I always match
> the file with the appropriate filesystem. i.e. if the files are /u/foo/bar/new
> and maybe /u/foobar/new AND the filesystems are /u, /u/foo, and /u/foo/bar.


Just for clarification, this on SCO Xenix 2.3.2, so doing a df on the directo-
ory of file will NOT work, but thanks to those who replied so quickly.  HELP??

--david



-- 
-------                                                                 -------
David E. Taylor, OMSS UNIX Development // Operation Mobilization USA
AT&T: (404) 631-0432  +====+  UUCP: {decvax, sun!sunatl, gatech}!emory!omusa!dt
FAX:  (404) 631-0439  +====+  Internet: dt%omusa.uucp@mathcs.emory.edu

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (11/06/90)

In article <6500@emory.mathcs.emory.edu> dt@mathcs.emory.edu (Dave Taylor {guest}) writes:
: > Curious to know if anyone can tell me the fastest way to find out which
: > filesystem a given file is on if the entire pathname is given.  I have only
: > 5 filesystems  but I'm stumped as to on how to make sure that I always match
: > the file with the appropriate filesystem. i.e. if the files are /u/foo/bar/new
: > and maybe /u/foobar/new AND the filesystems are /u, /u/foo, and /u/foo/bar.
: 
: 
: Just for clarification, this on SCO Xenix 2.3.2, so doing a df on the directo-
: ory of file will NOT work, but thanks to those who replied so quickly.  HELP??

If you happen to have perl handy, either of the following will work
(presuming you have no symbolic links):

#!/usr/bin/perl
$file = shift;
(($filedev) = stat($file)) || die "Can't stat $file: $!\n";
foreach $comp (split(m#/#,$file)) {
    $path .= "$comp/";			# try left to right
    ($dev) = stat($path);
    if ($dev == $filedev) {
	chop($path);
	print "$path\n";
	exit;
    }
}
print $file;

or

#!/usr/bin/perl
$file = shift;
(($filedev) = stat($file)) || die "Can't stat $file: $!\n";

$shortest = $file;
while ($file =~ s#(.*)/.*#$1#) {	# try right to left
    ($dev) = stat($file || '/');
    if ($dev != $filedev) {
	print $shortest,"\n";
	exit;
    }
    $shortest = $file;
}
print "/\n";

The first one is probably a little faster on the average, since it has
to stat shorter names, and most mount points come early in the average
path name.

In the absence of perl, your best bet will probably be to look for the longest
match from /etc/mtab, presuming you have a reasonable one.  The following
works on my /etc/mtab, but is suboptimal:

#!/bin/sh

file="$1"

(
    echo 'case "'"$file"'" in'
    awk '{print $2}' /etc/mtab | sort -r | sed 's#\(.*\)#\1*) echo "\1";exit;;#'
    echo 'esac'
) | sh

You could, for instance, lose the awk and sort on the second field, and
pick out the second field with the sed.

No doubt Dan will tell me a way to do the whole thing with sort...  :-)

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

cpcahil@virtech.uucp (Conor P. Cahill) (11/06/90)

In article <6495@emory.mathcs.emory.edu> dt@mathcs.emory.edu (Dave Taylor {guest}) writes:
>Curious to know if anyone can tell me the fastest way to find out which
>filesystem a given file is on if the entire pathname is given.  I have only

Maybe not the fastest, but it will work:

lookup=path_to_look_up
len=0
filesys=`(mount; echo done) | while read fs junk
do
	if [ "x$fs" = "xdone" ]; then
		echo $lfs
	fi
	tlen=\`expr "x$lookup" : "x$fs"\`
	if [ "$tlen" -gt "$len" ]; then
		lfs="$fs"
		len="$tlen"
	fi

done`

echo "$filesys"


-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

dcon@cbnewsc.att.com (david.r.connet) (11/07/90)

In article <10243@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
> In article <6500@emory.mathcs.emory.edu> dt@mathcs.emory.edu (Dave Taylor {guest}) writes:
> : > Curious to know if anyone can tell me the fastest way to find out which
> : > filesystem a given file is on if the entire pathname is given.
> 
> If you happen to have perl handy, either of the following will work
> (presuming you have no symbolic links):
[some perl examples]
> 
> In the absence of perl, your best bet will probably be to look for the longest
> match from /etc/mtab, presuming you have a reasonable one.  The following
> works on my /etc/mtab, but is suboptimal:
[shell example]
On some systems, /etc/mtab is known as /etc/mnttab.


Also, on SVR4 systems, [I know this doesn't help you Dave, just throwing
out some additional things] you can use the statvfs() call.
	int statvfs(char *path, struct statvfs *buf);
The field buf->f_fstr will give the filesystem name.

Dave Connet
dcon@iwtng.att.com

guy@auspex.auspex.com (Guy Harris) (11/08/90)

>Also, on SVR4 systems, [I know this doesn't help you Dave, just throwing
>out some additional things] you can use the statvfs() call.
>	int statvfs(char *path, struct statvfs *buf);
>The field buf->f_fstr will give the filesystem name.

Assuming that's what the particular file system type puts there.  The
manual page describes it as a "file-system specific string", so a file
system type could put a string giving its author's birthday there if it
chooses to....

jeff@onion.pdx.com (Jeff Beadles) (11/08/90)

dt@mathcs.emory.edu (Dave Taylor {guest}) writes:
>Curious to know if anyone can tell me the fastest way to find out which
>filesystem a given file is on if the entire pathname is given.  I have only

Well, I didn't see the entire question, but if you're trying this from the
shell (This is comp.unix.shell, ya know... :-), and have a newer version of
df, then you might be able to do something like this:

% df /usr2/jeff/.newsrc

Filesystem    kbytes    used   avail capacity  Mounted on
/dev/ds08a    279922   32566  219363    13%    /usr2

From that, you could do something like:

------------------------snip here-----------------------------
#!/bin/sh
if [ -z "$1" -o ! -r "$1" -o $# -ne 1 ] ; then
	echo "Usage: $0 filename"
	exit 1
fi

## Do the df, print the 6th field of a line starting with '/'.
df $1 | awk '/^\// { print $6 } '

exit 0
------------------------snip here-----------------------------


Of course if your output of df is different, you may have to change the $6
to something else.

If you're trying to do this from 'C', then look at the statfs(2) man page.

Hope this helps!

	-Jeff
-- 
Jeff Beadles		jeff@onion.pdx.com

cbp@icc.com (Chris Preston) (11/10/90)

In article <1990Nov06.021023.11941@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>In article <6495@emory.mathcs.emory.edu> dt@mathcs.emory.edu (Dave Taylor {guest}) writes:
>>Curious to know if anyone can tell me the fastest way to find out which
>>filesystem a given file is on if the entire pathname is given.  I have only
>
>Maybe not the fastest, but it will work:
[shell script deleted]
or an awk solution

mount | 
awk 'BEGIN{
# file is defined so as to minimize confusion by useing $1 in substr()
# also, I believe that this should be $3 in Xenixland
	file="'$1'"
	if ( file == "" ){
		print "Usage: '$0' <filename>"
		exit
	}
}
{
	lenfsnam=length($1)
	if ( $1 == substr(file,0,lenfsnam) ){
		list[lenfsnam]=$1
		if ( lenfsnam > closematch )
			closematch=lenfsnam
	}
}
END{ 
	if ( closematch )
		print list[closematch]
	else
#totally optional - should take out if meant for pipe usage
		print "no match"
}' 

cbp
---
Kurt Waldheim to Saddam Hussein:
"Saddam, I knew Hitler, and believe me, you're no Adolf Hitler."