blob: facdb42d44675099467a2dc1ed087b50fd1cbd9f [file] [log] [blame]
/*
* 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(<possible_kernel>) 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 <sys/fs/s5inode.h>
# if defined(HAS_NFS)
#include <sys/fs/nfs/dnlc.h>
# endif /* defined(HAS_NFS) */
# if OSRV>=500
# if OSRV<504
#include <sys/fs/dtdnlc.h>
#undef IFIR
#undef IFIW
#undef IRCOLL
#undef IWCOLL
#define _INKERNEL
#include <sys/fs/htinode.h>
#undef _INKERNEL
# else /* OSRV>=504 */
#include <sys/fs/dnlc.h>
# 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) */