blob: 9d6a94fb994256da7ded3e0409fdd26d0803c6f6 [file] [log] [blame]
/*
* dnode2.c - Solaris node functions for lsof
*
* This module must be separate to keep separate the multiple kernel inode
* structure definitions.
*/
/*
* 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
static char *rcsid = "$Id: dnode2.c,v 1.23 2010/01/18 19:03:54 abe Exp $";
#endif
#include "lsof.h"
#if defined(HASVXFS)
# if defined(HASVXFSUTIL)
#include <vxfsutil.h>
#define EMSGPFX "vx_inode: "
_PROTOTYPE(static char *add2em,(char * em, char *fmt, char *arg));
_PROTOTYPE(static char *ckptr,(char * em, char *ptr, int len, int slen,
char *nm));
_PROTOTYPE(static char *getioffs,(char **vx, int *vxl,
char **dev, int *devl,
char **ino, int *inol,
char **nl, int *nll,
char **sz, int *szl));
# else /* !defined(HASVXFSUTIL) */
# if defined(HASVXFS_FS_H) && !defined(HASVXFS_VX_INODE)
#undef fs_bsize
#include <sys/fs/vx_fs.h>
# endif /* defined(HASVXFS_FS_H) && !defined(HASVXFS_VX_INODE) */
# if HASVXFS_SOL_H
#include <sys/fs/vx_sol.h>
# endif /* defined(HSVXFS_SOL_H) */
# if defined(HASVXFS_SOLARIS_H) && defined(HASVXFS_U64_T)
#include <sys/fs/vx_solaris.h>
# endif /* defined(HASVXFS_SOLARIS_H) && defined(HASVXFS_U64_T) */
# if defined(HASVXFS_MACHDEP_H)
# if defined(HASVXFS_OFF32_T) && solaris>=70000
#define off32_t VXFS_off32_t
# endif /* defined(HASVXFS_OFF32_T) && solaris>=70000 */
#include <sys/fs/vx_machdep.h>
# endif /* defined(HASVXFS_MACHDEP_H) */
# if defined(HASVXFS_SOLARIS_H)
struct kdm_vnode { /* dummy for <sys/fs/vx_inode.h> */
int d1;
};
#undef fs_bsize
#define uint16_t VXFS_uint16_t
# if defined(HASVXFS_OFF64_T)
#define off64_t VXFS_off64_t
# endif /* defined(HASVXFS_OFF64_T) */
# if defined(HASVXFS_SOLARIS_H) && !defined(HASVXFS_U64_T)
#include <sys/fs/vx_solaris.h>
# endif /* defined(HASVXFS_SOLARIS_H) && !defined(HASVXFS_U64_T) */
#include <sys/fs/vx_layout.h>
#include <sys/fs/vx_const.h>
#include <sys/fs/vx_mlink.h>
# endif /* defined(HASVXFS_SOLARIS_H) */
#include <sys/fs/vx_inode.h>
# endif /* defined(HASVXFSUTIL) */
# if defined(HASVXFSUTIL)
static struct vx_ioffsets Ioffsets; /* VXFS inode offsets */
static int Ioffs_state = -1; /* Ioffsets state:
* -1 = uninitialized
* 0 = initialized
* >0 = initialization error */
/*
* access_vxfs_ioffsets() - access the VXFS inode offsets
*/
extern int
access_vxfs_ioffsets()
{
/*
* This operation is done in an external function, so it can be done before
* GID permission has been surrendered.
*/
Ioffs_state = vxfsu_get_ioffsets(&Ioffsets, sizeof(Ioffsets));
return(Ioffs_state);
}
/*
* add2em() - add to error message
*/
static char *
add2em(em, fmt, arg)
char *em; /* current error message */
char *fmt; /* message format */
char *arg; /* format's single string argument */
{
MALLOC_S al, eml, nl;
char msg[1024];
MALLOC_S msgl = (MALLOC_S)sizeof(msg);
(void) snpf(msg, msgl, fmt, arg);
msg[msgl - 1] = '\0';
nl = (MALLOC_S)strlen(msg);
if (!em) {
al = (MALLOC_S)strlen(EMSGPFX) + nl + 1;
em = (char *)malloc((MALLOC_S)al);
eml = (MALLOC_S)0;
} else {
if (!(eml = (MALLOC_S)strlen(em))) {
(void) fprintf(stderr, "%s: add2em: previous message empty\n",
Pn);
Exit(1);
}
al = eml + nl + 3;
em = (char *)realloc((MALLOC_P *)em, al);
}
if (!em) {
(void) fprintf(stderr, "%s: no VxFS error message space\n", Pn);
Exit(1);
}
(void) snpf(em + eml, al - eml, "%s%s%s",
eml ? "" : EMSGPFX,
eml ? "; " : "",
msg);
return(em);
}
/*
* ckptr() - check pointer and length
*/
static char *
ckptr(em, ptr, len, slen, nm)
char *em; /* pointer to previous error message */
char *ptr; /* pointer to check */
int len; /* pointer's value length */
int slen; /* value's storage length */
char *nm; /* element name */
{
#if defined(_LP64)
#define PTR_CAST unsigned long long
#else /* !defined(_LP64) */
#define PTR_CAST unsigned long
#endif /* defined(_LP64) */
PTR_CAST m;
char tbuf[1024];
if (!ptr)
return(add2em(em, "no %s pointer", nm ? nm : "(null)"));
if (len > slen) {
(void) snpf(tbuf, sizeof(tbuf) - 1,
"%s size, %d, > %d",
nm ? nm : "(null)",
len, slen);
tbuf[sizeof(tbuf) - 1] = '\0';
return(add2em(em, "%s", tbuf));
}
if ((m = (PTR_CAST)(len - 1)) < (PTR_CAST)1)
return(em);
if ((PTR_CAST)ptr & m)
return(add2em(em, "%s misaligned", nm ? nm : "(null)"));
return(em);
}
/*
* getioffs() - get the vx_inode offsets
*/
static char *
getioffs(vx, vxl, dev, devl, ino, inol, nl, nll, sz, szl)
char **vx; /* pointer to allocated vx_inode space */
int *vxl; /* sizeof(*vx) */
char **dev; /* pointer to device number element of *vx */
int *devl; /* sizeof(*dev) */
char **ino; /* pointer to node number element of *vx */
int *inol; /* sizeof(*ino) */
char **nl; /* pointer to nlink element of *vx */
int *nll; /* sizeof(*nl) */
char **sz; /* pointer to size element of *vx */
int *szl; /* sizeof(*sz) */
{
char *tv;
int tvl;
if (Ioffs_state)
return(add2em((char *)NULL, "%s error", "vxfsu_get_ioffsets"));
tvl = (int)(Ioffsets.ioff_dev + Ioffsets.ioff_dev_sz);
if ((Ioffsets.ioff_nlink + Ioffsets.ioff_nlink_sz) > tvl)
tvl = (int)(Ioffsets.ioff_nlink + Ioffsets.ioff_nlink_sz);
if ((Ioffsets.ioff_number + Ioffsets.ioff_number_sz) > tvl)
tvl = (int)(Ioffsets.ioff_number + Ioffsets.ioff_number_sz);
if ((Ioffsets.ioff_size + Ioffsets.ioff_size_sz) > tvl)
tvl = (int)(Ioffsets.ioff_size + Ioffsets.ioff_size_sz);
if (!tvl)
return(add2em((char *)NULL, "zero length %s", "vx_inode"));
if (!(tv = (char *)malloc((MALLOC_S)tvl))) {
(void) fprintf(stderr, "%s: no vx_inode space\n", Pn);
Exit(1);
}
*vx = tv;
*vxl = tvl;
*dev = tv + Ioffsets.ioff_dev;
*devl = (int)Ioffsets.ioff_dev_sz;
*ino = tv + Ioffsets.ioff_number;
*inol = (int)Ioffsets.ioff_number_sz;
*nl = tv + Ioffsets.ioff_nlink;
*nll = (int)Ioffsets.ioff_nlink_sz;
*sz = tv + Ioffsets.ioff_size;
*szl = (int)Ioffsets.ioff_size_sz;
return((char *)NULL);
}
# if defined(HASVXFSRNL)
#define RNLCINIT 64 /* inital RNL cache size */
#define RNLCINCR 32 /* RNL cache increment */
/*
* print_vxfs_rnl_path() -- print VxFS RNL path
*/
int
print_vxfs_rnl_path(lf)
struct lfile *lf; /* file whose name is to be printed */
{
char **bp = (char **)NULL;
int i, j, n, p;
typedef struct rmc { /* RNL mount point cache */
char *mp; /* mount point */
unsigned char s; /* RNL status: 0 = supported
* 1 = not supported */
} rmc_t;
static rmc_t *rm = (rmc_t *)NULL;
/* RNL mount point cache */
static int rma = 0; /* allocated cache entries */
static int rmu = 0; /* used cache entries */
size_t sz;
/*
* This must be a VxFS file, it must have an inode and its mount point must
* be known.
*/
if (!lf->is_vxfs || (lf->inp_ty != 1) || !lf->fsdir)
return(0);
/*
* Locate or create an RNL mount point cache entry.
*/
for (i = 0; i < rmu; i++) {
if (rm[i].mp == lf->fsdir)
break;
}
if (i >= rmu) {
/*
* A new entry must be created.
*/
if (i >= rma) {
/*
* RNL mount point cache space must be allocated.
*/
rma += rm ? RNLCINCR : RNLCINIT;
sz = (size_t)(rma * sizeof(rmc_t));
if (rm)
rm = (rmc_t *)realloc((MALLOC_P *)rm, (MALLOC_S)sz);
else
rm = (rmc_t *)malloc((MALLOC_S)sz);
if (!rm) {
(void) fprintf(stderr,
"%s: no RNL mount point cache space\n", Pn);
Exit(1);
}
}
i = rmu;
rm[rmu].mp = lf->fsdir;
rm[rmu++].s = 0;
}
if (rm[i].s)
return(0);
/*
* Get the RNL path for this mount point and inode.
*/
if (vxfs_inotopath(lf->fsdir, (uint64_t)lf->inode, 0, &bp, &n)) {
if (errno == ENOTSUP)
rm[i].s = 1;
return(0);
}
/*
* Print the first RNL path, then free the allocated function reply space.
*/
if (bp) {
for (j = 0; j < n; j++) {
if (bp[j] && *bp[j]) {
safestrprt(bp[j], stdout, 0);
p = 1;
break;
}
}
for (j = 0; j < n; j++) {
if (bp[j])
(void) free((FREE_P *)bp[j]);
}
(void) free((FREE_P *)bp);
} else
p = 0;
return(p);
}
# endif /* defined(HASVXFSRNL) */
# endif /* defined(HASVXFSUTIL) */
/*
* read_vxnode() - read Veritas file system inode information
*/
int
read_vxnode(va, v, vfs, fx, li, vnops)
KA_T va; /* containing vnode's address */
struct vnode *v; /* containing vnode */
struct l_vfs *vfs; /* local vfs structure */
int fx; /* file system index (-1 if none) */
struct l_ino *li; /* local inode value receiver */
KA_T *vnops; /* table of VxFS v_op values */
{
struct vnode cv;
char tbuf[32];
# if defined(HASVXFS_VX_INODE)
struct vx_inode vx;
int vxl = (int)sizeof(vx);
dev_t *vxn_dev = (dev_t *)&vx.i_dev;
int *vxn_nlink = (int *)&vx.i_nlink;
unsigned int *vxn_ino = (unsigned int *)&vx.i_number;
SZOFFTYPE *vxn_sz = (SZOFFTYPE *)&vx.i_size;
char *vxp = (char *)&vx;
# else /* !defined(HASVXFS_VX_INODE) */
# if defined(HASVXFSUTIL)
static char *em = (char *)NULL;
int devl, nll, szl;
static int inol;
static char *vxp = (char *)NULL;
static int vxl = 0;
static dev_t *vxn_dev = (dev_t *)NULL;
static int *vxn_nlink = (int *)NULL;
static char *vxn_ino = (char *)NULL;
static SZOFFTYPE *vxn_sz = (SZOFFTYPE *)NULL;
# else /* !defined(HASVXFSUTIL) */
struct inode vx;
int vxl = sizeof(vx);
dev_t *vxn_dev = (dev_t *)&vx.i_dev;
int *vxn_nlink = (int *)&vx.i_nlink;
long *vxn_ino = (long *)&vx.i_number;
SZOFFTYPE *vxn_sz = (SZOFFTYPE *)&vx.i_size;
char *vxp = (char &)&vx;
# endif /* defined(HASVXFSUTIL) */
# endif /* defined(HASVXFS_VX_INODE) */
li->dev_def = li->ino_def = li->nl_def = li->rdev_def = li->sz_def = 0;
/*
* See if this is vnode is served by fdd_chain_vnops. If it is, its
* v_data pointer leads to the "real" vnode.
*/
if (v->v_data && v->v_op && (VXVOP_FDDCH < VXVOP_NUM)
&& vnops[VXVOP_FDDCH] && ((KA_T)v->v_op == vnops[VXVOP_FDDCH]))
{
if (kread((KA_T)v->v_data, (char *)&cv, sizeof(cv))) {
(void) snpf(Namech, Namechl,
"node at %s: can't read real vx vnode: %s",
print_kptr(va, tbuf, sizeof(tbuf)),
print_kptr((KA_T)v->v_data, (char *)NULL, 0));
enter_nm(Namech);
return(1);
}
# if defined(HASNCACHE)
Lf->na = (KA_T)v->v_data;
# endif /* defined(HASNCACHE) */
*v = cv;
Ntype = vop2ty(v, fx);
}
# if defined(HASVXFSUTIL)
/*
* If libvxfsutil[64].a is in use, establish the vx_inode size and the
* locations and sizes of its device, link count, node number, and size
* elements.
*
* If an error was detected while determining the vx_inode values, repeat
* the error explanation in the NAME column.
*/
if (!vxp && !em) {
em = getioffs(&vxp, &vxl,
(char **)&vxn_dev, &devl,
&vxn_ino, &inol,
(char **)&vxn_nlink, &nll,
(char **)&vxn_sz, &szl);
if (!em) {
/*
* Check the returned pointers and their sizes.
*/
em = ckptr(em, (char *)vxn_dev, devl, sizeof(dev_t), "dev");
em = ckptr(em, (char *)vxn_ino, inol, sizeof(INODETYPE), "ino");
em = ckptr(em, (char *)vxn_nlink, nll, sizeof(int), "nlink");
em = ckptr(em, (char *)vxn_sz, szl, sizeof(SZOFFTYPE), "sz");
}
}
if (em) {
(void) snpf(Namech, Namechl, "%s", em);
(void) enter_nm(Namech);
return(1);
}
# endif /* !defined(HASVXFSUTIL) */
/*
* Read vnode's vx_inode.
*/
if (!v->v_data || kread((KA_T)v->v_data, vxp, vxl)) {
(void) snpf(Namech, Namechl, "node at %s: can't read vx_inode: %s",
print_kptr(va, tbuf, sizeof(tbuf)),
print_kptr((KA_T)v->v_data, (char *)NULL, 0));
(void) enter_nm(Namech);
return(1);
}
/*
* Return device number, inode number, link count, raw device number, and size.
*/
if (vfs && vfs->fsname) {
li->dev = (dev_t)vfs->dev;
li->dev_def = 1;
} else if (vxn_dev) {
li->dev = (dev_t)*vxn_dev;
li->dev_def = 1;
}
if (vxn_ino) {
# if defined(HASVXFSUTIL)
switch (inol) {
case sizeof(short):
li->ino = (INODETYPE)*((short *)vxn_ino);
li->ino_def = 1;
break;
case sizeof(unsigned int):
li->ino = (INODETYPE)*((unsigned int *)vxn_ino);
li->ino_def = 1;
break;
case sizeof(unsigned long long):
li->ino = (INODETYPE)*((unsigned long long *)vxn_ino);
li->ino_def = 1;
break;
default:
break;
}
# else /* !defined(HASVXFSUTIL) */
li->ino = (INODETYPE)*vxn_ino;
li->ino_def = 1;
# endif /* defined(HASVXFSUTIL) */
}
if (vxn_nlink) {
li->nl = (long)*vxn_nlink;
li->nl_def = 1;
}
li->rdev = v->v_rdev;
li->rdev_def = 1;
if (vxn_sz) {
li->sz = (SZOFFTYPE)*vxn_sz;
li->sz_def = 1;
}
return(0);
}
#endif /* defined(HASVXFS) */