netbsd32_fs.c revision 1.36 1 /* $NetBSD: netbsd32_fs.c,v 1.36 2007/03/04 06:01:26 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 * 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.36 2007/03/04 06:01:26 christos 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
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 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
65 int, off_t *, int, register_t *));
66 static int dofilewritev32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
67 int, off_t *, int, register_t *));
68 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct lwp *));
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 *)NETBSD32PTR64(SCARG(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 *)NETBSD32PTR64(SCARG(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 psignal(p, SIGPIPE);
298 }
299 cnt -= auio.uio_resid;
300 #ifdef KTRACE
301 if (KTRPOINT(p, KTR_GENIO))
302 if (error == 0) {
303 ktrgenio(l, fd, UIO_WRITE, ktriov, cnt,
304 error);
305 free(ktriov, M_TEMP);
306 }
307 #endif
308 *retval = cnt;
309 done:
310 if (needfree)
311 free(needfree, M_IOV);
312 out:
313 FILE_UNUSE(fp, l);
314 return (error);
315 }
316
317 int
318 netbsd32_utimes(l, v, retval)
319 struct lwp *l;
320 void *v;
321 register_t *retval;
322 {
323 struct netbsd32_utimes_args /* {
324 syscallarg(const netbsd32_charp) path;
325 syscallarg(const netbsd32_timevalp_t) tptr;
326 } */ *uap = v;
327 int error;
328 struct nameidata nd;
329
330 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
331 (char *)NETBSD32PTR64(SCARG(uap, path)), l);
332 if ((error = namei(&nd)) != 0)
333 return (error);
334
335 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l);
336
337 vrele(nd.ni_vp);
338 return (error);
339 }
340
341 /*
342 * Common routine to set access and modification times given a vnode.
343 */
344 static int
345 change_utimes32(vp, tptr, l)
346 struct vnode *vp;
347 netbsd32_timevalp_t tptr;
348 struct lwp *l;
349 {
350 struct netbsd32_timeval tv32[2];
351 struct timeval tv[2];
352 struct vattr vattr;
353 int error;
354
355 VATTR_NULL(&vattr);
356 if (tptr == 0) {
357 microtime(&tv[0]);
358 tv[1] = tv[0];
359 vattr.va_vaflags |= VA_UTIMES_NULL;
360 } else {
361 error = copyin((void *)NETBSD32PTR64(tptr), tv32,
362 sizeof(tv32));
363 if (error)
364 return (error);
365 netbsd32_to_timeval(&tv32[0], &tv[0]);
366 netbsd32_to_timeval(&tv32[1], &tv[1]);
367 }
368 VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
369 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
370 vattr.va_atime.tv_sec = tv[0].tv_sec;
371 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
372 vattr.va_mtime.tv_sec = tv[1].tv_sec;
373 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
374 error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
375 VOP_UNLOCK(vp, 0);
376 return (error);
377 }
378
379 int
380 netbsd32_statvfs1(l, v, retval)
381 struct lwp *l;
382 void *v;
383 register_t *retval;
384 {
385 struct netbsd32_statvfs1_args /* {
386 syscallarg(const netbsd32_charp) path;
387 syscallarg(netbsd32_statvfsp_t) buf;
388 syscallarg(int) flags;
389 } */ *uap = v;
390 struct mount *mp;
391 struct statvfs *sbuf;
392 struct netbsd32_statvfs *s32;
393 struct nameidata nd;
394 int error;
395
396 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
397 (char *)NETBSD32PTR64(SCARG(uap, path)), l);
398 if ((error = namei(&nd)) != 0)
399 return (error);
400 /* Allocating on the stack would blow it up */
401 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP,
402 M_WAITOK);
403 mp = nd.ni_vp->v_mount;
404 vrele(nd.ni_vp);
405 if ((error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 1)) != 0)
406 goto out;
407 s32 = (struct netbsd32_statvfs *)
408 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK);
409 netbsd32_from_statvfs(sbuf, s32);
410 error = copyout(s32, (void *)NETBSD32PTR64(SCARG(uap, buf)),
411 sizeof(struct netbsd32_statvfs));
412 free(s32, M_TEMP);
413 out:
414 free(sbuf, M_TEMP);
415 return (error);
416 }
417
418 int
419 netbsd32_fstatvfs1(l, v, retval)
420 struct lwp *l;
421 void *v;
422 register_t *retval;
423 {
424 struct netbsd32_fstatvfs1_args /* {
425 syscallarg(int) fd;
426 syscallarg(netbsd32_statvfsp_t) buf;
427 syscallarg(int) flags;
428 } */ *uap = v;
429 struct proc *p = l->l_proc;
430 struct file *fp;
431 struct mount *mp;
432 struct statvfs *sbuf;
433 struct netbsd32_statvfs *s32;
434 int error;
435
436 /* getvnode() will use the descriptor for us */
437 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
438 return (error);
439 mp = ((struct vnode *)fp->f_data)->v_mount;
440 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP,
441 M_WAITOK);
442 if ((error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 1)) != 0)
443 goto out;
444 s32 = (struct netbsd32_statvfs *)
445 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK);
446 netbsd32_from_statvfs(sbuf, s32);
447 error = copyout(s32, (void *)NETBSD32PTR64(SCARG(uap, buf)),
448 sizeof(struct netbsd32_statvfs));
449 free(s32, M_TEMP);
450 out:
451 free(sbuf, M_TEMP);
452 FILE_UNUSE(fp, l);
453 return error;
454 }
455
456 int
457 netbsd32_getvfsstat(l, v, retval)
458 struct lwp *l;
459 void *v;
460 register_t *retval;
461 {
462 struct netbsd32_getvfsstat_args /* {
463 syscallarg(netbsd32_statvfsp_t) buf;
464 syscallarg(netbsd32_size_t) bufsize;
465 syscallarg(int) flags;
466 } */ *uap = v;
467 int root = 0;
468 struct proc *p = l->l_proc;
469 struct mount *mp, *nmp;
470 struct statvfs *sbuf;
471 struct netbsd32_statvfs *sfsp;
472 struct netbsd32_statvfs *s32;
473 size_t count, maxcount;
474 int error = 0;
475
476 maxcount = SCARG(uap, bufsize) / sizeof(struct netbsd32_statvfs);
477 sfsp = (struct netbsd32_statvfs *)NETBSD32PTR64(SCARG(uap, buf));
478 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP,
479 M_WAITOK);
480 s32 = (struct netbsd32_statvfs *)
481 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK);
482 simple_lock(&mountlist_slock);
483 count = 0;
484 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
485 mp = nmp) {
486 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
487 nmp = CIRCLEQ_NEXT(mp, mnt_list);
488 continue;
489 }
490 if (sfsp && count < maxcount) {
491 error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 0);
492 if (error) {
493 simple_lock(&mountlist_slock);
494 nmp = CIRCLEQ_NEXT(mp, mnt_list);
495 vfs_unbusy(mp);
496 continue;
497 }
498 netbsd32_from_statvfs(sbuf, s32);
499 error = copyout(s32, sfsp, sizeof(*sfsp));
500 if (error) {
501 vfs_unbusy(mp);
502 goto out;
503 }
504 sfsp++;
505 root |= strcmp(sbuf->f_mntonname, "/") == 0;
506 }
507 count++;
508 simple_lock(&mountlist_slock);
509 nmp = CIRCLEQ_NEXT(mp, mnt_list);
510 vfs_unbusy(mp);
511 }
512 simple_unlock(&mountlist_slock);
513 if (root == 0 && p->p_cwdi->cwdi_rdir) {
514 /*
515 * fake a root entry
516 */
517 if ((error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, sbuf, l,
518 SCARG(uap, flags), 1)) != 0)
519 goto out;
520 if (sfsp) {
521 netbsd32_from_statvfs(sbuf, s32);
522 error = copyout(s32, sfsp, sizeof(*sfsp));
523 }
524 count++;
525 }
526 if (sfsp && count > maxcount)
527 *retval = maxcount;
528 else
529 *retval = count;
530
531 out:
532 free(s32, M_TEMP);
533 free(sbuf, M_TEMP);
534 return (error);
535 }
536
537 int
538 netbsd32___fhstatvfs140(l, v, retval)
539 struct lwp *l;
540 void *v;
541 register_t *retval;
542 {
543 struct netbsd32___fhstatvfs140_args /* {
544 syscallarg(const netbsd32_pointer_t) fhp;
545 syscallarg(netbsd32_size_t) fh_size;
546 syscallarg(netbsd32_statvfsp_t) buf;
547 syscallarg(int) flags;
548 } */ *uap = v;
549 struct statvfs *sbuf;
550 struct netbsd32_statvfs *s32;
551 fhandle_t *fh;
552 struct vnode *vp;
553 int error;
554
555 /*
556 * Must be super user
557 */
558 if ((error = kauth_authorize_system(l->l_cred,
559 KAUTH_SYSTEM_FILEHANDLE, 0, NULL, NULL, NULL)) != 0)
560 return error;
561
562 if ((error = vfs_copyinfh_alloc(NETBSD32PTR64(SCARG(uap, fhp)),
563 SCARG(uap, fh_size), &fh)) != 0)
564 goto bad;
565 if ((error = vfs_fhtovp(fh, &vp)) != 0)
566 goto bad;
567
568 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP,
569 M_WAITOK);
570 error = dostatvfs(vp->v_mount, sbuf, l, SCARG(uap, flags), 1);
571 vput(vp);
572 if (error != 0)
573 goto out;
574
575 s32 = (struct netbsd32_statvfs *)
576 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK);
577 netbsd32_from_statvfs(sbuf, s32);
578 error = copyout(s32, (void *)NETBSD32PTR64(SCARG(uap, buf)),
579 sizeof(struct netbsd32_statvfs));
580 free(s32, M_TEMP);
581
582 out:
583 free(sbuf, M_TEMP);
584 bad:
585 vfs_copyinfh_free(fh);
586 return (error);
587 }
588
589 int
590 netbsd32_futimes(l, v, retval)
591 struct lwp *l;
592 void *v;
593 register_t *retval;
594 {
595 struct netbsd32_futimes_args /* {
596 syscallarg(int) fd;
597 syscallarg(const netbsd32_timevalp_t) tptr;
598 } */ *uap = v;
599 int error;
600 struct file *fp;
601 struct proc *p = l->l_proc;
602
603 /* getvnode() will use the descriptor for us */
604 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
605 return (error);
606
607 error = change_utimes32((struct vnode *)fp->f_data,
608 SCARG(uap, tptr), l);
609 FILE_UNUSE(fp, l);
610 return (error);
611 }
612
613 int
614 netbsd32_sys___getdents30(l, v, retval)
615 struct lwp *l;
616 void *v;
617 register_t *retval;
618 {
619 struct netbsd32_sys___getdents30_args /* {
620 syscallarg(int) fd;
621 syscallarg(netbsd32_charp) buf;
622 syscallarg(netbsd32_size_t) count;
623 } */ *uap = v;
624 struct file *fp;
625 int error, done;
626 struct proc *p = l->l_proc;
627
628 /* getvnode() will use the descriptor for us */
629 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
630 return (error);
631 if ((fp->f_flag & FREAD) == 0) {
632 error = EBADF;
633 goto out;
634 }
635 error = vn_readdir(fp, (void *)NETBSD32PTR64(SCARG(uap, buf)),
636 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
637 *retval = done;
638 out:
639 FILE_UNUSE(fp, l);
640 return (error);
641 }
642
643 int
644 netbsd32_lutimes(l, v, retval)
645 struct lwp *l;
646 void *v;
647 register_t *retval;
648 {
649 struct netbsd32_lutimes_args /* {
650 syscallarg(const netbsd32_charp) path;
651 syscallarg(const netbsd32_timevalp_t) tptr;
652 } */ *uap = v;
653 int error;
654 struct nameidata nd;
655
656 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE,
657 (void *)NETBSD32PTR64(SCARG(uap, path)), l);
658 if ((error = namei(&nd)) != 0)
659 return (error);
660
661 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l);
662
663 vrele(nd.ni_vp);
664 return (error);
665 }
666
667 int
668 netbsd32_sys___stat30(l, v, retval)
669 struct lwp *l;
670 void *v;
671 register_t *retval;
672 {
673 struct netbsd32_sys___stat30_args /* {
674 syscallarg(const netbsd32_charp) path;
675 syscallarg(netbsd32_statp_t) ub;
676 } */ *uap = v;
677 struct netbsd32_stat sb32;
678 struct stat sb;
679 int error;
680 struct nameidata nd;
681 void *sg;
682 const char *path;
683 struct proc *p = l->l_proc;
684
685 path = (char *)NETBSD32PTR64(SCARG(uap, path));
686 sg = stackgap_init(p, 0);
687 CHECK_ALT_EXIST(l, &sg, path);
688
689 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, l);
690 if ((error = namei(&nd)) != 0)
691 return (error);
692 error = vn_stat(nd.ni_vp, &sb, l);
693 vput(nd.ni_vp);
694 if (error)
695 return (error);
696 netbsd32_from___stat30(&sb, &sb32);
697 error = copyout(&sb32, (void *)NETBSD32PTR64(SCARG(uap, ub)),
698 sizeof(sb32));
699 return (error);
700 }
701
702 int
703 netbsd32_sys___fstat30(l, v, retval)
704 struct lwp *l;
705 void *v;
706 register_t *retval;
707 {
708 struct netbsd32_sys___fstat30_args /* {
709 syscallarg(int) fd;
710 syscallarg(netbsd32_statp_t) sb;
711 } */ *uap = v;
712 int fd = SCARG(uap, fd);
713 struct proc *p = l->l_proc;
714 struct filedesc *fdp = p->p_fd;
715 struct file *fp;
716 struct netbsd32_stat sb32;
717 struct stat ub;
718 int error = 0;
719
720 if ((fp = fd_getfile(fdp, fd)) == NULL)
721 return (EBADF);
722
723 FILE_USE(fp);
724 error = (*fp->f_ops->fo_stat)(fp, &ub, l);
725 FILE_UNUSE(fp, l);
726
727 if (error == 0) {
728 netbsd32_from___stat30(&ub, &sb32);
729 error = copyout(&sb32, (void *)NETBSD32PTR64(SCARG(uap, sb)),
730 sizeof(sb32));
731 }
732 return (error);
733 }
734
735 int
736 netbsd32_sys___lstat30(l, v, retval)
737 struct lwp *l;
738 void *v;
739 register_t *retval;
740 {
741 struct netbsd32_sys___lstat30_args /* {
742 syscallarg(const netbsd32_charp) path;
743 syscallarg(netbsd32_statp_t) ub;
744 } */ *uap = v;
745 struct netbsd32_stat sb32;
746 struct stat sb;
747 int error;
748 struct nameidata nd;
749 void *sg;
750 const char *path;
751 struct proc *p = l->l_proc;
752
753 path = (char *)NETBSD32PTR64(SCARG(uap, path));
754 sg = stackgap_init(p, 0);
755 CHECK_ALT_EXIST(l, &sg, path);
756
757 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, path, l);
758 if ((error = namei(&nd)) != 0)
759 return (error);
760 error = vn_stat(nd.ni_vp, &sb, l);
761 vput(nd.ni_vp);
762 if (error)
763 return (error);
764 netbsd32_from___stat30(&sb, &sb32);
765 error = copyout(&sb32, (void *)NETBSD32PTR64(SCARG(uap, ub)),
766 sizeof(sb32));
767 return (error);
768 }
769
770 int netbsd32___fhstat40(l, v, retval)
771 struct lwp *l;
772 void *v;
773 register_t *retval;
774 {
775 struct netbsd32___fhstat40_args /* {
776 syscallarg(const netbsd32_pointer_t) fhp;
777 syscallarg(netbsd32_size_t) fh_size;
778 syscallarg(netbsd32_statp_t) sb;
779 } */ *uap = v;
780 struct stat sb;
781 struct netbsd32_stat sb32;
782 int error;
783 fhandle_t *fh;
784 struct vnode *vp;
785
786 /*
787 * Must be super user
788 */
789 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
790 0, NULL, NULL, NULL)))
791 return error;
792
793 if ((error = vfs_copyinfh_alloc(NETBSD32PTR64(SCARG(uap, fhp)),
794 SCARG(uap, fh_size), &fh)) != 0)
795 goto bad;
796
797 if ((error = vfs_fhtovp(fh, &vp)) != 0)
798 goto bad;
799
800 error = vn_stat(vp, &sb, l);
801 vput(vp);
802 if (error)
803 goto bad;
804 netbsd32_from___stat30(&sb, &sb32);
805 error = copyout(&sb32, NETBSD32PTR64(SCARG(uap, sb)), sizeof(sb));
806 bad:
807 vfs_copyinfh_free(fh);
808 return error;
809 }
810
811 int
812 netbsd32_preadv(l, v, retval)
813 struct lwp *l;
814 void *v;
815 register_t *retval;
816 {
817 struct netbsd32_preadv_args /* {
818 syscallarg(int) fd;
819 syscallarg(const netbsd32_iovecp_t) iovp;
820 syscallarg(int) iovcnt;
821 syscallarg(int) pad;
822 syscallarg(off_t) offset;
823 } */ *uap = v;
824 struct proc *p = l->l_proc;
825 struct filedesc *fdp = p->p_fd;
826 struct file *fp;
827 struct vnode *vp;
828 off_t offset;
829 int error, fd = SCARG(uap, fd);
830
831 if ((fp = fd_getfile(fdp, fd)) == NULL)
832 return (EBADF);
833
834 if ((fp->f_flag & FREAD) == 0)
835 return (EBADF);
836
837 FILE_USE(fp);
838
839 vp = (struct vnode *)fp->f_data;
840 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
841 error = ESPIPE;
842 goto out;
843 }
844
845 offset = SCARG(uap, offset);
846
847 /*
848 * XXX This works because no file systems actually
849 * XXX take any action on the seek operation.
850 */
851 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
852 goto out;
853
854 return (dofilereadv32(l, fd, fp,
855 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
856 SCARG(uap, iovcnt), &offset, 0, retval));
857
858 out:
859 FILE_UNUSE(fp, l);
860 return (error);
861 }
862
863 int
864 netbsd32_pwritev(l, v, retval)
865 struct lwp *l;
866 void *v;
867 register_t *retval;
868 {
869 struct netbsd32_pwritev_args /* {
870 syscallarg(int) fd;
871 syscallarg(const netbsd32_iovecp_t) iovp;
872 syscallarg(int) iovcnt;
873 syscallarg(int) pad;
874 syscallarg(off_t) offset;
875 } */ *uap = v;
876 struct proc *p = l->l_proc;
877 struct filedesc *fdp = p->p_fd;
878 struct file *fp;
879 struct vnode *vp;
880 off_t offset;
881 int error, fd = SCARG(uap, fd);
882
883 if ((fp = fd_getfile(fdp, fd)) == NULL)
884 return (EBADF);
885
886 if ((fp->f_flag & FWRITE) == 0)
887 return (EBADF);
888
889 FILE_USE(fp);
890
891 vp = (struct vnode *)fp->f_data;
892 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
893 error = ESPIPE;
894 goto out;
895 }
896
897 offset = SCARG(uap, offset);
898
899 /*
900 * XXX This works because no file systems actually
901 * XXX take any action on the seek operation.
902 */
903 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
904 goto out;
905
906 return (dofilewritev32(l, fd, fp,
907 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
908 SCARG(uap, iovcnt), &offset, 0, retval));
909
910 out:
911 FILE_UNUSE(fp, l);
912 return (error);
913 }
914
915 /*
916 * Find pathname of process's current directory.
917 *
918 * Use vfs vnode-to-name reverse cache; if that fails, fall back
919 * to reading directory contents.
920 */
921 /* XXX NH Why does this exist */
922 int
923 getcwd_common __P((struct vnode *, struct vnode *,
924 char **, char *, int, int, struct lwp *));
925
926 int netbsd32___getcwd(l, v, retval)
927 struct lwp *l;
928 void *v;
929 register_t *retval;
930 {
931 struct netbsd32___getcwd_args /* {
932 syscallarg(char *) bufp;
933 syscallarg(size_t) length;
934 } */ *uap = v;
935 struct proc *p = l->l_proc;
936 int error;
937 char *path;
938 char *bp, *bend;
939 int len = (int)SCARG(uap, length);
940 int lenused;
941
942 if (len > MAXPATHLEN*4)
943 len = MAXPATHLEN*4;
944 else if (len < 2)
945 return ERANGE;
946
947 path = (char *)malloc(len, M_TEMP, M_WAITOK);
948 if (!path)
949 return ENOMEM;
950
951 bp = &path[len];
952 bend = bp;
953 *(--bp) = '\0';
954
955 /*
956 * 5th argument here is "max number of vnodes to traverse".
957 * Since each entry takes up at least 2 bytes in the output buffer,
958 * limit it to N/2 vnodes for an N byte buffer.
959 */
960 #define GETCWD_CHECK_ACCESS 0x0001
961 error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2,
962 GETCWD_CHECK_ACCESS, l);
963
964 if (error)
965 goto out;
966 lenused = bend - bp;
967 *retval = lenused;
968 /* put the result into user buffer */
969 error = copyout(bp, (void *)NETBSD32PTR64(SCARG(uap, bufp)), lenused);
970
971 out:
972 free(path, M_TEMP);
973 return error;
974 }
975