parsenfsfh.c revision 75118
117680Spst/*
217680Spst * parsenfsfh.c - portable parser for NFS file handles
317680Spst *			uses all sorts of heuristics
417680Spst *
517680Spst * Jeffrey C. Mogul
617680Spst * Digital Equipment Corporation
717680Spst * Western Research Laboratory
856896Sfenner *
956896Sfenner * $FreeBSD: head/contrib/tcpdump/parsenfsfh.c 75118 2001-04-03 07:50:46Z fenner $
1017680Spst */
1117680Spst
1226183Sfenner#ifndef lint
1326183Sfennerstatic const char rcsid[] =
1475118Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/parsenfsfh.c,v 1.18 2000/07/01 03:39:00 assar Exp $ (LBL)";
1526183Sfenner#endif
1626183Sfenner
1756896Sfenner#ifdef HAVE_CONFIG_H
1856896Sfenner#include "config.h"
1956896Sfenner#endif
2056896Sfenner
2117680Spst#include <sys/types.h>
2217680Spst#include <sys/time.h>
2317680Spst
2417680Spst#include <ctype.h>
2517680Spst#include <stdio.h>
2617680Spst#include <string.h>
2717680Spst
2817680Spst#include "interface.h"
2917680Spst#include "nfsfh.h"
3017680Spst
3117680Spst/*
3217680Spst * This routine attempts to parse a file handle (in network byte order),
3317680Spst * using heuristics to guess what kind of format it is in.  See the
3417680Spst * file "fhandle_layouts" for a detailed description of the various
3517680Spst * patterns we know about.
3617680Spst *
3717680Spst * The file handle is parsed into our internal representation of a
3817680Spst * file-system id, and an internal representation of an inode-number.
3917680Spst */
4017680Spst
4117680Spst#define	FHT_UNKNOWN	0
4217680Spst#define	FHT_AUSPEX	1
4317680Spst#define	FHT_DECOSF	2
4417680Spst#define	FHT_IRIX4	3
4517680Spst#define	FHT_IRIX5	4
4617680Spst#define	FHT_SUNOS3	5
4717680Spst#define	FHT_SUNOS4	6
4817680Spst#define	FHT_ULTRIX	7
4917680Spst#define	FHT_VMSUCX	8
5017680Spst#define	FHT_SUNOS5	9
5117680Spst#define	FHT_AIX32	10
5217680Spst#define	FHT_HPUX9	11
5317680Spst
5417680Spst#ifdef	ultrix
5517680Spst/* Nasty hack to keep the Ultrix C compiler from emitting bogus warnings */
5617680Spst#define	XFF(x)	((u_int32_t)(x))
5717680Spst#else
5817680Spst#define	XFF(x)	(x)
5917680Spst#endif
6017680Spst
6117680Spst#define	make_uint32(msb,b,c,lsb)\
6217680Spst	(XFF(lsb) + (XFF(c)<<8) + (XFF(b)<<16) + (XFF(msb)<<24))
6317680Spst
6417680Spst#define	make_uint24(msb,b, lsb)\
6517680Spst	(XFF(lsb) + (XFF(b)<<8) + (XFF(msb)<<16))
6617680Spst
6717680Spst#define	make_uint16(msb,lsb)\
6817680Spst	(XFF(lsb) + (XFF(msb)<<8))
6917680Spst
7017680Spst#ifdef	__alpha
7117680Spst	/* or other 64-bit systems */
7217680Spst#define	make_uint48(msb,b,c,d,e,lsb)\
7317680Spst	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24) + ((b)<<32) + ((msb)<<40))
7417680Spst#else
7517680Spst	/* on 32-bit systems ignore high-order bits */
7617680Spst#define	make_uint48(msb,b,c,d,e,lsb)\
7717680Spst	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24))
7817680Spst#endif
7917680Spst
8017680Spststatic int is_UCX(unsigned char *);
8117680Spst
8217680Spstvoid
8318976SdfrParse_fh(fh, len, fsidp, inop, osnamep, fsnamep, ourself)
8417680Spstregister caddr_t *fh;
8518976Sdfrint len;
8617680Spstmy_fsid *fsidp;
8717680Spstino_t *inop;
8817680Spstchar **osnamep;		/* if non-NULL, return OS name here */
8917680Spstchar **fsnamep;		/* if non-NULL, return server fs name here (for VMS) */
9017680Spstint ourself;		/* true if file handle was generated on this host */
9117680Spst{
9217680Spst	register unsigned char *fhp = (unsigned char *)fh;
9317680Spst	u_int32_t temp;
9417680Spst	int fhtype = FHT_UNKNOWN;
9575118Sfenner	int i;
9617680Spst
9717680Spst	if (ourself) {
9817680Spst	    /* File handle generated on this host, no need for guessing */
9917680Spst#if	defined(IRIX40)
10017680Spst	    fhtype = FHT_IRIX4;
10117680Spst#endif
10217680Spst#if	defined(IRIX50)
10317680Spst	    fhtype = FHT_IRIX5;
10417680Spst#endif
10517680Spst#if	defined(IRIX51)
10617680Spst	    fhtype = FHT_IRIX5;
10717680Spst#endif
10817680Spst#if	defined(SUNOS4)
10917680Spst	    fhtype = FHT_SUNOS4;
11017680Spst#endif
11117680Spst#if	defined(SUNOS5)
11217680Spst	    fhtype = FHT_SUNOS5;
11317680Spst#endif
11417680Spst#if	defined(ultrix)
11517680Spst	    fhtype = FHT_ULTRIX;
11617680Spst#endif
11717680Spst#if	defined(__osf__)
11817680Spst	    fhtype = FHT_DECOSF;
11917680Spst#endif
12017680Spst	}
12117680Spst	/*
12217680Spst	 * This is basically a big decision tree
12317680Spst	 */
12417680Spst	else if ((fhp[0] == 0) && (fhp[1] == 0)) {
12517680Spst	    /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
12617680Spst	    /* probably rules out HP-UX, AIX unless they allow major=0 */
12717680Spst	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
12817680Spst		/* bytes[2,3] == (0,0); must be Auspex */
12917680Spst		/* XXX or could be Ultrix+MASSBUS "hp" disk? */
13017680Spst		fhtype = FHT_AUSPEX;
13117680Spst	    }
13217680Spst	    else {
13317680Spst		/*
13417680Spst		 * bytes[2,3] != (0,0); rules out Auspex, could be
13517680Spst		 * DECOSF, SUNOS4, or IRIX4
13617680Spst		 */
13717680Spst		if ((fhp[4] != 0) && (fhp[5] == 0) &&
13817680Spst			(fhp[8] == 12) && (fhp[9] == 0)) {
13917680Spst		    /* seems to be DECOSF, with minor == 0 */
14017680Spst		    fhtype = FHT_DECOSF;
14117680Spst		}
14217680Spst		else {
14317680Spst		    /* could be SUNOS4 or IRIX4 */
14417680Spst		    /* XXX the test of fhp[5] == 8 could be wrong */
14517680Spst		    if ((fhp[4] == 0) && (fhp[5] == 8) && (fhp[6] == 0) &&
14617680Spst			(fhp[7] == 0)) {
14717680Spst			/* looks like a length, not a file system typecode */
14817680Spst			fhtype = FHT_IRIX4;
14917680Spst		    }
15017680Spst		    else {
15117680Spst			/* by elimination */
15217680Spst			fhtype = FHT_SUNOS4;
15317680Spst		    }
15417680Spst		}
15517680Spst	    }
15617680Spst	}
15717680Spst	else {
15817680Spst	    /*
15917680Spst	     * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
16017680Spst	     * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
16117680Spst	     * could be AIX, HP-UX
16217680Spst	     */
16317680Spst	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
16417680Spst		/*
16517680Spst		 * bytes[2,3] == (0,0); rules out OSF, probably not UCX
16617680Spst		 * (unless the exported device name is just one letter!),
16717680Spst		 * could be Ultrix, IRIX5, AIX, or SUNOS5
16817680Spst		 * might be HP-UX (depends on their values for minor devs)
16917680Spst		 */
17017680Spst		/*XXX we probably only need to test of these two bytes */
17117680Spst		if ((fhp[21] == 0) && (fhp[23] == 0)) {
17217680Spst		    fhtype = FHT_ULTRIX;
17317680Spst		}
17417680Spst		else {
17517680Spst		    /* Could be SUNOS5/IRIX5, maybe AIX */
17617680Spst		    /* XXX no obvious difference between SUNOS5 and IRIX5 */
17717680Spst		    if (fhp[9] == 10)
17817680Spst			fhtype = FHT_SUNOS5;
17917680Spst		    /* XXX what about AIX? */
18017680Spst		}
18117680Spst	    }
18217680Spst	    else {
18317680Spst		/*
18417680Spst		 * bytes[2,3] != (0,0); rules out Ultrix, could be
18517680Spst		 * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
18617680Spst		 */
18717680Spst		if ((fhp[8] == 12) && (fhp[9] == 0)) {
18817680Spst		    fhtype = FHT_DECOSF;
18917680Spst		}
19017680Spst		else if ((fhp[8] == 0) && (fhp[9] == 10)) {
19117680Spst		    /* could be SUNOS5/IRIX5, AIX, HP-UX */
19217680Spst		    if ((fhp[7] == 0) && (fhp[6] == 0) &&
19317680Spst			(fhp[5] == 0) && (fhp[4] == 0)) {
19417680Spst			/* XXX is this always true of HP-UX? */
19517680Spst			fhtype = FHT_HPUX9;
19617680Spst		    }
19717680Spst		    else if (fhp[7] == 2) {
19817680Spst			/* This would be MNT_NFS on AIX, which is impossible */
19917680Spst			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
20017680Spst		    }
20117680Spst		    else {
20217680Spst			/*
20317680Spst			 * XXX Could be SUNOS5/IRIX5 or AIX.  I don't
20417680Spst			 * XXX see any way to disambiguate these, so
20517680Spst			 * XXX I'm going with the more likely guess.
20617680Spst			 * XXX Sorry, Big Blue.
20717680Spst			 */
20817680Spst			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
20917680Spst		    }
21017680Spst	        }
21117680Spst		else {
21217680Spst		    if (is_UCX(fhp)) {
21317680Spst			fhtype = FHT_VMSUCX;
21417680Spst		    }
21517680Spst		    else {
21617680Spst			fhtype = FHT_UNKNOWN;
21717680Spst		    }
21817680Spst		}
21917680Spst	    }
22017680Spst	}
22117680Spst
22217680Spst	/* XXX still needs to handle SUNOS3 */
22317680Spst
22417680Spst	switch (fhtype) {
22517680Spst	case FHT_AUSPEX:
22626183Sfenner	    fsidp->Fsid_dev.Minor = fhp[7];
22726183Sfenner	    fsidp->Fsid_dev.Major = fhp[6];
22817680Spst	    fsidp->fsid_code = 0;
22917680Spst
23017680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
23117680Spst	    *inop = temp;
23217680Spst
23317680Spst	    if (osnamep)
23417680Spst		*osnamep = "Auspex";
23517680Spst	    break;
23617680Spst
23717680Spst	case FHT_DECOSF:
23817680Spst	    fsidp->fsid_code = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
23917680Spst			/* XXX could ignore 3 high-order bytes */
24017680Spst
24117680Spst	    temp = make_uint32(fhp[3], fhp[2], fhp[1], fhp[0]);
24226183Sfenner	    fsidp->Fsid_dev.Minor = temp & 0xFFFFF;
24326183Sfenner	    fsidp->Fsid_dev.Major = (temp>>20) & 0xFFF;
24417680Spst
24517680Spst	    temp = make_uint32(fhp[15], fhp[14], fhp[13], fhp[12]);
24617680Spst	    *inop = temp;
24717680Spst	    if (osnamep)
24817680Spst		*osnamep = "OSF";
24917680Spst	    break;
25017680Spst
25117680Spst	case FHT_IRIX4:
25226183Sfenner	    fsidp->Fsid_dev.Minor = fhp[3];
25326183Sfenner	    fsidp->Fsid_dev.Major = fhp[2];
25417680Spst	    fsidp->fsid_code = 0;
25517680Spst
25617680Spst	    temp = make_uint32(fhp[8], fhp[9], fhp[10], fhp[11]);
25717680Spst	    *inop = temp;
25817680Spst
25917680Spst	    if (osnamep)
26017680Spst		*osnamep = "IRIX4";
26117680Spst	    break;
26217680Spst
26317680Spst	case FHT_IRIX5:
26426183Sfenner	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
26526183Sfenner	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
26617680Spst	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
26717680Spst
26817680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
26917680Spst	    *inop = temp;
27017680Spst
27117680Spst	    if (osnamep)
27217680Spst		*osnamep = "IRIX5";
27317680Spst	    break;
27417680Spst
27517680Spst	case FHT_SUNOS3:
27617680Spst	    if (osnamep)
27717680Spst		*osnamep = "SUNOS3";
27817680Spst	    break;
27917680Spst
28017680Spst	case FHT_SUNOS4:
28126183Sfenner	    fsidp->Fsid_dev.Minor = fhp[3];
28226183Sfenner	    fsidp->Fsid_dev.Major = fhp[2];
28317680Spst	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
28417680Spst
28517680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
28617680Spst	    *inop = temp;
28717680Spst
28817680Spst	    if (osnamep)
28917680Spst		*osnamep = "SUNOS4";
29017680Spst	    break;
29117680Spst
29217680Spst	case FHT_SUNOS5:
29317680Spst	    temp = make_uint16(fhp[0], fhp[1]);
29426183Sfenner	    fsidp->Fsid_dev.Major = (temp>>2) &  0x3FFF;
29517680Spst	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
29626183Sfenner	    fsidp->Fsid_dev.Minor = temp & 0x3FFFF;
29717680Spst	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
29817680Spst
29917680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
30017680Spst	    *inop = temp;
30117680Spst
30217680Spst	    if (osnamep)
30317680Spst		*osnamep = "SUNOS5";
30417680Spst	    break;
30517680Spst
30617680Spst	case FHT_ULTRIX:
30717680Spst	    fsidp->fsid_code = 0;
30826183Sfenner	    fsidp->Fsid_dev.Minor = fhp[0];
30926183Sfenner	    fsidp->Fsid_dev.Major = fhp[1];
31017680Spst
31117680Spst	    temp = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
31217680Spst	    *inop = temp;
31317680Spst	    if (osnamep)
31417680Spst		*osnamep = "Ultrix";
31517680Spst	    break;
31617680Spst
31717680Spst	case FHT_VMSUCX:
31817680Spst	    /* No numeric file system ID, so hash on the device-name */
31917680Spst	    if (sizeof(*fsidp) >= 14) {
32017680Spst		if (sizeof(*fsidp) > 14)
32117680Spst		    memset((char *)fsidp, 0, sizeof(*fsidp));
32239300Sfenner		/* just use the whole thing */
32339300Sfenner		memcpy((char *)fsidp, (char *)fh, 14);
32417680Spst	    }
32517680Spst	    else {
32617680Spst		u_int32_t tempa[4];	/* at least 16 bytes, maybe more */
32717680Spst
32817680Spst		memset((char *)tempa, 0, sizeof(tempa));
32939300Sfenner		memcpy((char *)tempa, (char *)fh, 14); /* ensure alignment */
33026183Sfenner		fsidp->Fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
33126183Sfenner		fsidp->Fsid_dev.Major = tempa[2] + (tempa[3]<<1);
33217680Spst		fsidp->fsid_code = 0;
33317680Spst	    }
33417680Spst
33517680Spst	    /* VMS file ID is: (RVN, FidHi, FidLo) */
33617680Spst	    *inop = make_uint32(fhp[26], fhp[27], fhp[23], fhp[22]);
33717680Spst
33817680Spst	    /* Caller must save (and null-terminate?) this value */
33917680Spst	    if (fsnamep)
34017680Spst		*fsnamep = (char *)&(fhp[1]);
34117680Spst
34217680Spst	    if (osnamep)
34317680Spst		*osnamep = "VMS";
34417680Spst	    break;
34517680Spst
34617680Spst	case FHT_AIX32:
34726183Sfenner	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
34826183Sfenner	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
34917680Spst	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
35017680Spst
35117680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
35217680Spst	    *inop = temp;
35317680Spst
35417680Spst	    if (osnamep)
35517680Spst		*osnamep = "AIX32";
35617680Spst	    break;
35717680Spst
35817680Spst	case FHT_HPUX9:
35926183Sfenner	    fsidp->Fsid_dev.Major = fhp[0];
36017680Spst	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
36126183Sfenner	    fsidp->Fsid_dev.Minor = temp;
36217680Spst	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
36317680Spst
36417680Spst	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
36517680Spst	    *inop = temp;
36617680Spst
36717680Spst	    if (osnamep)
36817680Spst		*osnamep = "HPUX9";
36917680Spst	    break;
37017680Spst
37117680Spst	case FHT_UNKNOWN:
37217680Spst#ifdef DEBUG
37375118Sfenner	    /* XXX debugging */
37475118Sfenner	    int i;
37575118Sfenner	    for (i = 0; i < 32; i++)
37675118Sfenner		(void)fprintf(stderr, "%x.", fhp[i]);
37775118Sfenner	    (void)fprintf(stderr, "\n");
37817680Spst#endif
37917680Spst	    /* XXX for now, give "bogus" values to aid debugging */
38075118Sfenner
38175118Sfenner	    /* Save the actual handle, so it can be display with -u */
38275118Sfenner	    for (i = 0; i < 32; i++)
38375118Sfenner	    	(void)sprintf(&(fsidp->Opaque_Handle[i*2]), "%.2X", fhp[i]);
38475118Sfenner
38517680Spst	    fsidp->fsid_code = 0;
38626183Sfenner	    fsidp->Fsid_dev.Minor = 257;
38726183Sfenner	    fsidp->Fsid_dev.Major = 257;
38817680Spst	    *inop = 1;
38917680Spst
39017680Spst	    /* display will show this string instead of (257,257) */
39117680Spst	    if (fsnamep)
39217680Spst		*fsnamep = "Unknown";
39317680Spst
39417680Spst	    if (osnamep)
39517680Spst		*osnamep = "Unknown";
39617680Spst	    break;
39717680Spst
39817680Spst	}
39917680Spst}
40017680Spst
40117680Spst/*
40217680Spst * Is this a VMS UCX file handle?
40317680Spst *	Check for:
40417680Spst *	(1) leading code byte	[XXX not yet]
40517680Spst *	(2) followed by string of printing chars & spaces
40617680Spst *	(3) followed by string of nulls
40717680Spst */
40817680Spststatic int
40917680Spstis_UCX(fhp)
41017680Spstunsigned char *fhp;
41117680Spst{
41217680Spst	register int i;
41317680Spst	int seen_null = 0;
41417680Spst
41517680Spst	for (i = 1; i < 14; i++) {
41617680Spst	    if (isprint(fhp[i])) {
41717680Spst		if (seen_null)
41817680Spst		   return(0);
41917680Spst		else
42017680Spst		   continue;
42117680Spst	    }
42217680Spst	    else if (fhp[i] == 0) {
42317680Spst		seen_null = 1;
42417680Spst		continue;
42517680Spst	    }
42617680Spst	    else
42717680Spst		return(0);
42817680Spst	}
42917680Spst
43017680Spst	return(1);
43117680Spst}
432