Define LSOF_CC to system CC
[platform/upstream/lsof.git] / lib / rnch.c
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)
38 static char copyright[] =
39 "@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
40 static 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
126 static 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
132 static NCACHE_SZ_CAST Nc = 0;           /* size of name cache */
133 static int Nch = 0;                     /* size of name cache hash pointer
134                                          * table */
135 struct 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
149 static struct l_nch *Ncache = (struct l_nch *)NULL;
150                                         /* the local name cache */
151 static struct l_nch **Nchash = (struct l_nch **)NULL;
152                                         /* Ncache hash pointers */
153 static int Ncfirst = 1;                 /* first-call status */
154
155 # if    defined(NCACHE_NEGVN)
156 static KA_T NegVN = (KA_T)NULL;         /* negative vnode address */
157 static 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
194 static struct l_nch *
195
196 # if    defined(NCACHE_NODEID)
197 ncache_addr(i, v)
198 # else  /* !defined(NCACHE_NODEID) */
199 ncache_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
234 static int
235 ncache_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
319 void
320 ncache_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
442 no_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
723 char *
724 ncache_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) */
810 char rnch_d1[] = "d"; char *rnch_d2 = rnch_d1;
811 #endif  /* defined(HASNCACHE) && defined(USE_LIB_RNCH) */