1 /**	$MirOS: src/sys/compat/common/vfs_syscalls_43.c,v 1.3 2005/07/03 21:18:55 tg Exp $ */
2 /*	$OpenBSD: vfs_syscalls_43.c,v 1.27 2005/05/26 01:15:12 pedro Exp $	*/
3 /*	$NetBSD: vfs_syscalls_43.c,v 1.4 1996/03/14 19:31:52 christos Exp $	*/
4 
5 /*
6  * Copyright (c) 1989, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  * (c) UNIX System Laboratories, Inc.
9  * All or some portions of this file are derived from material licensed
10  * to the University of California by American Telephone and Telegraph
11  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12  * the permission of UNIX System Laboratories, Inc.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)vfs_syscalls.c	8.28 (Berkeley) 12/10/94
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/filedesc.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/file.h>
47 #include <sys/vnode.h>
48 #include <sys/namei.h>
49 #include <sys/dirent.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/stat.h>
53 #include <sys/ioctl.h>
54 #include <sys/fcntl.h>
55 #include <sys/malloc.h>
56 #include <sys/syslog.h>
57 #include <sys/unistd.h>
58 #include <sys/resourcevar.h>
59 
60 #include <sys/mount.h>
61 #include <sys/syscallargs.h>
62 
63 #include <uvm/uvm_extern.h>
64 
65 #include <sys/pipe.h>
66 
67 #include <compat/common/compat_util.h>
68 #include <compat/common/kern_gen.h>
69 
70 struct stat43 {
71 	u_int16_t st_dev;		/* inode's device */
72 	ino_t	  st_ino;		/* inode's number */
73 	u_int16_t st_mode;		/* inode protection mode */
74 	u_int16_t st_nlink;		/* number of hard links */
75 	u_int16_t st_uid;		/* user ID of the file's owner */
76 	u_int16_t st_gid;		/* group ID of the file's group */
77 	u_int16_t st_rdev;		/* device type */
78 	int32_t	  st_size;		/* file size, in bytes */
79 	struct	timespec_compat st_atimespec;	/* time of last access */
80 	struct	timespec_compat st_mtimespec;	/* time of last data modification */
81 	struct	timespec_compat st_ctimespec;	/* time of last file status change */
82 	int32_t	  st_blksize;		/* optimal blocksize for I/O */
83 	int32_t	  st_blocks;		/* blocks allocated for file */
84 	u_int32_t st_flags;		/* user defined flags for file */
85 	u_int32_t st_gen;		/* file generation number */
86 };
87 
88 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
89 static void cvtstat(struct stat *, struct stat43 *);
90 #endif
91 
92 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
93 /*
94  * Convert from a new to an old stat structure.
95  */
96 static void
cvtstat(st,ost)97 cvtstat(st, ost)
98 	struct stat *st;
99 	struct stat43 *ost;
100 {
101 
102 	ost->st_dev = st->st_dev;
103 	ost->st_ino = st->st_ino;
104 	ost->st_mode = st->st_mode;
105 	ost->st_nlink = st->st_nlink;
106 	ost->st_uid = st->st_uid;
107 	ost->st_gid = st->st_gid;
108 	ost->st_rdev = st->st_rdev;
109 	if (st->st_size < (quad_t)1 << 32)
110 		ost->st_size = st->st_size;
111 	else
112 		ost->st_size = -2;
113 	ost->st_atime = __BOUNDLONG(st->st_atime);
114 	ost->st_mtime = __BOUNDLONG(st->st_mtime);
115 	ost->st_ctime = __BOUNDLONG(st->st_ctime);
116 	ost->st_blksize = st->st_blksize;
117 	ost->st_blocks = st->st_blocks;
118 	ost->st_flags = st->st_flags;
119 	ost->st_gen = st->st_gen;
120 }
121 #endif
122 
123 #if defined(COMPAT_OPENBSD)
124 
125 #include <compat/openbsd/compat_openbsd.h>
126 
127 /*
128  * Get file status; this version follows links.
129  */
130 /* ARGSUSED */
131 int
compat_43_openbsd_sys_stat(p,v,retval)132 compat_43_openbsd_sys_stat(p, v, retval)
133 	struct proc *p;
134 	void *v;
135 	register_t *retval;
136 {
137 	struct compat_43_openbsd_sys_stat_args /* {
138 		syscallarg(char *) path;
139 		syscallarg(struct stat43 *) ub;
140 	} */ *uap = v;
141 	struct stat sb;
142 	struct stat43 osb;
143 	int error;
144 	struct nameidata nd;
145 	caddr_t sg = stackgap_init(p->p_emul);
146 
147 	OPENBSD_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
148 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
149 	    SCARG(uap, path), p);
150 	if ((error = namei(&nd)) != 0)
151 		return (error);
152 	error = vn_stat(nd.ni_vp, &sb, p);
153 	vput(nd.ni_vp);
154 	if (error)
155 		return (error);
156 	/* Don't let non-root see generation numbers (for NFS security) */
157 	if (suser(p, 0))
158 		sb.st_gen = 0;
159 	cvtstat(&sb, &osb);
160 	error = copyout(&osb, SCARG(uap, ub), sizeof(osb));
161 	return (error);
162 }
163 #endif
164 
165 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
166 /*
167  * Get file status; this version does not follow links.
168  */
169 /* ARGSUSED */
170 int
compat_43_sys_lstat(p,v,retval)171 compat_43_sys_lstat(p, v, retval)
172 	struct proc *p;
173 	void *v;
174 	register_t *retval;
175 {
176 	register struct compat_43_sys_lstat_args /* {
177 		syscallarg(char *) path;
178 		syscallarg(struct stat43 *) ub;
179 	} */ *uap = v;
180 	struct stat sb;
181 	struct stat43 osb;
182 	int error;
183 	struct nameidata nd;
184 
185 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
186 	    SCARG(uap, path), p);
187 	if ((error = namei(&nd)) != 0)
188 		return (error);
189 	error = vn_stat(nd.ni_vp, &sb, p);
190 	vput(nd.ni_vp);
191 	if (error)
192 		return (error);
193 	/* Don't let non-root see generation numbers (for NFS security) */
194 	if (suser(p, 0))
195 		sb.st_gen = 0;
196 	cvtstat(&sb, &osb);
197 	error = copyout(&osb, SCARG(uap, ub), sizeof(osb));
198 	return (error);
199 }
200 #endif
201 
202 #if defined(COMPAT_OPENBSD)
203 /*
204  * Return status information about a file descriptor.
205  */
206 /* ARGSUSED */
207 int
compat_43_sys_fstat(p,v,retval)208 compat_43_sys_fstat(p, v, retval)
209 	struct proc *p;
210 	void *v;
211 	register_t *retval;
212 {
213 	struct compat_43_sys_fstat_args /* {
214 		syscallarg(int) fd;
215 		syscallarg(struct stat43 *) sb;
216 	} */ *uap = v;
217 	int fd = SCARG(uap, fd);
218 	struct filedesc *fdp = p->p_fd;
219 	struct file *fp;
220 	struct stat ub;
221 	struct stat43 oub;
222 	int error;
223 
224 	if ((fp = fd_getfile(fdp, fd)) == NULL)
225 		return (EBADF);
226 	FREF(fp);
227 	error = (*fp->f_ops->fo_stat)(fp, &ub, p);
228 	FRELE(fp);
229 	if (error == 0) {
230 		/* Don't let non-root see generation numbers
231 		   (for NFS security) */
232 		if (suser(p, 0))
233 			ub.st_gen = 0;
234 		cvtstat(&ub, &oub);
235 		error = copyout(&oub, SCARG(uap, sb), sizeof(oub));
236 	}
237 	return (error);
238 }
239 #endif
240 
241 #if defined(COMPAT_OPENBSD) || defined(COMPAT_LINUX)
242 /*
243  * Truncate a file given a file descriptor.
244  */
245 /* ARGSUSED */
246 int
compat_43_sys_ftruncate(p,v,retval)247 compat_43_sys_ftruncate(p, v, retval)
248 	struct proc *p;
249 	void *v;
250 	register_t *retval;
251 {
252 	register struct compat_43_sys_ftruncate_args /* {
253 		syscallarg(int) fd;
254 		syscallarg(long) length;
255 	} */ *uap = v;
256 	struct sys_ftruncate_args /* {
257 		syscallarg(int) fd;
258 		syscallarg(int) pad;
259 		syscallarg(off_t) length;
260 	} */ nuap;
261 
262 	SCARG(&nuap, fd) = SCARG(uap, fd);
263 	SCARG(&nuap, length) = SCARG(uap, length);
264 	return (sys_ftruncate(p, &nuap, retval));
265 }
266 
267 /*
268  * Truncate a file given its path name.
269  */
270 /* ARGSUSED */
271 int
compat_43_sys_truncate(p,v,retval)272 compat_43_sys_truncate(p, v, retval)
273 	struct proc *p;
274 	void *v;
275 	register_t *retval;
276 {
277 	register struct compat_43_sys_truncate_args /* {
278 		syscallarg(char *) path;
279 		syscallarg(long) length;
280 	} */ *uap = v;
281 	struct sys_truncate_args /* {
282 		syscallarg(char *) path;
283 		syscallarg(int) pad;
284 		syscallarg(off_t) length;
285 	} */ nuap;
286 
287 	SCARG(&nuap, path) = SCARG(uap, path);
288 	SCARG(&nuap, length) = SCARG(uap, length);
289 	return (sys_truncate(p, &nuap, retval));
290 }
291 
292 
293 /*
294  * Reposition read/write file offset.
295  */
296 int
compat_43_sys_lseek(p,v,retval)297 compat_43_sys_lseek(p, v, retval)
298 	struct proc *p;
299 	void *v;
300 	register_t *retval;
301 {
302 	register struct compat_43_sys_lseek_args /* {
303 		syscallarg(int) fd;
304 		syscallarg(long) offset;
305 		syscallarg(int) whence;
306 	} */ *uap = v;
307 	struct sys_lseek_args /* {
308 		syscallarg(int) fd;
309 		syscallarg(int) pad;
310 		syscallarg(off_t) offset;
311 		syscallarg(int) whence;
312 	} */ nuap;
313 	off_t qret;
314 	int error;
315 
316 	SCARG(&nuap, fd) = SCARG(uap, fd);
317 	SCARG(&nuap, offset) = SCARG(uap, offset);
318 	SCARG(&nuap, whence) = SCARG(uap, whence);
319 	error = sys_lseek(p, &nuap, (register_t *)&qret);
320 	*(long *)retval = qret;
321 	return (error);
322 }
323 #endif
324 
325 #if defined(COMPAT_OPENBSD)
326 /*
327  * Create a file.
328  */
329 int
compat_43_sys_creat(p,v,retval)330 compat_43_sys_creat(p, v, retval)
331 	struct proc *p;
332 	void *v;
333 	register_t *retval;
334 {
335 	register struct compat_43_sys_creat_args /* {
336 		syscallarg(char *) path;
337 		syscallarg(mode_t) mode;
338 	} */ *uap = v;
339 	struct sys_open_args /* {
340 		syscallarg(char *) path;
341 		syscallarg(int) flags;
342 		syscallarg(mode_t) mode;
343 	} */ nuap;
344 
345 	SCARG(&nuap, path) = SCARG(uap, path);
346 	SCARG(&nuap, mode) = SCARG(uap, mode);
347 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
348 	return (sys_open(p, &nuap, retval));
349 }
350 
351 /*
352  * Read a block of directory entries in a file system independent format.
353  */
354 int
compat_43_sys_getdirentries(p,v,retval)355 compat_43_sys_getdirentries(p, v, retval)
356 	struct proc *p;
357 	void *v;
358 	register_t *retval;
359 {
360 	register struct compat_43_sys_getdirentries_args /* {
361 		syscallarg(int) fd;
362 		syscallarg(char *) buf;
363 		syscallarg(int) count;
364 		syscallarg(long *) basep;
365 	} */ *uap = v;
366 	struct vnode *vp;
367 	struct file *fp;
368 	struct uio auio, kuio;
369 	struct iovec aiov, kiov;
370 	struct dirent *dp, *edp;
371 	caddr_t dirbuf;
372 	int error, eofflag, readcnt;
373 	long loff;
374 
375 	if (SCARG(uap, count) < 0)
376 		return EINVAL;
377 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
378 		return (error);
379 	if ((fp->f_flag & FREAD) == 0) {
380 		error = EBADF;
381 		goto bad;
382 	}
383 	vp = (struct vnode *)fp->f_data;
384 	if (vp->v_type != VDIR) {
385 		error = EINVAL;
386 		goto bad;
387 	}
388 	aiov.iov_base = SCARG(uap, buf);
389 	aiov.iov_len = SCARG(uap, count);
390 	auio.uio_iov = &aiov;
391 	auio.uio_iovcnt = 1;
392 	auio.uio_rw = UIO_READ;
393 	auio.uio_segflg = UIO_USERSPACE;
394 	auio.uio_procp = p;
395 	auio.uio_resid = SCARG(uap, count);
396 
397 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
398 	loff = auio.uio_offset = fp->f_offset;
399 #	if (BYTE_ORDER != LITTLE_ENDIAN)
400 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
401 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
402 			    (int *)0, (u_long **)0);
403 			fp->f_offset = auio.uio_offset;
404 		} else
405 #	endif
406 	{
407 		u_int  nbytes = SCARG(uap, count);
408 
409 		nbytes = min(nbytes, MAXBSIZE);
410 
411 		kuio = auio;
412 		kuio.uio_iov = &kiov;
413 		kuio.uio_segflg = UIO_SYSSPACE;
414 		kiov.iov_len = nbytes;
415 		dirbuf = (caddr_t)malloc(nbytes, M_TEMP, M_WAITOK);
416 		kiov.iov_base = dirbuf;
417 
418 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
419 				    0, 0);
420 		fp->f_offset = kuio.uio_offset;
421 		if (error == 0) {
422 			readcnt = nbytes - kuio.uio_resid;
423 			edp = (struct dirent *)&dirbuf[readcnt];
424 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
425 #				if (BYTE_ORDER == LITTLE_ENDIAN)
426 					/*
427 					 * The expected low byte of
428 					 * dp->d_namlen is our dp->d_type.
429 					 * The high MBZ byte of dp->d_namlen
430 					 * is our dp->d_namlen.
431 					 */
432 					dp->d_type = dp->d_namlen;
433 					dp->d_namlen = 0;
434 #				else
435 					/*
436 					 * The dp->d_type is the high byte
437 					 * of the expected dp->d_namlen,
438 					 * so must be zero'ed.
439 					 */
440 					dp->d_type = 0;
441 #				endif
442 				if (dp->d_reclen > 0) {
443 					dp = (struct dirent *)
444 					    ((char *)dp + dp->d_reclen);
445 				} else {
446 					error = EIO;
447 					break;
448 				}
449 			}
450 			if (dp >= edp)
451 				error = uiomove(dirbuf, readcnt, &auio);
452 		}
453 		FREE(dirbuf, M_TEMP);
454 	}
455 	VOP_UNLOCK(vp, 0, p);
456 	if (error)
457 		goto bad;
458 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
459 	    sizeof(long));
460 	*retval = SCARG(uap, count) - auio.uio_resid;
461 bad:
462 	FRELE(fp);
463 	return (error);
464 }
465 #endif
466