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