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