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