[comp.unix.wizards] RFS/NFS file detection - possible solution

clewis@eci386.uucp (Chris Lewis) (02/23/90)

For those of you who've expressed some interest in detecting RFS/NFS
files, I got a couple of leads by mail, plus I've discovered a few 
things on my own, plus I have some testcode if you're interested....

This was from Larry Wall:

> I don't know that it's documented either, but everywhere I've looked the
> dev of NFS is negative (treating it as a signed value).  This includes
> Vaxen, Suns, Masscomps and Pyramids.  I suspect that anyone that uses
> Sun's code will end up doing this, unless they've already reserved
> negative devices for some other purpose.
 
> If we make enough programs that rely on it, they might make it a standard. :-)
 
> I have no idea about RFS.
 
> Larry Wall
> lwall@jpl-devvax.jpl.nasa.gov

Thank you Larry!

This was sort of what I expected.  I also discovered on System VR3 (386/ix
1.0.6 specifically) and AIX that in /usr/include/sys/sysmacros.h (which
is where major() and minor() is defined on System Vish systems), has some
wierdishness that may imply similar functionality.  On 386/ix major()
returns a unsigned int that has bit 8 very carefully masked off:

    #define	major(x)	(int)((unsigned)((x)>>8)&0x7F)

(older code (eg: SCO pre-286 days) had 0xFF)

On AIX, they don't do the masking, but they define a "bmajor()" that does.
(on 386/ix, bmajor and major are the same).  On the system running AIX
I've had access to, the following was true for files/directories on 
networked file systems:

	major(stb.st_dev) != bmajor(stb.st_dev)

I have no access to a SVR3 with RFS actually running, but I suspect that
the upper bit would be turned on.

On HP9000, dev_t is a long, but they only use 8 bits for minor, and I believe
6 bits for major, and there are other bits that are set for NFS files.  

On HP9000, bmajor is defined, and I paraphrase:

    #define bmajor(x) major(x) /* Unsure of AT&T's intentions here,
				  bmajor masked off bits in porting base */

I betcha that the following would be fairly universal without having to
resort to individual #ifdef's for each variant of UNIX:

	if (makedev(major(stb.st_dev),minor(stb.st_dev)) != stb.st_dev) {
	    aha - NFS/RFS file!
	} else {
	    local disk file
	}

Anywho, could I get a few people to try the following C program on their
systems that have NFS and/or RFS partitions mounted on them and mail the
results to me?

This is what you would have to do:

	- unshar this file.
	- undef USG if you aren't a UNIX System V variant (if you get
	  major or minor undefined messages from cc, you probably need
	  to define USG)
	- compile the program ala:
		cc -o teststat teststat.c
	- Find the names of a couple of files on your local disks, plus
	  a few of them on filesystems mounted from other systems, and
	  run teststat with these file names as arguments.

	  Eg:
		./teststat / /etc <filename on NFS>
    
    To make the results perfectly clear, could you also include your
    teststat command line and the output of df from your system?

Thank you very much

#! /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 archive 1 (of 1)."
# Contents:  teststat.c
# Wrapped by clewis@eci386 on Thu Feb 22 17:19:16 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'teststat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'teststat.c'\"
else
echo shar: Extracting \"'teststat.c'\" \(685 characters\)
sed "s/^X//" >'teststat.c' <<'END_OF_FILE'
X/* %I% %E% */
X#define	USG	/* undef if you aren't some sort of System V */
X#include <stdio.h>
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifdef	USG
X#include <sys/sysmacros.h>
X#endif
X
Xstruct stat stb;
X
Xmain(argc, argv, envp)
Xint argc;
Xchar **argv; 
Xchar **envp; {
Xint i = 1;
X    for (;argv[i]; i++) {
X	if (stat(argv[i], &stb) == 0) {
X	    printf("file: %s dev: %x major: %x minor: %x\n", argv[i], 
X		stb.st_dev, major(stb.st_dev), minor(stb.st_dev));
X	    if (makedev(major(stb.st_dev),minor(stb.st_dev)) != stb.st_dev)
X		printf("I think %s is a networked file\n", argv[i]);
X	    else
X		printf("I don't think %s is a networked file\n", argv[i]);
X	} else
X	    perror(argv[i]);
X    }
X}
END_OF_FILE
if test 685 -ne `wc -c <'teststat.c'`; then
    echo shar: \"'teststat.c'\" unpacked with wrong size!
fi
# end of 'teststat.c'
fi
exit 0
-- 
Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis
Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list

tchrist@convex.COM (Tom Christiansen) (02/23/90)

The teststat program fails to identify NFS files on Convex
systems.  Here's the output from a C120 OS7.1:

% teststat.v7 / /usr /usr/spool/globdata/aliases/tacunix
file: / dev: 500 major: 5 minor: 0
I don't think / is a networked file
file: /usr dev: 702 major: 7 minor: 2
I don't think /usr is a networked file
file: /usr/spool/globdata/aliases/tacunix dev: ffffff02 major: ff minor: 2
I don't think /usr/spool/globdata/aliases/tacunix is a networked file

% df  / /usr /usr/spool/globdata/aliases/tacunix
Filesystem            kbytes    used   avail capacity  Mounted on
/dev/da0a              18067   15638     622    96%    /
/dev/st2              244047  190252   29390    87%    /usr
globhost:/usr/spool/globdata
                      315263  232782   50954    82%    /rmt/globhost/globdata


And here's the output from a C220 OS8.0, where major is defined this way:

#define major(x)        ((int)( ( (unsigned)(x) >> 20 ) & 0xfffff) )

% teststat.v8 / /usr /usr/spool/globdata/aliases/tacunix
file: / dev: 4000001 major: 40 minor: 1
I don't think / is a networked file
file: /usr dev: 1c00004 major: 1c minor: 4
I don't think /usr is a networked file
file: /usr/spool/globdata/aliases/tacunix dev: ff00000 major: ff minor: 0
I don't think /usr/spool/globdata/aliases/tacunix is a networked file

% df  / /usr /usr/spool/globdata/aliases/tacunix
Filesystem            kbytes    used   avail capacity  Mounted on
/dev/du0a              45978   19298   22082    47%    /
/dev/dd0e             122559  108944    1359    99%    /usr
globhost:/usr/spool/globdata
                      315263  232783   50953    82%    /rmt/globhost/globdata

You did't really want ALL the df output, did you?

--tom

clewis@eci386.uucp (Chris Lewis) (02/27/90)

In article <100210@convex.convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> The teststat program fails to identify NFS files on Convex
> systems.  Here's the output from a C120 OS7.1:

That's partially because my program was busted (the major should have
been bmajor), and partially because I'm not really taking account of
differing "major()" definitions.  In your teststat output, given:

> file: /usr/spool/globdata/aliases/tacunix dev: ffffff02 major: ff minor: 2
> I don't think /usr/spool/globdata/aliases/tacunix is a networked file

Note that the major has bit 7 on, which it doesn't on the local filesystems.

What I'm leaning towards is the following definitions:

    #if defined(locmajor)
    #undef locmajor
    #endif
    #define locmajor(x) (major(x)&0x7f)

    #define	REMOTEFS(dev)	(makedev(locmajor(dev),minor(dev)) != (dev))

Which should work on HPUX, AIX and now Convex, not to mention the other
systems that Larry Wall mentioned, even where major() itself masks off
the bit.

Though, the 0x7f may have to be parameterized on some systems.
-- 
Chris Lewis, Elegant Communications Inc, {uunet!attcan,utzoo}!lsuc!eci386!clewis
Ferret mailing list: eci386!ferret-list, psroff mailing list: eci386!psroff-list