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