xref: /netbsd-src/sys/compat/common/vfs_syscalls_43.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: vfs_syscalls_43.c,v 1.66 2020/06/24 10:28:16 jdolecek Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)vfs_syscalls.c	8.28 (Berkeley) 12/10/94
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_43.c,v 1.66 2020/06/24 10:28:16 jdolecek Exp $");
41 
42 #if defined(_KERNEL_OPT)
43 #include "opt_compat_netbsd.h"
44 #endif
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/filedesc.h>
49 #include <sys/kernel.h>
50 #include <sys/proc.h>
51 #include <sys/file.h>
52 #include <sys/vnode.h>
53 #include <sys/namei.h>
54 #include <sys/dirent.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/stat.h>
58 #include <sys/malloc.h>
59 #include <sys/ioctl.h>
60 #include <sys/fcntl.h>
61 #include <sys/syslog.h>
62 #include <sys/unistd.h>
63 #include <sys/resourcevar.h>
64 
65 #include <sys/mount.h>
66 #include <sys/syscall.h>
67 #include <sys/syscallvar.h>
68 #include <sys/syscallargs.h>
69 #include <sys/vfs_syscalls.h>
70 
71 #include <compat/sys/stat.h>
72 #include <compat/sys/mount.h>
73 #include <compat/sys/dirent.h>
74 
75 #include <compat/common/compat_util.h>
76 #include <compat/common/compat_mod.h>
77 
78 static void cvttimespec(struct timespec *, struct timespec50 *);
79 static void cvtstat(struct stat *, struct stat43 *);
80 
81 static struct syscall_package vfs_syscalls_43_syscalls[] = {
82 	{ SYS_compat_43_oquota,     0, (sy_call_t *)compat_43_sys_quota },
83 	{ SYS_compat_43_stat43,     0, (sy_call_t *)compat_43_sys_stat },
84 	{ SYS_compat_43_lstat43,    0, (sy_call_t *)compat_43_sys_lstat },
85 	{ SYS_compat_43_fstat43,    0, (sy_call_t *)compat_43_sys_fstat },
86 	{ SYS_compat_43_otruncate,  0, (sy_call_t *)compat_43_sys_ftruncate },
87 	{ SYS_compat_43_oftruncate, 0, (sy_call_t *)compat_43_sys_ftruncate },
88 	{ SYS_compat_43_olseek,     0, (sy_call_t *)compat_43_sys_lseek },
89 	{ SYS_compat_43_ocreat,     0, (sy_call_t *)compat_43_sys_creat },
90 	{ SYS_compat_43_ogetdirentries, 0,
91 	    (sy_call_t *)compat_43_sys_getdirentries },
92 	{ 0, 0, NULL }
93 };
94 
95 /*
96  * Convert from an old to a new timespec structure.
97  */
98 static void
99 cvttimespec(struct timespec *ts, struct timespec50 *ots)
100 {
101 
102 	if (ts->tv_sec > INT_MAX) {
103 #if defined(DEBUG) || 1
104 		static bool first = true;
105 
106 		if (first) {
107 			first = false;
108 			printf("%s[%s:%d]: time_t does not fit\n",
109 			    __func__, curlwp->l_proc->p_comm,
110 			    curlwp->l_lid);
111 		}
112 #endif
113 		ots->tv_sec = INT_MAX;
114 	} else
115 		ots->tv_sec = ts->tv_sec;
116 	ots->tv_nsec = ts->tv_nsec;
117 }
118 
119 /*
120  * Convert from an old to a new stat structure.
121  */
122 static void
123 cvtstat(struct stat *st, struct stat43 *ost)
124 {
125 
126 	/* Handle any padding. */
127 	memset(ost, 0, sizeof *ost);
128 	ost->st_dev = st->st_dev;
129 	ost->st_ino = st->st_ino;
130 	ost->st_mode = st->st_mode & 0xffff;
131 	ost->st_nlink = st->st_nlink;
132 	ost->st_uid = st->st_uid;
133 	ost->st_gid = st->st_gid;
134 	ost->st_rdev = st->st_rdev;
135 	if (st->st_size < (quad_t)1 << 32)
136 		ost->st_size = st->st_size;
137 	else
138 		ost->st_size = -2;
139 	cvttimespec(&st->st_atimespec, &ost->st_atimespec);
140 	cvttimespec(&st->st_mtimespec, &ost->st_mtimespec);
141 	cvttimespec(&st->st_ctimespec, &ost->st_ctimespec);
142 	ost->st_blksize = st->st_blksize;
143 	ost->st_blocks = st->st_blocks;
144 	ost->st_flags = st->st_flags;
145 	ost->st_gen = st->st_gen;
146 }
147 
148 /*
149  * Get file status; this version follows links.
150  */
151 /* ARGSUSED */
152 int
153 compat_43_sys_stat(struct lwp *l, const struct compat_43_sys_stat_args *uap, register_t *retval)
154 {
155 	/* {
156 		syscallarg(char *) path;
157 		syscallarg(struct stat43 *) ub;
158 	} */
159 	struct stat sb;
160 	struct stat43 osb;
161 	int error;
162 
163 	error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
164 	if (error)
165 		return (error);
166 	cvtstat(&sb, &osb);
167 	error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
168 	return (error);
169 }
170 
171 /*
172  * Get file status; this version does not follow links.
173  */
174 /* ARGSUSED */
175 int
176 compat_43_sys_lstat(struct lwp *l, const struct compat_43_sys_lstat_args *uap, register_t *retval)
177 {
178 	/* {
179 		syscallarg(char *) path;
180 		syscallarg(struct ostat *) ub;
181 	} */
182 	struct stat sb;
183 	struct stat43 osb;
184 	int error;
185 
186 	error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb);
187 	if (error)
188 		return error;
189 
190 	/*
191 	 * For symbolic links, BSD4.3 returned the attributes of its
192 	 * containing directory, except for mode, size, and links.
193 	 * This is no longer emulated, the parent directory is not consulted.
194 	 */
195 	cvtstat(&sb, &osb);
196 	error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb));
197 	return (error);
198 }
199 
200 /*
201  * Return status information about a file descriptor.
202  */
203 /* ARGSUSED */
204 int
205 compat_43_sys_fstat(struct lwp *l, const struct compat_43_sys_fstat_args *uap, register_t *retval)
206 {
207 	/* {
208 		syscallarg(int) fd;
209 		syscallarg(struct stat43 *) sb;
210 	} */
211 	struct stat ub;
212 	struct stat43 oub;
213 	int error;
214 
215 	error = do_sys_fstat(SCARG(uap, fd), &ub);
216 	if (error == 0) {
217 		cvtstat(&ub, &oub);
218 		error = copyout((void *)&oub, (void *)SCARG(uap, sb),
219 		    sizeof (oub));
220 	}
221 
222 	return (error);
223 }
224 
225 
226 /*
227  * Truncate a file given a file descriptor.
228  */
229 /* ARGSUSED */
230 int
231 compat_43_sys_ftruncate(struct lwp *l, const struct compat_43_sys_ftruncate_args *uap, register_t *retval)
232 {
233 	/* {
234 		syscallarg(int) fd;
235 		syscallarg(long) length;
236 	} */
237 	struct sys_ftruncate_args /* {
238 		syscallarg(int) fd;
239 		syscallarg(int) pad;
240 		syscallarg(off_t) length;
241 	} */ nuap;
242 
243 	SCARG(&nuap, fd) = SCARG(uap, fd);
244 	SCARG(&nuap, length) = SCARG(uap, length);
245 	return (sys_ftruncate(l, &nuap, retval));
246 }
247 
248 /*
249  * Truncate a file given its path name.
250  */
251 /* ARGSUSED */
252 int
253 compat_43_sys_truncate(struct lwp *l, const struct compat_43_sys_truncate_args *uap, register_t *retval)
254 {
255 	/* {
256 		syscallarg(char *) path;
257 		syscallarg(long) length;
258 	} */
259 	struct sys_truncate_args /* {
260 		syscallarg(char *) path;
261 		syscallarg(int) pad;
262 		syscallarg(off_t) length;
263 	} */ nuap;
264 
265 	SCARG(&nuap, path) = SCARG(uap, path);
266 	SCARG(&nuap, length) = SCARG(uap, length);
267 	return (sys_truncate(l, &nuap, retval));
268 }
269 
270 
271 /*
272  * Reposition read/write file offset.
273  */
274 int
275 compat_43_sys_lseek(struct lwp *l, const struct compat_43_sys_lseek_args *uap, register_t *retval)
276 {
277 	/* {
278 		syscallarg(int) fd;
279 		syscallarg(long) offset;
280 		syscallarg(int) whence;
281 	} */
282 	struct sys_lseek_args /* {
283 		syscallarg(int) fd;
284 		syscallarg(int) pad;
285 		syscallarg(off_t) offset;
286 		syscallarg(int) whence;
287 	} */ nuap;
288 	off_t qret;
289 	int error;
290 
291 	SCARG(&nuap, fd) = SCARG(uap, fd);
292 	SCARG(&nuap, offset) = SCARG(uap, offset);
293 	SCARG(&nuap, whence) = SCARG(uap, whence);
294 	error = sys_lseek(l, &nuap, (register_t *)&qret);
295 	*(long *)retval = qret;
296 	return (error);
297 }
298 
299 
300 /*
301  * Create a file.
302  */
303 int
304 compat_43_sys_creat(struct lwp *l, const struct compat_43_sys_creat_args *uap, register_t *retval)
305 {
306 	/* {
307 		syscallarg(char *) path;
308 		syscallarg(int) mode;
309 	} */
310 	struct sys_open_args /* {
311 		syscallarg(char *) path;
312 		syscallarg(int) flags;
313 		syscallarg(int) mode;
314 	} */ nuap;
315 
316 	SCARG(&nuap, path) = SCARG(uap, path);
317 	SCARG(&nuap, mode) = SCARG(uap, mode);
318 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
319 	return (sys_open(l, &nuap, retval));
320 }
321 
322 /*ARGSUSED*/
323 int
324 compat_43_sys_quota(struct lwp *l, const void *v, register_t *retval)
325 {
326 
327 	return (ENOSYS);
328 }
329 
330 
331 /*
332  * Read a block of directory entries in a file system independent format.
333  */
334 int
335 compat_43_sys_getdirentries(struct lwp *l, const struct compat_43_sys_getdirentries_args *uap, register_t *retval)
336 {
337 	/* {
338 		syscallarg(int) fd;
339 		syscallarg(char *) buf;
340 		syscallarg(u_int) count;
341 		syscallarg(long *) basep;
342 	} */
343 	struct dirent *bdp;
344 	struct vnode *vp;
345 	void *tbuf;			/* Current-format */
346 	char *inp;			/* Current-format */
347 	int len, reclen;		/* Current-format */
348 	char *outp;			/* Dirent12-format */
349 	int resid, old_reclen = 0;	/* Dirent12-format */
350 	struct file *fp;
351 	struct uio auio;
352 	struct iovec aiov;
353 	struct dirent43 idb;
354 	off_t off;		/* true file offset */
355 	int buflen, error, eofflag, nbytes;
356 	struct vattr va;
357 	off_t *cookiebuf = NULL, *cookie;
358 	int ncookies;
359 	long loff;
360 
361 	/* fd_getvnode() will use the descriptor for us */
362 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
363 		return (error);
364 
365 	if ((fp->f_flag & FREAD) == 0) {
366 		error = EBADF;
367 		goto out1;
368 	}
369 
370 	vp = fp->f_vnode;
371 	if (vp->v_type != VDIR) {
372 		error = ENOTDIR;
373 		goto out1;
374 	}
375 
376 	vn_lock(vp, LK_SHARED | LK_RETRY);
377 	error = VOP_GETATTR(vp, &va, l->l_cred);
378 	VOP_UNLOCK(vp);
379 	if (error)
380 		goto out1;
381 
382 	loff = fp->f_offset;
383 	nbytes = SCARG(uap, count);
384 	buflen = uimin(MAXBSIZE, nbytes);
385 	if (buflen < va.va_blocksize)
386 		buflen = va.va_blocksize;
387 	tbuf = malloc(buflen, M_TEMP, M_WAITOK);
388 
389 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
390 	off = fp->f_offset;
391 again:
392 	aiov.iov_base = tbuf;
393 	aiov.iov_len = buflen;
394 	auio.uio_iov = &aiov;
395 	auio.uio_iovcnt = 1;
396 	auio.uio_rw = UIO_READ;
397 	auio.uio_resid = buflen;
398 	auio.uio_offset = off;
399 	UIO_SETUP_SYSSPACE(&auio);
400 	/*
401          * First we read into the malloc'ed buffer, then
402          * we massage it into user space, one record at a time.
403          */
404 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
405 	    &ncookies);
406 	if (error)
407 		goto out;
408 
409 	inp = (char *)tbuf;
410 	outp = SCARG(uap, buf);
411 	resid = nbytes;
412 	if ((len = buflen - auio.uio_resid) == 0)
413 		goto eof;
414 
415 	for (cookie = cookiebuf; len > 0; len -= reclen) {
416 		bdp = (struct dirent *)inp;
417 		reclen = bdp->d_reclen;
418 		if (reclen & 3) {
419 			error = EIO;
420 			goto out;
421 		}
422 		if (bdp->d_fileno == 0) {
423 			inp += reclen;	/* it is a hole; squish it out */
424 			if (cookie)
425 				off = *cookie++;
426 			else
427 				off += reclen;
428 			continue;
429 		}
430 		if (bdp->d_namlen >= sizeof(idb.d_name))
431 			idb.d_namlen = sizeof(idb.d_name) - 1;
432 		else
433 			idb.d_namlen = bdp->d_namlen;
434 		old_reclen = _DIRENT_RECLEN(&idb, bdp->d_namlen);
435 		if (reclen > len || resid < old_reclen) {
436 			/* entry too big for buffer, so just stop */
437 			outp++;
438 			break;
439 		}
440 		/*
441 		 * Massage in place to make a Dirent12-shaped dirent (otherwise
442 		 * we have to worry about touching user memory outside of
443 		 * the copyout() call).
444 		 */
445 		idb.d_fileno = (uint32_t)bdp->d_fileno;
446 		idb.d_reclen = (uint16_t)old_reclen;
447 		idb.d_fileno = (uint32_t)bdp->d_fileno;
448 		(void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen);
449 		memset(idb.d_name + idb.d_namlen, 0,
450 		    idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen);
451 		if ((error = copyout(&idb, outp, old_reclen)))
452 			goto out;
453 		/* advance past this real entry */
454 		inp += reclen;
455 		if (cookie)
456 			off = *cookie++; /* each entry points to itself */
457 		else
458 			off += reclen;
459 		/* advance output past Dirent12-shaped entry */
460 		outp += old_reclen;
461 		resid -= old_reclen;
462 	}
463 
464 	/* if we squished out the whole block, try again */
465 	if (outp == SCARG(uap, buf)) {
466 		if (cookiebuf)
467 			free(cookiebuf, M_TEMP);
468 		cookiebuf = NULL;
469 		goto again;
470 	}
471 	fp->f_offset = off;	/* update the vnode offset */
472 
473 eof:
474 	*retval = nbytes - resid;
475 out:
476 	VOP_UNLOCK(vp);
477 	if (cookiebuf)
478 		free(cookiebuf, M_TEMP);
479 	free(tbuf, M_TEMP);
480 out1:
481 	fd_putfile(SCARG(uap, fd));
482 	if (error)
483 		return error;
484 	return copyout(&loff, SCARG(uap, basep), sizeof(long));
485 }
486 
487 int
488 vfs_syscalls_43_init(void)
489 {
490 
491 	return syscall_establish(NULL, vfs_syscalls_43_syscalls);
492 }
493 
494 int
495 vfs_syscalls_43_fini(void)
496 {
497 
498 	return syscall_disestablish(NULL, vfs_syscalls_43_syscalls);
499 }
500