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