1/*
2 * rnch.c -- Sun format name cache functions for lsof library
3 */
4
5
6/*
7 * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
8 * 47907.  All rights reserved.
9 *
10 * Written by Victor A. Abell
11 *
12 * This software is not subject to any license of the American Telephone
13 * and Telegraph Company or the Regents of the University of California.
14 *
15 * Permission is granted to anyone to use this software for any purpose on
16 * any computer system, and to alter it and redistribute it freely, subject
17 * to the following restrictions:
18 *
19 * 1. Neither the authors nor Purdue University are responsible for any
20 *    consequences of the use of this software.
21 *
22 * 2. The origin of this software must not be misrepresented, either by
23 *    explicit claim or by omission.  Credit to the authors and Purdue
24 *    University must appear in documentation and sources.
25 *
26 * 3. Altered versions must be plainly marked as such, and must not be
27 *    misrepresented as being the original software.
28 *
29 * 4. This notice may not be removed or altered.
30 */
31
32
33#include "../machine.h"
34
35#if	defined(HASNCACHE) && defined(USE_LIB_RNCH)
36
37# if	!defined(lint)
38static char copyright[] =
39"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
40static char *rcsid = "$Id: rnch.c,v 1.11 2008/10/21 16:13:23 abe Exp $";
41# endif	/* !defined(lint) */
42
43#include "../lsof.h"
44
45
46/*
47 * rnch.c - read Sun format (struct ncache) name cache
48 *
49 * This code is effective only when HASNCACHE is defined.
50 */
51
52/*
53 * The caller must:
54 *
55 *	#include the relevant header file -- e.g., <sys/dnlc.h>.
56 *
57 *	Define X_NCSIZE as the nickname for the kernel cache size variable,
58 *	or, if X_NCSIZE is undefined, define FIXED_NCSIZE as the size of the
59 *	kernel cache.
60 *
61 *	Define X_NCACHE as the nickname for the kernel cache address and
62 *	define ADDR_NCACHE if the address is the address of the cache,
63 *	rather than the address of a pointer to it.
64 *
65 *	Define NCACHE_NXT if the kernel's name cache is a linked list, starting
66 *	at the X_NCACHE address, rather than a table, starting at that address.
67 *
68 *	Define any of the following casts that differ from their defaults:
69 *
70 *		NCACHE_SZ_CAST	cast for X_NCACHE (default int)
71 *
72 * The caller may:
73 *
74 *	Define NCACHE_DP	as the name of the element in the
75 *				ncache structure that contains the
76 *				parent vnode pointer.
77 *
78 *				Default: dp
79 *
80 *	Define NCACHE_NAME	as the name of the element in the
81 *				ncache structure that contains the
82 *				name.
83 *
84 *				Default: name
85 *
86 *	Define NCACHE_NAMLEN	as the name of the element in the
87 *				ncache structure that contains the
88 *				name length.
89 *
90 *				Deafult: namlen
91 *
92 *	Define NCACHE_NEGVN	as the name of the name list element
93 *				whose value is a vnode address to
94 *				ignore when loading the kernel name
95 *				cache.
96 *
97 *	Define NCACHE_NODEID	as the name of the element in the
98 *				ncache structure that contains the
99 *				vnode's capability ID.
100 *
101 *	Define NCACHE_PARID	as the name of the element in the
102 *				ncache structure that contains the
103 *				parent vnode's capability ID.
104 *
105 *	Define NCACHE_VP	as the name of the element in the
106 *				ncache structure that contains the
107 *				vnode pointer.
108 *
109 *				Default: vp
110 *
111 * Note: if NCACHE_NODEID is defined, then NCACHE_PARID must be defined.
112 *
113 *
114 * The caller must:
115 *
116 *	Define this prototype for ncache_load():
117 *
118 *		_PROTOTYPE(void ncache_load,(void));
119 */
120
121
122/*
123 * Local static values
124 */
125
126static int Mch;				/* name cache hash mask */
127
128# if	!defined(NCACHE_NC_CAST)
129#define	NCACHE_SZ_CAST	int
130# endif	/* !defined(NCACHE_NC_CAST) */
131
132static NCACHE_SZ_CAST Nc = 0;		/* size of name cache */
133static int Nch = 0;			/* size of name cache hash pointer
134					 * table */
135struct l_nch {
136	KA_T vp;			/* vnode address */
137	KA_T dp;			/* parent vnode address */
138	struct l_nch *pa;		/* parent Ncache address */
139
140# if	defined(NCACHE_NODEID)
141	unsigned long id;		/* node's capability ID */
142	unsigned long did;		/* parent node's capability ID */
143# endif	/* defined(NCACHE_NODEID) */
144
145	char *nm;			/* name */
146	int nl;				/* name length */
147};
148
149static struct l_nch *Ncache = (struct l_nch *)NULL;
150					/* the local name cache */
151static struct l_nch **Nchash = (struct l_nch **)NULL;
152					/* Ncache hash pointers */
153static int Ncfirst = 1;			/* first-call status */
154
155# if 	defined(NCACHE_NEGVN)
156static KA_T NegVN = (KA_T)NULL;		/* negative vnode address */
157static int NegVNSt = 0;			/* NegVN status: 0 = not loaded */
158# endif	/* defined(NCACHE_NEGVN) */
159
160# if	defined(NCACHE_NODEID)
161_PROTOTYPE(static struct l_nch *ncache_addr,(unsigned long i, KA_T v));
162#define ncachehash(i,v)		Nchash+(((((int)(v)>>2)+((int)(i)))*31415)&Mch)
163# else	/* !defined(NCACHE_NODEID) */
164_PROTOTYPE(static struct l_nch *ncache_addr,(KA_T v));
165#define ncachehash(v)		Nchash+((((int)(v)>>2)*31415)&Mch)
166# endif	/* defined(NCACHE_NODEID) */
167
168_PROTOTYPE(static int ncache_isroot,(KA_T va, char *cp));
169
170#define DEFNCACHESZ	1024	/* local size if X_NCSIZE kernel value < 1 */
171#define	LNCHINCRSZ	64	/* local size increment */
172
173# if	!defined(NCACHE_DP)
174#define	NCACHE_DP	dp
175# endif	/* !defined(NCACHE_DP) */
176
177# if	!defined(NCACHE_NAME)
178#define	NCACHE_NAME	name
179# endif	/* !defined(NCACHE_NAME) */
180
181# if	!defined(NCACHE_NAMLEN)
182#define	NCACHE_NAMLEN	namlen
183# endif	/* !defined(NCACHE_NAMLEN) */
184
185# if	!defined(NCACHE_VP)
186#define	NCACHE_VP	vp
187# endif	/* !defined(NCACHE_VP) */
188
189
190/*
191 * ncache_addr() - look up a node's local ncache address
192 */
193
194static struct l_nch *
195
196# if	defined(NCACHE_NODEID)
197ncache_addr(i, v)
198# else	/* !defined(NCACHE_NODEID) */
199ncache_addr(v)
200# endif	/* defined(NCACHE_NODEID) */
201
202# if	defined(NCACHE_NODEID)
203	unsigned long i;			/* capability ID */
204# endif	/* defined(NCACHE_NODEID) */
205
206	KA_T v;					/* vnode's address */
207{
208	struct l_nch **hp;
209
210# if	defined(NCACHE_NODEID)
211	for (hp = ncachehash(i, v); *hp; hp++)
212# else	/* !defined(NCACHE_NODEID) */
213	for (hp = ncachehash(v); *hp; hp++)
214# endif	/* defined(NCACHE_NODEID) */
215
216	{
217
218# if	defined(NCACHE_NODEID)
219	    if ((*hp)->vp == v && (*hp)->id == i)
220# else	/* !defined(NCACHE_NODEID) */
221	    if ((*hp)->vp == v)
222# endif	/* defined(NCACHE_NODEID) */
223
224		return(*hp);
225	}
226	return((struct l_nch *)NULL);
227}
228
229
230/*
231 * ncache_isroot() - is head of name cache path a file system root?
232 */
233
234static int
235ncache_isroot(va, cp)
236	KA_T va;			/* kernel vnode address */
237	char *cp;			/* partial path */
238{
239	char buf[MAXPATHLEN];
240	int i;
241	MALLOC_S len;
242	struct mounts *mtp;
243	struct stat sb;
244	struct vnode v;
245	static int vca = 0;
246	static int vcn = 0;
247	static KA_T *vc = (KA_T *)NULL;
248
249	if (!va)
250	    return(0);
251/*
252 * Search the root vnode cache.
253 */
254	for (i = 0; i < vcn; i++) {
255	    if (va == vc[i])
256		return(1);
257	}
258/*
259 * Read the vnode and see if it's a VDIR node with the VROOT flag set.  If
260 * it is, then the path is complete.
261 *
262 * If it isn't, and if the file has an inode number, search the mount table
263 * and see if the file system's inode number is known.  If it is, form the
264 * possible full path, safely stat() it, and see if it's inode number matches
265 * the one we have for this file.  If it does, then the path is complete.
266 */
267	if (kread((KA_T)va, (char *)&v, sizeof(v))
268	||  v.v_type != VDIR || !(v.v_flag & VROOT)) {
269
270	/*
271	 * The vnode tests failed.  Try the inode tests.
272	 */
273	    if (Lf->inp_ty != 1 || !Lf->inode
274	    ||  !Lf->fsdir || (len = strlen(Lf->fsdir)) < 1)
275		return(0);
276	    if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
277		return(0);
278	    for (mtp = readmnt(); mtp; mtp = mtp->next) {
279		if (!mtp->dir || !mtp->inode)
280		    continue;
281		if (strcmp(Lf->fsdir, mtp->dir) == 0)
282		    break;
283	    }
284	    if (!mtp)
285		return(0);
286	    (void) strcpy(buf, Lf->fsdir);
287	    if (buf[len - 1] != '/')
288		buf[len++] = '/';
289	    (void) strcpy(&buf[len], cp);
290	    if (statsafely(buf, &sb) != 0
291	    ||  (unsigned long)sb.st_ino != Lf->inode)
292		return(0);
293	}
294/*
295 * Add the vnode address to the root vnode cache.
296 */
297	if (vcn >= vca) {
298	    vca += 10;
299	    len = (MALLOC_S)(vca * sizeof(KA_T));
300	    if (!vc)
301		vc = (KA_T *)malloc(len);
302	    else
303		vc = (KA_T *)realloc(vc, len);
304	    if (!vc) {
305		(void) fprintf(stderr, "%s: no space for root vnode table\n",
306		    Pn);
307		Exit(1);
308	    }
309	}
310	vc[vcn++] = va;
311	return(1);
312}
313
314
315/*
316 * ncache_load() - load the kernel's name cache
317 */
318
319void
320ncache_load()
321{
322	char *cp, *np;
323	struct l_nch **hp, *lc;
324	int i, len, n;
325	static int iNc = 0;
326	struct ncache *kc;
327	static KA_T kp = (KA_T)NULL;
328	KA_T v;
329
330# if	defined(HASDNLCPTR)
331	static int na = 0;
332	static char *nb = (char *)NULL;
333# endif	/* defined(HASDNLCPTR) */
334
335# if	defined(NCACHE_NXT)
336	static KA_T kf;
337	struct ncache nc;
338# else	/* !defined(NCACHE_NXT) */
339	static struct ncache *kca = (struct ncache *)NULL;
340# endif	/* defined(NCACHE_NXT) */
341
342	if (!Fncache)
343	    return;
344	if (Ncfirst) {
345
346	/*
347	 * Do startup (first-time) functions.
348	 */
349	    Ncfirst = 0;
350	/*
351	 * Establish kernel cache size.
352	 */
353
354# if	defined(X_NCSIZE)
355	    v = (KA_T)0;
356	    if (get_Nl_value(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0
357	    ||  !v
358	    ||  kread((KA_T)v, (char *)&Nc, sizeof(Nc)))
359	    {
360		if (!Fwarn)
361		(void) fprintf(stderr,
362		    "%s: WARNING: can't read name cache size: %s\n",
363			Pn, print_kptr(v, (char *)NULL, 0));
364		iNc = Nc = 0;
365		return;
366	    }
367	    iNc = Nc;
368# else	/* !defined(X_NCSIZE) */
369	    iNc = Nc = FIXED_NCSIZE;
370# endif	/* defined(X_NCSIZE) */
371
372	    if (Nc < 1) {
373		if (!Fwarn) {
374		    (void) fprintf(stderr,
375			"%s: WARNING: kernel name cache size: %d\n", Pn, Nc);
376		    (void) fprintf(stderr,
377			"      Cache size assumed to be: %d\n", DEFNCACHESZ);
378		}
379		iNc = Nc = DEFNCACHESZ;
380	    }
381
382# if	defined(NCACHE_NEGVN)
383	/*
384	 * Get negative vnode address.
385	 */
386	    if (!NegVNSt) {
387		if (get_Nl_value(NCACHE_NEGVN, (struct drive_Nl *)NULL, &NegVN)
388		< 0)
389		    NegVN = (KA_T)NULL;
390		NegVNSt = 1;
391	    }
392# endif	/* defined(NCACHE_NEGVN) */
393
394	/*
395	 * Establish kernel cache address.
396	 */
397
398# if	defined(ADDR_NCACHE)
399	    kp = (KA_T)0;
400	    if (get_Nl_value(X_NCACHE,(struct drive_Nl *)NULL,(KA_T *)&kp) < 0
401	    || !kp) {
402		if (!Fwarn)
403		    (void) fprintf(stderr,
404			"%s: WARNING: no name cache address\n", Pn);
405		iNc = Nc = 0;
406		return;
407	    }
408# else	/* !defined(ADDR_NCACHE) */
409	    v = (KA_T)0;
410	    if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0
411	    || !v
412	    ||  kread((KA_T)v, (char *)&kp, sizeof(kp))) {
413		if (!Fwarn)
414		    (void) fprintf(stderr,
415			"%s: WARNING: can't read name cache ptr: %s\n",
416			Pn, print_kptr(v, (char *)NULL, 0));
417		iNc = Nc = 0;
418		return;
419	    }
420# endif	/* defined(ADDR_NCACHE) */
421
422	/*
423	 * Allocate space for a local copy of the kernel's cache.
424	 */
425
426# if	!defined(NCACHE_NXT)
427	    len = Nc * sizeof(struct ncache);
428	    if (!(kca = (struct ncache *)malloc((MALLOC_S)len))) {
429		if (!Fwarn)
430		    (void) fprintf(stderr,
431			"%s: can't allocate name cache space: %d\n", Pn, len);
432		Exit(1);
433	    }
434# endif	/* !defined(NCACHE_NXT) */
435
436	/*
437	 * Allocate space for the local cache.
438	 */
439	    len = Nc * sizeof(struct l_nch);
440	    if (!(Ncache = (struct l_nch *)calloc(Nc, sizeof(struct l_nch)))) {
441
442no_local_space:
443
444		if (!Fwarn)
445		    (void) fprintf(stderr,
446		      "%s: no space for %d byte local name cache\n", Pn, len);
447		Exit(1);
448	    }
449	} else {
450
451	/*
452	 * Do setup for repeat calls.
453	 */
454	    if (!iNc)
455		return;
456	    if (Nchash) {
457		(void) free((FREE_P *)Nchash);
458		Nchash = (struct l_nch **)NULL;
459	    }
460	    if (Ncache) {
461
462	    /*
463	     * Free space malloc'd to names in local name cache.
464	     */
465	        for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
466		    if (lc->nm) {
467			(void) free((FREE_P *)lc->nm);
468			lc->nm = (char *)NULL;
469		    }
470	        }
471	    }
472	    Nc = iNc;
473
474# if	defined(NCACHE_NXT)
475	    kp = kf;
476# endif	/* defined(NCACHE_NXT) */
477
478	}
479
480# if	!defined(NCACHE_NXT)
481
482/*
483 * Read the kernel's name cache.
484 */
485	if (kread(kp, (char *)kca, (Nc * sizeof(struct ncache)))) {
486	    if (!Fwarn)
487		(void) fprintf(stderr,
488		    "%s: WARNING: can't read kernel's name cache: %s\n",
489		    Pn, print_kptr(kp, (char *)NULL, 0));
490	    Nc = 0;
491	    return;
492	}
493# endif	/* !defined(NCACHE_NXT) */
494
495/*
496 * Build a local copy of the kernel name cache.
497 */
498
499# if	defined(NCACHE_NXT)
500	for (i = iNc * 16, kc = &nc, kf = kp, lc = Ncache, n = 0; kp; )
501# else	/* !defined(NCACHE_NXT) */
502	for (i = n = 0, kc = kca, lc = Ncache; i < Nc; i++, kc++)
503# endif	/* defined(NCACHE_NXT) */
504
505	{
506
507# if	defined(NCACHE_NXT)
508	    if (kread(kp, (char *)kc, sizeof(nc)))
509		break;
510	    if ((kp = (KA_T)kc->NCACHE_NXT) == kf)
511		kp = (KA_T)NULL;
512# endif	/* defined(NCACHE_NXT) */
513
514	    if (!kc->NCACHE_VP || (len = kc->NCACHE_NAMLEN) < 1)
515		continue;
516
517# if	defined(NCACHE_NEGVN)
518	    if (NegVN && ((KA_T)kc->NCACHE_VP == NegVN))
519		continue;
520# endif	/* defined(NCACHE_NEGVN) */
521
522# if	defined(HASDNLCPTR)
523	/*
524	 * Read name from kernel to a temporary buffer.
525	 */
526	    if (len > na) {
527		na = len;
528		if (!nb)
529		    nb = (char *)malloc(na);
530		else
531		    nb = (char *)realloc((MALLOC_P *)nb, na);
532		if (!nb) {
533		    (void) fprintf(stderr,
534			"%s: can't allocate %d byte temporary name buffer\n",
535			Pn, na);
536		    Exit(1);
537		}
538	    }
539	    if (!kc->NCACHE_NAME || kread((KA_T)kc->NCACHE_NAME, nb, len))
540		continue;
541	    np = nb;
542# else	/* !defined(HASDNLCPTR) */
543	/*
544	 * Use name that is in the kernel cache entry.
545	 */
546	    if (len > NC_NAMLEN)
547		continue;
548	    np = kc->NCACHE_NAME;
549# endif	/* defined(HASDNLCPTR) */
550
551	    if (len < 3 && *np == '.') {
552		if (len == 1 || (len == 2 && np[1] == '.'))
553		    continue;
554	    }
555	/*
556	 * Allocate space for name in local cache entry.
557	 */
558	    if (!(cp = (char *)malloc(len + 1))) {
559		(void) fprintf(stderr,
560		    "%s: can't allocate %d bytes for name cache name: %s\n",
561		    Pn, len + 1, np);
562		Exit(1);
563	    }
564	    (void) strncpy(cp, np, len);
565	    cp[len] = '\0';
566
567# if	defined(NCACHE_NXT)
568	    if (n >= Nc) {
569
570	    /*
571	     * Allocate more local space to receive the kernel's linked
572	     * entries.
573	     */
574		Nc += LNCHINCRSZ;
575		if (!(Ncache = (struct l_nch *)realloc(Ncache,
576		     (MALLOC_S)(Nc * sizeof(struct l_nch)))))
577		{
578		    (void) fprintf(stderr,
579			"%s: no more space for %d entry local name cache\n",
580			Pn, Nc);
581		    Exit(1);
582		}
583		lc = &Ncache[n];
584		iNc = Nc;
585	    }
586# endif	/* defined(NCACHE_NXT) */
587
588	/*
589	 * Complete the local cache entry.
590	 */
591	    lc->vp = (KA_T)kc->NCACHE_VP;
592	    lc->dp = (KA_T)kc->NCACHE_DP;
593	    lc->pa = (struct l_nch *)NULL;
594	    lc->nm = cp;
595	    lc->nl = len;
596
597# if	defined(NCACHE_NODEID)
598	    lc->id = (unsigned long)kc->NCACHE_NODEID;
599	    lc->did = (unsigned long)kc->NCACHE_PARID;
600# endif	/* defined(NCACHE_NODEID) */
601
602	    n++;
603	    lc++;
604
605# if	defined(NCACHE_NXT)
606	    if (n >= i) {
607		if (!Fwarn)
608		    (void) fprintf(stderr,
609			"%s: WARNING: name cache truncated at %d entries\n",
610			Pn, n);
611		break;
612	    }
613# endif	/* defined(NCACHE_NXT) */
614
615	}
616/*
617 * Reduce memory usage, as required.
618 */
619
620# if	!defined(NCACHE_NXT)
621	if (!RptTm)
622	    (void) free((FREE_P *)kca);
623# endif	/* !defined(NCACHE_NXT) */
624
625	if (n < 1) {
626	    if (!RptTm && Ncache) {
627
628	    /*
629	     * If not in repeat mode, free the space that has been malloc'd
630	     * to the local name cache.
631	     */
632		for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
633		    if (lc->nm) {
634			(void) free((FREE_P *)lc->nm);
635			lc->nm = (char *)NULL;
636		    }
637		}
638		(void) free((FREE_P *)Ncache);
639	 	Ncache = (struct l_nch *)NULL;
640		Nc = 0;
641	    }
642	    if (!Fwarn)
643		(void) fprintf(stderr,
644		    "%s: WARNING: unusable name cache size: %d\n", Pn, n);
645	    return;
646	}
647	if (n < Nc) {
648	    Nc = n;
649	    if (!RptTm) {
650		len = Nc * sizeof(struct l_nch);
651		if (!(Ncache = (struct l_nch *)realloc(Ncache, len)))
652		    goto no_local_space;
653	    }
654	}
655/*
656 * Build a hash table to locate Ncache entries.
657 */
658	for (Nch = 1; Nch < Nc; Nch <<= 1)
659	    ;
660	Nch <<= 1;
661	Mch = Nch - 1;
662	if (!(Nchash = (struct l_nch **)calloc(Nch+Nc, sizeof(struct l_nch *))))
663	{
664	    if (!Fwarn)
665		(void) fprintf(stderr,
666		    "%s: no space for %d name cache hash pointers\n",
667		    Pn, Nch + Nc);
668	    Exit(1);
669	}
670	for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
671
672# if	defined(NCACHE_NODEID)
673	    for (hp = ncachehash(lc->id, lc->vp), n = 1; *hp; hp++)
674# else	/* !defined(NCACHE_NODEID) */
675	    for (hp = ncachehash(lc->vp), n = 1; *hp; hp++)
676# endif	/* defined(NCACHE_NODEID) */
677
678	    {
679		if ((*hp)->vp == lc->vp && strcmp((*hp)->nm, lc->nm) == 0
680		&&  (*hp)->dp == lc->dp
681
682# if	defined(NCACHE_NODEID)
683		&&  (*hp)->id == lc->id && (*hp)->did == lc->did
684# endif	/* defined(NCACHE_NODEID) */
685
686		) {
687		    n = 0;
688		    break;
689		}
690	    }
691	    if (n)
692		*hp = lc;
693	}
694/*
695 * Make a final pass through the local cache and convert parent vnode
696 * addresses to local name cache pointers.
697 */
698	for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
699	    if (!lc->dp)
700		continue;
701
702# if	defined(NCACHE_NEGVN)
703	     if (NegVN && (lc->dp == NegVN)) {
704		lc->pa = (struct l_nch *)NULL;
705		continue;
706	     }
707# endif	/* defined(NCACHE_NEGVN) */
708
709# if	defined(NCACHE_NODEID)
710	    lc->pa = ncache_addr(lc->did, lc->dp);
711# else	/* !defined(NCACHE_NODEID) */
712	    lc->pa = ncache_addr(lc->dp);
713# endif	/* defined(NCACHE_NODEID) */
714
715	}
716}
717
718
719/*
720 * ncache_lookup() - look up a node's name in the kernel's name cache
721 */
722
723char *
724ncache_lookup(buf, blen, fp)
725	char *buf;			/* receiving name buffer */
726	int blen;			/* receiving buffer length */
727	int *fp;			/* full path reply */
728{
729	char *cp = buf;
730	struct l_nch *lc;
731	struct mounts *mtp;
732	int nl, rlen;
733
734	*cp = '\0';
735	*fp = 0;
736
737# if	defined(HASFSINO)
738/*
739 * If the entry has an inode number that matches the inode number of the
740 * file system mount point, return an empty path reply.  That tells the
741 * caller to print the file system mount point name only.
742 */
743	if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
744	    return(cp);
745# endif	/* defined(HASFSINO) */
746
747/*
748 * Look up the name cache entry for the node address.
749 */
750	if (!Nc
751
752# if	defined(NCACHE_NODEID)
753	||  !(lc = ncache_addr(Lf->id, Lf->na))
754# else	/* !defined(NCACHE_NODEID) */
755	||  !(lc = ncache_addr(Lf->na))
756# endif	/* defined(NCACHE_NODEID) */
757
758	) {
759
760	/*
761	 * If the node has no cache entry, see if it's the mount
762	 * point of a known file system.
763	 */
764	    if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
765		return((char *)NULL);
766	    for (mtp = readmnt(); mtp; mtp = mtp->next) {
767		if (!mtp->dir || !mtp->inode)
768		    continue;
769		if (Lf->dev == mtp->dev
770		&&  mtp->inode == Lf->inode
771		&&  strcmp(mtp->dir, Lf->fsdir) == 0)
772		    return(cp);
773	    }
774	    return((char *)NULL);
775	}
776/*
777 * Begin the path assembly.
778 */
779	if ((nl = lc->nl) > (blen - 1))
780	    return((char *)NULL);
781	cp = buf + blen - nl - 1;
782	rlen = blen - nl - 1;
783	(void) strcpy(cp, lc->nm);
784/*
785 * Look up the name cache entries that are parents of the node address.
786 * Quit when:
787 *
788 *	there's no parent;
789 *	the name is too large to fit in the receiving buffer.
790 */
791	for (;;) {
792	    if (!lc->pa) {
793		if (ncache_isroot(lc->dp, cp))
794		    *fp = 1;
795		break;
796	    }
797	    lc = lc->pa;
798	    if (((nl = lc->nl) + 1) > rlen)
799		break;
800	    *(cp - 1) = '/';
801	    cp--;
802	    rlen--;
803	    (void) strncpy((cp - nl), lc->nm, nl);
804	    cp -= nl;
805	    rlen -= nl;
806	}
807	return(cp);
808}
809#else	/* !defined(HASNCACHE) || !defined(USE_LIB_RNCH) */
810char rnch_d1[] = "d"; char *rnch_d2 = rnch_d1;
811#endif	/* defined(HASNCACHE) && defined(USE_LIB_RNCH) */
812