1/*	$NetBSD: ultrix_fs.c,v 1.50 2008/12/17 20:51:34 cegger Exp $	*/
2
3/*
4 * Copyright (c) 1995, 1997 Jonathan Stone
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Jonathan Stone for
18 *      the NetBSD Project.
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: ultrix_fs.c,v 1.50 2008/12/17 20:51:34 cegger Exp $");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/malloc.h>
41#include <sys/exec.h>
42#include <sys/namei.h>
43#include <sys/mount.h>
44#include <sys/proc.h>
45#include <sys/vnode.h>
46#include <sys/vnode_if.h>
47#include <net/if.h>
48#include <netinet/in.h>
49
50#include <nfs/rpcv2.h>
51#include <nfs/nfsproto.h>
52#include <nfs/nfs.h>
53#include <nfs/nfsmount.h>
54
55#include <ufs/ufs/quota.h>
56#include <ufs/ufs/ufsmount.h>
57
58#include <sys/syscallargs.h>
59#include <compat/ultrix/ultrix_syscallargs.h>
60#include <compat/common/compat_util.h>
61#include <compat/sys/mount.h>
62
63#define	ULTRIX_MAXPATHLEN	1024
64
65/**
66 ** Ultrix filesystem operations: mount(), getmnt().
67 ** These are included purely so one can place an (ECOFF or ELF)
68 ** NetBSD/pmax kernel in an Ultrix root filesystem, boot it,
69 ** and over-write the Ultrix root parition with NetBSD binaries.
70 **/
71
72/*
73 * Ultrix file system data structure, as modified by
74 * Ultrix getmntent(). This  structure is padded to 2560 bytes, for
75 * compatibility with the size the Ultrix kernel and user apps expect.
76 */
77struct ultrix_fs_data {
78	uint32_t	ufsd_flags;	/* how mounted */
79	uint32_t	ufsd_mtsize;	/* max transfer size in bytes */
80	uint32_t	ufsd_otsize;	/* optimal transfer size in bytes */
81	uint32_t	ufsd_bsize;	/* fs block size (bytes) for vm code */
82	uint32_t	ufsd_fstype;	/* see ../h/fs_types.h  */
83	uint32_t	ufsd_gtot;	/* total number of gnodes */
84	uint32_t	ufsd_gfree;	/* # of free gnodes */
85	uint32_t	ufsd_btot;	/* total number of 1K blocks */
86	uint32_t	ufsd_bfree;	/* # of free 1K blocks */
87	uint32_t	ufsd_bfreen;	/* user consumable 1K blocks */
88	uint32_t	ufsd_pgthresh;	/* min size in bytes before paging*/
89	int32_t		ufsd_uid;	/* uid that mounted me */
90	int16_t		ufsd_dev;	/* major/minor of fs */
91	int16_t		ufsd_exroot;	/* root mapping from exports */
92	char		ufsd_devname[ULTRIX_MAXPATHLEN + 4]; /* name of dev */
93	char		ufsd_path[ULTRIX_MAXPATHLEN + 4]; /* name of mnt point */
94	uint32_t	ufsd_nupdate;	/* number of writes */
95	uint32_t	ufsd_pad[112];	/* pad to 2560 bytes. */
96};
97
98/*
99 * Get statistics on mounted filesystems.
100 */
101#if 0
102struct ultrix_getmnt_args {
103	int32_t *start;
104	struct ultrix_fs_data *buf;
105	int32_t bufsize;
106	int32_t mode;
107	char *path;
108};
109
110#endif
111/*
112 * Ultrix getmnt() flags.
113 * The operation getmnt() should perform is incoded in the flag
114 * argument.  There are two independent attributes.
115 *
116 * ULTRIX_NOSTAT_xxx will never hang, but it may not return
117 * up-to-date statistics. (For NFS clients, it returns whatever is
118 * in the cache.) ULTRIX_STAT_xxx returns up-to-date info but may
119 * hang (e.g., on dead NFS servers).
120 *
121 * ULTRIX_xxSTAT_ONE returns statistics on just one filesystem, determined
122 * by the parth argument.  ULTRIX_xxSTAT_MANY ignores the path argument and
123 * returns info on as many  filesystems fit in the structure.
124 * the start argument, which should be zero on the first call,
125 * can be used to iterate over all filesystems.
126 *
127 */
128#define	ULTRIX_NOSTAT_MANY	1
129#define	ULTRIX_STAT_MANY	2
130#define	ULTRIX_STAT_ONE		3
131#define	ULTRIX_NOSTAT_ONE	4
132
133/*
134 * Ultrix gnode-layer  filesystem codes.
135 */
136#define ULTRIX_FSTYPE_UNKNOWN	0x0
137#define ULTRIX_FSTYPE_ULTRIX	0x1	/*  Ultrix UFS: basically 4.2bsd FFS */
138#define ULTRIX_FSTYPE_NFS	0x5	/*  NFS v2 */
139
140/*
141 * Ultrix mount(2) options
142 */
143#define ULTRIX_NM_RONLY    0x0001  /* mount read-only */
144#define ULTRIX_NM_SOFT     0x0002  /* soft mount (hard is default) */
145#define ULTRIX_NM_WSIZE    0x0004  /* set write size */
146#define ULTRIX_NM_RSIZE    0x0008  /* set read size */
147#define ULTRIX_NM_TIMEO    0x0010  /* set initial timeout */
148#define ULTRIX_NM_RETRANS  0x0020  /* set number of request retrys */
149#define ULTRIX_NM_HOSTNAME 0x0040  /* set hostname for error printf */
150#define ULTRIX_NM_PGTHRESH 0x0080  /* set page threshold for exec */
151#define ULTRIX_NM_INT      0x0100  /* allow hard mount keyboard interrupts */
152#define ULTRIX_NM_NOAC     0x0200  /* don't cache attributes */
153
154
155static void
156make_ultrix_mntent(struct statvfs *, struct ultrix_fs_data *);
157
158/*
159 * Construct an Ultrix getmnt() ultrix_fs_data from the native NetBSD
160 * struct statfs.
161 */
162static void
163make_ultrix_mntent(struct statvfs *sp, struct ultrix_fs_data *tem)
164{
165
166	memset(tem, 0, sizeof (*tem));
167
168	tem->ufsd_flags = sp->f_flag;		/* XXX translate */
169	tem->ufsd_mtsize = sp->f_bsize;		/* XXX max transfer size */
170	tem->ufsd_otsize = sp->f_iosize;
171	tem->ufsd_bsize = sp->f_bsize;
172	/*
173	 * Translate file system type. NetBSD/1.1 has f_type zero,
174	 * and uses an fstype string instead.
175	 * For now, map types not in Ultrix (kernfs, null, procfs...)
176	 * to UFS, since Ultrix mout will try and call mount_unknown
177	 * for ULTRIX_FSTYPE_UNKNOWN, but lacks a mount_unknown binary.
178	 */
179	tem->ufsd_fstype = ULTRIX_FSTYPE_NFS;
180	if (strcmp(sp->f_fstypename, "ffs") == 0)
181		tem->ufsd_fstype = ULTRIX_FSTYPE_ULTRIX;
182
183	tem->ufsd_gtot = sp->f_files;		/* total "gnodes" */
184	tem->ufsd_gfree = sp->f_ffree;		/* free "gnodes" */
185	tem->ufsd_btot = sp->f_blocks;		/* total 1k blocks */
186#ifdef needsmorethought	/* XXX */
187	/* tem->ufsd_bfree = sp->f_bfree; */	/* free 1k blocks */
188	/* tem->ufsd_bfree = sp->f_bavail; */	/* free 1k blocks */
189#endif
190
191	tem->ufsd_bfreen = sp->f_bavail;	/* blocks available to users */
192	tem->ufsd_pgthresh = 0;			/* not relevant */
193	tem->ufsd_uid = 0;			/* XXX kept where ?*/
194	tem->ufsd_dev = 0;			/* ?? */
195	tem->ufsd_exroot  = 0;			/* ?? */
196	strncpy(tem->ufsd_path, sp->f_mntonname, ULTRIX_MAXPATHLEN);
197	strncpy(tem->ufsd_devname, sp->f_mntfromname, ULTRIX_MAXPATHLEN);
198#if 0
199	/* In NetBSD-1.1, filesystem type is unused and always 0 */
200	printf("mntent: %s type %d\n", tem->ufsd_devname, tem->ufsd_fstype);
201	printf("mntent: %s tot %d free %d user%d\n",
202	 tem->ufsd_devname, sp->f_blocks, sp->f_bfree, sp->f_bavail);
203#endif
204}
205
206int
207ultrix_sys_getmnt(struct lwp *l, const struct ultrix_sys_getmnt_args *uap, register_t *retval)
208{
209	struct mount *mp, *nmp;
210	struct statvfs *sp;
211	struct ultrix_fs_data *sfsp;
212	char *path;
213	int mntflags;
214	int skip;
215	int start;
216	long count, maxcount;
217	int error = 0;
218
219	nmp = NULL;	/* XXX keep gcc quiet */
220	path = NULL;
221	error = 0;
222	maxcount = SCARG(uap, bufsize) / sizeof(struct ultrix_fs_data);
223	sfsp = SCARG(uap, buf);
224
225	if (SCARG(uap, mode) == ULTRIX_STAT_ONE ||
226	    SCARG(uap, mode) == ULTRIX_STAT_MANY)
227		mntflags = MNT_WAIT;
228	else
229		mntflags = MNT_NOWAIT;
230
231	if (SCARG(uap, mode) == ULTRIX_STAT_ONE || SCARG(uap, mode) == ULTRIX_NOSTAT_ONE) {
232		/*
233		 * Only get info on mountpoints that matches the path
234		 * provided.
235		 */
236		path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
237		if ((error = copyinstr(SCARG(uap, path), path,
238				       MAXPATHLEN, NULL)) != 0)
239			goto bad;
240		maxcount = 1;
241	} else {
242		/*
243		 * Get info on any mountpoints, somewhat like readdir().
244		 * Find out how many mount list entries to skip, and skip
245		 * them.
246		 */
247		if ((error = copyin((void *)SCARG(uap, start), &start,
248				    sizeof(*SCARG(uap, start))))  != 0)
249			goto bad;
250		mutex_enter(&mountlist_lock);
251		for (skip = start, mp = mountlist.cqh_first;
252		    mp != (void*)&mountlist && skip-- > 0; mp = nmp)
253			nmp = mp->mnt_list.cqe_next;
254		mutex_exit(&mountlist_lock);
255	}
256
257	mutex_enter(&mountlist_lock);
258	for (count = 0, mp = mountlist.cqh_first;
259	    mp != (void*)&mountlist && count < maxcount; mp = nmp) {
260		if (vfs_busy(mp, &nmp)) {
261			continue;
262		}
263		if (sfsp != NULL) {
264			struct ultrix_fs_data tem;
265			sp = &mp->mnt_stat;
266
267			/*
268			 * If requested, refresh the fsstat cache.
269			 */
270			if (mntflags != MNT_WAIT &&
271			    (error = VFS_STATVFS(mp, sp)) != 0)
272				continue;
273
274			/*
275			 * XXX what does this do? -- cgd
276			 */
277			sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
278			if (path == NULL ||
279			    strcmp(path, sp->f_mntonname) == 0) {
280				make_ultrix_mntent(sp, &tem);
281				if ((error = copyout((void *)&tem, sfsp,
282				    sizeof(tem))) != 0) {
283					vfs_unbusy(mp, false, NULL);
284					goto bad;
285				}
286				sfsp++;
287				count++;
288			}
289		}
290		vfs_unbusy(mp, false, &nmp);
291	}
292	mutex_exit(&mountlist_lock);
293
294	if (sfsp != NULL && count > maxcount)
295		*retval = maxcount;
296	else
297		*retval = count;
298
299bad:
300	if (path)
301		free(path, M_TEMP);
302	return error;
303}
304
305
306
307/* Old-style inet sockaddr (no len field) as passed to Ultrix mount(2) */
308struct osockaddr_in {
309	short   sin_family;
310	u_short sin_port;
311	struct  in_addr sin_addr;
312	char    sin_zero[8];
313};
314
315
316/*
317 * fstype-dependent structure passed to Ultrix mount(2) when
318 * mounting NFS filesystems
319 */
320struct	ultrix_nfs_args {
321	struct	osockaddr_in *addr;	/* file server address */
322	void	*fh;			/* file handle to be mounted */
323	int	flags;			/* flags */
324	int	wsize;			/* write size in bytes */
325	int	rsize;			/* read size in bytes */
326	int	timeo;			/* initial timeout in .1 secs */
327	int	retrans;		/* times to retry send */
328	char	*hostname;		/* server's hostname */
329	char	*optstr;		/* string of nfs mount options*/
330	int	gfs_flags;		/* gnode flags (ugh) */
331	int	pg_thresh;		/* paging threshold ? */
332};
333
334
335/*
336 * fstype-dependent structure passed to Ultrix mount(2) when
337 * mounting local (4.2bsd FFS) filesystems
338 */
339struct ultrix_ufs_args {
340	uint32_t ufs_flags;		/* mount flags?*/
341	uint32_t ufs_pgthresh;		/* minimum file size to page */
342};
343
344int
345ultrix_sys_mount(struct lwp *l, const struct ultrix_sys_mount_args *uap, register_t *retval)
346{
347	int error;
348	int otype = SCARG(uap, type);
349	char fsname[MFSNAMELEN];
350	register_t dummy;
351	int nflags;
352
353	nflags = 0;
354
355	/*
356	 * Translate Ultrix integer mount codes for UFS and NFS to
357	 * NetBSD fstype strings.  Other Ultrix filesystem types
358	 *  (msdos, DEC ods-2) are not supported.
359	 */
360
361	/* Translate the Ultrix mount-readonly option parameter */
362	if (SCARG(uap, rdonly))
363		nflags |= MNT_RDONLY;
364
365
366#ifdef later
367	parse ultrix mount option string and set NetBSD flags
368#endif
369
370	if (otype == ULTRIX_FSTYPE_NFS) {
371		struct ultrix_nfs_args una;
372		struct nfs_args na;
373
374		if ((error = copyin(SCARG(uap, data), &una, sizeof(una))) != 0)
375			return error;
376#if 0
377		/*
378		 * This is the only syscall boundary the
379		 * address of the server passes, so do backwards
380		 * compatibility on 4.3style sockaddrs here.
381		 */
382		if ((error = copyin(una.addr, &osa, sizeof osa)) != 0) {
383			printf("ultrix_mount: nfs copyin osa\n");
384			return error;
385		}
386		sap->sin_family = (u_char)osa.sin_family;
387		sap->sin_len = sizeof(*sap);
388		/* XXXX teach nfs how to do the above */
389#endif
390		na.version = NFS_ARGSVERSION;
391		na.addr = (void *)una.addr;
392		na.addrlen = sizeof (struct sockaddr_in);
393		na.sotype = SOCK_DGRAM;
394		na.proto = IPPROTO_UDP;
395		na.fh = una.fh;
396		na.fhsize = NFSX_V2FH;
397		na.flags = /*una.flags;*/ NFSMNT_NOCONN | NFSMNT_RESVPORT;
398		na.wsize = una.wsize;
399		na.rsize = una.rsize;
400		na.timeo = una.timeo;
401		na.retrans = una.retrans;
402		na.hostname = una.hostname;
403		return do_sys_mount(l, vfs_getopsbyname("nfs"), NULL,
404		    SCARG(uap, special), nflags, &na, UIO_SYSSPACE,
405		    sizeof na, &dummy);
406	}
407
408	/*
409	 * Translate fstype-dependent mount options from
410	 * Ultrix format to native.
411	 */
412	if (otype == ULTRIX_FSTYPE_ULTRIX) {
413		/* attempt to mount a native, rather than 4.2bsd, ffs */
414		struct ufs_args ua;
415
416		memset(&ua, 0, sizeof(ua));
417		ua.fspec = SCARG(uap, special);
418
419		/*
420		 * Ultrix mount has no MNT_UPDATE flag.
421		 * Attempt to see if this is the root we're mounting,
422		 * and if so, set MNT_UPDATE so we can mount / read-write.
423		 */
424		fsname[0] = 0;
425		if ((error = copyinstr(SCARG(uap, dir), fsname,
426				      sizeof fsname, NULL)) != 0)
427			return(error);
428		if (strcmp(fsname, "/") == 0) {
429			nflags |= MNT_UPDATE;
430			printf("COMPAT_ULTRIX: mount with MNT_UPDATE on %s\n",
431			    fsname);
432		}
433		return do_sys_mount(l, vfs_getopsbyname("ffs"), NULL,
434		    SCARG(uap, dir), nflags, &ua, UIO_SYSSPACE, sizeof ua,
435		    &dummy);
436	}
437
438	return EINVAL;
439}
440