/* * dproc.c - SCO OpenServer process access functions for lsof */ /* * Copyright 1995 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. */ #ifndef lint static char copyright[] = "@(#) Copyright 1995 Purdue Research Foundation.\nAll rights reserved.\n"; static char *rcsid = "$Id: dproc.c,v 1.18 2007/04/24 16:22:40 abe Exp $"; #endif #include "lsof.h" /* * Local static values */ static KA_T Kp; /* kernel process table address */ static KA_T *Nc = (KA_T *)NULL; /* node cache */ static int Nn = 0; /* number of Nc[] entries allocated */ #if OSRV<500 static int Npp = 0; /* number of pregions per process */ static struct pregion *Pr = (struct pregion *)NULL; /* pregion buffer */ static int Prsz = 0; /* size of Pr */ #endif /* OSRV<500 */ static struct var Var; /* kernel variables */ _PROTOTYPE(static void get_cdevsw,(void)); _PROTOTYPE(static void get_kernel_access,(void)); #if !defined(N_UNIX) _PROTOTYPE(static int is_boot,(char *p)); #endif /* !defined(N_UNIX) */ _PROTOTYPE(static int open_kmem,(int nx)); _PROTOTYPE(static void process_text,(KA_T prp)); _PROTOTYPE(static void readfsinfo,(void)); /* * Ckkv - check kernel version */ static void Ckkv(d, er, ev, ea) char *d; /* dialect */ char *er; /* expected release */ char *ev; /* expected version */ char *ea; /* expected architecture */ { #if defined(HASKERNIDCK) struct scoutsname s; if (Fwarn) return; /* * Read OSR kernel information. */ if (__scoinfo(&s, sizeof(s)) < 0) { (void) fprintf(stderr, "%s: can't get __scoinfo: %s\n", Pn, strerror(errno)); Exit(1); } /* * Warn if the actual and expected releases don't match. */ if (!er || strcmp(er, s.release)) (void) fprintf(stderr, "%s: WARNING: compiled for %s release %s; this is %s.\n", Pn, d, er ? er : "UNKNOWN", s.release); #endif /* defined(HASKERNIDCK) */ } /* * gather_proc_info() -- gather process information */ void gather_proc_info() { int i, j, nf, pbc, px; struct proc *p; static char *pb = (char *)NULL; int pid, pgrp; short pss, sf; static struct user *u; static char *ua = (char *)NULL; static MALLOC_S ual = 0; unsigned int uid; #if defined(HASFSTRUCT) static MALLOC_S npofb = 0; char *pof; static char *pofb = (char *)NULL; #endif /* defined(HASFSTRUCT) */ /* * Allocate user structure buffer. */ if (!ua) { ual = (MALLOC_S)(MAXUSIZE * NBPC); if (!(ua = (char *)malloc(ual))) { (void) fprintf(stderr, "%s: no space for %d byte user structure buffer\n", Pn, ual); Exit(1); } u = (struct user *)ua; } /* * Allocate proc structure buffer. */ if (!pb) { if (!(pb = (char *)malloc(sizeof(struct proc) * PROCBFRD))) { (void) fprintf(stderr, "%s: no space for %d proc structures\n", Pn, PROCBFRD); Exit(1); } } /* * Examine proc structures and their associated information. */ for (pbc = px = 0; px < Var.v_proc; px++) { if (px >= pbc) { /* * Refill proc buffer. */ i = Var.v_proc - px; if (i > PROCBFRD) i = PROCBFRD; j = kread((KA_T)(Kp + (px * sizeof(struct proc))), pb, sizeof(struct proc) * i); pbc = px + i; p = (struct proc *)pb; if (j) { px += i; continue; } } else p++; if (p->p_stat == 0 || p->p_stat == SZOMB) continue; /* * Get Process ID, Process group ID, and User ID. */ pid = (int)p->p_pid; pgrp = (int)p->p_pgrp; uid = (unsigned int)p->p_uid; if (is_proc_excl(pid, pgrp, (UID_ARG)uid, &pss, &sf)) continue; /* * Get the user area associated with the process. */ if (sysi86(RDUBLK, pid, ua, MAXUSIZE * NBPC) == -1) continue; /* * Allocate a local process structure. */ if (is_cmd_excl(u->u_comm, &pss, &sf)) continue; alloc_lproc(pid, pgrp, (int)p->p_ppid, (UID_ARG)uid, u->u_comm, (int)pss, (int)sf); Plf = (struct lfile *)NULL; /* * Save current working directory information. */ if (u->u_cdir) { alloc_lfile(CWD, -1); process_node((KA_T)u->u_cdir); if (Lf->sf) link_lfile(); } /* * Save root directory information. */ if (u->u_rdir) { alloc_lfile(RTD, -1); process_node((KA_T)u->u_rdir); if (Lf->sf) link_lfile(); } /* * Print information on the text file. */ if (p->p_region) process_text((KA_T)p->p_region); /* * Save information on file descriptors. */ #if OSRV<42 nf = Var.v_nofiles; #else /* OSRV>=42 */ nf = u->u_nofiles ? u->u_nofiles : Var.v_nofiles; #endif /* OSRV<42 */ #if defined(HASFSTRUCT) if (Fsv & FSV_FG) { /* * If u_pofile is in the u block, set its address. */ if (nf && u->u_pofile && ((unsigned)u->u_pofile >= UVUBLK) && ((MALLOC_S)((unsigned)u->u_pofile - UVUBLK + nf) <= ual)) { pof = ua + (unsigned)u->u_pofile - UVUBLK; } else if (nf && u->u_pofile) { /* * Allocate space for u_pofile and read it from kernel memory. */ if (nf > npofb) { if (!pofb) pofb = (char *)malloc((MALLOC_S)nf); else pofb = (char *)realloc((MALLOC_P *)pofb, (MALLOC_S)nf); if (!pofb) { (void) fprintf(stderr, "%s: no pofile space\n", Pn); Exit(1); } npofb = nf; } if (kread((KA_T)u->u_pofile, pofb, nf)) pof = (char *)NULL; else pof = pofb; } else pof = (char *)NULL; } #endif /* defined(HASFSTRUCT) */ for (i = 0; i < nf; i++) { if (u->u_ofile[i]) { alloc_lfile((char *)NULL, i); process_file((KA_T)u->u_ofile[i]); if (Lf->sf) { #if defined(HASFSTRUCT) if (Fsv & FSV_FG && pof) Lf->pof = (long)pof[i]; #endif /* defined(HASFSTRUCT) */ link_lfile(); } } } /* * Examine results. */ if (examine_lproc()) return; } } /* * get_cdevsw() - get cdevsw[] names and record clone major device number */ void get_cdevsw() { char buf[16]; struct cdevsw *c, *tmp; int i, j, len; struct stat sb; KA_T v[2]; /* * Check cdevsw[] kernel addresses. * Read cdevsw[] count from kernel's cdevcnt. */ if (get_Nl_value("cdev", Drive_Nl, &v[0]) < 0 || get_Nl_value("ncdev", Drive_Nl, &v[1]) < 0 || !v[0] || !v[1] || kread(v[1], (char *)&Cdevcnt, sizeof(Cdevcnt)) || Cdevcnt < 1) return; /* * Allocate cache space. */ if (!(Cdevsw = (char **)malloc(Cdevcnt * sizeof(char *)))) { (void) fprintf(stderr, "%s: no space for %d cdevsw[] names\n", Pn, Cdevcnt); Exit(1); } /* * Allocate temporary space for a copy of cdevsw[] and read it. */ i = Cdevcnt * sizeof(struct cdevsw); if (!(tmp = (struct cdevsw *)malloc(i))) { (void) fprintf(stderr, "%s: no space for %d cdevsw[] entries\n", Pn, Cdevcnt); Exit(1); } if (kread((KA_T)v[0], (char *)tmp, i)) { (void) free((FREE_P *)Cdevsw); Cdevsw = (char **)NULL; Cdevcnt = 0; (void) free((FREE_P *)tmp); return; } /* * Cache the names from cdevsw[].d_name. * Record the number of the "clone" device. */ j = sizeof(buf) - 1; buf[j] = '\0'; for (c = tmp, i = 0; i < Cdevcnt; c++, i++) { Cdevsw[i] = (char *)NULL; if (!c->d_name) continue; if (kread((KA_T)c->d_name, buf, j)) { (void) fprintf(stderr, "%s: WARNING: can't read name for cdevsw[%d]: %#x\n", Pn, i, c->d_name); continue; } if (!buf[0]) continue; len = strlen(buf) + 1; if (!(Cdevsw[i] = (char *)malloc(len))) { (void) fprintf(stderr, "%s: no space for cdevsw[%d] name: %s\n", Pn, i, buf); Exit(1); } (void) snpf(Cdevsw[i], len, "%s", buf); if (!HaveCloneMajor && strcmp(buf, "clone") == 0) { CloneMajor = i; HaveCloneMajor = 1; continue; } if (!HaveEventMajor && strcmp(buf, "ev") == 0) { if (stat("/dev/event", &sb) == 0 && GET_MAJ_DEV(sb.st_rdev) == i) { EventMajor = i; HaveEventMajor = 1; } } } (void) free((FREE_P *)tmp); } /* * get_kernel_access() - get access to kernel memory */ static void get_kernel_access() { time_t lbolt; MALLOC_S len; KA_T v; /* * Check kernel version. */ (void) Ckkv("OSR", LSOF_VSTR, (char *)NULL, (char *)NULL); /* * See if the name list file is readable. */ if (Nmlst && !is_readable(Nmlst, 1)) Exit(1); /* * Access kernel symbols. */ #if defined(N_UNIX) (void) build_Nl(Drive_Nl); if (nlist(Nmlst ? Nmlst : N_UNIX, Nl) < 0) #else /* !defined(N_UNIX) */ if (!get_nlist_path(0)) #endif /* defined(N_UNIX) */ { (void) fprintf(stderr, "%s: can't read kernel name list.\n", Pn); Exit(1); } /* * Open access to kernel memory. */ (void) open_kmem(0); #if defined(WILLDROPGID) /* * Drop setgid permission. */ (void) dropgid(); #endif /* defined(WILLDROPGID) */ /* * Check proc table pointer. */ if (get_Nl_value("proc", Drive_Nl, &Kp) < 0 || !Kp) { (void) fprintf(stderr, "%s: no proc table pointer\n", Pn); Exit(1); } #if OSRV<500 /* * Read pregion information. */ v = (KA_T)0; if (get_Nl_value("pregpp", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&Npp, sizeof(Npp)) || Npp < 1) { (void) fprintf(stderr, "%s: can't read pregion count (%d) from %s\n", Pn, Npp, print_kptr(v, (char *)NULL, 0)); Exit(1); } Prsz = (MALLOC_S)(Npp * sizeof(struct pregion)); if (!(Pr = (struct pregion *)malloc(Prsz))) { (void) fprintf(stderr, "%s: can't allocate space for %d pregions\n", Pn, Npp); Exit(1); } #endif /* OSRV< 500 */ /* * Read system configuration information. */ if (get_Nl_value("var", Drive_Nl, &v) < 0 || !v || kread((KA_T)v, (char *)&Var, sizeof(Var))) { (void) fprintf(stderr, "%s: can't read system configuration info\n", Pn); Exit(1); } /* * Read system clock values -- Hz and lightning bolt timer. */ v = (KA_T)0; if (get_Nl_value("hz", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&Hz, sizeof(Hz))) { if (!Fwarn) (void) fprintf(stderr, "%s: WARNING: can't read Hz from %s\n", Pn, print_kptr(v, (char *)NULL, 0)); Hz = -1; } if (get_Nl_value("lbolt", Drive_Nl, &Lbolt) < 0 || !v || kread((KA_T)v, (char *)&lbolt, sizeof(lbolt))) { if (!Fwarn) (void) fprintf(stderr, "%s: WARNING: can't read lightning bolt timer from %s\n", Pn, print_kptr(v, (char *)NULL, 0)); Lbolt = (KA_T)0; } /* * Get socket device number and socket table address. */ if (get_Nl_value("sockd", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&Sockdev, sizeof(Sockdev))) { (void) fprintf(stderr, "%s: WARNING: can't identify socket device.\n", Pn); (void) fprintf(stderr, " Socket output may be incomplete.\n"); return; } if (get_Nl_value("sockt", Drive_Nl, &Socktab) < 0 || !Socktab) { (void) fprintf(stderr, "%s: WARNING: socket table address is NULL.\n", Pn); (void) fprintf(stderr, " Socket output may be incomplete.\n"); return; } #if OSRV>=40 /* * Get extended device table parameters. These are needed by the kernel * versions of the major() and minor() device number macros; they also * identify socket devices and assist in the conversion of socket device * numbers to socket table addresses. */ v = (KA_T)0; if (get_Nl_value("nxdm", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&nxdevmaps, sizeof(nxdevmaps)) || nxdevmaps < 0) { (void) fprintf(stderr, "%s: bad extended device table size (%d) at %s.\n", Pn, nxdevmaps, print_kptr(v, (char *)NULL, 0)); Exit(1); } len = (MALLOC_S)((nxdevmaps + 1) * sizeof(struct XDEVMAP)); if (!(Xdevmap = (struct XDEVMAP *)malloc(len))) { (void) fprintf(stderr, "%s: no space for %d byte xdevmap table\n", Pn, len); Exit(1); } v = (KA_T)0; if (get_Nl_value("xdm", Drive_Nl, &v) < 0 || !v || kread((KA_T)v, (char *)Xdevmap, len)) { (void) fprintf(stderr, "%s: can't read %d byte xdevmap table at #x\n", Pn, len, v); Exit(1); } #endif /* OSRV>=40 */ HaveSockdev = 1; } #if !defined(N_UNIX) /* * get_nlist_path() - get kernel nlist() path * * As a side effect on a successful return (non-NULL character pointer), the * boot path's name list will have been loaded into Nl[]. */ char * get_nlist_path(ap) int ap; /* on success, return an allocated path * string pointer if 1; return a * constant character pointer if 0; * return NULL if failure */ { FILE *bf; char *bfp, b1[MAXPATHLEN+1], b2[MAXPATHLEN+1], *pp, *tp; struct dirent *de; char *dir[] = { "/", "/stand/", NULL }; DIR *dp; int i; MALLOC_S len; /* * If a kernel name list file was specified, use it. */ if (Nmlst) { if (is_boot(Nmlst)) return(Nmlst); return((char *)NULL); } /* * If it's possible to open /etc/ps/booted system, search it for a preferred * boot path, defined by the value of a line that begins with "KERNEL=". */ bfp = pp = (char *)NULL; if ((bf = fopen("/etc/ps/booted.system", "r"))) { len = strlen("KERNEL="); while (fgets(b1, sizeof(b1), bf)) { if (strncmp(b1, "KERNEL=", len) != 0) continue; if ((tp = strrchr(&b1[len], '\n'))) { *tp = '\0'; if (b1[len]) { bfp = &b1[len]; if (is_boot(bfp)) { pp = bfp; (void) fclose(bf); goto get_nlist_return_path; } break; } } } (void) fclose(bf); } /* * Look for possible unix* boot paths. */ for (i = 0; dir[i]; i++) { if (!(dp = opendir(dir[i]))) continue; while ((de = readdir(dp))) { /* * Use the next entry that begins with "unix". */ if (strncmp("unix", de->d_name, 4) != 0) continue; /* * Construct a temporary copy of the path name, * If it matches the preferred boot name, skip it. */ len = strlen(dir[i]) + strlen(de->d_name) + 1; if (len >= sizeof(b2)) continue; (void) snpf(b2, sizeof(b2), "%s%s", dir[i], de->d_name); if (bfp && strcmp(b2, bfp) == 0) continue; /* * See if it's the booted kernel. */ if (is_boot(b2)) { (void) closedir(dp); pp = b2; get_nlist_return_path: /* * A boot path has been located. As requested return a * malloc'd pointer to it. */ if (!ap) return(""); len = (MALLOC_S)(strlen(pp) + 1); if (!(tp = (char *)malloc(len))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for: %s\n", Pn, len , pp); Exit(1); } (void) snpf(tp, len, "%s", pp); return(tp); } } if (dp) (void) closedir(dp); } return((char *)NULL); } #endif /* !defined(N_UNIX) */ /* * initialize() - perform all initialization */ void initialize() { get_kernel_access(); get_cdevsw(); readfsinfo(); if (Fsv & FSV_NI) NiTtl = "INODE-ADDR"; } #if !defined(N_UNIX) /* * is_boot() - does the specified path lead to a booted kernel */ is_boot(p) char *p; /* specified path */ { int i; KA_T ka; union { struct scoutsname s; unsigned char sc[sizeof(struct scoutsname)]; } s1, s2; /* * Get the scoutsname structure via __scoinfo() to use as a reference against * the one obtained via kread()'ing from the nlist() address. * If __scoinfo() fails, return the default boot path. */ if (__scoinfo(&s1.s, sizeof(s1.s)) < 0) return 0; /* * Get the name list for this boot path. Using the scoutsname address, read * the scoutsname structure and compare it to the _s_scoinfo() one. If the * two match, this is the boot path. */ if (Nl) { (void) free((FREE_P *)Nl); Nl = (struct NLIST_TYPE *)NULL; } (void) build_Nl(Drive_Nl); if (nlist(p, Nl) < 0) return(0); if (get_Nl_value("scouts", Drive_Nl, &ka) < 0 || !ka) return(0); if (Kd < 0) { if (open_kmem(1)) return(0); } if (kread(ka, (char *)&s2.s, sizeof(s2.s))) return(0); for (i = 0; i < sizeof(struct scoutsname); i++) { if (s1.sc[i] != s2.sc[i]) return(0); } return(1); } #endif /* !defined(N_UNIX) */ /* * kread() - read from kernel memory */ int kread(addr, buf, len) KA_T addr; /* kernel memory address */ char *buf; /* buffer to receive data */ READLEN_T len; /* length to read */ { int br; if (lseek(Kd, (off_t)addr, SEEK_SET) == (off_t)-1L) return(1); if ((br = read(Kd, buf, len)) < 0) return(1); return(((READLEN_T)br == len) ? 0 : 1); } /* * open_kmem() - open kernel memory access */ static int open_kmem(nx) int nx; /* no Exit(1) if 1 */ { if (Kd >= 0) return(0); /* * See if the non-KMEM memory file is readable. */ if (Memory && !is_readable(Memory, 1)) { if (nx) return(1); Exit(1); } /* * Open kernel memory access. */ if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) { if (nx) return(1); (void) fprintf(stderr, "%s: can't open %s: %s\n", Pn, Memory ? Memory : KMEM, strerror(errno)); Exit(1); } return(0); } /* * process_text() - process text access information */ static void process_text(prp) KA_T prp; /* process region pointer */ { int i, j, k; struct pregion *p; struct region r; KA_T na; char *ty, tyb[8]; #if OSRV>=500 KA_T pc; struct pregion ps; #endif /* OSRV>=500 */ /* * Read and process the pregions. */ #if OSRV<500 if (kread(prp, (char *)Pr, Prsz)) return; for (i = j = 0, p = Pr; i < Npp; i++, p++) #else /* OSRV>=500 */ for (i = j = 0, p = &ps, pc = prp; pc; pc = (KA_T)p->p_next, i++) #endif /* OSRV<500 */ { #if OSRV>=500 /* * Avoid infinite loop. */ if (i > 1000) { if (!Fwarn) (void) fprintf(stderr, "%s: too many virtual address regions for PID %d\n", Pn, Lp->pid); return; } if ((i && pc == prp) || kread((KA_T)pc, (char *)p, sizeof(ps))) return; #endif /* OSRV>=500 */ if (!p->p_reg) continue; /* * Read the region. * Skip entries with no node pointers and duplicate node addresses. */ if (kread((KA_T)p->p_reg, (char *)&r, sizeof(r))) continue; if (!(na = (KA_T)r.r_iptr)) continue; for (k = 0; k < j; k++) { if (Nc[k] == na) break; } if (k < j) continue; /* * Cache the node address for duplicate checking. */ if (!Nc) { if (!(Nc = (KA_T *)malloc((MALLOC_S)(sizeof(KA_T) * 10)))) { (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", Pn, Lp->pid); Exit(1); } Nn = 10; } else if (j >= Nn) { Nn += 10; if (!(Nc = (KA_T *)realloc((MALLOC_P *)Nc, (MALLOC_S)(Nn * sizeof(KA_T))))) { (void) fprintf(stderr, "%s: no more txt ptr space, PID %d\n", Pn, Lp->pid); Exit(1); } } Nc[j++] = na; /* * Save text node and mapped region information. */ switch (p->p_type) { case PT_DATA: /* data and text of */ case PT_TEXT: /* executing binaries */ ty = " txt"; break; case PT_LIBDAT: /* shared library data and */ case PT_LIBTXT: /* COFF format text */ ty = " ltx"; break; case PT_SHFIL: /* memory mapped file */ ty = " mem"; break; case PT_V86: /* virtual 8086 mode */ ty = " v86"; break; case PT_VM86: /* MERGE386 vm86 region */ ty = " m86"; break; default: /* all others as a hex number */ (void) snpf(tyb, sizeof(tyb), " M%02x", p->p_type & 0xff); ty = tyb; } if (ty) { alloc_lfile(ty, -1); process_node(na); if (Lf->sf) link_lfile(); } } } /* * readfsinfo() - read file system information */ static void readfsinfo() { char buf[FSTYPSZ+1]; int i, len; if ((Fsinfomax = sysfs(GETNFSTYP)) == -1) { (void) fprintf(stderr, "%s: sysfs(GETNFSTYP) error: %s\n", Pn, strerror(errno)); Exit(1); } if (Fsinfomax == 0) return; if (!(Fsinfo = (char **)malloc((MALLOC_S)(Fsinfomax * sizeof(char *))))) { (void) fprintf(stderr, "%s: no space for sysfs info\n", Pn); Exit(1); } for (i = 1; i <= Fsinfomax; i++) { if (sysfs(GETFSTYP, i, buf) == -1) { (void) fprintf(stderr, "%s: sysfs(GETFSTYP) error: %s\n", Pn, strerror(errno)); Exit(1); } buf[FSTYPSZ] = '\0'; len = strlen(buf) + 1; if (!(Fsinfo[i-1] = (char *)malloc((MALLOC_S)len))) { (void) fprintf(stderr, "%s: no space for file system entry %s\n", Pn, buf); Exit(1); } (void) snpf(Fsinfo[i-1], len, "%s", buf); } } #if defined(HASNCACHE) /* * Prepare for and #include the appropriate header files. */ # if OSRV>=500 #undef IFIR #undef IFIW #undef IRCOLL #undef IWCOLL # endif /* OSRV>=500 */ #include # if defined(HAS_NFS) #include # endif /* defined(HAS_NFS) */ # if OSRV>=500 # if OSRV<504 #include #undef IFIR #undef IFIW #undef IRCOLL #undef IWCOLL #define _INKERNEL #include #undef _INKERNEL # else /* OSRV>=504 */ #include # endif /* OSRV<504 */ # endif /* OSRV>=500 */ /* * Determine the maximum size of the cache name character array. */ # if OSRV<504 #define MAXNSZ DIRSIZ # if OSRV>=500 && DTNCMAX>MAXNSZ #undef MAXNSZ #define MAXNSZ DTNCMAX # endif /* OSRV>=500 && DTNCMAX>MAXNSZ */ # else /* OSRV>=504 */ #define MAXNSZ DNLC_NAMELEN # endif /* OSRV<504 */ # if defined(HAS_NFS) && NC_NAMLEN>MAXNSZ #undef MAXNSZ #define MAXNSZ NC_NAMLEN # endif /* defined(HAS_NFS) && NC_NAMLEN>MAXNSZ */ /* * Define the local name cache structures. */ struct lnch { /* local name cache structure */ union { struct ldev { /* device-inode info */ dev_t dev; /* device */ unsigned long inum; /* inode number */ unsigned long pa_inum; /* parent inode number */ } ld; struct lnfs { /* NFS info */ KA_T rp; /* rnode address */ KA_T dp; /* parent rnode address */ } ln; } u; char nm[MAXNSZ+1]; /* name */ unsigned char nl; /* name length */ unsigned char dup; /* duplicate if 1 */ unsigned char type; /* type: 0 = device-inode; 1 = NFS */ struct lnch *pa; /* parent address */ struct lnch *next; /* link to next same-type structure */ }; struct lnch_hh { /* device-inode and NFS hash head */ struct lnch *hp[2]; /* [0] = device-inode; [1] = NFS*/ }; /* * Local name cache (LNC) definitions, macros, and static values */ #define LCHUNKSZ 256 /* local "chunk" size for reading the * kernel DNLC -- used for OSRV>=504 */ static int LNC_asz = 0; /* LNC cache allocated size */ static int LNC_csz = 0; /* LNC cache current size */ #define LNCHHLEN 64 /* hash head length (must be a * power of 2) */ #define LNCINCR 256 /* LNC size increment */ #define LNCINIT 1024 /* LNC initial size */ #define DIN_hash(d, i) &LNC_hh[((((int)(d + i)>>2)*31415)&(LNCHHLEN-1))] # if defined(HAS_NFS) #define NFS_hash(r) &LNC_hh[((((int)(r)>>2)*31415)&(LNCHHLEN-1))] # endif /* defined(HAS_NFS) */ static struct lnch_hh *LNC_hh = (struct lnch_hh *)NULL; /* LNC hash head pointers */ static struct lnch *LNC_nc = (struct lnch *)NULL; /* the linear LNC */ /* * Local function prototypes */ _PROTOTYPE(static struct lnch *DIN_addr,(dev_t *d, unsigned long i)); # if OSRV>=500 # if OSRV>=504 _PROTOTYPE(static void DNLC_load,()); # else /* OSRV<504 */ _PROTOTYPE(static void DTFS_load,()); _PROTOTYPE(static void HTFS_load,()); # endif /* OSRV>=504 */ # endif /* OSRV>=500 */ _PROTOTYPE(static int LNC_enter,(struct lnch *le, char *nm, int nl, char *fs)); _PROTOTYPE(static void LNC_nosp,(int len)); # if defined(HAS_NFS) _PROTOTYPE(static struct lnch *NFS_addr,(KA_T r)); _PROTOTYPE(static void NFS_load,(void)); _PROTOTYPE(static int NFS_root,(KA_T r)); # endif /* defined(HAS_NFS) */ # if OSRV<504 _PROTOTYPE(static void SYSV_load,()); # endif /* OSRV<504 */ /* * DIN_addr() - look up a node's local device-inode address */ static struct lnch * DIN_addr(d, i) dev_t *d; /* device number */ unsigned long i; /* inode number */ { struct lnch_hh *hh = DIN_hash(*d, i); struct lnch *lc = hh->hp[0]; while (lc) { if (lc->u.ld.dev == *d && lc->u.ld.inum == i) return(lc); lc = lc->next; } return((struct lnch *)NULL); } # if OSRV>=504 /* * DNLC_load() - load DNLC cache */ static void DNLC_load() { int ccl; /* current "chunk" length */ int ccs; /* current "chunk" size */ int ccx; /* current "chunk" index */ static int cha = 0; /* "chunk" allocation size */ static int chl = 0; /* "chunk" allocation length */ struct dnlc__cachent *cp; static struct dnlc__cachent *dnlc = (struct dnlc__cachent *)NULL; static int dnlce = 0; int i, len; static KA_T ka = (KA_T)0; struct lnch lc; char nm[DNLC_NAMELEN+1]; KA_T v; char *wa; /* "working" kernel DNLC * address */ /* * Do first-time setup, as required. */ if (dnlce == 0) { /* * Quit if the DNLC name cache address is unknown. */ if (get_Nl_value("dnlc", Drive_Nl, &ka) < 0 || !ka) return; /* * Determine of the DNLC name cache address is that of an array or a * pointer to the array. */ v = (KA_T)NULL; if (get_Nl_value("pdnlc", Drive_Nl, &v) >= 0 && v) { /* * If the DNLC name cache address is that of a pointer to an array, * get the array's address. If that fails, return without comment * and without further action. */ if (kread(ka, (char *)&ka, sizeof(ka))) return; } /* * Get the kernel's DNLC name cache size. */ if (get_Nl_value("ndnlc", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&dnlce, sizeof(dnlce)) || dnlce < 1) return; /* * Allocate space for a copy of a portion ("chunk") of the kernel's * DNLC name cache. */ cha = (dnlce <= LCHUNKSZ) ? dnlce : LCHUNKSZ; chl = sizeof(struct dnlc__cachent) * cha; if (!(dnlc = (struct dnlc__cachent *)malloc(chl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for DNLC chunk\n", Pn, chl); cha = 0; Exit(1); } } /* * Prepare to read the kernel's DNLC name cache. */ if (!cha || !chl || !dnlc || !ka) return; /* * Build a local copy of the kernel's DNLC name cache, reading the kernel data * a "chunk" at a time. */ nm[DNLC_NAMELEN] = '\0'; lc.type = 0; for (ccl = ccs = i = 0, wa = (char *)ka; i < dnlce; i += ccs, wa += ccl) { /* * Read the next "chunk". */ ccs = ((dnlce - i) < cha) ? (dnlce - i) : cha; ccl = sizeof(struct dnlc__cachent) * ccs; if (kread((KA_T)wa, (char *)dnlc, ccl)) break; /* * Process the "chunk". */ for (ccx = 0, cp = dnlc; ccx < ccs; cp++, ccx++) { if (!cp->dev && !cp->newinum) continue; (void) strncpy(nm, cp->name, DNLC_NAMELEN); if ((len = strlen(nm)) < 1) continue; if (len < 3 && nm[0] == '.') { if (len == 1 || (len == 2 && nm[1] == '.')) continue; } lc.u.ld.dev = cp->dev; lc.u.ld.inum = (unsigned long)cp->newinum; lc.u.ld.pa_inum = (unsigned long)cp->inum; if (LNC_enter(&lc, nm, len, "DNLC")) break; } } /* * If not repeating, free kernel DNLC name cache buffer space. */ if (dnlc && !RptTm) { (void) free((MALLOC_P *)dnlc); dnlc = (struct dnlc__cachent *)NULL; dnlce = cha = chl = 0; } } # endif /* OSRV>=504 */ # if OSRV>=500 && OSRV<504 /* * DTFS_load() - load DTFS cache */ static void DTFS_load() { struct dtcachent *cp; static struct dtcachent *dtnc = (struct dtcachent *)NULL; static int dtnce = 0; int i, len; static KA_T ka = (KA_T)NULL; static int kcl = 0; struct lnch lc; char nm[DTNCMAX+1]; KA_T v; /* * Do first-time setup, as required. */ if (dtnce == 0) { /* * Quit if the DTFS name cache address is unknown. */ if (get_Nl_value("dtnc", Drive_Nl, &ka) < 0 || !ka) return; /* * Get the kernel's DTFS name cache size. */ if (get_Nl_value("ndtnc", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&dtnce, sizeof(dtnce)) || dtnce < 1) return; /* * Allocate space for a copy of the kernel's DTFS name cache. */ kcl = sizeof(struct dtcachent) * dtnce; if (!(dtnc = (struct dtcachent *)malloc(kcl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for DTFS name cache\n", Pn, kcl); Exit(1); } } /* * Read the kernel's DTFS name cache. */ if (!dtnc || !kcl || !ka || kread(ka, (char *)dtnc, kcl)) return; /* * Build a local copy of the kernel's DTFS name cache. */ lc.type = 0; nm[DTNCMAX] = '\0'; for (cp = dtnc, i = 0; i < dtnce; cp++, i++) { if (!cp->dn_dev && !cp->dn_newinum) continue; (void) strncpy(nm, cp->dn_name, DTNCMAX); if ((len = strlen(nm)) < 1) continue; if (len < 3 && cp->dn_name[0] == '.') { if (len == 1 || (len == 2 && cp->dn_name[1] == '.')) continue; } lc.u.ld.dev = cp->dn_dev; lc.u.ld.inum = (unsigned long)cp->dn_newinum; lc.u.ld.pa_inum = (unsigned long)cp->dn_inum; if (LNC_enter(&lc, nm, len, "DTFS")) break; } /* * If not repeating, free kernel DTFS name cache buffer space. */ if (dtnc && !RptTm) { (void) free((MALLOC_P *)dtnc); dtnc = (struct dtcachent *)NULL; dtnce = kcl = 0; } } /* * HTFS_load() - load HTFS cache */ static void HTFS_load() { struct htcachent *cp; static struct htcachent *htnc = (struct htcachent *)NULL; static int htnce = 0; int i, len; static KA_T ka = (KA_T)NULL; static int kcl = 0; struct lnch lc; char nm[DIRSIZ+1]; KA_T v; /* * Do first-time setup, as required. */ if (htnce == 0) { /* * Quit if the HTFS name cache address is unknown. */ if (get_Nl_value("htnc", Drive_Nl, &ka) < 0 || !ka) return; /* * Get the kernel's HTFS name cache size. */ if (get_Nl_value("nhtnc", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&htnce, sizeof(htnce)) || htnce < 1) return; /* * Allocate space for a copy of the kernel's HTFS name cache. */ kcl = sizeof(struct htcachent) * htnce; if (!(htnc = (struct htcachent *)malloc(kcl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for HTFS name cache\n", Pn, kcl); Exit(1); } } /* * Read the kernel's HTFS name cache. */ if (!htnc || !kcl || !ka || kread(ka, (char *)htnc, kcl)) return; /* * Build a local copy of the kernel's HTFS name cache. */ lc.type = 0; nm[DIRSIZ] = '\0'; for (cp = htnc, i = 0; i < htnce; cp++, i++) { if (!cp->dev && !cp->newinum) continue; (void) strncpy(nm, cp->name, DIRSIZ); if ((len = strlen(nm)) < 1) continue; if (len < 3 && cp->name[0] == '.') { if (len == 1 || (len == 2 && cp->name[1] == '.')) continue; } lc.u.ld.dev = (dev_t)cp->dev; lc.u.ld.inum = (unsigned long)cp->newinum; lc.u.ld.pa_inum = (unsigned long)cp->inum; if (LNC_enter(&lc, nm, len, "HTFS")) break; } /* * If not repeating, free kernel HTFS name cache buffer space. */ if (htnc && !RptTm) { (void) free((MALLOC_P *)htnc); htnc = (struct htcachent *)NULL; htnce = kcl = 0; } } # endif /* OSRV>=500 && OSRV<504 */ /* * LNC_enter() - make a local name cache entry */ static int LNC_enter(le, nm, nl, fs) struct lnch *le; /* skeleton local entry */ char *nm; /* name */ int nl; /* name length */ char *fs; /* file system name */ { struct lnch *lc; MALLOC_S len; if (LNC_csz >= LNC_asz) { LNC_asz += LNCINCR; len = (MALLOC_S)(LNC_asz * sizeof(struct lnch)); if (!(LNC_nc = (struct lnch *)realloc(LNC_nc, len))) { (void) fprintf(stderr, "%s: no more space for %d byte local name cache: %s\n", Pn, len, fs); Exit(1); } } lc = &LNC_nc[LNC_csz]; if ((lc->type = le->type) == 1) { /* * Make an NFS entry. */ lc->u.ln.rp = le->u.ln.rp; lc->u.ln.dp = le->u.ln.dp; } else { /* * Make a device-inode entry. */ lc->u.ld.dev = le->u.ld.dev; lc->u.ld.inum = le->u.ld.inum; lc->u.ld.pa_inum = le->u.ld.pa_inum; } /* * Enter the name and its size, clear the duplicate flag, * and advance the linear cache entry count. */ if (nl > MAXNSZ) { if (!Fwarn) (void) fprintf(stderr, "%s: WARNING: length for \"%s\" too large: %d\n", Pn, nm, nl); nl = MAXNSZ; } (void) strncpy(lc->nm, nm, nl); lc->nm[nl] = '\0'; lc->nl = (unsigned char)nl; lc->dup = 0; lc->next = lc->pa = (struct lnch *)NULL; LNC_csz++; return(0); } /* * LNC_nosp() - notify that we're out of space for the local name cache */ static void LNC_nosp(len) int len; /* attempted length */ { if (!Fwarn) (void) fprintf(stderr, "%s: no space for %d byte local name cache\n", Pn, len); Exit(1); } /* * ncache_load() - load the kernel's NFS and DEV name caches */ void ncache_load() { struct lnch_hh *hh; struct lnch *hl, *hlp, *lc; int f, i, len; if (!Fncache) return; /* * Initialize local name cache, as required. */ if (LNC_asz == 0) { LNC_asz = LNCINIT; len = LNCINIT * sizeof(struct lnch); if (!(LNC_nc = (struct lnch *)malloc((MALLOC_S)len))) (void) LNC_nosp(len); } LNC_csz = 0; # if defined(HAS_NFS) /* * Load NFS cache. */ (void) NFS_load(); # endif /* defined(HAS_NFS) */ # if OSRV<504 /* * Load the device-inode SYSV file system cache. */ (void) SYSV_load(); # if OSRV>=500 /* * Load the device-inode DT and HT file system caches. */ (void) DTFS_load(); (void) HTFS_load(); # endif /* OSRV>=500 */ # else /* OSRV>=504 */ /* * Load the device-inode combined file system cache. */ (void) DNLC_load(); # endif /* OSRV<504 */ /* * Reduce local name cache memory usage, as required. */ if (LNC_csz < 1) { LNC_csz = 0; if (!RptTm) { (void) free((FREE_P *)LNC_nc); LNC_nc = (struct lnch *)NULL; } return; } if (LNC_csz < LNC_asz && !RptTm) { len = LNC_csz * sizeof(struct lnch); if (!(LNC_nc = (struct lnch *)realloc(LNC_nc, len))) (void)LNC_nosp(len); LNC_asz = LNC_csz; } /* * Initialize hash head pointers. */ if (!LNC_hh) { LNC_hh = (struct lnch_hh *)calloc(LNCHHLEN, sizeof(struct lnch_hh)); if (!LNC_hh) { (void) fprintf(stderr, "%s: can't allocate %d bytes for name cache hash table\n", Pn, LNCHHLEN * sizeof(struct lnch_hh)); Exit(1); } } else (void) zeromem((void *)LNC_hh, (LNCHHLEN * sizeof(struct lnch_hh))); /* * Enter local name cache pointers in the hash table. Look for entries with * the same identifications that have different names. */ for (i = 0, lc = LNC_nc; i < LNC_csz; i++, lc++) { # if defined(HAS_NFS) if (lc->type) hh = NFS_hash(lc->u.ln.rp); else # endif /* defined(HAS_NFS) */ hh = DIN_hash(lc->u.ld.dev, lc->u.ld.inum); if (!(hl = hh->hp[lc->type])) { hh->hp[lc->type] = lc; continue; } for (f = 0, hlp = hl; hl; hlp = hl, hl = hl->next) { # if defined(HAS_NFS) if (lc->type == 1) { if (lc->u.ln.rp != hl->u.ln.rp) continue; } else # endif /* defined(HAS_NFS) */ { if (lc->u.ld.dev != hl->u.ld.dev || lc->u.ld.inum != hl->u.ld.inum) continue; } if (strcmp(lc->nm, hl->nm) == 0) f = 1; else { f = 2; /* same identifiers, different names */ break; } } if (!f) hlp->next = lc; else if (f == 2) { /* * Since entries with the same identification but different names * were located, mark entries with the same identification as * duplicates. */ for (hl = hh->hp[lc->type]; hl; hl = hl->next) { # if defined(HAS_NFS) if (lc->type == 1) { if (lc->u.ln.rp == hl->u.ln.rp) hl->dup = 1; continue; } # endif /* defined(HAS_NFS) */ if (hl->u.ld.dev == lc->u.ld.dev && hl->u.ld.inum == lc->u.ld.inum) hl->dup = 1; } } } /* * Make a final pass through the local name cache and convert parent * identifications to local name cache pointers. Ignore duplicates. */ for (i = 0, lc = LNC_nc; i < LNC_csz; i++, lc++) { if (lc->dup) continue; # if defined(HAS_NFS) if (lc->type == 1) { if (lc->u.ln.dp) lc->pa = NFS_addr(lc->u.ln.dp); continue; } # endif /* defined(HAS_NFS) */ if (lc->u.ld.dev && lc->u.ld.pa_inum) lc->pa = DIN_addr(&lc->u.ld.dev, lc->u.ld.pa_inum); } } /* * ncache_lookup() - look up a node's name in the kernel's name caches */ char * ncache_lookup(buf, blen, fp) char *buf; /* receiving name buffer */ int blen; /* receiving buffer length */ int *fp; /* full path reply */ { char *cp = buf; int nl, rlen; struct lnch *lc; *cp = '\0'; *fp = 0; /* * 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); if (!LNC_nc) return((char *)NULL); #if defined(HAS_NFS) /* * Look up the NFS name cache entry. */ if (Lf->is_nfs) { if ((lc = NFS_addr(Lf->na)) && !lc->dup) { if ((nl = (int)lc->nl) > (blen - 1)) return(*cp ? cp : (char *)NULL); cp = buf + blen - nl - 1; rlen = blen - nl - 1; (void) snpf(cp, nl + 1, "%s", lc->nm); /* * Look up the NFS name cache entries that are parents of the * rnode address. Quit when: * * there's no parent; * the parent is a duplicate; * the name is too large to fit in the receiving buffer. */ for (;;) { if (!lc->pa) { if (NFS_root(lc->u.ln.dp)) *fp = 1; break; } lc = lc->pa; if (lc->dup) break; if (((nl = (int)lc->nl) + 1) > rlen) break; *(cp - 1) = '/'; cp--; rlen--; (void) strncpy((cp - nl), lc->nm, nl); cp -= nl; rlen -= nl; } return(*cp ? cp : (char *)NULL); } return((char *)NULL); } # endif /* defined(HAS_NFS) */ /* * Look up the device-inode name cache entry. */ if (Lf->dev_def && Lf->inp_ty == 1 && (lc = DIN_addr(&Lf->dev, Lf->inode)) && !lc->dup) { if ((nl = (int)lc->nl) > (blen - 1)) return(*cp ? cp : (char *)NULL); cp = buf + blen - nl - 1; rlen = blen - nl - 1; (void) snpf(cp, nl + 1, "%s", lc->nm); /* * Look up the LNC name cache entries that are parents of the * device and inode number. Quit when: * * there's no parent; * the parent is a duplicate cache entry; * the name is too large to fit in the receiving buffer. */ for (;;) { if (!lc->pa) { if (lc->u.ld.pa_inum && Lf->fs_ino && lc->u.ld.pa_inum == Lf->fs_ino) *fp = 1; break; } lc = lc->pa; if (lc->dup) break; if (lc->u.ld.inum && Lf->fs_ino && lc->u.ld.inum == Lf->fs_ino) { *fp = 1; break; } if (((nl = (int)lc->nl) + 1) > rlen) break; *(cp - 1) = '/'; cp--; rlen--; (void) strncpy((cp - nl), lc->nm, nl); cp -= nl; rlen -= nl; } return(*cp ? cp : (char *)NULL); } return((char *)NULL); } # if defined(HAS_NFS) /* * NFS_addr() - look up a node's local NFS_nc address */ static struct lnch * NFS_addr(r) KA_T r; /* rnode's address */ { struct lnch_hh *hh = NFS_hash(r); struct lnch *lc = hh->hp[1]; while (lc) { if (lc->u.ln.rp == r) return(lc); lc = lc->next; } return((struct lnch *)NULL); } /* * NFS_load() -- load kernel's NFS name cache */ static void NFS_load() { struct ncache *cp; int i, len; struct lnch lc; static KA_T ka = (KA_T)NULL; static int kcl = 0; static struct ncache *nfnc = (struct ncache *)NULL; static int nfnce = 0; char nm[NC_NAMLEN+1]; KA_T v; /* * Do first-time setup, as required. */ if (nfnce == 0) { /* * Quit if the NFS name cache address is unknown. */ if (get_Nl_value("nfnc", Drive_Nl, &ka) < 0 || !ka) return; /* * Get the kernel's NFS name cache size. */ if (get_Nl_value("nnfnc", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&nfnce, sizeof(nfnce)) || nfnce < 1) return; /* * Allocate space for a copy of the kernel's NFS name cache. */ kcl = nfnce * sizeof(struct ncache); if (!(nfnc = (struct ncache *)malloc(kcl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for NFS name cache\n", Pn, kcl); Exit(1); } } /* * Read the kernel's NFS name cache. */ if (!nfnc || !kcl || !ka || kread(ka, (char *)nfnc, kcl)) return; /* * Build a local copy of the kernel's NFS name cache. */ lc.type = 1; for (cp = nfnc, i = 0; i < nfnce; cp++, i++) { if (!cp->rp) continue; if ((len = cp->namlen) < 0 || len > NC_NAMLEN) continue; (void) strncpy(nm, cp->name, len); nm[len] = '\0'; if ((len = strlen(nm)) < 1) continue; if (len < 3 && nm[0] == '.') { if (len == 1 || (len == 2 && nm[1] == '.')) continue; } lc.u.ln.rp = (KA_T)cp->rp; lc.u.ln.dp = (KA_T)cp->dp; if (LNC_enter(&lc, nm, len, "NFS")) break; } /* * If not repeating, free kernel NFS name cache buffer space. */ if (nfnc && !RptTm) { (void) free((MALLOC_P *)nfnc); nfnc = (struct ncache *)NULL; kcl = nfnce = 0; } } static int NFS_root(r) KA_T r; /* node's rnode address */ { int i; MALLOC_S len; static int rnc = 0; static int rnca = 0; static KA_T *rc = (KA_T *)NULL; struct rnode rn; unsigned short *n; unsigned long nnum; # if OSRV>=500 unsigned short *n1; # endif /* OSRV>=500 */ if (!Lf->fs_ino || !r) return(0); /* * Search NFS root rnode cache. */ for (i = 0; i < rnc; i++) { if (rc[i] == r) return(1); } /* * Read rnode and get the node number. */ if (kread(r, (char *)&rn, sizeof(rn))) return(0); # if OSRV<500 n = (unsigned short *)&rn.r_fh.fh_pad[14]; if (!(nnum = (unsigned long)ntohs(*n))) nnum = (unsigned long)rn.r_fh.fh_u.fh_fgen_u; # else /* OSRV>=500 */ n = (unsigned short *)&rn.r_fh.fh_u.fh_fid_u[4]; n1 = (unsigned short *)&rn.r_fh.fh_u.fh_fid_u[2]; if (!(nnum = (unsigned long)*n)) nnum = (unsigned long)*n1; # endif /* OSRV<500 */ if (!nnum || nnum != Lf->fs_ino) return(0); /* * Add the rnode address to the NFS root rnode cache. */ if (rnc >= rnca) { if (rnca == 0) { len = (MALLOC_S)(10 * sizeof(KA_T)); if ((rc = (KA_T *)malloc(len))) rnca = 10; } else { len = (MALLOC_S)((rnca + 10) * sizeof(KA_T)); if ((rc = (KA_T *)realloc(rc, len))) rnca += 10; } if (!rc) { (void) fprintf(stderr, "%s: no space for root rnode table\n", Pn); Exit(1); } } rc[rnc++] = r; return(1); } # endif /* defined(HAS_NFS) */ # if OSRV<504 /* * SYSV_load() - load SYSV cache */ static void SYSV_load() { struct s5cachent *cp; int i, len; static KA_T ka = (KA_T)NULL; static int kcl = 0; struct lnch lc; char nm[DIRSIZ+1]; static struct s5cachent *s5nc = (struct s5cachent *)NULL; static int s5nce = 0; KA_T v; /* * Do first-time setup, as required. */ if (s5nce == 0) { /* * Quit if the SYSV name cache address is unknown. */ if (get_Nl_value("s5nc", Drive_Nl, &ka) < 0 || !ka) return; /* * Get the kernel's SYSV name cache size. */ # if OSRV<500 s5nce = Var.v_s5cacheents; # else /* OSRV>=500 */ if (get_Nl_value("nsfnc", Drive_Nl, &v) < 0 || !v || kread(v, (char *)&s5nce, sizeof(s5nce))) return; # endif /* OSRV<500 */ if (s5nce < 1) return; /* * Allocate space for a copy of the kernel's SYSV name cache. */ kcl = sizeof(struct s5cachent) * s5nce; if (!(s5nc = (struct s5cachent *)malloc(kcl))) { (void) fprintf(stderr, "%s: can't allocate %d bytes for SYSV name cache\n", Pn, kcl); Exit(1); } } /* * Read the kernel's SYSV name cache. */ if (!s5nc || !kcl || !ka || kread(ka, (char *)s5nc, kcl)) return; /* * Build a local copy of the kernel's SYSV name cache. */ nm[DIRSIZ] = '\0'; lc.type = 0; for (cp = s5nc, i = 0; i < s5nce; cp++, i++) { if (!cp->dev && !cp->newinum) continue; (void) strncpy(nm, cp->name, DIRSIZ); if ((len = strlen(nm)) < 1) continue; if (len < 3 && cp->name[0] == '.') { if (len == 1 || (len == 2 && cp->name[1] == '.')) continue; } lc.u.ld.dev = (dev_t)cp->dev; lc.u.ld.inum = (unsigned long)cp->newinum; lc.u.ld.pa_inum = (unsigned long)cp->inum; if (LNC_enter(&lc, nm, len, "SYSV")) break; } /* * If not repeating, free kernel SYSV name cache buffer space. */ if (s5nc && !RptTm) { (void) free((MALLOC_P *)s5nc); s5nc = (struct s5cachent *)NULL; kcl = s5nce = 0; } } # endif /* OSRV<504 */ #endif /* defined(HASNCACHE) */