summaryrefslogtreecommitdiff
path: root/lib/rnch.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rnch.c')
-rw-r--r--lib/rnch.c811
1 files changed, 811 insertions, 0 deletions
diff --git a/lib/rnch.c b/lib/rnch.c
new file mode 100644
index 0000000..0bdb7db
--- /dev/null
+++ b/lib/rnch.c
@@ -0,0 +1,811 @@
+/*
+ * rnch.c -- Sun format name cache functions for lsof library
+ */
+
+
+/*
+ * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#include "../machine.h"
+
+#if defined(HASNCACHE) && defined(USE_LIB_RNCH)
+
+# if !defined(lint)
+static char copyright[] =
+"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: rnch.c,v 1.11 2008/10/21 16:13:23 abe Exp $";
+# endif /* !defined(lint) */
+
+#include "../lsof.h"
+
+
+/*
+ * rnch.c - read Sun format (struct ncache) name cache
+ *
+ * This code is effective only when HASNCACHE is defined.
+ */
+
+/*
+ * The caller must:
+ *
+ * #include the relevant header file -- e.g., <sys/dnlc.h>.
+ *
+ * Define X_NCSIZE as the nickname for the kernel cache size variable,
+ * or, if X_NCSIZE is undefined, define FIXED_NCSIZE as the size of the
+ * kernel cache.
+ *
+ * Define X_NCACHE as the nickname for the kernel cache address and
+ * define ADDR_NCACHE if the address is the address of the cache,
+ * rather than the address of a pointer to it.
+ *
+ * Define NCACHE_NXT if the kernel's name cache is a linked list, starting
+ * at the X_NCACHE address, rather than a table, starting at that address.
+ *
+ * Define any of the following casts that differ from their defaults:
+ *
+ * NCACHE_SZ_CAST cast for X_NCACHE (default int)
+ *
+ * The caller may:
+ *
+ * Define NCACHE_DP as the name of the element in the
+ * ncache structure that contains the
+ * parent vnode pointer.
+ *
+ * Default: dp
+ *
+ * Define NCACHE_NAME as the name of the element in the
+ * ncache structure that contains the
+ * name.
+ *
+ * Default: name
+ *
+ * Define NCACHE_NAMLEN as the name of the element in the
+ * ncache structure that contains the
+ * name length.
+ *
+ * Deafult: namlen
+ *
+ * Define NCACHE_NEGVN as the name of the name list element
+ * whose value is a vnode address to
+ * ignore when loading the kernel name
+ * cache.
+ *
+ * Define NCACHE_NODEID as the name of the element in the
+ * ncache structure that contains the
+ * vnode's capability ID.
+ *
+ * Define NCACHE_PARID as the name of the element in the
+ * ncache structure that contains the
+ * parent vnode's capability ID.
+ *
+ * Define NCACHE_VP as the name of the element in the
+ * ncache structure that contains the
+ * vnode pointer.
+ *
+ * Default: vp
+ *
+ * Note: if NCACHE_NODEID is defined, then NCACHE_PARID must be defined.
+ *
+ *
+ * The caller must:
+ *
+ * Define this prototype for ncache_load():
+ *
+ * _PROTOTYPE(void ncache_load,(void));
+ */
+
+
+/*
+ * Local static values
+ */
+
+static int Mch; /* name cache hash mask */
+
+# if !defined(NCACHE_NC_CAST)
+#define NCACHE_SZ_CAST int
+# endif /* !defined(NCACHE_NC_CAST) */
+
+static NCACHE_SZ_CAST Nc = 0; /* size of name cache */
+static int Nch = 0; /* size of name cache hash pointer
+ * table */
+struct l_nch {
+ KA_T vp; /* vnode address */
+ KA_T dp; /* parent vnode address */
+ struct l_nch *pa; /* parent Ncache address */
+
+# if defined(NCACHE_NODEID)
+ unsigned long id; /* node's capability ID */
+ unsigned long did; /* parent node's capability ID */
+# endif /* defined(NCACHE_NODEID) */
+
+ char *nm; /* name */
+ int nl; /* name length */
+};
+
+static struct l_nch *Ncache = (struct l_nch *)NULL;
+ /* the local name cache */
+static struct l_nch **Nchash = (struct l_nch **)NULL;
+ /* Ncache hash pointers */
+static int Ncfirst = 1; /* first-call status */
+
+# if defined(NCACHE_NEGVN)
+static KA_T NegVN = (KA_T)NULL; /* negative vnode address */
+static int NegVNSt = 0; /* NegVN status: 0 = not loaded */
+# endif /* defined(NCACHE_NEGVN) */
+
+# if defined(NCACHE_NODEID)
+_PROTOTYPE(static struct l_nch *ncache_addr,(unsigned long i, KA_T v));
+#define ncachehash(i,v) Nchash+(((((int)(v)>>2)+((int)(i)))*31415)&Mch)
+# else /* !defined(NCACHE_NODEID) */
+_PROTOTYPE(static struct l_nch *ncache_addr,(KA_T v));
+#define ncachehash(v) Nchash+((((int)(v)>>2)*31415)&Mch)
+# endif /* defined(NCACHE_NODEID) */
+
+_PROTOTYPE(static int ncache_isroot,(KA_T va, char *cp));
+
+#define DEFNCACHESZ 1024 /* local size if X_NCSIZE kernel value < 1 */
+#define LNCHINCRSZ 64 /* local size increment */
+
+# if !defined(NCACHE_DP)
+#define NCACHE_DP dp
+# endif /* !defined(NCACHE_DP) */
+
+# if !defined(NCACHE_NAME)
+#define NCACHE_NAME name
+# endif /* !defined(NCACHE_NAME) */
+
+# if !defined(NCACHE_NAMLEN)
+#define NCACHE_NAMLEN namlen
+# endif /* !defined(NCACHE_NAMLEN) */
+
+# if !defined(NCACHE_VP)
+#define NCACHE_VP vp
+# endif /* !defined(NCACHE_VP) */
+
+
+/*
+ * ncache_addr() - look up a node's local ncache address
+ */
+
+static struct l_nch *
+
+# if defined(NCACHE_NODEID)
+ncache_addr(i, v)
+# else /* !defined(NCACHE_NODEID) */
+ncache_addr(v)
+# endif /* defined(NCACHE_NODEID) */
+
+# if defined(NCACHE_NODEID)
+ unsigned long i; /* capability ID */
+# endif /* defined(NCACHE_NODEID) */
+
+ KA_T v; /* vnode's address */
+{
+ struct l_nch **hp;
+
+# if defined(NCACHE_NODEID)
+ for (hp = ncachehash(i, v); *hp; hp++)
+# else /* !defined(NCACHE_NODEID) */
+ for (hp = ncachehash(v); *hp; hp++)
+# endif /* defined(NCACHE_NODEID) */
+
+ {
+
+# if defined(NCACHE_NODEID)
+ if ((*hp)->vp == v && (*hp)->id == i)
+# else /* !defined(NCACHE_NODEID) */
+ if ((*hp)->vp == v)
+# endif /* defined(NCACHE_NODEID) */
+
+ return(*hp);
+ }
+ return((struct l_nch *)NULL);
+}
+
+
+/*
+ * ncache_isroot() - is head of name cache path a file system root?
+ */
+
+static int
+ncache_isroot(va, cp)
+ KA_T va; /* kernel vnode address */
+ char *cp; /* partial path */
+{
+ char buf[MAXPATHLEN];
+ int i;
+ MALLOC_S len;
+ struct mounts *mtp;
+ struct stat sb;
+ struct vnode v;
+ static int vca = 0;
+ static int vcn = 0;
+ static KA_T *vc = (KA_T *)NULL;
+
+ if (!va)
+ return(0);
+/*
+ * Search the root vnode cache.
+ */
+ for (i = 0; i < vcn; i++) {
+ if (va == vc[i])
+ return(1);
+ }
+/*
+ * Read the vnode and see if it's a VDIR node with the VROOT flag set. If
+ * it is, then the path is complete.
+ *
+ * If it isn't, and if the file has an inode number, search the mount table
+ * and see if the file system's inode number is known. If it is, form the
+ * possible full path, safely stat() it, and see if it's inode number matches
+ * the one we have for this file. If it does, then the path is complete.
+ */
+ if (kread((KA_T)va, (char *)&v, sizeof(v))
+ || v.v_type != VDIR || !(v.v_flag & VROOT)) {
+
+ /*
+ * The vnode tests failed. Try the inode tests.
+ */
+ if (Lf->inp_ty != 1 || !Lf->inode
+ || !Lf->fsdir || (len = strlen(Lf->fsdir)) < 1)
+ return(0);
+ if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
+ return(0);
+ for (mtp = readmnt(); mtp; mtp = mtp->next) {
+ if (!mtp->dir || !mtp->inode)
+ continue;
+ if (strcmp(Lf->fsdir, mtp->dir) == 0)
+ break;
+ }
+ if (!mtp)
+ return(0);
+ (void) strcpy(buf, Lf->fsdir);
+ if (buf[len - 1] != '/')
+ buf[len++] = '/';
+ (void) strcpy(&buf[len], cp);
+ if (statsafely(buf, &sb) != 0
+ || (unsigned long)sb.st_ino != Lf->inode)
+ return(0);
+ }
+/*
+ * Add the vnode address to the root vnode cache.
+ */
+ if (vcn >= vca) {
+ vca += 10;
+ len = (MALLOC_S)(vca * sizeof(KA_T));
+ if (!vc)
+ vc = (KA_T *)malloc(len);
+ else
+ vc = (KA_T *)realloc(vc, len);
+ if (!vc) {
+ (void) fprintf(stderr, "%s: no space for root vnode table\n",
+ Pn);
+ Exit(1);
+ }
+ }
+ vc[vcn++] = va;
+ return(1);
+}
+
+
+/*
+ * ncache_load() - load the kernel's name cache
+ */
+
+void
+ncache_load()
+{
+ char *cp, *np;
+ struct l_nch **hp, *lc;
+ int i, len, n;
+ static int iNc = 0;
+ struct ncache *kc;
+ static KA_T kp = (KA_T)NULL;
+ KA_T v;
+
+# if defined(HASDNLCPTR)
+ static int na = 0;
+ static char *nb = (char *)NULL;
+# endif /* defined(HASDNLCPTR) */
+
+# if defined(NCACHE_NXT)
+ static KA_T kf;
+ struct ncache nc;
+# else /* !defined(NCACHE_NXT) */
+ static struct ncache *kca = (struct ncache *)NULL;
+# endif /* defined(NCACHE_NXT) */
+
+ if (!Fncache)
+ return;
+ if (Ncfirst) {
+
+ /*
+ * Do startup (first-time) functions.
+ */
+ Ncfirst = 0;
+ /*
+ * Establish kernel cache size.
+ */
+
+# if defined(X_NCSIZE)
+ v = (KA_T)0;
+ if (get_Nl_value(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0
+ || !v
+ || kread((KA_T)v, (char *)&Nc, sizeof(Nc)))
+ {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: can't read name cache size: %s\n",
+ Pn, print_kptr(v, (char *)NULL, 0));
+ iNc = Nc = 0;
+ return;
+ }
+ iNc = Nc;
+# else /* !defined(X_NCSIZE) */
+ iNc = Nc = FIXED_NCSIZE;
+# endif /* defined(X_NCSIZE) */
+
+ if (Nc < 1) {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: kernel name cache size: %d\n", Pn, Nc);
+ (void) fprintf(stderr,
+ " Cache size assumed to be: %d\n", DEFNCACHESZ);
+ }
+ iNc = Nc = DEFNCACHESZ;
+ }
+
+# if defined(NCACHE_NEGVN)
+ /*
+ * Get negative vnode address.
+ */
+ if (!NegVNSt) {
+ if (get_Nl_value(NCACHE_NEGVN, (struct drive_Nl *)NULL, &NegVN)
+ < 0)
+ NegVN = (KA_T)NULL;
+ NegVNSt = 1;
+ }
+# endif /* defined(NCACHE_NEGVN) */
+
+ /*
+ * Establish kernel cache address.
+ */
+
+# if defined(ADDR_NCACHE)
+ kp = (KA_T)0;
+ if (get_Nl_value(X_NCACHE,(struct drive_Nl *)NULL,(KA_T *)&kp) < 0
+ || !kp) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: no name cache address\n", Pn);
+ iNc = Nc = 0;
+ return;
+ }
+# else /* !defined(ADDR_NCACHE) */
+ v = (KA_T)0;
+ if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0
+ || !v
+ || kread((KA_T)v, (char *)&kp, sizeof(kp))) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: can't read name cache ptr: %s\n",
+ Pn, print_kptr(v, (char *)NULL, 0));
+ iNc = Nc = 0;
+ return;
+ }
+# endif /* defined(ADDR_NCACHE) */
+
+ /*
+ * Allocate space for a local copy of the kernel's cache.
+ */
+
+# if !defined(NCACHE_NXT)
+ len = Nc * sizeof(struct ncache);
+ if (!(kca = (struct ncache *)malloc((MALLOC_S)len))) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: can't allocate name cache space: %d\n", Pn, len);
+ Exit(1);
+ }
+# endif /* !defined(NCACHE_NXT) */
+
+ /*
+ * Allocate space for the local cache.
+ */
+ len = Nc * sizeof(struct l_nch);
+ if (!(Ncache = (struct l_nch *)calloc(Nc, sizeof(struct l_nch)))) {
+
+no_local_space:
+
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: no space for %d byte local name cache\n", Pn, len);
+ Exit(1);
+ }
+ } else {
+
+ /*
+ * Do setup for repeat calls.
+ */
+ if (!iNc)
+ return;
+ if (Nchash) {
+ (void) free((FREE_P *)Nchash);
+ Nchash = (struct l_nch **)NULL;
+ }
+ if (Ncache) {
+
+ /*
+ * Free space malloc'd to names in local name cache.
+ */
+ for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+ if (lc->nm) {
+ (void) free((FREE_P *)lc->nm);
+ lc->nm = (char *)NULL;
+ }
+ }
+ }
+ Nc = iNc;
+
+# if defined(NCACHE_NXT)
+ kp = kf;
+# endif /* defined(NCACHE_NXT) */
+
+ }
+
+# if !defined(NCACHE_NXT)
+
+/*
+ * Read the kernel's name cache.
+ */
+ if (kread(kp, (char *)kca, (Nc * sizeof(struct ncache)))) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: can't read kernel's name cache: %s\n",
+ Pn, print_kptr(kp, (char *)NULL, 0));
+ Nc = 0;
+ return;
+ }
+# endif /* !defined(NCACHE_NXT) */
+
+/*
+ * Build a local copy of the kernel name cache.
+ */
+
+# if defined(NCACHE_NXT)
+ for (i = iNc * 16, kc = &nc, kf = kp, lc = Ncache, n = 0; kp; )
+# else /* !defined(NCACHE_NXT) */
+ for (i = n = 0, kc = kca, lc = Ncache; i < Nc; i++, kc++)
+# endif /* defined(NCACHE_NXT) */
+
+ {
+
+# if defined(NCACHE_NXT)
+ if (kread(kp, (char *)kc, sizeof(nc)))
+ break;
+ if ((kp = (KA_T)kc->NCACHE_NXT) == kf)
+ kp = (KA_T)NULL;
+# endif /* defined(NCACHE_NXT) */
+
+ if (!kc->NCACHE_VP || (len = kc->NCACHE_NAMLEN) < 1)
+ continue;
+
+# if defined(NCACHE_NEGVN)
+ if (NegVN && ((KA_T)kc->NCACHE_VP == NegVN))
+ continue;
+# endif /* defined(NCACHE_NEGVN) */
+
+# if defined(HASDNLCPTR)
+ /*
+ * Read name from kernel to a temporary buffer.
+ */
+ if (len > na) {
+ na = len;
+ if (!nb)
+ nb = (char *)malloc(na);
+ else
+ nb = (char *)realloc((MALLOC_P *)nb, na);
+ if (!nb) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte temporary name buffer\n",
+ Pn, na);
+ Exit(1);
+ }
+ }
+ if (!kc->NCACHE_NAME || kread((KA_T)kc->NCACHE_NAME, nb, len))
+ continue;
+ np = nb;
+# else /* !defined(HASDNLCPTR) */
+ /*
+ * Use name that is in the kernel cache entry.
+ */
+ if (len > NC_NAMLEN)
+ continue;
+ np = kc->NCACHE_NAME;
+# endif /* defined(HASDNLCPTR) */
+
+ if (len < 3 && *np == '.') {
+ if (len == 1 || (len == 2 && np[1] == '.'))
+ continue;
+ }
+ /*
+ * Allocate space for name in local cache entry.
+ */
+ if (!(cp = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for name cache name: %s\n",
+ Pn, len + 1, np);
+ Exit(1);
+ }
+ (void) strncpy(cp, np, len);
+ cp[len] = '\0';
+
+# if defined(NCACHE_NXT)
+ if (n >= Nc) {
+
+ /*
+ * Allocate more local space to receive the kernel's linked
+ * entries.
+ */
+ Nc += LNCHINCRSZ;
+ if (!(Ncache = (struct l_nch *)realloc(Ncache,
+ (MALLOC_S)(Nc * sizeof(struct l_nch)))))
+ {
+ (void) fprintf(stderr,
+ "%s: no more space for %d entry local name cache\n",
+ Pn, Nc);
+ Exit(1);
+ }
+ lc = &Ncache[n];
+ iNc = Nc;
+ }
+# endif /* defined(NCACHE_NXT) */
+
+ /*
+ * Complete the local cache entry.
+ */
+ lc->vp = (KA_T)kc->NCACHE_VP;
+ lc->dp = (KA_T)kc->NCACHE_DP;
+ lc->pa = (struct l_nch *)NULL;
+ lc->nm = cp;
+ lc->nl = len;
+
+# if defined(NCACHE_NODEID)
+ lc->id = (unsigned long)kc->NCACHE_NODEID;
+ lc->did = (unsigned long)kc->NCACHE_PARID;
+# endif /* defined(NCACHE_NODEID) */
+
+ n++;
+ lc++;
+
+# if defined(NCACHE_NXT)
+ if (n >= i) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: name cache truncated at %d entries\n",
+ Pn, n);
+ break;
+ }
+# endif /* defined(NCACHE_NXT) */
+
+ }
+/*
+ * Reduce memory usage, as required.
+ */
+
+# if !defined(NCACHE_NXT)
+ if (!RptTm)
+ (void) free((FREE_P *)kca);
+# endif /* !defined(NCACHE_NXT) */
+
+ if (n < 1) {
+ if (!RptTm && Ncache) {
+
+ /*
+ * If not in repeat mode, free the space that has been malloc'd
+ * to the local name cache.
+ */
+ for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+ if (lc->nm) {
+ (void) free((FREE_P *)lc->nm);
+ lc->nm = (char *)NULL;
+ }
+ }
+ (void) free((FREE_P *)Ncache);
+ Ncache = (struct l_nch *)NULL;
+ Nc = 0;
+ }
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: unusable name cache size: %d\n", Pn, n);
+ return;
+ }
+ if (n < Nc) {
+ Nc = n;
+ if (!RptTm) {
+ len = Nc * sizeof(struct l_nch);
+ if (!(Ncache = (struct l_nch *)realloc(Ncache, len)))
+ goto no_local_space;
+ }
+ }
+/*
+ * Build a hash table to locate Ncache entries.
+ */
+ for (Nch = 1; Nch < Nc; Nch <<= 1)
+ ;
+ Nch <<= 1;
+ Mch = Nch - 1;
+ if (!(Nchash = (struct l_nch **)calloc(Nch+Nc, sizeof(struct l_nch *))))
+ {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: no space for %d name cache hash pointers\n",
+ Pn, Nch + Nc);
+ Exit(1);
+ }
+ for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+
+# if defined(NCACHE_NODEID)
+ for (hp = ncachehash(lc->id, lc->vp), n = 1; *hp; hp++)
+# else /* !defined(NCACHE_NODEID) */
+ for (hp = ncachehash(lc->vp), n = 1; *hp; hp++)
+# endif /* defined(NCACHE_NODEID) */
+
+ {
+ if ((*hp)->vp == lc->vp && strcmp((*hp)->nm, lc->nm) == 0
+ && (*hp)->dp == lc->dp
+
+# if defined(NCACHE_NODEID)
+ && (*hp)->id == lc->id && (*hp)->did == lc->did
+# endif /* defined(NCACHE_NODEID) */
+
+ ) {
+ n = 0;
+ break;
+ }
+ }
+ if (n)
+ *hp = lc;
+ }
+/*
+ * Make a final pass through the local cache and convert parent vnode
+ * addresses to local name cache pointers.
+ */
+ for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+ if (!lc->dp)
+ continue;
+
+# if defined(NCACHE_NEGVN)
+ if (NegVN && (lc->dp == NegVN)) {
+ lc->pa = (struct l_nch *)NULL;
+ continue;
+ }
+# endif /* defined(NCACHE_NEGVN) */
+
+# if defined(NCACHE_NODEID)
+ lc->pa = ncache_addr(lc->did, lc->dp);
+# else /* !defined(NCACHE_NODEID) */
+ lc->pa = ncache_addr(lc->dp);
+# endif /* defined(NCACHE_NODEID) */
+
+ }
+}
+
+
+/*
+ * ncache_lookup() - look up a node's name in the kernel's name cache
+ */
+
+char *
+ncache_lookup(buf, blen, fp)
+ char *buf; /* receiving name buffer */
+ int blen; /* receiving buffer length */
+ int *fp; /* full path reply */
+{
+ char *cp = buf;
+ struct l_nch *lc;
+ struct mounts *mtp;
+ int nl, rlen;
+
+ *cp = '\0';
+ *fp = 0;
+
+# if defined(HASFSINO)
+/*
+ * If the entry has an inode number that matches the inode number of the
+ * file system mount point, return an empty path reply. That tells the
+ * caller to print the file system mount point name only.
+ */
+ if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
+ return(cp);
+# endif /* defined(HASFSINO) */
+
+/*
+ * Look up the name cache entry for the node address.
+ */
+ if (!Nc
+
+# if defined(NCACHE_NODEID)
+ || !(lc = ncache_addr(Lf->id, Lf->na))
+# else /* !defined(NCACHE_NODEID) */
+ || !(lc = ncache_addr(Lf->na))
+# endif /* defined(NCACHE_NODEID) */
+
+ ) {
+
+ /*
+ * If the node has no cache entry, see if it's the mount
+ * point of a known file system.
+ */
+ if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
+ return((char *)NULL);
+ for (mtp = readmnt(); mtp; mtp = mtp->next) {
+ if (!mtp->dir || !mtp->inode)
+ continue;
+ if (Lf->dev == mtp->dev
+ && mtp->inode == Lf->inode
+ && strcmp(mtp->dir, Lf->fsdir) == 0)
+ return(cp);
+ }
+ return((char *)NULL);
+ }
+/*
+ * Begin the path assembly.
+ */
+ if ((nl = lc->nl) > (blen - 1))
+ return((char *)NULL);
+ cp = buf + blen - nl - 1;
+ rlen = blen - nl - 1;
+ (void) strcpy(cp, lc->nm);
+/*
+ * Look up the name cache entries that are parents of the node address.
+ * Quit when:
+ *
+ * there's no parent;
+ * the name is too large to fit in the receiving buffer.
+ */
+ for (;;) {
+ if (!lc->pa) {
+ if (ncache_isroot(lc->dp, cp))
+ *fp = 1;
+ break;
+ }
+ lc = lc->pa;
+ if (((nl = lc->nl) + 1) > rlen)
+ break;
+ *(cp - 1) = '/';
+ cp--;
+ rlen--;
+ (void) strncpy((cp - nl), lc->nm, nl);
+ cp -= nl;
+ rlen -= nl;
+ }
+ return(cp);
+}
+#else /* !defined(HASNCACHE) || !defined(USE_LIB_RNCH) */
+char rnch_d1[] = "d"; char *rnch_d2 = rnch_d1;
+#endif /* defined(HASNCACHE) && defined(USE_LIB_RNCH) */