netbsd32_fs.c revision 1.62 1 /* $NetBSD: netbsd32_fs.c,v 1.62 2012/01/25 14:06:07 christos 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.62 2012/01/25 14:06:07 christos 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 && (fp->f_flag & FNOSIGPIPE) == 0) {
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