xref: /netbsd-src/sys/compat/netbsd32/netbsd32_fs.c (revision a536ee5124e62c9a0051a252f7833dc8f50f44c9)
1 /*	$NetBSD: netbsd32_fs.c,v 1.64 2012/12/13 15:16:57 matt Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 2001 Matthew R. Green
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.64 2012/12/13 15:16:57 matt Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/mount.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/ktrace.h>
40 #include <sys/resourcevar.h>
41 #include <sys/vnode.h>
42 #include <sys/file.h>
43 #include <sys/filedesc.h>
44 #include <sys/namei.h>
45 #include <sys/statvfs.h>
46 #include <sys/syscallargs.h>
47 #include <sys/proc.h>
48 #include <sys/dirent.h>
49 #include <sys/kauth.h>
50 #include <sys/vfs_syscalls.h>
51 
52 #include <fs/cd9660/cd9660_mount.h>
53 #include <fs/msdosfs/bpb.h>
54 #include <fs/msdosfs/msdosfsmount.h>
55 #include <ufs/ufs/ufsmount.h>
56 
57 #define NFS_ARGS_ONLY
58 #include <nfs/nfsmount.h>
59 
60 #include <compat/netbsd32/netbsd32.h>
61 #include <compat/netbsd32/netbsd32_syscallargs.h>
62 #include <compat/netbsd32/netbsd32_conv.h>
63 #include <compat/sys/mount.h>
64 
65 
66 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *,
67 			      int, off_t *, int, register_t *);
68 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *,
69 			       int,  off_t *, int, register_t *);
70 
71 struct iovec *
72 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov,
73     int aiov_len)
74 {
75 #define N_IOV32 8
76 	struct netbsd32_iovec aiov32[N_IOV32];
77 	struct iovec *iov = aiov;
78 	struct iovec *iovp;
79 	int i, n, j;
80 	int error;
81 
82 	if (iovlen < 0 || iovlen > IOV_MAX)
83 		return NULL;
84 
85 	if (iovlen > aiov_len)
86 		iov = kmem_alloc(iovlen * sizeof(*iov), KM_SLEEP);
87 
88 	iovp = iov;
89 	for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) {
90 		n = iovlen - i;
91 		if (n > N_IOV32)
92 			n = N_IOV32;
93 		error = copyin(iov32, aiov32, n * sizeof (*iov32));
94 		if (error != 0) {
95 			if (iov != aiov)
96 				kmem_free(iov, iovlen * sizeof(*iov));
97 			return NULL;
98 		}
99 		for (j = 0; j < n; iovp++, j++) {
100 			iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base);
101 			iovp->iov_len = aiov32[j].iov_len;
102 		}
103 	}
104 	return iov;
105 #undef N_IOV32
106 }
107 
108 int
109 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval)
110 {
111 	/* {
112 		syscallarg(int) fd;
113 		syscallarg(const netbsd32_iovecp_t) iovp;
114 		syscallarg(int) iovcnt;
115 	} */
116 	int fd = SCARG(uap, fd);
117 	file_t *fp;
118 
119 	if ((fp = fd_getfile(fd)) == NULL)
120 		return (EBADF);
121 
122 	if ((fp->f_flag & FREAD) == 0) {
123 		fd_putfile(fd);
124 		return (EBADF);
125 	}
126 
127 	return (dofilereadv32(fd, fp,
128 	    (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
129 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
130 }
131 
132 /* Damn thing copies in the iovec! */
133 int
134 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
135 {
136 	struct uio auio;
137 	struct iovec *iov;
138 	struct iovec *needfree;
139 	struct iovec aiov[UIO_SMALLIOV];
140 	long i, cnt, error = 0;
141 	u_int iovlen;
142 	struct iovec *ktriov = NULL;
143 
144 	/* note: can't use iovlen until iovcnt is validated */
145 	iovlen = iovcnt * sizeof(struct iovec);
146 	if ((u_int)iovcnt > UIO_SMALLIOV) {
147 		if ((u_int)iovcnt > IOV_MAX) {
148 			error = EINVAL;
149 			goto out;
150 		}
151 		iov = kmem_alloc(iovlen, KM_SLEEP);
152 		needfree = iov;
153 	} else if ((u_int)iovcnt > 0) {
154 		iov = aiov;
155 		needfree = NULL;
156 	} else {
157 		error = EINVAL;
158 		goto out;
159 	}
160 
161 	auio.uio_iov = iov;
162 	auio.uio_iovcnt = iovcnt;
163 	auio.uio_rw = UIO_READ;
164 	auio.uio_vmspace = curproc->p_vmspace;
165 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
166 	if (error)
167 		goto done;
168 	auio.uio_resid = 0;
169 	for (i = 0; i < iovcnt; i++) {
170 		auio.uio_resid += iov->iov_len;
171 		/*
172 		 * Reads return ssize_t because -1 is returned on error.
173 		 * Therefore we must restrict the length to SSIZE_MAX to
174 		 * avoid garbage return values.
175 		 */
176 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
177 			error = EINVAL;
178 			goto done;
179 		}
180 		iov++;
181 	}
182 
183 	/*
184 	 * if tracing, save a copy of iovec
185 	 */
186 	if (ktrpoint(KTR_GENIO)) {
187 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
188 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
189 	}
190 
191 	cnt = auio.uio_resid;
192 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
193 	if (error)
194 		if (auio.uio_resid != cnt && (error == ERESTART ||
195 		    error == EINTR || error == EWOULDBLOCK))
196 			error = 0;
197 	cnt -= auio.uio_resid;
198 
199 	if (ktriov != NULL) {
200 		ktrgeniov(fd, UIO_READ, ktriov, cnt, error);
201 		kmem_free(ktriov, iovlen);
202 	}
203 
204 	*retval = cnt;
205 done:
206 	if (needfree)
207 		kmem_free(needfree, iovlen);
208 out:
209 	fd_putfile(fd);
210 	return (error);
211 }
212 
213 int
214 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval)
215 {
216 	/* {
217 		syscallarg(int) fd;
218 		syscallarg(const netbsd32_iovecp_t) iovp;
219 		syscallarg(int) iovcnt;
220 	} */
221 	int fd = SCARG(uap, fd);
222 	file_t *fp;
223 
224 	if ((fp = fd_getfile(fd)) == NULL)
225 		return (EBADF);
226 
227 	if ((fp->f_flag & FWRITE) == 0) {
228 		fd_putfile(fd);
229 		return (EBADF);
230 	}
231 
232 	return (dofilewritev32(fd, fp,
233 	    (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
234 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
235 }
236 
237 int
238 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
239 {
240 	struct uio auio;
241 	struct iovec *iov;
242 	struct iovec *needfree;
243 	struct iovec aiov[UIO_SMALLIOV];
244 	long i, cnt, error = 0;
245 	u_int iovlen;
246 	struct iovec *ktriov = NULL;
247 
248 	/* note: can't use iovlen until iovcnt is validated */
249 	iovlen = iovcnt * sizeof(struct iovec);
250 	if ((u_int)iovcnt > UIO_SMALLIOV) {
251 		if ((u_int)iovcnt > IOV_MAX) {
252 			error = EINVAL;
253 			goto out;
254 		}
255 		iov = kmem_alloc(iovlen, KM_SLEEP);
256 		needfree = iov;
257 	} else if ((u_int)iovcnt > 0) {
258 		iov = aiov;
259 		needfree = NULL;
260 	} else {
261 		error = EINVAL;
262 		goto out;
263 	}
264 
265 	auio.uio_iov = iov;
266 	auio.uio_iovcnt = iovcnt;
267 	auio.uio_rw = UIO_WRITE;
268 	auio.uio_vmspace = curproc->p_vmspace;
269 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
270 	if (error)
271 		goto done;
272 	auio.uio_resid = 0;
273 	for (i = 0; i < iovcnt; i++) {
274 		auio.uio_resid += iov->iov_len;
275 		/*
276 		 * Writes return ssize_t because -1 is returned on error.
277 		 * Therefore we must restrict the length to SSIZE_MAX to
278 		 * avoid garbage return values.
279 		 */
280 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
281 			error = EINVAL;
282 			goto done;
283 		}
284 		iov++;
285 	}
286 
287 	/*
288 	 * if tracing, save a copy of iovec
289 	 */
290 	if (ktrpoint(KTR_GENIO))  {
291 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
292 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
293 	}
294 
295 	cnt = auio.uio_resid;
296 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
297 	if (error) {
298 		if (auio.uio_resid != cnt && (error == ERESTART ||
299 		    error == EINTR || error == EWOULDBLOCK))
300 			error = 0;
301 		if (error == EPIPE && (fp->f_flag & FNOSIGPIPE) == 0) {
302 			mutex_enter(proc_lock);
303 			psignal(curproc, SIGPIPE);
304 			mutex_exit(proc_lock);
305 		}
306 	}
307 	cnt -= auio.uio_resid;
308 	if (ktriov != NULL) {
309 		ktrgenio(fd, UIO_WRITE, ktriov, cnt, error);
310 		kmem_free(ktriov, iovlen);
311 	}
312 	*retval = cnt;
313 done:
314 	if (needfree)
315 		kmem_free(needfree, iovlen);
316 out:
317 	fd_putfile(fd);
318 	return (error);
319 }
320 
321 /*
322  * Common routine to set access and modification times given a vnode.
323  */
324 static int
325 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv,
326     struct timeval **tvp)
327 {
328 	int error;
329 	struct netbsd32_timeval tv32[2];
330 
331 	if (tptr == NULL) {
332 		*tvp = NULL;
333 		return 0;
334 	}
335 
336 	error = copyin(tptr, tv32, sizeof(tv32));
337 	if (error)
338 		return error;
339 	netbsd32_to_timeval(&tv32[0], &tv[0]);
340 	netbsd32_to_timeval(&tv32[1], &tv[1]);
341 
342 	*tvp = tv;
343 	return 0;
344 }
345 
346 int
347 netbsd32___utimes50(struct lwp *l, const struct netbsd32___utimes50_args *uap, register_t *retval)
348 {
349 	/* {
350 		syscallarg(const netbsd32_charp) path;
351 		syscallarg(const netbsd32_timevalp_t) tptr;
352 	} */
353 	int error;
354 	struct timeval tv[2], *tvp;
355 
356 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
357 	if (error != 0)
358 		return error;
359 
360 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
361 			    tvp, UIO_SYSSPACE);
362 }
363 
364 static int
365 netbds32_copyout_statvfs(const void *kp, void *up, size_t len)
366 {
367 	struct netbsd32_statvfs *sbuf_32;
368 	int error;
369 
370 	sbuf_32 = kmem_alloc(sizeof(*sbuf_32), KM_SLEEP);
371 	netbsd32_from_statvfs(kp, sbuf_32);
372 	error = copyout(sbuf_32, up, sizeof(*sbuf_32));
373 	kmem_free(sbuf_32, sizeof(*sbuf_32));
374 
375 	return error;
376 }
377 
378 int
379 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval)
380 {
381 	/* {
382 		syscallarg(const netbsd32_charp) path;
383 		syscallarg(netbsd32_statvfsp_t) buf;
384 		syscallarg(int) flags;
385 	} */
386 	struct statvfs *sb;
387 	int error;
388 
389 	sb = STATVFSBUF_GET();
390 	error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb);
391 	if (error == 0)
392 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
393 	STATVFSBUF_PUT(sb);
394 	return error;
395 }
396 
397 int
398 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval)
399 {
400 	/* {
401 		syscallarg(int) fd;
402 		syscallarg(netbsd32_statvfsp_t) buf;
403 		syscallarg(int) flags;
404 	} */
405 	struct statvfs *sb;
406 	int error;
407 
408 	sb = STATVFSBUF_GET();
409 	error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
410 	if (error == 0)
411 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
412 	STATVFSBUF_PUT(sb);
413 	return error;
414 }
415 
416 int
417 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval)
418 {
419 	/* {
420 		syscallarg(netbsd32_statvfsp_t) buf;
421 		syscallarg(netbsd32_size_t) bufsize;
422 		syscallarg(int) flags;
423 	} */
424 
425 	return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize),
426 	    SCARG(uap, flags), netbds32_copyout_statvfs,
427 	    sizeof (struct netbsd32_statvfs), retval);
428 }
429 
430 int
431 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval)
432 {
433 	/* {
434 		syscallarg(const netbsd32_pointer_t) fhp;
435 		syscallarg(netbsd32_size_t) fh_size;
436 		syscallarg(netbsd32_statvfsp_t) buf;
437 		syscallarg(int) flags;
438 	} */
439 	struct statvfs *sb;
440 	int error;
441 
442 	sb = STATVFSBUF_GET();
443 	error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb,
444 	    SCARG(uap, flags));
445 
446 	if (error == 0)
447 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
448 	STATVFSBUF_PUT(sb);
449 
450 	return error;
451 }
452 
453 int
454 netbsd32___futimes50(struct lwp *l, const struct netbsd32___futimes50_args *uap, register_t *retval)
455 {
456 	/* {
457 		syscallarg(int) fd;
458 		syscallarg(const netbsd32_timevalp_t) tptr;
459 	} */
460 	int error;
461 	file_t *fp;
462 	struct timeval tv[2], *tvp;
463 
464 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
465 	if (error != 0)
466 		return error;
467 
468 	/* fd_getvnode() will use the descriptor for us */
469 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
470 		return (error);
471 
472 	error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE);
473 
474 	fd_putfile(SCARG(uap, fd));
475 	return (error);
476 }
477 
478 int
479 netbsd32___getdents30(struct lwp *l,
480     const struct netbsd32___getdents30_args *uap, register_t *retval)
481 {
482 	/* {
483 		syscallarg(int) fd;
484 		syscallarg(netbsd32_charp) buf;
485 		syscallarg(netbsd32_size_t) count;
486 	} */
487 	file_t *fp;
488 	int error, done;
489 
490 	/* fd_getvnode() will use the descriptor for us */
491 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
492 		return (error);
493 	if ((fp->f_flag & FREAD) == 0) {
494 		error = EBADF;
495 		goto out;
496 	}
497 	error = vn_readdir(fp, SCARG_P32(uap, buf),
498 	    UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
499 	*retval = done;
500  out:
501 	fd_putfile(SCARG(uap, fd));
502 	return (error);
503 }
504 
505 int
506 netbsd32___lutimes50(struct lwp *l,
507     const struct netbsd32___lutimes50_args *uap, register_t *retval)
508 {
509 	/* {
510 		syscallarg(const netbsd32_charp) path;
511 		syscallarg(const netbsd32_timevalp_t) tptr;
512 	} */
513 	int error;
514 	struct timeval tv[2], *tvp;
515 
516 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
517 	if (error != 0)
518 		return error;
519 
520 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW,
521 			    tvp, UIO_SYSSPACE);
522 }
523 
524 int
525 netbsd32___stat50(struct lwp *l, const struct netbsd32___stat50_args *uap, register_t *retval)
526 {
527 	/* {
528 		syscallarg(const netbsd32_charp) path;
529 		syscallarg(netbsd32_statp_t) ub;
530 	} */
531 	struct netbsd32_stat sb32;
532 	struct stat sb;
533 	int error;
534 	const char *path;
535 
536 	path = SCARG_P32(uap, path);
537 
538 	error = do_sys_stat(path, FOLLOW, &sb);
539 	if (error)
540 		return (error);
541 	netbsd32_from_stat(&sb, &sb32);
542 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
543 	return (error);
544 }
545 
546 int
547 netbsd32___fstat50(struct lwp *l, const struct netbsd32___fstat50_args *uap, register_t *retval)
548 {
549 	/* {
550 		syscallarg(int) fd;
551 		syscallarg(netbsd32_statp_t) sb;
552 	} */
553 	struct netbsd32_stat sb32;
554 	struct stat ub;
555 	int error;
556 
557 	error = do_sys_fstat(SCARG(uap, fd), &ub);
558 	if (error == 0) {
559 		netbsd32_from_stat(&ub, &sb32);
560 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32));
561 	}
562 	return (error);
563 }
564 
565 int
566 netbsd32___lstat50(struct lwp *l, const struct netbsd32___lstat50_args *uap, register_t *retval)
567 {
568 	/* {
569 		syscallarg(const netbsd32_charp) path;
570 		syscallarg(netbsd32_statp_t) ub;
571 	} */
572 	struct netbsd32_stat sb32;
573 	struct stat sb;
574 	int error;
575 	const char *path;
576 
577 	path = SCARG_P32(uap, path);
578 
579 	error = do_sys_stat(path, NOFOLLOW, &sb);
580 	if (error)
581 		return (error);
582 	netbsd32_from_stat(&sb, &sb32);
583 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
584 	return (error);
585 }
586 
587 int
588 netbsd32___fhstat50(struct lwp *l, const struct netbsd32___fhstat50_args *uap, register_t *retval)
589 {
590 	/* {
591 		syscallarg(const netbsd32_pointer_t) fhp;
592 		syscallarg(netbsd32_size_t) fh_size;
593 		syscallarg(netbsd32_statp_t) sb;
594 	} */
595 	struct stat sb;
596 	struct netbsd32_stat sb32;
597 	int error;
598 
599 	error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb);
600 	if (error == 0) {
601 		netbsd32_from_stat(&sb, &sb32);
602 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb));
603 	}
604 	return error;
605 }
606 
607 int
608 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval)
609 {
610 	/* {
611 		syscallarg(int) fd;
612 		syscallarg(const netbsd32_iovecp_t) iovp;
613 		syscallarg(int) iovcnt;
614 		syscallarg(int) pad;
615 		syscallarg(off_t) offset;
616 	} */
617 	file_t *fp;
618 	struct vnode *vp;
619 	off_t offset;
620 	int error, fd = SCARG(uap, fd);
621 
622 	if ((fp = fd_getfile(fd)) == NULL)
623 		return (EBADF);
624 
625 	if ((fp->f_flag & FREAD) == 0) {
626 		fd_putfile(fd);
627 		return (EBADF);
628 	}
629 
630 	vp = fp->f_data;
631 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
632 		error = ESPIPE;
633 		goto out;
634 	}
635 
636 	offset = SCARG(uap, offset);
637 
638 	/*
639 	 * XXX This works because no file systems actually
640 	 * XXX take any action on the seek operation.
641 	 */
642 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
643 		goto out;
644 
645 	return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp),
646 	    SCARG(uap, iovcnt), &offset, 0, retval));
647 
648 out:
649 	fd_putfile(fd);
650 	return (error);
651 }
652 
653 int
654 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval)
655 {
656 	/* {
657 		syscallarg(int) fd;
658 		syscallarg(const netbsd32_iovecp_t) iovp;
659 		syscallarg(int) iovcnt;
660 		syscallarg(int) pad;
661 		syscallarg(off_t) offset;
662 	} */
663 	file_t *fp;
664 	struct vnode *vp;
665 	off_t offset;
666 	int error, fd = SCARG(uap, fd);
667 
668 	if ((fp = fd_getfile(fd)) == NULL)
669 		return (EBADF);
670 
671 	if ((fp->f_flag & FWRITE) == 0) {
672 		fd_putfile(fd);
673 		return (EBADF);
674 	}
675 
676 	vp = fp->f_data;
677 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
678 		error = ESPIPE;
679 		goto out;
680 	}
681 
682 	offset = SCARG(uap, offset);
683 
684 	/*
685 	 * XXX This works because no file systems actually
686 	 * XXX take any action on the seek operation.
687 	 */
688 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
689 		goto out;
690 
691 	return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp),
692 	    SCARG(uap, iovcnt), &offset, 0, retval));
693 
694 out:
695 	fd_putfile(fd);
696 	return (error);
697 }
698 
699 /*
700  * Find pathname of process's current directory.
701  *
702  * Use vfs vnode-to-name reverse cache; if that fails, fall back
703  * to reading directory contents.
704  */
705 /* XXX NH Why does this exist */
706 int
707 getcwd_common(struct vnode *, struct vnode *,
708 		   char **, char *, int, int, struct lwp *);
709 
710 int
711 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval)
712 {
713 	/* {
714 		syscallarg(char *) bufp;
715 		syscallarg(size_t) length;
716 	} */
717 	struct proc *p = l->l_proc;
718 	int     error;
719 	char   *path;
720 	char   *bp, *bend;
721 	int     len = (int)SCARG(uap, length);
722 	int	lenused;
723 	struct	cwdinfo *cwdi;
724 
725 	if (len > MAXPATHLEN*4)
726 		len = MAXPATHLEN*4;
727 	else if (len < 2)
728 		return ERANGE;
729 
730 	path = kmem_alloc(len, KM_SLEEP);
731 	if (!path)
732 		return ENOMEM;
733 
734 	bp = &path[len];
735 	bend = bp;
736 	*(--bp) = '\0';
737 
738 	/*
739 	 * 5th argument here is "max number of vnodes to traverse".
740 	 * Since each entry takes up at least 2 bytes in the output buffer,
741 	 * limit it to N/2 vnodes for an N byte buffer.
742 	 */
743 #define GETCWD_CHECK_ACCESS 0x0001
744 	cwdi = p->p_cwdi;
745 	rw_enter(&cwdi->cwdi_lock, RW_READER);
746 	error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2,
747 			       GETCWD_CHECK_ACCESS, l);
748 	rw_exit(&cwdi->cwdi_lock);
749 
750 	if (error)
751 		goto out;
752 	lenused = bend - bp;
753 	*retval = lenused;
754 	/* put the result into user buffer */
755 	error = copyout(bp, SCARG_P32(uap, bufp), lenused);
756 
757 out:
758 	kmem_free(path, len);
759 	return error;
760 }
761 
762 int
763 netbsd32___mount50(struct lwp *l, const struct netbsd32___mount50_args *uap,
764 	register_t *retval)
765 {
766 	/* {
767 		syscallarg(netbsd32_charp) type;
768 		syscallarg(netbsd32_charp) path;
769 		syscallarg(int) flags;
770 		syscallarg(netbsd32_voidp) data;
771 		syscallarg(netbsd32_size_t) data_len;
772 	} */
773 	char mtype[MNAMELEN];
774 	union {
775 		struct netbsd32_ufs_args ufs_args;
776 		struct netbsd32_mfs_args mfs_args;
777 		struct netbsd32_iso_args iso_args;
778 		struct netbsd32_nfs_args nfs_args;
779 		struct netbsd32_msdosfs_args msdosfs_args;
780 	} fs_args32;
781 	union {
782 		struct ufs_args ufs_args;
783 		struct mfs_args mfs_args;
784 		struct iso_args iso_args;
785 		struct nfs_args nfs_args;
786 		struct msdosfs_args msdosfs_args;
787 	} fs_args;
788 	const char *type = SCARG_P32(uap, type);
789 	const char *path = SCARG_P32(uap, path);
790 	int flags = SCARG(uap, flags);
791 	void *data = SCARG_P32(uap, data);
792 	size_t data_len = SCARG(uap, data_len);
793 	enum uio_seg data_seg;
794 	size_t len;
795 	int error;
796 
797 	error = copyinstr(type, mtype, sizeof(mtype), &len);
798 	if (error)
799 		return error;
800 	if (strcmp(mtype, MOUNT_MFS) == 0) {
801 		if (data_len != sizeof(fs_args32.mfs_args))
802 			return EINVAL;
803 		if ((flags & MNT_GETARGS) == 0) {
804 			error = copyin(data, &fs_args32.mfs_args,
805 			    sizeof(fs_args32.mfs_args));
806 			if (error)
807 				return error;
808 			fs_args.mfs_args.fspec =
809 			    NETBSD32PTR64(fs_args32.mfs_args.fspec);
810 			memset(&fs_args.mfs_args._pad1, 0,
811 			    sizeof(fs_args.mfs_args._pad1));
812 			fs_args.mfs_args.base =
813 			    NETBSD32PTR64(fs_args32.mfs_args.base);
814 			fs_args.mfs_args.size = fs_args32.mfs_args.size;
815 		}
816 		data_seg = UIO_SYSSPACE;
817 		data = &fs_args.mfs_args;
818 		data_len = sizeof(fs_args.mfs_args);
819 	} else if ((strcmp(mtype, MOUNT_UFS) == 0) ||
820 		   (strcmp(mtype, MOUNT_EXT2FS) == 0) ||
821 		   (strcmp(mtype, MOUNT_LFS) == 0)) {
822 		if (data_len > sizeof(fs_args32.ufs_args))
823 			return EINVAL;
824 		if ((flags & MNT_GETARGS) == 0) {
825 			error = copyin(data, &fs_args32.ufs_args,
826 			    sizeof(fs_args32.ufs_args));
827 			if (error)
828 				return error;
829 			fs_args.ufs_args.fspec =
830 			    NETBSD32PTR64(fs_args32.ufs_args.fspec);
831 		}
832 		data_seg = UIO_SYSSPACE;
833 		data = &fs_args.ufs_args;
834 		data_len = sizeof(fs_args.ufs_args);
835 	} else if (strcmp(mtype, MOUNT_CD9660) == 0) {
836 		if (data_len != sizeof(fs_args32.iso_args))
837 			return EINVAL;
838 		if ((flags & MNT_GETARGS) == 0) {
839 			error = copyin(data, &fs_args32.iso_args,
840 			    sizeof(fs_args32.iso_args));
841 			if (error)
842 				return error;
843 			fs_args.iso_args.fspec =
844 			    NETBSD32PTR64(fs_args32.iso_args.fspec);
845 			memset(&fs_args.iso_args._pad1, 0,
846 			    sizeof(fs_args.iso_args._pad1));
847 			fs_args.iso_args.flags = fs_args32.iso_args.flags;
848 		}
849 		data_seg = UIO_SYSSPACE;
850 		data = &fs_args.iso_args;
851 		data_len = sizeof(fs_args.iso_args);
852 	} else if (strcmp(mtype, MOUNT_MSDOS) == 0) {
853 		if (data_len != sizeof(fs_args32.msdosfs_args))
854 			return EINVAL;
855 		if ((flags & MNT_GETARGS) == 0) {
856 			error = copyin(data, &fs_args32.msdosfs_args,
857 			    sizeof(fs_args32.msdosfs_args));
858 			if (error)
859 				return error;
860 			fs_args.msdosfs_args.fspec =
861 			    NETBSD32PTR64(fs_args32.msdosfs_args.fspec);
862 			memset(&fs_args.msdosfs_args._pad1, 0,
863 			    sizeof(fs_args.msdosfs_args._pad1));
864 			fs_args.msdosfs_args.uid =
865 			    fs_args32.msdosfs_args.uid;
866 			fs_args.msdosfs_args.gid =
867 			    fs_args32.msdosfs_args.gid;
868 			fs_args.msdosfs_args.mask =
869 			    fs_args32.msdosfs_args.mask;
870 			fs_args.msdosfs_args.flags =
871 			    fs_args32.msdosfs_args.flags;
872 			fs_args.msdosfs_args.version =
873 			    fs_args32.msdosfs_args.version;
874 			fs_args.msdosfs_args.dirmask =
875 			    fs_args32.msdosfs_args.dirmask;
876 			fs_args.msdosfs_args.gmtoff =
877 			    fs_args32.msdosfs_args.gmtoff;
878 		}
879 		data_seg = UIO_SYSSPACE;
880 		data = &fs_args.msdosfs_args;
881 		data_len = sizeof(fs_args.msdosfs_args);
882 	} else if (strcmp(mtype, MOUNT_NFS) == 0) {
883 		if (data_len != sizeof(fs_args32.nfs_args))
884 			return EINVAL;
885 		if ((flags & MNT_GETARGS) == 0) {
886 			error = copyin(data, &fs_args32.nfs_args,
887 			    sizeof(fs_args32.nfs_args));
888 			if (error)
889 				return error;
890 			fs_args.nfs_args.version = fs_args32.nfs_args.version;
891 			fs_args.nfs_args.addr =
892 			    NETBSD32PTR64(fs_args32.nfs_args.addr);
893 			memcpy(&fs_args.nfs_args.addrlen,
894 			    &fs_args32.nfs_args.addrlen,
895 			    offsetof(struct nfs_args, fh)
896 				- offsetof(struct nfs_args, addrlen));
897 			fs_args.nfs_args.fh =
898 			    NETBSD32PTR64(fs_args32.nfs_args.fh);
899 			memcpy(&fs_args.nfs_args.fhsize,
900 			    &fs_args32.nfs_args.fhsize,
901 			    offsetof(struct nfs_args, hostname)
902 				- offsetof(struct nfs_args, fhsize));
903 			fs_args.nfs_args.hostname =
904 			    NETBSD32PTR64(fs_args32.nfs_args.hostname);
905 		}
906 		data_seg = UIO_SYSSPACE;
907 		data = &fs_args.nfs_args;
908 		data_len = sizeof(fs_args.nfs_args);
909 	} else {
910 		data_seg = UIO_USERSPACE;
911 	}
912 	error = do_sys_mount(l, NULL, type, path, flags, data, data_seg,
913 	    data_len, retval);
914 	if (error)
915 		return error;
916 	if (flags & MNT_GETARGS) {
917 		data_len = *retval;
918 		if (strcmp(mtype, MOUNT_MFS) == 0) {
919 			if (data_len != sizeof(fs_args.mfs_args))
920 				return EINVAL;
921 			NETBSD32PTR32(fs_args32.mfs_args.fspec,
922 			    fs_args.mfs_args.fspec);
923 			memset(&fs_args32.mfs_args._pad1, 0,
924 			    sizeof(fs_args32.mfs_args._pad1));
925 			NETBSD32PTR32(fs_args32.mfs_args.base,
926 			    fs_args.mfs_args.base);
927 			fs_args32.mfs_args.size = fs_args.mfs_args.size;
928 			error = copyout(&fs_args32.mfs_args, data,
929 				    sizeof(fs_args32.mfs_args));
930 		} else if (strcmp(mtype, MOUNT_UFS) == 0) {
931 			if (data_len != sizeof(fs_args.ufs_args))
932 				return EINVAL;
933 			NETBSD32PTR32(fs_args32.ufs_args.fspec,
934 			    fs_args.ufs_args.fspec);
935 			error = copyout(&fs_args32.ufs_args, data,
936 			    sizeof(fs_args32.ufs_args));
937 		} else if (strcmp(mtype, MOUNT_CD9660) == 0) {
938 			if (data_len != sizeof(fs_args.iso_args))
939 				return EINVAL;
940 			NETBSD32PTR32(fs_args32.iso_args.fspec,
941 			    fs_args.iso_args.fspec);
942 			memset(&fs_args32.iso_args._pad1, 0,
943 			    sizeof(fs_args32.iso_args._pad1));
944 			fs_args32.iso_args.flags = fs_args.iso_args.flags;
945 			error = copyout(&fs_args32.iso_args, data,
946 				    sizeof(fs_args32.iso_args));
947 		} else if (strcmp(mtype, MOUNT_NFS) == 0) {
948 			if (data_len != sizeof(fs_args.nfs_args))
949 				return EINVAL;
950 			error = copyin(data, &fs_args32.nfs_args,
951 			    sizeof(fs_args32.nfs_args));
952 			if (error)
953 				return error;
954 			fs_args.nfs_args.version = fs_args32.nfs_args.version;
955 			NETBSD32PTR32(fs_args32.nfs_args.addr,
956 			    fs_args.nfs_args.addr);
957 			memcpy(&fs_args32.nfs_args.addrlen,
958 			    &fs_args.nfs_args.addrlen,
959 			    offsetof(struct nfs_args, fh)
960 				- offsetof(struct nfs_args, addrlen));
961 			NETBSD32PTR32(fs_args32.nfs_args.fh,
962 			    fs_args.nfs_args.fh);
963 			memcpy(&fs_args32.nfs_args.fhsize,
964 			    &fs_args.nfs_args.fhsize,
965 			    offsetof(struct nfs_args, hostname)
966 				- offsetof(struct nfs_args, fhsize));
967 			NETBSD32PTR32(fs_args32.nfs_args.hostname,
968 			    fs_args.nfs_args.hostname);
969 			error = copyout(&fs_args32.nfs_args, data,
970 			    sizeof(fs_args32.nfs_args));
971 		}
972 	}
973 	return error;
974 }
975