/*
 * dmnt.c - HP-UX 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.8 96/03/05 12:52:23 abe Exp $";
#endif


#include "lsof.h"


/*
 * completevfs() - complete local vfs structure
 */
void

#if	_HPUXV>=800
completevfs(vfs, dev, v)
	struct l_vfs *vfs;		/* local vfs structure pointer */
	dev_t *dev;			/* device */
	struct vfs *v;			/* kernel vfs structure */
#else	/* _HPUXV<800 */
completevfs(vfs, dev, v)
	struct l_vfs *vfs;		/* local vfs structure pointer */
	dev_t *dev;			/* device */
#endif	/* _HPUXV>=800 */

{
	struct mounts *mp;

#if	_HPUXV>=800
	struct stat sb;
	char *ty;
/*
 * On HP-UX 8 and above, first search for a match on the file system name
 * from the vfs structure.
 */
	if (v) {
		for (mp = Mtab; mp; mp = mp->next) {
			if (strcmp(mp->fsname, v->vfs_name) == 0) {
				vfs->dev = mp->dev;
				vfs->dir = mp->dir;
				vfs->fsname = mp->fsname;

# if	defined(HASFSINO)
				vfs->fs_ino = mp->inode;
# endif	/* defined(HASFSINO) */

				return;
			}
		}
	}
#endif	/* _HPUXV>=800 */

/*
 * Search for a match on device number.
 */
	for (mp = Mtab; mp; mp = mp->next) {
		if (mp->dev == *dev) {
			vfs->dev = mp->dev;
			vfs->dir = mp->dir;
			vfs->fsname = mp->fsname;

#if	defined(HASFSINO)
			vfs->fs_ino = mp->inode;
#endif	/* defined(HASFSINO) */

			return;
		}
	}

#if	_HPUXV>=800
/*
 * If the file system name and device number searches fail, use the
 * vfs structure name, if there is one.
 */
	if (v && v->vfs_name[0]) {

	/*
	 * Stat the vfs_name and use its device number to search the mount
	 * table once more.
	 */
		if (statsafely(v->vfs_name, &sb) == 0) {
			for (mp = Mtab; mp; mp = mp->next) {
				if (mp->dev == sb.st_dev) {
					vfs->dev = mp->dev;
					vfs->dir = mp->dir;
					vfs->fsname = mp->fsname;

# if	defined(HASFSINO)
					vfs->fs_ino = mp->inode;
# endif	/* defined(HASFSINO) */

					return;
				}
			}
		} else {
		    if (!Fwarn) {
			switch(v->vfs_mtype) {
			case MOUNT_UFS:
				ty = "ufs";
				break;
			case MOUNT_NFS:
				ty = "nfs";
				break;
			case MOUNT_CDFS:
				ty = "cdfs";
				break;
			default:
				ty = "unknown";
			}
			(void) fprintf(stderr,
				"%s: WARNING: can't stat() %s file system %s\n",
				Pn, ty, v->vfs_name);
		    }
		}
	/*
	 * As a last recourse, use the vfs_name.
	 */
		if ((vfs->dir = (char *)malloc(strlen(v->vfs_name)+1))
		== NULL) {
			(void) fprintf(stderr, "%s: no space for vfs name\n",
				Pn);
			exit(1);
		}
		(void) strcpy(vfs->dir, v->vfs_name);
		vfs->dev = mp->dev;
	}
#endif	/* _HPUXV>=800 */

}


/*
 * readvfs() - read vfs structure
 */

struct l_vfs *
readvfs(la, lv)
	struct vfs *la;			/* local vfs structure address, non-
					 * NULL if already read from kernel */
	struct vnode *lv;		/* local vnode */
{
	struct mount m;
	struct mntinfo mi;
	int ms;
	dev_t td;
	struct vfs tv, *v;
	struct l_vfs *vp;

	if (!la && !lv->v_vfsp)
		return(NULL);
	for (vp = Lvfs; vp; vp = vp->next) {
		if (lv->v_vfsp == vp->addr)
			return(vp);
	}
	if ((vp = (struct l_vfs *)malloc(sizeof(struct l_vfs))) == NULL) {
		(void) fprintf(stderr, "%s: PID %d, no space for vfs\n",
			Pn, Lp->pid);
		exit(1);
	}
	vp->dev = 0;
	vp->dir = NULL;
	vp->fsname = NULL;

#if	defined(HASFSINO)
	vp->fs_ino = 0;
#endif	/* defined(HASFSINO) */

	if (la)
		v = la;
	else {
		v = &tv;
		if (lv->v_vfsp
		&&  kread((KA_T)lv->v_vfsp, (char *)v, sizeof(tv))) {
			(void) free((FREE_P *)vp);
			return(NULL);
		}
	}
/*
 * Complete the mount information.
 */

	if (Ntype == N_NFS) {

	/*
	 * HP-UX NFS vnode device values have a major number of 255.
	 * The minor number is a serial number found in the mntinfo
	 * structure to which the virtual file system's vfs_data points.
	 */
		if (v->vfs_data
		&&  kread((KA_T)v->vfs_data, (char *)&mi, sizeof(mi)) == 0) {
			td = (dev_t)makedev(255, (int)mi.mi_mntno);

#if	_HPUXV>=800
			(void) completevfs(vp, &td, NULL);
#else	/* _HPUXV<800 */
			(void) completevfs(vp, &td);
#endif	/* _HPUXV>=800 */

		}
	} else {
		if (v->vfs_data) {
			if (kread((KA_T)v->vfs_data, (char *)&m, sizeof(m))
			== 0)
				ms = 1;
			else
				ms = 0;
		}

#if	defined(HAS_AFS)
	/*
	 * Fake the device number for an AFS device.
	 */
		else if (Ntype == N_AFS) {
			m.m_dev = AFSDEV;
			ms = 1;
		}
#endif	/* defined(HAS_AFS) */

		else
			ms = 0;
		if (ms)

#if	_HPUXV>=800
			(void) completevfs(vp, (dev_t *)&m.m_dev, v);
#else	/* _HPUXV<800 */
			(void) completevfs(vp, (dev_t *)&m.m_dev);
#endif	/* _HPUXV>=800 */

	}
/*
 * Complete local vfs structure and link to the others.
 */
	vp->next = Lvfs;
	vp->addr = lv->v_vfsp;
	Lvfs = vp;
	return(vp);
}


/*
 * The readmnt() function is obtained from ../common/rmnt.frag.
 */

#define	EXPDEV(n)	n
#define MNTSKIP \
	{ if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0) \
		continue; }
