parsenfsfh.c revision 39300
1/*
2 * parsenfsfh.c - portable parser for NFS file handles
3 *			uses all sorts of heuristics
4 *
5 * Jeffrey C. Mogul
6 * Digital Equipment Corporation
7 * Western Research Laboratory
8 */
9
10#ifndef lint
11static const char rcsid[] =
12    "@(#) $Header: parsenfsfh.c,v 1.14 97/06/15 13:20:27 leres Exp $ (LBL)";
13#endif
14
15#include <sys/types.h>
16#include <sys/time.h>
17
18#include <ctype.h>
19#ifdef HAVE_MEMORY_H
20#include <memory.h>
21#endif
22#include <stdio.h>
23#include <string.h>
24
25#include "interface.h"
26#include "nfsfh.h"
27
28/*
29 * This routine attempts to parse a file handle (in network byte order),
30 * using heuristics to guess what kind of format it is in.  See the
31 * file "fhandle_layouts" for a detailed description of the various
32 * patterns we know about.
33 *
34 * The file handle is parsed into our internal representation of a
35 * file-system id, and an internal representation of an inode-number.
36 */
37
38#define	FHT_UNKNOWN	0
39#define	FHT_AUSPEX	1
40#define	FHT_DECOSF	2
41#define	FHT_IRIX4	3
42#define	FHT_IRIX5	4
43#define	FHT_SUNOS3	5
44#define	FHT_SUNOS4	6
45#define	FHT_ULTRIX	7
46#define	FHT_VMSUCX	8
47#define	FHT_SUNOS5	9
48#define	FHT_AIX32	10
49#define	FHT_HPUX9	11
50
51#ifdef	ultrix
52/* Nasty hack to keep the Ultrix C compiler from emitting bogus warnings */
53#define	XFF(x)	((u_int32_t)(x))
54#else
55#define	XFF(x)	(x)
56#endif
57
58#define	make_uint32(msb,b,c,lsb)\
59	(XFF(lsb) + (XFF(c)<<8) + (XFF(b)<<16) + (XFF(msb)<<24))
60
61#define	make_uint24(msb,b, lsb)\
62	(XFF(lsb) + (XFF(b)<<8) + (XFF(msb)<<16))
63
64#define	make_uint16(msb,lsb)\
65	(XFF(lsb) + (XFF(msb)<<8))
66
67#ifdef	__alpha
68	/* or other 64-bit systems */
69#define	make_uint48(msb,b,c,d,e,lsb)\
70	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24) + ((b)<<32) + ((msb)<<40))
71#else
72	/* on 32-bit systems ignore high-order bits */
73#define	make_uint48(msb,b,c,d,e,lsb)\
74	((lsb) + ((e)<<8) + ((d)<<16) + ((c)<<24))
75#endif
76
77static int is_UCX(unsigned char *);
78
79void
80Parse_fh(fh, len, fsidp, inop, osnamep, fsnamep, ourself)
81register caddr_t *fh;
82int len;
83my_fsid *fsidp;
84ino_t *inop;
85char **osnamep;		/* if non-NULL, return OS name here */
86char **fsnamep;		/* if non-NULL, return server fs name here (for VMS) */
87int ourself;		/* true if file handle was generated on this host */
88{
89	register unsigned char *fhp = (unsigned char *)fh;
90	u_int32_t temp;
91	int fhtype = FHT_UNKNOWN;
92
93	if (ourself) {
94	    /* File handle generated on this host, no need for guessing */
95#if	defined(IRIX40)
96	    fhtype = FHT_IRIX4;
97#endif
98#if	defined(IRIX50)
99	    fhtype = FHT_IRIX5;
100#endif
101#if	defined(IRIX51)
102	    fhtype = FHT_IRIX5;
103#endif
104#if	defined(SUNOS4)
105	    fhtype = FHT_SUNOS4;
106#endif
107#if	defined(SUNOS5)
108	    fhtype = FHT_SUNOS5;
109#endif
110#if	defined(ultrix)
111	    fhtype = FHT_ULTRIX;
112#endif
113#if	defined(__osf__)
114	    fhtype = FHT_DECOSF;
115#endif
116	}
117	/*
118	 * This is basically a big decision tree
119	 */
120	else if ((fhp[0] == 0) && (fhp[1] == 0)) {
121	    /* bytes[0,1] == (0,0); rules out Ultrix, IRIX5, SUNOS5 */
122	    /* probably rules out HP-UX, AIX unless they allow major=0 */
123	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
124		/* bytes[2,3] == (0,0); must be Auspex */
125		/* XXX or could be Ultrix+MASSBUS "hp" disk? */
126		fhtype = FHT_AUSPEX;
127	    }
128	    else {
129		/*
130		 * bytes[2,3] != (0,0); rules out Auspex, could be
131		 * DECOSF, SUNOS4, or IRIX4
132		 */
133		if ((fhp[4] != 0) && (fhp[5] == 0) &&
134			(fhp[8] == 12) && (fhp[9] == 0)) {
135		    /* seems to be DECOSF, with minor == 0 */
136		    fhtype = FHT_DECOSF;
137		}
138		else {
139		    /* could be SUNOS4 or IRIX4 */
140		    /* XXX the test of fhp[5] == 8 could be wrong */
141		    if ((fhp[4] == 0) && (fhp[5] == 8) && (fhp[6] == 0) &&
142			(fhp[7] == 0)) {
143			/* looks like a length, not a file system typecode */
144			fhtype = FHT_IRIX4;
145		    }
146		    else {
147			/* by elimination */
148			fhtype = FHT_SUNOS4;
149		    }
150		}
151	    }
152	}
153	else {
154	    /*
155	     * bytes[0,1] != (0,0); rules out Auspex, IRIX4, SUNOS4
156	     * could be IRIX5, DECOSF, UCX, Ultrix, SUNOS5
157	     * could be AIX, HP-UX
158	     */
159	    if ((fhp[2] == 0) && (fhp[3] == 0)) {
160		/*
161		 * bytes[2,3] == (0,0); rules out OSF, probably not UCX
162		 * (unless the exported device name is just one letter!),
163		 * could be Ultrix, IRIX5, AIX, or SUNOS5
164		 * might be HP-UX (depends on their values for minor devs)
165		 */
166		/*XXX we probably only need to test of these two bytes */
167		if ((fhp[21] == 0) && (fhp[23] == 0)) {
168		    fhtype = FHT_ULTRIX;
169		}
170		else {
171		    /* Could be SUNOS5/IRIX5, maybe AIX */
172		    /* XXX no obvious difference between SUNOS5 and IRIX5 */
173		    if (fhp[9] == 10)
174			fhtype = FHT_SUNOS5;
175		    /* XXX what about AIX? */
176		}
177	    }
178	    else {
179		/*
180		 * bytes[2,3] != (0,0); rules out Ultrix, could be
181		 * DECOSF, SUNOS5, IRIX5, AIX, HP-UX, or UCX
182		 */
183		if ((fhp[8] == 12) && (fhp[9] == 0)) {
184		    fhtype = FHT_DECOSF;
185		}
186		else if ((fhp[8] == 0) && (fhp[9] == 10)) {
187		    /* could be SUNOS5/IRIX5, AIX, HP-UX */
188		    if ((fhp[7] == 0) && (fhp[6] == 0) &&
189			(fhp[5] == 0) && (fhp[4] == 0)) {
190			/* XXX is this always true of HP-UX? */
191			fhtype = FHT_HPUX9;
192		    }
193		    else if (fhp[7] == 2) {
194			/* This would be MNT_NFS on AIX, which is impossible */
195			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
196		    }
197		    else {
198			/*
199			 * XXX Could be SUNOS5/IRIX5 or AIX.  I don't
200			 * XXX see any way to disambiguate these, so
201			 * XXX I'm going with the more likely guess.
202			 * XXX Sorry, Big Blue.
203			 */
204			fhtype = FHT_SUNOS5;	/* or maybe IRIX5 */
205		    }
206	        }
207		else {
208		    if (is_UCX(fhp)) {
209			fhtype = FHT_VMSUCX;
210		    }
211		    else {
212			fhtype = FHT_UNKNOWN;
213		    }
214		}
215	    }
216	}
217
218	/* XXX still needs to handle SUNOS3 */
219
220	switch (fhtype) {
221	case FHT_AUSPEX:
222	    fsidp->Fsid_dev.Minor = fhp[7];
223	    fsidp->Fsid_dev.Major = fhp[6];
224	    fsidp->fsid_code = 0;
225
226	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
227	    *inop = temp;
228
229	    if (osnamep)
230		*osnamep = "Auspex";
231	    break;
232
233	case FHT_DECOSF:
234	    fsidp->fsid_code = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
235			/* XXX could ignore 3 high-order bytes */
236
237	    temp = make_uint32(fhp[3], fhp[2], fhp[1], fhp[0]);
238	    fsidp->Fsid_dev.Minor = temp & 0xFFFFF;
239	    fsidp->Fsid_dev.Major = (temp>>20) & 0xFFF;
240
241	    temp = make_uint32(fhp[15], fhp[14], fhp[13], fhp[12]);
242	    *inop = temp;
243	    if (osnamep)
244		*osnamep = "OSF";
245	    break;
246
247	case FHT_IRIX4:
248	    fsidp->Fsid_dev.Minor = fhp[3];
249	    fsidp->Fsid_dev.Major = fhp[2];
250	    fsidp->fsid_code = 0;
251
252	    temp = make_uint32(fhp[8], fhp[9], fhp[10], fhp[11]);
253	    *inop = temp;
254
255	    if (osnamep)
256		*osnamep = "IRIX4";
257	    break;
258
259	case FHT_IRIX5:
260	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
261	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
262	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
263
264	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
265	    *inop = temp;
266
267	    if (osnamep)
268		*osnamep = "IRIX5";
269	    break;
270
271	case FHT_SUNOS3:
272	    if (osnamep)
273		*osnamep = "SUNOS3";
274	    break;
275
276	case FHT_SUNOS4:
277	    fsidp->Fsid_dev.Minor = fhp[3];
278	    fsidp->Fsid_dev.Major = fhp[2];
279	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
280
281	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
282	    *inop = temp;
283
284	    if (osnamep)
285		*osnamep = "SUNOS4";
286	    break;
287
288	case FHT_SUNOS5:
289	    temp = make_uint16(fhp[0], fhp[1]);
290	    fsidp->Fsid_dev.Major = (temp>>2) &  0x3FFF;
291	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
292	    fsidp->Fsid_dev.Minor = temp & 0x3FFFF;
293	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
294
295	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
296	    *inop = temp;
297
298	    if (osnamep)
299		*osnamep = "SUNOS5";
300	    break;
301
302	case FHT_ULTRIX:
303	    fsidp->fsid_code = 0;
304	    fsidp->Fsid_dev.Minor = fhp[0];
305	    fsidp->Fsid_dev.Major = fhp[1];
306
307	    temp = make_uint32(fhp[7], fhp[6], fhp[5], fhp[4]);
308	    *inop = temp;
309	    if (osnamep)
310		*osnamep = "Ultrix";
311	    break;
312
313	case FHT_VMSUCX:
314	    /* No numeric file system ID, so hash on the device-name */
315	    if (sizeof(*fsidp) >= 14) {
316		if (sizeof(*fsidp) > 14)
317		    memset((char *)fsidp, 0, sizeof(*fsidp));
318		/* just use the whole thing */
319		memcpy((char *)fsidp, (char *)fh, 14);
320	    }
321	    else {
322		u_int32_t tempa[4];	/* at least 16 bytes, maybe more */
323
324		memset((char *)tempa, 0, sizeof(tempa));
325		memcpy((char *)tempa, (char *)fh, 14); /* ensure alignment */
326		fsidp->Fsid_dev.Minor = tempa[0] + (tempa[1]<<1);
327		fsidp->Fsid_dev.Major = tempa[2] + (tempa[3]<<1);
328		fsidp->fsid_code = 0;
329	    }
330
331	    /* VMS file ID is: (RVN, FidHi, FidLo) */
332	    *inop = make_uint32(fhp[26], fhp[27], fhp[23], fhp[22]);
333
334	    /* Caller must save (and null-terminate?) this value */
335	    if (fsnamep)
336		*fsnamep = (char *)&(fhp[1]);
337
338	    if (osnamep)
339		*osnamep = "VMS";
340	    break;
341
342	case FHT_AIX32:
343	    fsidp->Fsid_dev.Minor = make_uint16(fhp[2], fhp[3]);
344	    fsidp->Fsid_dev.Major = make_uint16(fhp[0], fhp[1]);
345	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
346
347	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
348	    *inop = temp;
349
350	    if (osnamep)
351		*osnamep = "AIX32";
352	    break;
353
354	case FHT_HPUX9:
355	    fsidp->Fsid_dev.Major = fhp[0];
356	    temp = make_uint24(fhp[1], fhp[2], fhp[3]);
357	    fsidp->Fsid_dev.Minor = temp;
358	    fsidp->fsid_code = make_uint32(fhp[4], fhp[5], fhp[6], fhp[7]);
359
360	    temp = make_uint32(fhp[12], fhp[13], fhp[14], fhp[15]);
361	    *inop = temp;
362
363	    if (osnamep)
364		*osnamep = "HPUX9";
365	    break;
366
367	case FHT_UNKNOWN:
368#ifdef DEBUG
369	    {
370		/* XXX debugging */
371		int i;
372		for (i = 0; i < 32; i++)
373			(void)fprintf(stderr, "%x.", fhp[i]);
374		(void)fprintf(stderr, "\n");
375	    }
376#endif
377	    /* XXX for now, give "bogus" values to aid debugging */
378	    fsidp->fsid_code = 0;
379	    fsidp->Fsid_dev.Minor = 257;
380	    fsidp->Fsid_dev.Major = 257;
381	    *inop = 1;
382
383	    /* display will show this string instead of (257,257) */
384	    if (fsnamep)
385		*fsnamep = "Unknown";
386
387	    if (osnamep)
388		*osnamep = "Unknown";
389	    break;
390
391	}
392}
393
394/*
395 * Is this a VMS UCX file handle?
396 *	Check for:
397 *	(1) leading code byte	[XXX not yet]
398 *	(2) followed by string of printing chars & spaces
399 *	(3) followed by string of nulls
400 */
401static int
402is_UCX(fhp)
403unsigned char *fhp;
404{
405	register int i;
406	int seen_null = 0;
407
408	for (i = 1; i < 14; i++) {
409	    if (isprint(fhp[i])) {
410		if (seen_null)
411		   return(0);
412		else
413		   continue;
414	    }
415	    else if (fhp[i] == 0) {
416		seen_null = 1;
417		continue;
418	    }
419	    else
420		return(0);
421	}
422
423	return(1);
424}
425