Subject: Code review of Ultrix getmnt() sought.
To: None <port-pmax@sun-lamp.cs.berkeley.edu>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: port-pmax
Date: 08/22/1994 16:45:35
[[An earlier  mailing of this bounced, because  I can't spell sun-lamp.
 Apologies to those who see it twice, or late.]]

Below is a first pass at an Ultrix getmnt().
It's not yet ready for inclusion in an official source tree.
There's a bunch of things it doesn't do;  but it works well enough
for Ultrix mount and df to list the mounted filesystems
and the free space on each of them.

Things I'd like some help on are: which source file  to
put this in, given that it's both Ultrix-compatibility
specific, and closely tied to the VFS code (compare it
with getfsstat() in kern/vfs_syscalls.c).

Also I don't know where in the VFS to find a major/minor
device number of a mounted special file, if that's what
the  mount is.

I have no idea how Ultrix matches a path argument, if
one is given, to a mount point; but I expect it goes
through namei(), which this doesn't. Neither mount
nor df nor unmount seem to ask Ultrix getmnt()
for a specific path, so I haven't bothered...

--------
#ifdef COMPAT_ULTRIX
struct ult_fs_data {
		u_int	flags;		/* how mounted */
		u_int	mtsize;		/* max transfer size in bytes */
		u_int	otsize;		/* optimal transfer size in bytes */
		u_int	bsize;		/* fs block size in bytes for vm code */
		u_int	fstype;		/* see ../h/fs_types.h  */
		u_int	gtot;		/* total number of gnodes */
		u_int	gfree;		/* # of free gnodes */
		u_int	btot;		/* total number of 1K blocks */
		u_int	bfree;		/* # of free 1K blocks */
		u_int	bfreen;		/* user consumable 1K blocks */
		u_int	pgthresh;	/* min size in bytes before paging*/
		int	uid;		/* uid that mounted me */
		short /*dev_t*/	dev;		/* major/minor of fs */
		short	exroot;		/* root mapping from exports */
#define ULT_MAXPATHLEN 1024/* in case NetBSD MAXPATHLEN changes */
		char	devname[ULT_MAXPATHLEN + 4]; /* name of dev */
		char	path[ULT_MAXPATHLEN + 4]; /* name of mount point */
		u_int	nupdate;	/* number of writes */

		/* 2112 bytes */
		u_int	fd_spare[112];	/* this structure is exactly  */
					/* 14 * 4 + 2 * 1028 + 112 *4 = 2560 */
					/* bytes - KEEP IT THAT WAY - rr */
					/* since we malloc memory in 512 byte */
					/* chunks, the last 113 u_int's are */
					/* FREE */
};


/*
 * Get statistics on mounted filesystems.
 */
struct ult_getmnt_args {
	long *start;
	struct ult_fs_data *buf;
	long bufsize, mode;
	char *path;
};

#define ULT_NOSTAT_MANY 1
#define ULT_STAT_MANY   2
#define ULT_NOSTAT_ONE  4
#define ULT_STAT_ONE    3


/* construct Ultrix_compat structure */
static 
make_ult_mntent(sp, tem)
	register struct statfs *sp;
	register struct ult_fs_data *tem;

{
	tem->mtsize = sp->f_bsize; /*XXX should be max transfer size */
	tem->flags = sp->f_flags; /*XXX should translate */
	tem->otsize = sp->f_iosize;
	tem->bsize = sp->f_bsize;
	tem->fstype = sp->f_type ; /*XXX*/ /* translate */
	tem->gtot = 0; 	/* kept where? Superblock? */
	tem->gfree = sp->f_ffree;
	tem->bfreen = sp->f_bfree;
	tem->pgthresh = 0; /* not relevant */
	tem->uid = 0 ;	 /* kept where ?*/
	tem->dev = 0 ; /* ?? */
	tem->exroot  = 0 ; /* ?? */
	strncpy(tem->path, sp->f_mntonname, ULT_MAXPATHLEN);
	strncpy(tem->devname , sp->f_mntfromname, ULT_MAXPATHLEN);
}

ult_getmnt(p, uap, retval)
	struct proc *p;
	register struct ult_getmnt_args *uap;
	int *retval;
{
	register struct mount *mp, *nmp;
	register struct statfs *sp;
	caddr_t sfsp;
	register long count, maxcount, error = 0;

	int mntflags = MNT_NOWAIT;
	register int skip;
	int start;
	char *path = 0;

	if (uap->mode == ULT_STAT_ONE || uap->mode == ULT_STAT_MANY)
	  mntflags = MNT_WAIT;

	maxcount = uap->bufsize / sizeof(struct ult_fs_data);
	sfsp = (caddr_t)uap->buf;

	if (uap->mode == ULT_STAT_ONE || uap->mode == ULT_NOSTAT_ONE)
	{
		/* just get the one that matches */
		MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
		if (error = copyinstr(uap->path, path, MAXPATHLEN, (u_int*)0))
		  goto bad;

		maxcount = 1;
	} else {
		if (error = copyin((caddr_t)uap->start, &start, sizeof(*uap->start)))
		  goto bad;


		skip = start;
		/* skip to the |start|th element in internal list */
		for (mp = mountlist.tqh_first; mp != NULL && skip > 0; mp = nmp) {
			nmp = mp->mnt_list.tqe_next;
			skip--;
		}
	}
	
	for (count = 0, mp = mountlist.tqh_first; mp != NULL && count < maxcount; mp = nmp) {
		nmp = mp->mnt_list.tqe_next;
		if (sfsp && count < maxcount &&
		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
			struct ult_fs_data tem;
			sp = &mp->mnt_stat;
			/*
			 * If requested, refresh the fsstat cache.
			 */
			if ((mntflags & MNT_WAIT) &&
			    (error = VFS_STATFS(mp, sp, p)))
				continue;
			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
			if (!path || (strcmp(path, sp->f_mntonname) == 0))
			  {
				  make_ult_mntent(sp, &tem);
				  if (error = copyout((caddr_t)&tem, sfsp, sizeof(tem)))
				    goto bad;
				  sfsp += sizeof(tem);
				  count++;
			  }
		}
	}
	if (sfsp && count > maxcount)
		*retval = maxcount;
	else
		*retval = count;
	return (0);
bad:
	if (path)
	  FREE(path, M_NAMEI);
	return(error);
	
}
#endif /*COMPAT_ULTRIX*/


------------------------------------------------------------------------------