netbsd32_fs.c revision 1.11 1 /* $NetBSD: netbsd32_fs.c,v 1.11 2003/01/18 08:28:26 thorpej 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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.11 2003/01/18 08:28:26 thorpej Exp $");
33
34 #if defined(_KERNEL_OPT)
35 #include "opt_ktrace.h"
36 #endif
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include <sys/ktrace.h>
47 #include <sys/resourcevar.h>
48 #include <sys/vnode.h>
49 #include <sys/file.h>
50 #include <sys/filedesc.h>
51 #include <sys/namei.h>
52 #include <sys/sa.h>
53 #include <sys/syscallargs.h>
54 #include <sys/proc.h>
55
56 #include <compat/netbsd32/netbsd32.h>
57 #include <compat/netbsd32/netbsd32_syscallargs.h>
58 #include <compat/netbsd32/netbsd32_conv.h>
59
60
61 static int dofilereadv32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *,
62 int, off_t *, int, register_t *));
63 static int dofilewritev32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *,
64 int, off_t *, int, register_t *));
65 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct proc *));
66
67 int
68 netbsd32_getfsstat(l, v, retval)
69 struct lwp *l;
70 void *v;
71 register_t *retval;
72 {
73 struct netbsd32_getfsstat_args /* {
74 syscallarg(netbsd32_statfsp_t) buf;
75 syscallarg(netbsd32_long) bufsize;
76 syscallarg(int) flags;
77 } */ *uap = v;
78 struct mount *mp, *nmp;
79 struct statfs *sp;
80 struct netbsd32_statfs sb32;
81 caddr_t sfsp;
82 long count, maxcount, error;
83 struct proc *p = l->l_proc;
84
85 maxcount = SCARG(uap, bufsize) / sizeof(struct netbsd32_statfs);
86 sfsp = (caddr_t)NETBSD32PTR64(SCARG(uap, buf));
87 simple_lock(&mountlist_slock);
88 count = 0;
89 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
90 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
91 nmp = mp->mnt_list.cqe_next;
92 continue;
93 }
94 if (sfsp && count < maxcount) {
95 sp = &mp->mnt_stat;
96 /*
97 * If MNT_NOWAIT or MNT_LAZY is specified, do not
98 * refresh the fsstat cache. MNT_WAIT or MNT_LAXY
99 * overrides MNT_NOWAIT.
100 */
101 if (SCARG(uap, flags) != MNT_NOWAIT &&
102 SCARG(uap, flags) != MNT_LAZY &&
103 (SCARG(uap, flags) == MNT_WAIT ||
104 SCARG(uap, flags) == 0) &&
105 (error = VFS_STATFS(mp, sp, p)) != 0) {
106 simple_lock(&mountlist_slock);
107 nmp = mp->mnt_list.cqe_next;
108 vfs_unbusy(mp);
109 continue;
110 }
111 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
112 sp->f_oflags = sp->f_flags & 0xffff;
113 netbsd32_from_statfs(sp, &sb32);
114 error = copyout(&sb32, sfsp, sizeof(sb32));
115 if (error) {
116 vfs_unbusy(mp);
117 return (error);
118 }
119 sfsp += sizeof(sb32);
120 }
121 count++;
122 simple_lock(&mountlist_slock);
123 nmp = mp->mnt_list.cqe_next;
124 vfs_unbusy(mp);
125 }
126 simple_unlock(&mountlist_slock);
127 if (sfsp && count > maxcount)
128 *retval = maxcount;
129 else
130 *retval = count;
131 return (0);
132 }
133
134 int
135 netbsd32_readv(l, v, retval)
136 struct lwp *l;
137 void *v;
138 register_t *retval;
139 {
140 struct netbsd32_readv_args /* {
141 syscallarg(int) fd;
142 syscallarg(const netbsd32_iovecp_t) iovp;
143 syscallarg(int) iovcnt;
144 } */ *uap = v;
145 int fd = SCARG(uap, fd);
146 struct proc *p = l->l_proc;
147 struct file *fp;
148 struct filedesc *fdp = p->p_fd;
149
150 if ((fp = fd_getfile(fdp, fd)) == NULL)
151 return (EBADF);
152
153 if ((fp->f_flag & FREAD) == 0)
154 return (EBADF);
155
156 FILE_USE(fp);
157
158 return (dofilereadv32(p, fd, fp,
159 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
160 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
161 }
162
163 /* Damn thing copies in the iovec! */
164 int
165 dofilereadv32(p, fd, fp, iovp, iovcnt, offset, flags, retval)
166 struct proc *p;
167 int fd;
168 struct file *fp;
169 struct netbsd32_iovec *iovp;
170 int iovcnt;
171 off_t *offset;
172 int flags;
173 register_t *retval;
174 {
175 struct uio auio;
176 struct iovec *iov;
177 struct iovec *needfree;
178 struct iovec aiov[UIO_SMALLIOV];
179 long i, cnt, error = 0;
180 u_int iovlen;
181 #ifdef KTRACE
182 struct iovec *ktriov = NULL;
183 #endif
184
185 /* note: can't use iovlen until iovcnt is validated */
186 iovlen = iovcnt * sizeof(struct iovec);
187 if ((u_int)iovcnt > UIO_SMALLIOV) {
188 if ((u_int)iovcnt > IOV_MAX) {
189 error = EINVAL;
190 goto out;
191 }
192 iov = malloc(iovlen, M_IOV, M_WAITOK);
193 needfree = iov;
194 } else if ((u_int)iovcnt > 0) {
195 iov = aiov;
196 needfree = NULL;
197 } else {
198 error = EINVAL;
199 goto out;
200 }
201
202 auio.uio_iov = iov;
203 auio.uio_iovcnt = iovcnt;
204 auio.uio_rw = UIO_READ;
205 auio.uio_segflg = UIO_USERSPACE;
206 auio.uio_procp = p;
207 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
208 if (error)
209 goto done;
210 auio.uio_resid = 0;
211 for (i = 0; i < iovcnt; i++) {
212 auio.uio_resid += iov->iov_len;
213 /*
214 * Reads return ssize_t because -1 is returned on error.
215 * Therefore we must restrict the length to SSIZE_MAX to
216 * avoid garbage return values.
217 */
218 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
219 error = EINVAL;
220 goto done;
221 }
222 iov++;
223 }
224 #ifdef KTRACE
225 /*
226 * if tracing, save a copy of iovec
227 */
228 if (KTRPOINT(p, KTR_GENIO)) {
229 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
230 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen);
231 }
232 #endif
233 cnt = auio.uio_resid;
234 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
235 if (error)
236 if (auio.uio_resid != cnt && (error == ERESTART ||
237 error == EINTR || error == EWOULDBLOCK))
238 error = 0;
239 cnt -= auio.uio_resid;
240 #ifdef KTRACE
241 if (KTRPOINT(p, KTR_GENIO))
242 if (error == 0) {
243 ktrgenio(p, fd, UIO_READ, ktriov, cnt,
244 error);
245 free(ktriov, M_TEMP);
246 }
247 #endif
248 *retval = cnt;
249 done:
250 if (needfree)
251 free(needfree, M_IOV);
252 out:
253 FILE_UNUSE(fp, p);
254 return (error);
255 }
256
257 int
258 netbsd32_writev(l, v, retval)
259 struct lwp *l;
260 void *v;
261 register_t *retval;
262 {
263 struct netbsd32_writev_args /* {
264 syscallarg(int) fd;
265 syscallarg(const netbsd32_iovecp_t) iovp;
266 syscallarg(int) iovcnt;
267 } */ *uap = v;
268 int fd = SCARG(uap, fd);
269 struct file *fp;
270 struct proc *p = l->l_proc;
271 struct filedesc *fdp = p->p_fd;
272
273 if ((fp = fd_getfile(fdp, fd)) == NULL)
274 return (EBADF);
275
276 if ((fp->f_flag & FWRITE) == 0)
277 return (EBADF);
278
279 FILE_USE(fp);
280
281 return (dofilewritev32(p, fd, fp,
282 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
283 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
284 }
285
286 int
287 dofilewritev32(p, fd, fp, iovp, iovcnt, offset, flags, retval)
288 struct proc *p;
289 int fd;
290 struct file *fp;
291 struct netbsd32_iovec *iovp;
292 int iovcnt;
293 off_t *offset;
294 int flags;
295 register_t *retval;
296 {
297 struct uio auio;
298 struct iovec *iov;
299 struct iovec *needfree;
300 struct iovec aiov[UIO_SMALLIOV];
301 long i, cnt, error = 0;
302 u_int iovlen;
303 #ifdef KTRACE
304 struct iovec *ktriov = NULL;
305 #endif
306
307 /* note: can't use iovlen until iovcnt is validated */
308 iovlen = iovcnt * sizeof(struct iovec);
309 if ((u_int)iovcnt > UIO_SMALLIOV) {
310 if ((u_int)iovcnt > IOV_MAX) {
311 error = EINVAL;
312 goto out;
313 }
314 iov = malloc(iovlen, M_IOV, M_WAITOK);
315 needfree = iov;
316 } else if ((u_int)iovcnt > 0) {
317 iov = aiov;
318 needfree = NULL;
319 } else {
320 error = EINVAL;
321 goto out;
322 }
323
324 auio.uio_iov = iov;
325 auio.uio_iovcnt = iovcnt;
326 auio.uio_rw = UIO_WRITE;
327 auio.uio_segflg = UIO_USERSPACE;
328 auio.uio_procp = p;
329 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
330 if (error)
331 goto done;
332 auio.uio_resid = 0;
333 for (i = 0; i < iovcnt; i++) {
334 auio.uio_resid += iov->iov_len;
335 /*
336 * Writes return ssize_t because -1 is returned on error.
337 * Therefore we must restrict the length to SSIZE_MAX to
338 * avoid garbage return values.
339 */
340 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
341 error = EINVAL;
342 goto done;
343 }
344 iov++;
345 }
346 #ifdef KTRACE
347 /*
348 * if tracing, save a copy of iovec
349 */
350 if (KTRPOINT(p, KTR_GENIO)) {
351 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
352 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen);
353 }
354 #endif
355 cnt = auio.uio_resid;
356 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
357 if (error) {
358 if (auio.uio_resid != cnt && (error == ERESTART ||
359 error == EINTR || error == EWOULDBLOCK))
360 error = 0;
361 if (error == EPIPE)
362 psignal(p, SIGPIPE);
363 }
364 cnt -= auio.uio_resid;
365 #ifdef KTRACE
366 if (KTRPOINT(p, KTR_GENIO))
367 if (error == 0) {
368 ktrgenio(p, fd, UIO_WRITE, ktriov, cnt,
369 error);
370 free(ktriov, M_TEMP);
371 }
372 #endif
373 *retval = cnt;
374 done:
375 if (needfree)
376 free(needfree, M_IOV);
377 out:
378 FILE_UNUSE(fp, p);
379 return (error);
380 }
381
382 int
383 netbsd32_utimes(l, v, retval)
384 struct lwp *l;
385 void *v;
386 register_t *retval;
387 {
388 struct netbsd32_utimes_args /* {
389 syscallarg(const netbsd32_charp) path;
390 syscallarg(const netbsd32_timevalp_t) tptr;
391 } */ *uap = v;
392 int error;
393 struct nameidata nd;
394 struct proc *p = l->l_proc;
395
396 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
397 (char *)NETBSD32PTR64(SCARG(uap, path)), p);
398 if ((error = namei(&nd)) != 0)
399 return (error);
400
401 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p);
402
403 vrele(nd.ni_vp);
404 return (error);
405 }
406
407 /*
408 * Common routine to set access and modification times given a vnode.
409 */
410 static int
411 change_utimes32(vp, tptr, p)
412 struct vnode *vp;
413 netbsd32_timevalp_t tptr;
414 struct proc *p;
415 {
416 struct netbsd32_timeval tv32[2];
417 struct timeval tv[2];
418 struct vattr vattr;
419 int error;
420
421 VATTR_NULL(&vattr);
422 if (tptr == NULL) {
423 microtime(&tv[0]);
424 tv[1] = tv[0];
425 vattr.va_vaflags |= VA_UTIMES_NULL;
426 } else {
427 error = copyin((caddr_t)NETBSD32PTR64(tptr), tv32,
428 sizeof(tv32));
429 if (error)
430 return (error);
431 netbsd32_to_timeval(&tv32[0], &tv[0]);
432 netbsd32_to_timeval(&tv32[1], &tv[1]);
433 }
434 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
435 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
436 vattr.va_atime.tv_sec = tv[0].tv_sec;
437 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
438 vattr.va_mtime.tv_sec = tv[1].tv_sec;
439 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
440 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
441 VOP_UNLOCK(vp, 0);
442 return (error);
443 }
444
445 int
446 netbsd32_statfs(l, v, retval)
447 struct lwp *l;
448 void *v;
449 register_t *retval;
450 {
451 struct netbsd32_statfs_args /* {
452 syscallarg(const netbsd32_charp) path;
453 syscallarg(netbsd32_statfsp_t) buf;
454 } */ *uap = v;
455 struct mount *mp;
456 struct statfs *sp;
457 struct netbsd32_statfs s32;
458 int error;
459 struct nameidata nd;
460 struct proc *p = l->l_proc;
461
462 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
463 (char *)NETBSD32PTR64(SCARG(uap, path)), p);
464 if ((error = namei(&nd)) != 0)
465 return (error);
466 mp = nd.ni_vp->v_mount;
467 sp = &mp->mnt_stat;
468 vrele(nd.ni_vp);
469 if ((error = VFS_STATFS(mp, sp, p)) != 0)
470 return (error);
471 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
472 netbsd32_from_statfs(sp, &s32);
473 return (copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
474 sizeof(s32)));
475 }
476
477 int
478 netbsd32_fstatfs(l, v, retval)
479 struct lwp *l;
480 void *v;
481 register_t *retval;
482 {
483 struct netbsd32_fstatfs_args /* {
484 syscallarg(int) fd;
485 syscallarg(netbsd32_statfsp_t) buf;
486 } */ *uap = v;
487 struct file *fp;
488 struct mount *mp;
489 struct statfs *sp;
490 struct netbsd32_statfs s32;
491 int error;
492 struct proc *p = l->l_proc;
493
494 /* getvnode() will use the descriptor for us */
495 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
496 return (error);
497 mp = ((struct vnode *)fp->f_data)->v_mount;
498 sp = &mp->mnt_stat;
499 if ((error = VFS_STATFS(mp, sp, p)) != 0)
500 goto out;
501 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
502 netbsd32_from_statfs(sp, &s32);
503 error = copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
504 sizeof(s32));
505 out:
506 FILE_UNUSE(fp, p);
507 return (error);
508 }
509
510 int
511 netbsd32_futimes(l, v, retval)
512 struct lwp *l;
513 void *v;
514 register_t *retval;
515 {
516 struct netbsd32_futimes_args /* {
517 syscallarg(int) fd;
518 syscallarg(const netbsd32_timevalp_t) tptr;
519 } */ *uap = v;
520 int error;
521 struct file *fp;
522 struct proc *p = l->l_proc;
523
524 /* getvnode() will use the descriptor for us */
525 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
526 return (error);
527
528 error = change_utimes32((struct vnode *)fp->f_data,
529 SCARG(uap, tptr), p);
530 FILE_UNUSE(fp, p);
531 return (error);
532 }
533
534 int
535 netbsd32_getdents(l, v, retval)
536 struct lwp *l;
537 void *v;
538 register_t *retval;
539 {
540 struct netbsd32_getdents_args /* {
541 syscallarg(int) fd;
542 syscallarg(netbsd32_charp) buf;
543 syscallarg(netbsd32_size_t) count;
544 } */ *uap = v;
545 struct file *fp;
546 int error, done;
547 struct proc *p = l->l_proc;
548
549 /* getvnode() will use the descriptor for us */
550 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
551 return (error);
552 if ((fp->f_flag & FREAD) == 0) {
553 error = EBADF;
554 goto out;
555 }
556 error = vn_readdir(fp, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
557 UIO_USERSPACE, SCARG(uap, count), &done, p, 0, 0);
558 *retval = done;
559 out:
560 FILE_UNUSE(fp, p);
561 return (error);
562 }
563
564 int
565 netbsd32_lutimes(l, v, retval)
566 struct lwp *l;
567 void *v;
568 register_t *retval;
569 {
570 struct netbsd32_lutimes_args /* {
571 syscallarg(const netbsd32_charp) path;
572 syscallarg(const netbsd32_timevalp_t) tptr;
573 } */ *uap = v;
574 int error;
575 struct nameidata nd;
576 struct proc *p = l->l_proc;
577
578 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE,
579 (caddr_t)NETBSD32PTR64(SCARG(uap, path)), p);
580 if ((error = namei(&nd)) != 0)
581 return (error);
582
583 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p);
584
585 vrele(nd.ni_vp);
586 return (error);
587 }
588
589 int
590 netbsd32___stat13(l, v, retval)
591 struct lwp *l;
592 void *v;
593 register_t *retval;
594 {
595 struct netbsd32___stat13_args /* {
596 syscallarg(const netbsd32_charp) path;
597 syscallarg(netbsd32_statp_t) ub;
598 } */ *uap = v;
599 struct netbsd32_stat sb32;
600 struct stat sb;
601 int error;
602 struct nameidata nd;
603 caddr_t sg;
604 const char *path;
605 struct proc *p = l->l_proc;
606
607 path = (char *)NETBSD32PTR64(SCARG(uap, path));
608 sg = stackgap_init(p, 0);
609 CHECK_ALT_EXIST(p, &sg, path);
610
611 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p);
612 if ((error = namei(&nd)) != 0)
613 return (error);
614 error = vn_stat(nd.ni_vp, &sb, p);
615 vput(nd.ni_vp);
616 if (error)
617 return (error);
618 netbsd32_from___stat13(&sb, &sb32);
619 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)),
620 sizeof(sb32));
621 return (error);
622 }
623
624 int
625 netbsd32___fstat13(l, v, retval)
626 struct lwp *l;
627 void *v;
628 register_t *retval;
629 {
630 struct netbsd32___fstat13_args /* {
631 syscallarg(int) fd;
632 syscallarg(netbsd32_statp_t) sb;
633 } */ *uap = v;
634 int fd = SCARG(uap, fd);
635 struct proc *p = l->l_proc;
636 struct filedesc *fdp = p->p_fd;
637 struct file *fp;
638 struct netbsd32_stat sb32;
639 struct stat ub;
640 int error = 0;
641
642 if ((fp = fd_getfile(fdp, fd)) == NULL)
643 return (EBADF);
644
645 FILE_USE(fp);
646 error = (*fp->f_ops->fo_stat)(fp, &ub, p);
647 FILE_UNUSE(fp, p);
648
649 if (error == 0) {
650 netbsd32_from___stat13(&ub, &sb32);
651 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, sb)),
652 sizeof(sb32));
653 }
654 return (error);
655 }
656
657 int
658 netbsd32___lstat13(l, v, retval)
659 struct lwp *l;
660 void *v;
661 register_t *retval;
662 {
663 struct netbsd32___lstat13_args /* {
664 syscallarg(const netbsd32_charp) path;
665 syscallarg(netbsd32_statp_t) ub;
666 } */ *uap = v;
667 struct netbsd32_stat sb32;
668 struct stat sb;
669 int error;
670 struct nameidata nd;
671 caddr_t sg;
672 const char *path;
673 struct proc *p = l->l_proc;
674
675 path = (char *)NETBSD32PTR64(SCARG(uap, path));
676 sg = stackgap_init(p, 0);
677 CHECK_ALT_EXIST(p, &sg, path);
678
679 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p);
680 if ((error = namei(&nd)) != 0)
681 return (error);
682 error = vn_stat(nd.ni_vp, &sb, p);
683 vput(nd.ni_vp);
684 if (error)
685 return (error);
686 netbsd32_from___stat13(&sb, &sb32);
687 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)),
688 sizeof(sb32));
689 return (error);
690 }
691
692 int
693 netbsd32_preadv(l, v, retval)
694 struct lwp *l;
695 void *v;
696 register_t *retval;
697 {
698 struct netbsd32_preadv_args /* {
699 syscallarg(int) fd;
700 syscallarg(const netbsd32_iovecp_t) iovp;
701 syscallarg(int) iovcnt;
702 syscallarg(int) pad;
703 syscallarg(off_t) offset;
704 } */ *uap = v;
705 struct proc *p = l->l_proc;
706 struct filedesc *fdp = p->p_fd;
707 struct file *fp;
708 struct vnode *vp;
709 off_t offset;
710 int error, fd = SCARG(uap, fd);
711
712 if ((fp = fd_getfile(fdp, fd)) == NULL)
713 return (EBADF);
714
715 if ((fp->f_flag & FREAD) == 0)
716 return (EBADF);
717
718 FILE_USE(fp);
719
720 vp = (struct vnode *)fp->f_data;
721 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
722 error = ESPIPE;
723 goto out;
724 }
725
726 offset = SCARG(uap, offset);
727
728 /*
729 * XXX This works because no file systems actually
730 * XXX take any action on the seek operation.
731 */
732 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
733 goto out;
734
735 return (dofilereadv32(p, fd, fp,
736 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
737 SCARG(uap, iovcnt), &offset, 0, retval));
738
739 out:
740 FILE_UNUSE(fp, p);
741 return (error);
742 }
743
744 int
745 netbsd32_pwritev(l, v, retval)
746 struct lwp *l;
747 void *v;
748 register_t *retval;
749 {
750 struct netbsd32_pwritev_args /* {
751 syscallarg(int) fd;
752 syscallarg(const netbsd32_iovecp_t) iovp;
753 syscallarg(int) iovcnt;
754 syscallarg(int) pad;
755 syscallarg(off_t) offset;
756 } */ *uap = v;
757 struct proc *p = l->l_proc;
758 struct filedesc *fdp = p->p_fd;
759 struct file *fp;
760 struct vnode *vp;
761 off_t offset;
762 int error, fd = SCARG(uap, fd);
763
764 if ((fp = fd_getfile(fdp, fd)) == NULL)
765 return (EBADF);
766
767 if ((fp->f_flag & FWRITE) == 0)
768 return (EBADF);
769
770 FILE_USE(fp);
771
772 vp = (struct vnode *)fp->f_data;
773 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
774 error = ESPIPE;
775 goto out;
776 }
777
778 offset = SCARG(uap, offset);
779
780 /*
781 * XXX This works because no file systems actually
782 * XXX take any action on the seek operation.
783 */
784 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
785 goto out;
786
787 return (dofilewritev32(p, fd, fp,
788 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
789 SCARG(uap, iovcnt), &offset, 0, retval));
790
791 out:
792 FILE_UNUSE(fp, p);
793 return (error);
794 }
795
796 /*
797 * Find pathname of process's current directory.
798 *
799 * Use vfs vnode-to-name reverse cache; if that fails, fall back
800 * to reading directory contents.
801 */
802 int
803 getcwd_common __P((struct vnode *, struct vnode *,
804 char **, char *, int, int, struct proc *));
805
806 int netbsd32___getcwd(l, v, retval)
807 struct lwp *l;
808 void *v;
809 register_t *retval;
810 {
811 struct netbsd32___getcwd_args /* {
812 syscallarg(char *) bufp;
813 syscallarg(size_t) length;
814 } */ *uap = v;
815 struct proc *p = l->l_proc;
816 int error;
817 char *path;
818 char *bp, *bend;
819 int len = (int)SCARG(uap, length);
820 int lenused;
821
822 if (len > MAXPATHLEN*4)
823 len = MAXPATHLEN*4;
824 else if (len < 2)
825 return ERANGE;
826
827 path = (char *)malloc(len, M_TEMP, M_WAITOK);
828 if (!path)
829 return ENOMEM;
830
831 bp = &path[len];
832 bend = bp;
833 *(--bp) = '\0';
834
835 /*
836 * 5th argument here is "max number of vnodes to traverse".
837 * Since each entry takes up at least 2 bytes in the output buffer,
838 * limit it to N/2 vnodes for an N byte buffer.
839 */
840 #define GETCWD_CHECK_ACCESS 0x0001
841 error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2,
842 GETCWD_CHECK_ACCESS, p);
843
844 if (error)
845 goto out;
846 lenused = bend - bp;
847 *retval = lenused;
848 /* put the result into user buffer */
849 error = copyout(bp, (caddr_t)NETBSD32PTR64(SCARG(uap, bufp)), lenused);
850
851 out:
852 free(path, M_TEMP);
853 return error;
854 }
855