parsenfsfh.c revision 18976
169800Stomsoft#ifndef lint
269800Stomsoftstatic char *RCSid = "$Header: parsenfsfh.c,v 1.9 95/10/19 20:27:44 leres Exp $";
369800Stomsoft#endif
469800Stomsoft
5114067Sschweikh/*
669800Stomsoft * parsenfsfh.c - portable parser for NFS file handles
769800Stomsoft *			uses all sorts of heuristics
8114067Sschweikh *
969800Stomsoft * Jeffrey C. Mogul
1069800Stomsoft * Digital Equipment Corporation
1169800Stomsoft * Western Research Laboratory
1269800Stomsoft */
1369800Stomsoft
1469800Stomsoft#include <sys/types.h>
1569800Stomsoft#include <sys/time.h>
1669800Stomsoft
1769800Stomsoft#include <ctype.h>
1869800Stomsoft#include <memory.h>
1969800Stomsoft#include <stdio.h>
2069800Stomsoft#include <string.h>
2169800Stomsoft
2269800Stomsoft#include "interface.h"
2369800Stomsoft#include "nfsfh.h"
2469800Stomsoft
25114067Sschweikh/*
2669800Stomsoft * This routine attempts to parse a file handle (in network byte order),
2769800Stomsoft * using heuristics to guess what kind of format it is in.  See the
2869800Stomsoft * file "fhandle_layouts" for a detailed description of the various
2969800Stomsoft * patterns we know about.
3069800Stomsoft *
3169800Stomsoft * The file handle is parsed into our internal representation of a
3269800Stomsoft * file-system id, and an internal representation of an inode-number.
3369800Stomsoft */
3469800Stomsoft
3569800Stomsoft#define	FHT_UNKNOWN	0
3669800Stomsoft#define	FHT_AUSPEX	1
3769800Stomsoft#define	FHT_DECOSF	2
3869926Stomsoft#define	FHT_IRIX4	3
3969800Stomsoft#define	FHT_IRIX5	4
4069800Stomsoft#define	FHT_SUNOS3	5
4169800Stomsoft#define	FHT_SUNOS4	6
4269800Stomsoft#define	FHT_ULTRIX	7
4369800Stomsoft#define	FHT_VMSUCX	8
4469800Stomsoft#define	FHT_SUNOS5	9
4569800Stomsoft#define	FHT_AIX32	10
4669800Stomsoft#define	FHT_HPUX9	11
4769800Stomsoft
4869800Stomsoft#ifdef	ultrix
49140351Scharnier/* Nasty hack to keep the Ultrix C compiler from emitting bogus warnings */
50140351Scharnier#define	XFF(x)	((u_int32_t)(x))
5169800Stomsoft#else
5269800Stomsoft#define	XFF(x)	(x)
5369800Stomsoft#endif
5469800Stomsoft
5569800Stomsoft#define	make_uint32(msb,b,c,lsb)\
5669800Stomsoft	(XFF(lsb) + (XFF(c)<<8) + (XFF(b)<<16) + (XFF(msb)<<24))
57114936Sgrog
5869800Stomsoft#define	make_uint24(msb,b, lsb)\
5969800Stomsoft	(XFF(lsb) + (XFF(b)<<8) + (XFF(msb)<<16))
6069800Stomsoft
6169800Stomsoft#define	make_uint16(msb,lsb)\
6269800Stomsoft	(XFF(lsb) + (XFF(msb)<<8))
6369800Stomsoft
64103949Smike#ifdef	__alpha
6569800Stomsoft	/* or other 64-bit systems */
66127798Sle#define	make_uint48(msb,b,c,d,e,lsb)\
6769800Stomsoft	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24) + ((b)<<32) + ((msb)<<40))
68127821Sbde#else
6969800Stomsoft	/* on 32-bit systems ignore high-order bits */
7069800Stomsoft#define	make_uint48(msb,b,c,d,e,lsb)\
7169800Stomsoft	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24))
7269800Stomsoft#endif
7369800Stomsoft
7469800Stomsoftstatic int is_UCX(unsigned char *);
7569800Stomsoft
7669800Stomsoftvoid
7769800StomsoftParse_fh(fh, len, fsidp, inop, osnamep, fsnamep, ourself)
7869800Stomsoftregister caddr_t *fh;
7969800Stomsoftint len;
8069800Stomsoftmy_fsid *fsidp;
8169800Stomsoftino_t *inop;
8298542Smckusickchar **osnamep;		/* if non-NULL, return OS name here */
8369800Stomsoftchar **fsnamep;		/* if non-NULL, return server fs name here (for VMS) */
8469800Stomsoftint ourself;		/* true if file handle was generated on this host */
8569800Stomsoft{
8669800Stomsoft	register unsigned char *fhp = (unsigned char *)fh;
8798542Smckusick	u_int32_t temp;
8898542Smckusick	int fhtype = FHT_UNKNOWN;
8998542Smckusick
9098542Smckusick	if (ourself) {
9198542Smckusick	    /* File handle generated on this host, no need for guessing */
9298542Smckusick#if	defined(IRIX40)
9369800Stomsoft	    fhtype = FHT_IRIX4;
9469800Stomsoft#endif
9569800Stomsoft#if	defined(IRIX50)
9669800Stomsoft	    fhtype = FHT_IRIX5;
9769800Stomsoft#endif
9869800Stomsoft#if	defined(IRIX51)
9969800Stomsoft	    fhtype = FHT_IRIX5;
10098542Smckusick#endif
10169800Stomsoft#if	defined(SUNOS4)
10298542Smckusick	    fhtype = FHT_SUNOS4;
10369800Stomsoft#endif
10498542Smckusick#if	defined(SUNOS5)
10598542Smckusick	    fhtype = FHT_SUNOS5;
10698542Smckusick#endif
10769800Stomsoft#if	defined(ultrix)
10898542Smckusick	    fhtype = FHT_ULTRIX;
10998542Smckusick#endif
110127798Sle#if	defined(__osf__)
111132832Sle	    fhtype = FHT_DECOSF;
112132832Sle#endif
113132832Sle	}
114132832Sle	/*
115132832Sle	 * This is basically a big decision tree
116132832Sle	 */
11798542Smckusick	else if ((fhp[0] == 0) && (fhp[1] == 0)) {
11898542Smckusick	    /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
119127798Sle	    /* probably rules out HP-UX, AIX unless they allow major=0 */
120114936Sgrog	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
12169800Stomsoft		/* bytes[2,3] == (0,0); must be Auspex */
12269800Stomsoft		/* XXX or could be Ultrix+MASSBUS "hp" disk? */
123114067Sschweikh		fhtype = FHT_AUSPEX;
12469800Stomsoft	    }
12569800Stomsoft	    else {
12669800Stomsoft		/*
12769800Stomsoft		 * bytes[2,3] != (0,0); rules out Auspex, could be
12898542Smckusick		 * DECOSF, SUNOS4, or IRIX4
12998542Smckusick		 */
13069800Stomsoft		if ((fhp[4] != 0) && (fhp[5] == 0) &&
13169800Stomsoft			(fhp[8] == 12) && (fhp[9] == 0)) {
13277885Stomsoft		    /* seems to be DECOSF, with minor == 0 */
13369800Stomsoft		    fhtype = FHT_DECOSF;
13469800Stomsoft		}
13569800Stomsoft		else {
13669800Stomsoft		    /* could be SUNOS4 or IRIX4 */
13777885Stomsoft		    /* XXX the test of fhp[5] == 8 could be wrong */
13898542Smckusick		    if ((fhp[4] == 0) && (fhp[5] == 8) && (fhp[6] == 0) &&
13998542Smckusick			(fhp[7] == 0)) {
14098542Smckusick			/* looks like a length, not a file system typecode */
14169800Stomsoft			fhtype = FHT_IRIX4;
14269926Stomsoft		    }
14369800Stomsoft		    else {
14469800Stomsoft			/* by elimination */
14569800Stomsoft			fhtype = FHT_SUNOS4;
14677885Stomsoft		    }
14777885Stomsoft		}
14877885Stomsoft	    }
14969800Stomsoft	}
15077885Stomsoft	else {
15198542Smckusick	    /*
15298542Smckusick	     * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
15398542Smckusick	     * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
15498542Smckusick	     * could be AIX, HP-UX
15569800Stomsoft	     */
15677885Stomsoft	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
15798542Smckusick		/*
15898542Smckusick		 * bytes[2,3] == (0,0); rules out OSF, probably not UCX
159114936Sgrog		 * (unless the exported device name is just one letter!),
16069800Stomsoft		 * could be Ultrix, IRIX5, AIX, or SUNOS5
16169800Stomsoft		 * might be HP-UX (depends on their values for minor devs)
16269800Stomsoft		 */
163114067Sschweikh		/*XXX we probably only need to test of these two bytes */
164114067Sschweikh		if ((fhp[21] == 0) && (fhp[23] == 0)) {
165114067Sschweikh		    fhtype = FHT_ULTRIX;
16669800Stomsoft		}
167114067Sschweikh		else {
168114067Sschweikh		    /* Could be SUNOS5/IRIX5, maybe AIX */
169114067Sschweikh		    /* XXX no obvious difference between SUNOS5 and IRIX5 */
17069800Stomsoft		    if (fhp[9] == 10)
17169800Stomsoft			fhtype = FHT_SUNOS5;
17269800Stomsoft		    /* XXX what about AIX? */
17369800Stomsoft		}
17477885Stomsoft	    }
17569800Stomsoft	    else {
17669800Stomsoft		/*
17769800Stomsoft		 * bytes[2,3] != (0,0); rules out Ultrix, could be
178203770Smckusick		 * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
179203770Smckusick		 */
18069800Stomsoft		if ((fhp[8] == 12) && (fhp[9] == 0)) {
18169800Stomsoft		    fhtype = FHT_DECOSF;
18269800Stomsoft		}
18369800Stomsoft		else if ((fhp[8] == 0) && (fhp[9] == 10)) {
18469800Stomsoft		    /* could be SUNOS5/IRIX5, AIX, HP-UX */
18569800Stomsoft		    if ((fhp[7] == 0) && (fhp[6] == 0) &&
18669800Stomsoft			(fhp[5] == 0) && (fhp[4] == 0)) {
18769800Stomsoft			/* XXX is this always true of HP-UX? */
18869800Stomsoft			fhtype = FHT_HPUX9;
18969800Stomsoft		    }
19069800Stomsoft		    else if (fhp[7] == 2) {
19169800Stomsoft			/* This would be MNT_NFS on AIX, which is impossible */
19269800Stomsoft			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
19369800Stomsoft		    }
19469800Stomsoft		    else {
19569800Stomsoft			/*
19669800Stomsoft			 * XXX Could be SUNOS5/IRIX5 or AIX.  I don't
19769800Stomsoft			 * XXX see any way to disambiguate these, so
19869800Stomsoft			 * XXX I'm going with the more likely guess.
19969800Stomsoft			 * XXX Sorry, Big Blue.
20077885Stomsoft			 */
20169926Stomsoft			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
20269926Stomsoft		    }
20369926Stomsoft	        }
20469800Stomsoft		else {
20569800Stomsoft		    if (is_UCX(fhp)) {
20677885Stomsoft			fhtype = FHT_VMSUCX;
20777885Stomsoft		    }
20869800Stomsoft		    else {
20969800Stomsoft			fhtype = FHT_UNKNOWN;
21069800Stomsoft		    }
21169800Stomsoft		}
21269800Stomsoft	    }
21369800Stomsoft	}
21469800Stomsoft
21569800Stomsoft	/* XXX still needs to handle SUNOS3 */
21669800Stomsoft
21769800Stomsoft	switch (fhtype) {
21877885Stomsoft	case FHT_AUSPEX:
21977885Stomsoft	    fsidp->fsid_dev.Minor = fhp[7];
22069926Stomsoft	    fsidp->fsid_dev.Major = fhp[6];
22169926Stomsoft	    fsidp->fsid_code = 0;
22269926Stomsoft
22369800Stomsoft	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
22469800Stomsoft	    *inop = temp;
22569800Stomsoft
22669800Stomsoft	    if (osnamep)
22769800Stomsoft		*osnamep = "Auspex";
22869800Stomsoft	    break;
22969800Stomsoft
23069800Stomsoft	case FHT_DECOSF:
23169800Stomsoft	    fsidp->fsid_code = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
23269800Stomsoft			/* XXX could ignore 3 high-order bytes */
23369800Stomsoft
234102231Strhodes	    temp = make_uint32(fhp[3], fhp[2], fhp[1], fhp[0]);
23569800Stomsoft	    fsidp->fsid_dev.Minor = temp & 0xFFFFF;
23698542Smckusick	    fsidp->fsid_dev.Major = (temp>>20) & 0xFFF;
237127816Smux
23869800Stomsoft	    temp = make_uint32(fhp[15], fhp[14], fhp[13], fhp[12]);
239127816Smux	    *inop = temp;
240127816Smux	    if (osnamep)
24198542Smckusick		*osnamep = "OSF";
24298542Smckusick	    break;
24398542Smckusick
24498542Smckusick	case FHT_IRIX4:
24598542Smckusick	    fsidp->fsid_dev.Minor = fhp[3];
24698542Smckusick	    fsidp->fsid_dev.Major = fhp[2];
24769800Stomsoft	    fsidp->fsid_code = 0;
24869800Stomsoft
24969800Stomsoft	    temp = make_uint32(fhp[8], fhp[9], fhp[10], fhp[11]);
25069800Stomsoft	    *inop = temp;
25169800Stomsoft
25269800Stomsoft	    if (osnamep)
25369800Stomsoft		*osnamep = "IRIX4";
25469800Stomsoft	    break;
25569800Stomsoft
25669800Stomsoft	case FHT_IRIX5:
25769800Stomsoft	    fsidp->fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
25869800Stomsoft	    fsidp->fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
25969800Stomsoft	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
26069800Stomsoft
261174706Sdas	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
262174706Sdas	    *inop = temp;
26369800Stomsoft
26469800Stomsoft	    if (osnamep)
26569800Stomsoft		*osnamep = "IRIX5";
26669800Stomsoft	    break;
26769800Stomsoft
26869800Stomsoft	case FHT_SUNOS3:
26969800Stomsoft	    if (osnamep)
27069800Stomsoft		*osnamep = "SUNOS3";
27169800Stomsoft	    break;
27269800Stomsoft
27369800Stomsoft	case FHT_SUNOS4:
27469800Stomsoft	    fsidp->fsid_dev.Minor = fhp[3];
27569800Stomsoft	    fsidp->fsid_dev.Major = fhp[2];
27669800Stomsoft	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
27769800Stomsoft
27869800Stomsoft	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
27969800Stomsoft	    *inop = temp;
28069800Stomsoft
28169800Stomsoft	    if (osnamep)
28269800Stomsoft		*osnamep = "SUNOS4";
28369800Stomsoft	    break;
28469800Stomsoft
28577885Stomsoft	case FHT_SUNOS5:
28677885Stomsoft	    temp = make_uint16(fhp[0], fhp[1]);
28769800Stomsoft	    fsidp->fsid_dev.Major = (temp>>2) &  0x3FFF;
28869800Stomsoft	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
28969800Stomsoft	    fsidp->fsid_dev.Minor = temp & 0x3FFFF;
29069800Stomsoft	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
29169800Stomsoft
29269800Stomsoft	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
29369800Stomsoft	    *inop = temp;
29469800Stomsoft
29569800Stomsoft	    if (osnamep)
29669800Stomsoft		*osnamep = "SUNOS5";
29769800Stomsoft	    break;
29877885Stomsoft
29977885Stomsoft	case FHT_ULTRIX:
30069926Stomsoft	    fsidp->fsid_code = 0;
30169926Stomsoft	    fsidp->fsid_dev.Minor = fhp[0];
30269926Stomsoft	    fsidp->fsid_dev.Major = fhp[1];
30369800Stomsoft
30469800Stomsoft	    temp = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
30569800Stomsoft	    *inop = temp;
30669800Stomsoft	    if (osnamep)
30769800Stomsoft		*osnamep = "Ultrix";
30869800Stomsoft	    break;
30969800Stomsoft
31069800Stomsoft	case FHT_VMSUCX:
31198542Smckusick	    /* No numeric file system ID, so hash on the device-name */
31269800Stomsoft	    if (sizeof(*fsidp) >= 14) {
31369926Stomsoft		if (sizeof(*fsidp) > 14)
31469926Stomsoft		    memset((char *)fsidp, 0, sizeof(*fsidp));
31569800Stomsoft		memcpy((char *)fsidp, fh, 14);	/* just use the whole thing */
31669800Stomsoft	    }
31769800Stomsoft	    else {
31869800Stomsoft		u_int32_t tempa[4];	/* at least 16 bytes, maybe more */
31969800Stomsoft
32069800Stomsoft		memset((char *)tempa, 0, sizeof(tempa));
32169800Stomsoft		memcpy((char *)tempa, fh, 14);	/* ensure alignment */
32269800Stomsoft		fsidp->fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
32369800Stomsoft		fsidp->fsid_dev.Major = tempa[2] + (tempa[3]<<1);
32469800Stomsoft		fsidp->fsid_code = 0;
32569800Stomsoft	    }
32669800Stomsoft
32769800Stomsoft	    /* VMS file ID is: (RVN, FidHi, FidLo) */
32869800Stomsoft	    *inop = make_uint32(fhp[26], fhp[27], fhp[23], fhp[22]);
329114067Sschweikh
33069800Stomsoft	    /* Caller must save (and null-terminate?) this value */
33169800Stomsoft	    if (fsnamep)
33269800Stomsoft		*fsnamep = (char *)&(fhp[1]);
33369800Stomsoft
33469800Stomsoft	    if (osnamep)
33569800Stomsoft		*osnamep = "VMS";
33669800Stomsoft	    break;
33769800Stomsoft
33869800Stomsoft	case FHT_AIX32:
33969800Stomsoft	    fsidp->fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
34069800Stomsoft	    fsidp->fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
341114067Sschweikh	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
34269800Stomsoft
34369800Stomsoft	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
344114067Sschweikh	    *inop = temp;
34569800Stomsoft
34669800Stomsoft	    if (osnamep)
34769800Stomsoft		*osnamep = "AIX32";
34869800Stomsoft	    break;
34969800Stomsoft
35069800Stomsoft	case FHT_HPUX9:
35169800Stomsoft	    fsidp->fsid_dev.Major = fhp[0];
35269800Stomsoft	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
35398542Smckusick	    fsidp->fsid_dev.Minor = temp;
35469800Stomsoft	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
35569800Stomsoft
35669926Stomsoft	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
35769926Stomsoft	    *inop = temp;
35869800Stomsoft
35969800Stomsoft	    if (osnamep)
36069800Stomsoft		*osnamep = "HPUX9";
36169800Stomsoft	    break;
36269800Stomsoft
36369800Stomsoft	case FHT_UNKNOWN:
36469800Stomsoft#ifdef DEBUG
365114067Sschweikh	    {
366114067Sschweikh		/* XXX debugging */
367114067Sschweikh		int i;
36869800Stomsoft		for (i = 0; i < 32; i++)
36969800Stomsoft			(void)fprintf(stderr, "%x.", fhp[i]);
37069800Stomsoft		(void)fprintf(stderr, "\n");
37177885Stomsoft	    }
37269800Stomsoft#endif
37369800Stomsoft	    /* XXX for now, give "bogus" values to aid debugging */
374127816Smux	    fsidp->fsid_code = 0;
375203770Smckusick	    fsidp->fsid_dev.Minor = 257;
376127798Sle	    fsidp->fsid_dev.Major = 257;
37798542Smckusick	    *inop = 1;
37892806Sobrien
379203770Smckusick	    /* display will show this string instead of (257,257) */
38069800Stomsoft	    if (fsnamep)
38198542Smckusick		*fsnamep = "Unknown";
38298542Smckusick
38398542Smckusick	    if (osnamep)
38469800Stomsoft		*osnamep = "Unknown";
38569800Stomsoft	    break;
38698542Smckusick
38798542Smckusick	}
38869800Stomsoft}
38969800Stomsoft
39069800Stomsoft/*
39198542Smckusick * Is this a VMS UCX file handle?
39269800Stomsoft *	Check for:
39369800Stomsoft *	(1) leading code byte	[XXX not yet]
39469800Stomsoft *	(2) followed by string of printing chars & spaces
39598542Smckusick *	(3) followed by string of nulls
39669800Stomsoft */
39798542Smckusickstatic int
39898542Smckusickis_UCX(fhp)
399197763Smjacobunsigned char *fhp;
400197763Smjacob{
401197763Smjacob	register int i;
402197763Smjacob	int seen_null = 0;
403197763Smjacob
404197763Smjacob	for (i = 1; i < 14; i++) {
405197763Smjacob	    if (isprint(fhp[i])) {
40669800Stomsoft		if (seen_null)
40769800Stomsoft		   return(0);
40869800Stomsoft		else
40969800Stomsoft		   continue;
41069800Stomsoft	    }
41198542Smckusick	    else if (fhp[i] == 0) {
41269800Stomsoft		seen_null = 1;
41398542Smckusick		continue;
41498542Smckusick	    }
41598542Smckusick	    else
41698542Smckusick		return(0);
41798542Smckusick	}
41898542Smckusick
41998542Smckusick	return(1);
42098542Smckusick}
42198542Smckusick