blob: c9c023cc353ca44e799f60bec6d9cc1905a68452 [file] [log] [blame]
/*
* dmnt.c - Solaris mount support functions for lsof
*/
/*
* Copyright 1994 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: dmnt.c,v 1.15 2005/08/29 10:24:25 abe Exp $";
#endif
#include "lsof.h"
/*
* Local static definitions
*/
static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */
static int Lmist = 0; /* Lmi status */
_PROTOTYPE(static char *getmntdev,(char *o, int l, struct stat *s, char *f));
/*
* getmntdev() - get mount entry's device number
*/
static char *
getmntdev(o, l, s, f)
char *o; /* start of device option */
int l; /* length of device keyword (not
* including `=') */
struct stat *s; /* pointer to stat buffer to create */
char *f; /* file system type */
{
char *opte;
memset((char *)s, 0, sizeof(struct stat));
if (!(opte = x2dev(o + l + 1, &s->st_dev)))
return((char *)NULL);
#if solaris>=70000 && L_BITSMAJOR!=L_BITSMAJOR32
/*
* If this is a Solaris 7 system with a 64 bit kernel, convert the 32 bit
* device number to a 64 bit device number.
*/
s->st_dev = (((s->st_dev >> L_BITSMINOR32) & L_MAXMAJ32) << L_BITSMINOR)
| (s->st_dev & L_MAXMIN32);
#endif /* solaris>=70000 && L_BITSMAJOR!=L_BITSMAJOR32 */
s->st_mode = S_IFDIR | 0777;
#if defined(HASFSTYPE)
if (f) {
(void) strncpy(s->st_fstype, f, sizeof(s->st_fstype));
s->st_fstype[sizeof(s->st_fstype) - 1] = '\0';
}
#endif /* defined(HASFSTYPE) */
return(opte);
}
/*
* readmnt() - read mount table
*/
struct mounts *
readmnt()
{
int devl, ignore;
char *cp, *dir, *fs;
char *dn = (char *)NULL;
char *ln;
FILE *mfp;
struct mounts *mtp;
char *dopt, *dopte;
struct stat sb;
struct mnttab me;
struct mnttab *mp;
#if defined(HASPROCFS)
int procfs = 0;
#endif /* defined(HASPROCFS) */
unsigned char stat;
char *zopt;
#if defined(HASZONES)
int zwarn = 0;
#endif /* definesd(HASZONES) */
if (Lmi || Lmist)
return(Lmi);
devl = strlen(MNTOPT_DEV);
/*
* Open access to the mount table and read mount table entries.
*/
if (!(mfp = fopen(MNTTAB, "r"))) {
(void) fprintf(stderr, "%s: can't access %s\n", Pn, MNTTAB);
return(0);
}
for (mp = &me; getmntent(mfp, mp) == 0;) {
/*
* Skip loop-back mounts, since they are aliases for legitimate file
* systems and there is no way to determine that a vnode refers to a
* loop-back alias.
*/
if (strcmp(mp->mnt_fstype, MNTTYPE_LO) == 0)
continue;
/*
* Save pointers to the directory and file system names for later use.
*
* Check the file system name. If it doesn't begin with a `/'
* but contains a `:' not followed by a '/', ignore this entry.
*/
dir = mp->mnt_mountp;
fs = mp->mnt_special;
if (*fs != '/' && (cp = strchr(fs, ':')) && *(cp+1) != '/')
continue;
/*
* Check for a "ignore" type (SunOS) or "ignore" option (Solaris).
*/
if (hasmntopt(mp, MNTOPT_IGNORE))
ignore = 1;
else
ignore = 0;
/*
* Interpolate a possible symbolic directory link.
*/
if (dn)
(void) free((FREE_P *)dn);
if (!(dn = mkstrcpy(dir, (MALLOC_S *)NULL))) {
no_space_for_mount:
(void) fprintf(stderr, "%s: no space for mount ", Pn);
safestrprt(fs, stderr, 0);
(void) fprintf(stderr, " (");
safestrprt(dir, stderr, 0);
(void) fprintf(stderr, ")\n");
Exit(1);
}
if (!(ln = Readlink(dn))) {
if (!Fwarn) {
(void) fprintf(stderr,
" Output information may be incomplete.\n");
}
continue;
}
if (ln != dn) {
(void) free((FREE_P *)dn);
dn = ln;
}
if (*dn != '/')
continue;
/*
* Stat() the directory.
*
* Avoid the stat() if the mount entry has an "ignore" option and
* try to use the mount entry's device number instead.
*/
dopt = hasmntopt(mp, MNTOPT_DEV);
if (ignore) {
if (!dopt
|| !(dopte = getmntdev(dopt, devl, &sb,
#if defined(HASFSTYPE)
mp->mnt_fstype
#else /* !defined(HASFSTYPE) */
(char *)NULL
#endif /* defined(HASFSTYPE) */
))
)
continue;
stat = 1;
} else if (statsafely(dn, &sb)) {
if (dopt) {
if (!(dopte = getmntdev(dopt, devl, &sb,
#if defined(HASFSTYPE)
mp->mnt_fstype
#else /* !defined(HASFSTYPE) */
(char *)NULL
#endif /* defined(HASFSTYPE) */
))
)
dopt = (char *)NULL;
} else
dopte = (char *)NULL;
if (!Fwarn) {
#if defined(HASZONES)
if ((zopt = hasmntopt(mp, "zone")) && dopte)
zwarn++;
#else /* !defined(HASZONES) */
zopt = (char *)NULL;
#endif /* defined(HASZONES) */
if (!zopt || !dopte) {
(void) fprintf(stderr,
"%s: WARNING: can't stat() ", Pn);
safestrprt(mp->mnt_fstype, stderr, 0);
(void) fprintf(stderr, " file system ");
safestrprt(dir, stderr, 1);
(void) fprintf(stderr,
" Output information may be incomplete.\n");
if (dopte) {
(void) fprintf(stderr,
" assuming \"%.*s\" from %s\n",
(int)(dopte - dopt), dopt, MNTTAB);
}
}
}
if (!dopt)
continue;
stat = 1;
} else
stat = 0;
/*
* Allocate and fill a local mount structure.
*/
if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
goto no_space_for_mount;
#if defined(HASFSTYPE)
if (!(mtp->fstype = mkstrcpy(sb.st_fstype, (MALLOC_S *)NULL)))
goto no_space_for_mount;
#endif /* defined(HASFSTYPE) */
mtp->dir = dn;
dn = (char *)NULL;
mtp->next = Lmi;
mtp->dev = sb.st_dev;
mtp->rdev = sb.st_rdev;
mtp->inode = (INODETYPE)sb.st_ino;
mtp->mode = sb.st_mode;
#if solaris>=80000
mtp->nlink = sb.st_nlink;
mtp->size = sb.st_size;
#endif /* solaris>=80000 */
#if defined(HASMNTSTAT)
mtp->stat = stat;
#endif /* defined(HASMNTSTAT) */
#if defined(HASPROCFS)
if (strcmp(sb.st_fstype, HASPROCFS) == 0) {
/*
* Save information on exactly one proc file system.
*/
if (procfs)
Mtprocfs = (struct mounts *)NULL;
else {
procfs = 1;
Mtprocfs = mtp;
}
}
#endif /* defined(HASPROCFS) */
/*
* Interpolate a possible file system (mounted-on) device name link.
*/
if (!(dn = mkstrcpy(fs, (MALLOC_S *)NULL)))
goto no_space_for_mount;
mtp->fsname = dn;
ln = Readlink(dn);
dn = (char *)NULL;
/*
* Stat() the file system (mounted-on) name and add file system
* information to the local mount table entry.
*/
if (!ln || statsafely(ln, &sb))
sb.st_mode = 0;
mtp->fsnmres = ln;
mtp->fs_mode = sb.st_mode;
Lmi = mtp;
#if defined(HAS_AFS)
/*
* If an AFS device number hasn't yet been defined, look for it.
*/
if (!AFSdevStat
&& mtp->dir && strcmp(mtp->dir, "/afs") == 0
&& mtp->fsname && strcmp(mtp->fsname, "AFS") == 0) {
AFSdev = mtp->dev;
AFSdevStat = 1;
}
#endif /* defined(HAS_AFS) && solaris>=20600 */
}
(void) fclose(mfp);
#if defined(HASZONES)
/*
* If some zone file systems were encountered, issue a warning.
*/
if (!Fwarn && zwarn) {
(void) fprintf(stderr,
"%s: WARNING: can't stat() %d zone file system%s", Pn, zwarn,
(zwarn == 1) ? "" : "s");
(void) fprintf(stderr, "; using dev= option%s\n",
(zwarn == 1) ? "" : "s");
}
#endif /* defined(HASZONES) */
/*
* Clean up and return local mount info table address.
*/
if (dn)
(void) free((FREE_P *)dn);
Lmist = 1;
return(Lmi);
}
/*
* readvfs() - read vfs structure
*/
struct l_vfs *
readvfs(ka, la, lv)
KA_T ka; /* vfs structure kernel address, if
* must be read from kernel */
struct vfs *la; /* local vfs structure address, non-
* NULL if already read from kernel */
struct vnode *lv; /* local vnode */
{
struct vfs *v, tv;
struct l_vfs *vp;
if (!ka && !la)
return((struct l_vfs *)NULL);
for (vp = Lvfs; vp; vp = vp->next) {
if (ka == vp->addr)
return(vp);
}
if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) {
(void) fprintf(stderr, "%s: PID %d, no space for vfs\n",
Pn, Lp->pid);
Exit(1);
}
vp->dir = (char *)NULL;
vp->fsname = (char *)NULL;
#if defined(HASFSINO)
vp->fs_ino = 0;
#endif /* defined(HASFSINO) */
/*
* Read vfs structure from kernel, if necessary.
*/
if (la)
v = la;
else {
v = &tv;
if (kread((KA_T)ka, (char *)v, sizeof(tv))) {
(void) free((FREE_P *)vp);
return((struct l_vfs *)NULL);
}
}
#if defined(HAS_AFS)
/*
* Fake the device number for an AFS device.
*/
if (v->vfs_fstype == AFSfstype) {
if (!AFSdevStat)
(void) readmnt();
v->vfs_dev = AFSdevStat ? AFSdev : 0;
}
#endif /* defined(HAS_AFS) */
/*
* Complete mount information.
*/
(void) completevfs(vp, (dev_t *)&v->vfs_dev);
vp->next = Lvfs;
vp->addr = ka;
Lvfs = vp;
return(vp);
}