xref: /freebsd/sys/compat/linux/linux_file.c (revision 42249ef2)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1994-1995 Søren Schmidt
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "opt_compat.h"
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/capsicum.h>
37 #include <sys/conf.h>
38 #include <sys/dirent.h>
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/filedesc.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/mutex.h>
46 #include <sys/namei.h>
47 #include <sys/proc.h>
48 #include <sys/stat.h>
49 #include <sys/sx.h>
50 #include <sys/syscallsubr.h>
51 #include <sys/sysproto.h>
52 #include <sys/tty.h>
53 #include <sys/unistd.h>
54 #include <sys/vnode.h>
55 
56 #ifdef COMPAT_LINUX32
57 #include <machine/../linux32/linux.h>
58 #include <machine/../linux32/linux32_proto.h>
59 #else
60 #include <machine/../linux/linux.h>
61 #include <machine/../linux/linux_proto.h>
62 #endif
63 #include <compat/linux/linux_misc.h>
64 #include <compat/linux/linux_util.h>
65 #include <compat/linux/linux_file.h>
66 
67 static int	linux_common_open(struct thread *, int, char *, int, int);
68 static int	linux_getdents_error(struct thread *, int, int);
69 
70 
71 #ifdef LINUX_LEGACY_SYSCALLS
72 int
73 linux_creat(struct thread *td, struct linux_creat_args *args)
74 {
75 	char *path;
76 	int error;
77 
78 	LCONVPATHEXIST(td, args->path, &path);
79 
80 	error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
81 	    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
82 	LFREEPATH(path);
83 	return (error);
84 }
85 #endif
86 
87 static int
88 linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
89 {
90 	struct proc *p = td->td_proc;
91 	struct file *fp;
92 	int fd;
93 	int bsd_flags, error;
94 
95 	bsd_flags = 0;
96 	switch (l_flags & LINUX_O_ACCMODE) {
97 	case LINUX_O_WRONLY:
98 		bsd_flags |= O_WRONLY;
99 		break;
100 	case LINUX_O_RDWR:
101 		bsd_flags |= O_RDWR;
102 		break;
103 	default:
104 		bsd_flags |= O_RDONLY;
105 	}
106 	if (l_flags & LINUX_O_NDELAY)
107 		bsd_flags |= O_NONBLOCK;
108 	if (l_flags & LINUX_O_APPEND)
109 		bsd_flags |= O_APPEND;
110 	if (l_flags & LINUX_O_SYNC)
111 		bsd_flags |= O_FSYNC;
112 	if (l_flags & LINUX_O_NONBLOCK)
113 		bsd_flags |= O_NONBLOCK;
114 	if (l_flags & LINUX_FASYNC)
115 		bsd_flags |= O_ASYNC;
116 	if (l_flags & LINUX_O_CREAT)
117 		bsd_flags |= O_CREAT;
118 	if (l_flags & LINUX_O_TRUNC)
119 		bsd_flags |= O_TRUNC;
120 	if (l_flags & LINUX_O_EXCL)
121 		bsd_flags |= O_EXCL;
122 	if (l_flags & LINUX_O_NOCTTY)
123 		bsd_flags |= O_NOCTTY;
124 	if (l_flags & LINUX_O_DIRECT)
125 		bsd_flags |= O_DIRECT;
126 	if (l_flags & LINUX_O_NOFOLLOW)
127 		bsd_flags |= O_NOFOLLOW;
128 	if (l_flags & LINUX_O_DIRECTORY)
129 		bsd_flags |= O_DIRECTORY;
130 	/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
131 
132 	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
133 	if (error != 0)
134 		goto done;
135 	if (bsd_flags & O_NOCTTY)
136 		goto done;
137 
138 	/*
139 	 * XXX In between kern_openat() and fget(), another process
140 	 * having the same filedesc could use that fd without
141 	 * checking below.
142 	*/
143 	fd = td->td_retval[0];
144 	if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) {
145 		if (fp->f_type != DTYPE_VNODE) {
146 			fdrop(fp, td);
147 			goto done;
148 		}
149 		sx_slock(&proctree_lock);
150 		PROC_LOCK(p);
151 		if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
152 			PROC_UNLOCK(p);
153 			sx_sunlock(&proctree_lock);
154 			/* XXXPJD: Verify if TIOCSCTTY is allowed. */
155 			(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
156 			    td->td_ucred, td);
157 		} else {
158 			PROC_UNLOCK(p);
159 			sx_sunlock(&proctree_lock);
160 		}
161 		fdrop(fp, td);
162 	}
163 
164 done:
165 	LFREEPATH(path);
166 	return (error);
167 }
168 
169 int
170 linux_openat(struct thread *td, struct linux_openat_args *args)
171 {
172 	char *path;
173 	int dfd;
174 
175 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
176 	if (args->flags & LINUX_O_CREAT)
177 		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
178 	else
179 		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
180 
181 	return (linux_common_open(td, dfd, path, args->flags, args->mode));
182 }
183 
184 #ifdef LINUX_LEGACY_SYSCALLS
185 int
186 linux_open(struct thread *td, struct linux_open_args *args)
187 {
188 	char *path;
189 
190 	if (args->flags & LINUX_O_CREAT)
191 		LCONVPATHCREAT(td, args->path, &path);
192 	else
193 		LCONVPATHEXIST(td, args->path, &path);
194 
195 	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
196 }
197 #endif
198 
199 int
200 linux_lseek(struct thread *td, struct linux_lseek_args *args)
201 {
202 
203 	return (kern_lseek(td, args->fdes, args->off, args->whence));
204 }
205 
206 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
207 int
208 linux_llseek(struct thread *td, struct linux_llseek_args *args)
209 {
210 	int error;
211 	off_t off;
212 
213 	off = (args->olow) | (((off_t) args->ohigh) << 32);
214 
215 	error = kern_lseek(td, args->fd, off, args->whence);
216 	if (error != 0)
217 		return (error);
218 
219 	error = copyout(td->td_retval, args->res, sizeof(off_t));
220 	if (error != 0)
221 		return (error);
222 
223 	td->td_retval[0] = 0;
224 	return (0);
225 }
226 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
227 
228 /*
229  * Note that linux_getdents(2) and linux_getdents64(2) have the same
230  * arguments. They only differ in the definition of struct dirent they
231  * operate on.
232  * Note that linux_readdir(2) is a special case of linux_getdents(2)
233  * where count is always equals 1, meaning that the buffer is one
234  * dirent-structure in size and that the code can't handle more anyway.
235  * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
236  * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
237  * trash user stack.
238  */
239 
240 static int
241 linux_getdents_error(struct thread *td, int fd, int err)
242 {
243 	struct vnode *vp;
244 	struct file *fp;
245 	int error;
246 
247 	/* Linux return ENOTDIR in case when fd is not a directory. */
248 	error = getvnode(td, fd, &cap_read_rights, &fp);
249 	if (error != 0)
250 		return (error);
251 	vp = fp->f_vnode;
252 	if (vp->v_type != VDIR) {
253 		fdrop(fp, td);
254 		return (ENOTDIR);
255 	}
256 	fdrop(fp, td);
257 	return (err);
258 }
259 
260 struct l_dirent {
261 	l_ulong		d_ino;
262 	l_off_t		d_off;
263 	l_ushort	d_reclen;
264 	char		d_name[LINUX_NAME_MAX + 1];
265 };
266 
267 struct l_dirent64 {
268 	uint64_t	d_ino;
269 	int64_t		d_off;
270 	l_ushort	d_reclen;
271 	u_char		d_type;
272 	char		d_name[LINUX_NAME_MAX + 1];
273 };
274 
275 /*
276  * Linux uses the last byte in the dirent buffer to store d_type,
277  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
278  */
279 #define LINUX_RECLEN(namlen)						\
280     roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
281 
282 #define LINUX_RECLEN64(namlen)						\
283     roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
284     sizeof(uint64_t))
285 
286 #ifdef LINUX_LEGACY_SYSCALLS
287 int
288 linux_getdents(struct thread *td, struct linux_getdents_args *args)
289 {
290 	struct dirent *bdp;
291 	caddr_t inp, buf;		/* BSD-format */
292 	int len, reclen;		/* BSD-format */
293 	caddr_t outp;			/* Linux-format */
294 	int resid, linuxreclen;		/* Linux-format */
295 	caddr_t lbuf;			/* Linux-format */
296 	off_t base;
297 	struct l_dirent *linux_dirent;
298 	int buflen, error;
299 	size_t retval;
300 
301 	buflen = min(args->count, MAXBSIZE);
302 	buf = malloc(buflen, M_TEMP, M_WAITOK);
303 
304 	error = kern_getdirentries(td, args->fd, buf, buflen,
305 	    &base, NULL, UIO_SYSSPACE);
306 	if (error != 0) {
307 		error = linux_getdents_error(td, args->fd, error);
308 		goto out1;
309 	}
310 
311 	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
312 
313 	len = td->td_retval[0];
314 	inp = buf;
315 	outp = (caddr_t)args->dent;
316 	resid = args->count;
317 	retval = 0;
318 
319 	while (len > 0) {
320 		bdp = (struct dirent *) inp;
321 		reclen = bdp->d_reclen;
322 		linuxreclen = LINUX_RECLEN(bdp->d_namlen);
323 		/*
324 		 * No more space in the user supplied dirent buffer.
325 		 * Return EINVAL.
326 		 */
327 		if (resid < linuxreclen) {
328 			error = EINVAL;
329 			goto out;
330 		}
331 
332 		linux_dirent = (struct l_dirent*)lbuf;
333 		linux_dirent->d_ino = bdp->d_fileno;
334 		linux_dirent->d_off = base + reclen;
335 		linux_dirent->d_reclen = linuxreclen;
336 		/*
337 		 * Copy d_type to last byte of l_dirent buffer
338 		 */
339 		lbuf[linuxreclen - 1] = bdp->d_type;
340 		strlcpy(linux_dirent->d_name, bdp->d_name,
341 		    linuxreclen - offsetof(struct l_dirent, d_name)-1);
342 		error = copyout(linux_dirent, outp, linuxreclen);
343 		if (error != 0)
344 			goto out;
345 
346 		inp += reclen;
347 		base += reclen;
348 		len -= reclen;
349 
350 		retval += linuxreclen;
351 		outp += linuxreclen;
352 		resid -= linuxreclen;
353 	}
354 	td->td_retval[0] = retval;
355 
356 out:
357 	free(lbuf, M_TEMP);
358 out1:
359 	free(buf, M_TEMP);
360 	return (error);
361 }
362 #endif
363 
364 int
365 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
366 {
367 	struct dirent *bdp;
368 	caddr_t inp, buf;		/* BSD-format */
369 	int len, reclen;		/* BSD-format */
370 	caddr_t outp;			/* Linux-format */
371 	int resid, linuxreclen;		/* Linux-format */
372 	caddr_t lbuf;			/* Linux-format */
373 	off_t base;
374 	struct l_dirent64 *linux_dirent64;
375 	int buflen, error;
376 	size_t retval;
377 
378 	buflen = min(args->count, MAXBSIZE);
379 	buf = malloc(buflen, M_TEMP, M_WAITOK);
380 
381 	error = kern_getdirentries(td, args->fd, buf, buflen,
382 	    &base, NULL, UIO_SYSSPACE);
383 	if (error != 0) {
384 		error = linux_getdents_error(td, args->fd, error);
385 		goto out1;
386 	}
387 
388 	lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
389 
390 	len = td->td_retval[0];
391 	inp = buf;
392 	outp = (caddr_t)args->dirent;
393 	resid = args->count;
394 	retval = 0;
395 
396 	while (len > 0) {
397 		bdp = (struct dirent *) inp;
398 		reclen = bdp->d_reclen;
399 		linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
400 		/*
401 		 * No more space in the user supplied dirent buffer.
402 		 * Return EINVAL.
403 		 */
404 		if (resid < linuxreclen) {
405 			error = EINVAL;
406 			goto out;
407 		}
408 
409 		linux_dirent64 = (struct l_dirent64*)lbuf;
410 		linux_dirent64->d_ino = bdp->d_fileno;
411 		linux_dirent64->d_off = base + reclen;
412 		linux_dirent64->d_reclen = linuxreclen;
413 		linux_dirent64->d_type = bdp->d_type;
414 		strlcpy(linux_dirent64->d_name, bdp->d_name,
415 		    linuxreclen - offsetof(struct l_dirent64, d_name));
416 		error = copyout(linux_dirent64, outp, linuxreclen);
417 		if (error != 0)
418 			goto out;
419 
420 		inp += reclen;
421 		base += reclen;
422 		len -= reclen;
423 
424 		retval += linuxreclen;
425 		outp += linuxreclen;
426 		resid -= linuxreclen;
427 	}
428 	td->td_retval[0] = retval;
429 
430 out:
431 	free(lbuf, M_TEMP);
432 out1:
433 	free(buf, M_TEMP);
434 	return (error);
435 }
436 
437 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
438 int
439 linux_readdir(struct thread *td, struct linux_readdir_args *args)
440 {
441 	struct dirent *bdp;
442 	caddr_t buf;			/* BSD-format */
443 	int linuxreclen;		/* Linux-format */
444 	caddr_t lbuf;			/* Linux-format */
445 	off_t base;
446 	struct l_dirent *linux_dirent;
447 	int buflen, error;
448 
449 	buflen = LINUX_RECLEN(LINUX_NAME_MAX);
450 	buf = malloc(buflen, M_TEMP, M_WAITOK);
451 
452 	error = kern_getdirentries(td, args->fd, buf, buflen,
453 	    &base, NULL, UIO_SYSSPACE);
454 	if (error != 0) {
455 		error = linux_getdents_error(td, args->fd, error);
456 		goto out;
457 	}
458 	if (td->td_retval[0] == 0)
459 		goto out;
460 
461 	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
462 
463 	bdp = (struct dirent *) buf;
464 	linuxreclen = LINUX_RECLEN(bdp->d_namlen);
465 
466 	linux_dirent = (struct l_dirent*)lbuf;
467 	linux_dirent->d_ino = bdp->d_fileno;
468 	linux_dirent->d_off = linuxreclen;
469 	linux_dirent->d_reclen = bdp->d_namlen;
470 	strlcpy(linux_dirent->d_name, bdp->d_name,
471 	    linuxreclen - offsetof(struct l_dirent, d_name));
472 	error = copyout(linux_dirent, args->dent, linuxreclen);
473 	if (error == 0)
474 		td->td_retval[0] = linuxreclen;
475 
476 	free(lbuf, M_TEMP);
477 out:
478 	free(buf, M_TEMP);
479 	return (error);
480 }
481 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
482 
483 
484 /*
485  * These exist mainly for hooks for doing /compat/linux translation.
486  */
487 
488 #ifdef LINUX_LEGACY_SYSCALLS
489 int
490 linux_access(struct thread *td, struct linux_access_args *args)
491 {
492 	char *path;
493 	int error;
494 
495 	/* Linux convention. */
496 	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
497 		return (EINVAL);
498 
499 	LCONVPATHEXIST(td, args->path, &path);
500 
501 	error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
502 	    args->amode);
503 	LFREEPATH(path);
504 
505 	return (error);
506 }
507 #endif
508 
509 int
510 linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
511 {
512 	char *path;
513 	int error, dfd;
514 
515 	/* Linux convention. */
516 	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
517 		return (EINVAL);
518 
519 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
520 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
521 
522 	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
523 	LFREEPATH(path);
524 
525 	return (error);
526 }
527 
528 #ifdef LINUX_LEGACY_SYSCALLS
529 int
530 linux_unlink(struct thread *td, struct linux_unlink_args *args)
531 {
532 	char *path;
533 	int error;
534 	struct stat st;
535 
536 	LCONVPATHEXIST(td, args->path, &path);
537 
538 	error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0);
539 	if (error == EPERM) {
540 		/* Introduce POSIX noncompliant behaviour of Linux */
541 		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
542 		    NULL) == 0) {
543 			if (S_ISDIR(st.st_mode))
544 				error = EISDIR;
545 		}
546 	}
547 	LFREEPATH(path);
548 	return (error);
549 }
550 #endif
551 
552 int
553 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
554 {
555 	char *path;
556 	int error, dfd;
557 	struct stat st;
558 
559 	if (args->flag & ~LINUX_AT_REMOVEDIR)
560 		return (EINVAL);
561 
562 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
563 	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
564 
565 	if (args->flag & LINUX_AT_REMOVEDIR)
566 		error = kern_frmdirat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0);
567 	else
568 		error = kern_funlinkat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0,
569 		    0);
570 	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
571 		/* Introduce POSIX noncompliant behaviour of Linux */
572 		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
573 		    UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
574 			error = EISDIR;
575 	}
576 	LFREEPATH(path);
577 	return (error);
578 }
579 int
580 linux_chdir(struct thread *td, struct linux_chdir_args *args)
581 {
582 	char *path;
583 	int error;
584 
585 	LCONVPATHEXIST(td, args->path, &path);
586 
587 	error = kern_chdir(td, path, UIO_SYSSPACE);
588 	LFREEPATH(path);
589 	return (error);
590 }
591 
592 #ifdef LINUX_LEGACY_SYSCALLS
593 int
594 linux_chmod(struct thread *td, struct linux_chmod_args *args)
595 {
596 	char *path;
597 	int error;
598 
599 	LCONVPATHEXIST(td, args->path, &path);
600 
601 	error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
602 	    args->mode, 0);
603 	LFREEPATH(path);
604 	return (error);
605 }
606 #endif
607 
608 int
609 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
610 {
611 	char *path;
612 	int error, dfd;
613 
614 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
615 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
616 
617 	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
618 	LFREEPATH(path);
619 	return (error);
620 }
621 
622 #ifdef LINUX_LEGACY_SYSCALLS
623 int
624 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
625 {
626 	char *path;
627 	int error;
628 
629 	LCONVPATHCREAT(td, args->path, &path);
630 
631 	error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
632 	LFREEPATH(path);
633 	return (error);
634 }
635 #endif
636 
637 int
638 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
639 {
640 	char *path;
641 	int error, dfd;
642 
643 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
644 	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
645 
646 	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
647 	LFREEPATH(path);
648 	return (error);
649 }
650 
651 #ifdef LINUX_LEGACY_SYSCALLS
652 int
653 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
654 {
655 	char *path;
656 	int error;
657 
658 	LCONVPATHEXIST(td, args->path, &path);
659 
660 	error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
661 	LFREEPATH(path);
662 	return (error);
663 }
664 
665 int
666 linux_rename(struct thread *td, struct linux_rename_args *args)
667 {
668 	char *from, *to;
669 	int error;
670 
671 	LCONVPATHEXIST(td, args->from, &from);
672 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
673 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
674 	if (to == NULL) {
675 		LFREEPATH(from);
676 		return (error);
677 	}
678 
679 	error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
680 	LFREEPATH(from);
681 	LFREEPATH(to);
682 	return (error);
683 }
684 #endif
685 
686 int
687 linux_renameat(struct thread *td, struct linux_renameat_args *args)
688 {
689 	char *from, *to;
690 	int error, olddfd, newdfd;
691 
692 	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
693 	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
694 	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
695 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
696 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
697 	if (to == NULL) {
698 		LFREEPATH(from);
699 		return (error);
700 	}
701 
702 	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
703 	LFREEPATH(from);
704 	LFREEPATH(to);
705 	return (error);
706 }
707 
708 #ifdef LINUX_LEGACY_SYSCALLS
709 int
710 linux_symlink(struct thread *td, struct linux_symlink_args *args)
711 {
712 	char *path, *to;
713 	int error;
714 
715 	LCONVPATHEXIST(td, args->path, &path);
716 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
717 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
718 	if (to == NULL) {
719 		LFREEPATH(path);
720 		return (error);
721 	}
722 
723 	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
724 	LFREEPATH(path);
725 	LFREEPATH(to);
726 	return (error);
727 }
728 #endif
729 
730 int
731 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
732 {
733 	char *path, *to;
734 	int error, dfd;
735 
736 	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
737 	LCONVPATHEXIST(td, args->oldname, &path);
738 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
739 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
740 	if (to == NULL) {
741 		LFREEPATH(path);
742 		return (error);
743 	}
744 
745 	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
746 	LFREEPATH(path);
747 	LFREEPATH(to);
748 	return (error);
749 }
750 
751 #ifdef LINUX_LEGACY_SYSCALLS
752 int
753 linux_readlink(struct thread *td, struct linux_readlink_args *args)
754 {
755 	char *name;
756 	int error;
757 
758 	LCONVPATHEXIST(td, args->name, &name);
759 
760 	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
761 	    args->buf, UIO_USERSPACE, args->count);
762 	LFREEPATH(name);
763 	return (error);
764 }
765 #endif
766 
767 int
768 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
769 {
770 	char *name;
771 	int error, dfd;
772 
773 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
774 	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
775 
776 	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
777 	    UIO_USERSPACE, args->bufsiz);
778 	LFREEPATH(name);
779 	return (error);
780 }
781 
782 int
783 linux_truncate(struct thread *td, struct linux_truncate_args *args)
784 {
785 	char *path;
786 	int error;
787 
788 	LCONVPATHEXIST(td, args->path, &path);
789 
790 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
791 	LFREEPATH(path);
792 	return (error);
793 }
794 
795 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
796 int
797 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
798 {
799 	char *path;
800 	int error;
801 
802 	LCONVPATHEXIST(td, args->path, &path);
803 
804 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
805 	LFREEPATH(path);
806 	return (error);
807 }
808 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
809 
810 int
811 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
812 {
813 
814 	return (kern_ftruncate(td, args->fd, args->length));
815 }
816 
817 #ifdef LINUX_LEGACY_SYSCALLS
818 int
819 linux_link(struct thread *td, struct linux_link_args *args)
820 {
821 	char *path, *to;
822 	int error;
823 
824 	LCONVPATHEXIST(td, args->path, &path);
825 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
826 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
827 	if (to == NULL) {
828 		LFREEPATH(path);
829 		return (error);
830 	}
831 
832 	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
833 	    FOLLOW);
834 	LFREEPATH(path);
835 	LFREEPATH(to);
836 	return (error);
837 }
838 #endif
839 
840 int
841 linux_linkat(struct thread *td, struct linux_linkat_args *args)
842 {
843 	char *path, *to;
844 	int error, olddfd, newdfd, follow;
845 
846 	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
847 		return (EINVAL);
848 
849 	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
850 	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
851 	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
852 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
853 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
854 	if (to == NULL) {
855 		LFREEPATH(path);
856 		return (error);
857 	}
858 
859 	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
860 	    FOLLOW;
861 	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
862 	LFREEPATH(path);
863 	LFREEPATH(to);
864 	return (error);
865 }
866 
867 int
868 linux_fdatasync(td, uap)
869 	struct thread *td;
870 	struct linux_fdatasync_args *uap;
871 {
872 
873 	return (kern_fsync(td, uap->fd, false));
874 }
875 
876 int
877 linux_pread(struct thread *td, struct linux_pread_args *uap)
878 {
879 	struct vnode *vp;
880 	int error;
881 
882 	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
883 	if (error == 0) {
884 		/* This seems to violate POSIX but Linux does it. */
885 		error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
886 		if (error != 0)
887 			return (error);
888 		if (vp->v_type == VDIR) {
889 			vrele(vp);
890 			return (EISDIR);
891 		}
892 		vrele(vp);
893 	}
894 	return (error);
895 }
896 
897 int
898 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
899 {
900 
901 	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
902 }
903 
904 int
905 linux_preadv(struct thread *td, struct linux_preadv_args *uap)
906 {
907 	struct uio *auio;
908 	int error;
909 	off_t offset;
910 
911 	/*
912 	 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
913 	 * pos_l and pos_h, respectively, contain the
914 	 * low order and high order 32 bits of offset.
915 	 */
916 	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
917 	    (sizeof(offset) * 4)) | uap->pos_l;
918 	if (offset < 0)
919 		return (EINVAL);
920 #ifdef COMPAT_LINUX32
921 	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
922 #else
923 	error = copyinuio(uap->vec, uap->vlen, &auio);
924 #endif
925 	if (error != 0)
926 		return (error);
927 	error = kern_preadv(td, uap->fd, auio, offset);
928 	free(auio, M_IOV);
929 	return (error);
930 }
931 
932 int
933 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
934 {
935 	struct uio *auio;
936 	int error;
937 	off_t offset;
938 
939 	/*
940 	 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
941 	 * pos_l and pos_h, respectively, contain the
942 	 * low order and high order 32 bits of offset.
943 	 */
944 	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
945 	    (sizeof(offset) * 4)) | uap->pos_l;
946 	if (offset < 0)
947 		return (EINVAL);
948 #ifdef COMPAT_LINUX32
949 	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
950 #else
951 	error = copyinuio(uap->vec, uap->vlen, &auio);
952 #endif
953 	if (error != 0)
954 		return (error);
955 	error = kern_pwritev(td, uap->fd, auio, offset);
956 	free(auio, M_IOV);
957 	return (error);
958 }
959 
960 int
961 linux_mount(struct thread *td, struct linux_mount_args *args)
962 {
963 	char fstypename[MFSNAMELEN];
964 	char *mntonname, *mntfromname;
965 	int error, fsflags;
966 
967 	mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
968 	mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
969 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
970 	    NULL);
971 	if (error != 0)
972 		goto out;
973 	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
974 	if (error != 0)
975 		goto out;
976 	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
977 	if (error != 0)
978 		goto out;
979 
980 	if (strcmp(fstypename, "ext2") == 0) {
981 		strcpy(fstypename, "ext2fs");
982 	} else if (strcmp(fstypename, "proc") == 0) {
983 		strcpy(fstypename, "linprocfs");
984 	} else if (strcmp(fstypename, "vfat") == 0) {
985 		strcpy(fstypename, "msdosfs");
986 	}
987 
988 	fsflags = 0;
989 
990 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
991 		/*
992 		 * Linux SYNC flag is not included; the closest equivalent
993 		 * FreeBSD has is !ASYNC, which is our default.
994 		 */
995 		if (args->rwflag & LINUX_MS_RDONLY)
996 			fsflags |= MNT_RDONLY;
997 		if (args->rwflag & LINUX_MS_NOSUID)
998 			fsflags |= MNT_NOSUID;
999 		if (args->rwflag & LINUX_MS_NOEXEC)
1000 			fsflags |= MNT_NOEXEC;
1001 		if (args->rwflag & LINUX_MS_REMOUNT)
1002 			fsflags |= MNT_UPDATE;
1003 	}
1004 
1005 	error = kernel_vmount(fsflags,
1006 	    "fstype", fstypename,
1007 	    "fspath", mntonname,
1008 	    "from", mntfromname,
1009 	    NULL);
1010 out:
1011 	free(mntonname, M_TEMP);
1012 	free(mntfromname, M_TEMP);
1013 	return (error);
1014 }
1015 
1016 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1017 int
1018 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1019 {
1020 	struct linux_umount_args args2;
1021 
1022 	args2.path = args->path;
1023 	args2.flags = 0;
1024 	return (linux_umount(td, &args2));
1025 }
1026 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1027 
1028 #ifdef LINUX_LEGACY_SYSCALLS
1029 int
1030 linux_umount(struct thread *td, struct linux_umount_args *args)
1031 {
1032 	struct unmount_args bsd;
1033 
1034 	bsd.path = args->path;
1035 	bsd.flags = args->flags;	/* XXX correct? */
1036 	return (sys_unmount(td, &bsd));
1037 }
1038 #endif
1039 
1040 /*
1041  * fcntl family of syscalls
1042  */
1043 
1044 struct l_flock {
1045 	l_short		l_type;
1046 	l_short		l_whence;
1047 	l_off_t		l_start;
1048 	l_off_t		l_len;
1049 	l_pid_t		l_pid;
1050 }
1051 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1052 __packed
1053 #endif
1054 ;
1055 
1056 static void
1057 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1058 {
1059 	switch (linux_flock->l_type) {
1060 	case LINUX_F_RDLCK:
1061 		bsd_flock->l_type = F_RDLCK;
1062 		break;
1063 	case LINUX_F_WRLCK:
1064 		bsd_flock->l_type = F_WRLCK;
1065 		break;
1066 	case LINUX_F_UNLCK:
1067 		bsd_flock->l_type = F_UNLCK;
1068 		break;
1069 	default:
1070 		bsd_flock->l_type = -1;
1071 		break;
1072 	}
1073 	bsd_flock->l_whence = linux_flock->l_whence;
1074 	bsd_flock->l_start = (off_t)linux_flock->l_start;
1075 	bsd_flock->l_len = (off_t)linux_flock->l_len;
1076 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1077 	bsd_flock->l_sysid = 0;
1078 }
1079 
1080 static void
1081 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1082 {
1083 	switch (bsd_flock->l_type) {
1084 	case F_RDLCK:
1085 		linux_flock->l_type = LINUX_F_RDLCK;
1086 		break;
1087 	case F_WRLCK:
1088 		linux_flock->l_type = LINUX_F_WRLCK;
1089 		break;
1090 	case F_UNLCK:
1091 		linux_flock->l_type = LINUX_F_UNLCK;
1092 		break;
1093 	}
1094 	linux_flock->l_whence = bsd_flock->l_whence;
1095 	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1096 	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1097 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1098 }
1099 
1100 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1101 struct l_flock64 {
1102 	l_short		l_type;
1103 	l_short		l_whence;
1104 	l_loff_t	l_start;
1105 	l_loff_t	l_len;
1106 	l_pid_t		l_pid;
1107 }
1108 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1109 __packed
1110 #endif
1111 ;
1112 
1113 static void
1114 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1115 {
1116 	switch (linux_flock->l_type) {
1117 	case LINUX_F_RDLCK:
1118 		bsd_flock->l_type = F_RDLCK;
1119 		break;
1120 	case LINUX_F_WRLCK:
1121 		bsd_flock->l_type = F_WRLCK;
1122 		break;
1123 	case LINUX_F_UNLCK:
1124 		bsd_flock->l_type = F_UNLCK;
1125 		break;
1126 	default:
1127 		bsd_flock->l_type = -1;
1128 		break;
1129 	}
1130 	bsd_flock->l_whence = linux_flock->l_whence;
1131 	bsd_flock->l_start = (off_t)linux_flock->l_start;
1132 	bsd_flock->l_len = (off_t)linux_flock->l_len;
1133 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1134 	bsd_flock->l_sysid = 0;
1135 }
1136 
1137 static void
1138 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1139 {
1140 	switch (bsd_flock->l_type) {
1141 	case F_RDLCK:
1142 		linux_flock->l_type = LINUX_F_RDLCK;
1143 		break;
1144 	case F_WRLCK:
1145 		linux_flock->l_type = LINUX_F_WRLCK;
1146 		break;
1147 	case F_UNLCK:
1148 		linux_flock->l_type = LINUX_F_UNLCK;
1149 		break;
1150 	}
1151 	linux_flock->l_whence = bsd_flock->l_whence;
1152 	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1153 	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1154 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1155 }
1156 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1157 
1158 static int
1159 fcntl_common(struct thread *td, struct linux_fcntl_args *args)
1160 {
1161 	struct l_flock linux_flock;
1162 	struct flock bsd_flock;
1163 	struct file *fp;
1164 	long arg;
1165 	int error, result;
1166 
1167 	switch (args->cmd) {
1168 	case LINUX_F_DUPFD:
1169 		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1170 
1171 	case LINUX_F_GETFD:
1172 		return (kern_fcntl(td, args->fd, F_GETFD, 0));
1173 
1174 	case LINUX_F_SETFD:
1175 		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1176 
1177 	case LINUX_F_GETFL:
1178 		error = kern_fcntl(td, args->fd, F_GETFL, 0);
1179 		result = td->td_retval[0];
1180 		td->td_retval[0] = 0;
1181 		if (result & O_RDONLY)
1182 			td->td_retval[0] |= LINUX_O_RDONLY;
1183 		if (result & O_WRONLY)
1184 			td->td_retval[0] |= LINUX_O_WRONLY;
1185 		if (result & O_RDWR)
1186 			td->td_retval[0] |= LINUX_O_RDWR;
1187 		if (result & O_NDELAY)
1188 			td->td_retval[0] |= LINUX_O_NONBLOCK;
1189 		if (result & O_APPEND)
1190 			td->td_retval[0] |= LINUX_O_APPEND;
1191 		if (result & O_FSYNC)
1192 			td->td_retval[0] |= LINUX_O_SYNC;
1193 		if (result & O_ASYNC)
1194 			td->td_retval[0] |= LINUX_FASYNC;
1195 #ifdef LINUX_O_NOFOLLOW
1196 		if (result & O_NOFOLLOW)
1197 			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1198 #endif
1199 #ifdef LINUX_O_DIRECT
1200 		if (result & O_DIRECT)
1201 			td->td_retval[0] |= LINUX_O_DIRECT;
1202 #endif
1203 		return (error);
1204 
1205 	case LINUX_F_SETFL:
1206 		arg = 0;
1207 		if (args->arg & LINUX_O_NDELAY)
1208 			arg |= O_NONBLOCK;
1209 		if (args->arg & LINUX_O_APPEND)
1210 			arg |= O_APPEND;
1211 		if (args->arg & LINUX_O_SYNC)
1212 			arg |= O_FSYNC;
1213 		if (args->arg & LINUX_FASYNC)
1214 			arg |= O_ASYNC;
1215 #ifdef LINUX_O_NOFOLLOW
1216 		if (args->arg & LINUX_O_NOFOLLOW)
1217 			arg |= O_NOFOLLOW;
1218 #endif
1219 #ifdef LINUX_O_DIRECT
1220 		if (args->arg & LINUX_O_DIRECT)
1221 			arg |= O_DIRECT;
1222 #endif
1223 		return (kern_fcntl(td, args->fd, F_SETFL, arg));
1224 
1225 	case LINUX_F_GETLK:
1226 		error = copyin((void *)args->arg, &linux_flock,
1227 		    sizeof(linux_flock));
1228 		if (error)
1229 			return (error);
1230 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1231 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1232 		if (error)
1233 			return (error);
1234 		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1235 		return (copyout(&linux_flock, (void *)args->arg,
1236 		    sizeof(linux_flock)));
1237 
1238 	case LINUX_F_SETLK:
1239 		error = copyin((void *)args->arg, &linux_flock,
1240 		    sizeof(linux_flock));
1241 		if (error)
1242 			return (error);
1243 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1244 		return (kern_fcntl(td, args->fd, F_SETLK,
1245 		    (intptr_t)&bsd_flock));
1246 
1247 	case LINUX_F_SETLKW:
1248 		error = copyin((void *)args->arg, &linux_flock,
1249 		    sizeof(linux_flock));
1250 		if (error)
1251 			return (error);
1252 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1253 		return (kern_fcntl(td, args->fd, F_SETLKW,
1254 		     (intptr_t)&bsd_flock));
1255 
1256 	case LINUX_F_GETOWN:
1257 		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1258 
1259 	case LINUX_F_SETOWN:
1260 		/*
1261 		 * XXX some Linux applications depend on F_SETOWN having no
1262 		 * significant effect for pipes (SIGIO is not delivered for
1263 		 * pipes under Linux-2.2.35 at least).
1264 		 */
1265 		error = fget(td, args->fd,
1266 		    &cap_fcntl_rights, &fp);
1267 		if (error)
1268 			return (error);
1269 		if (fp->f_type == DTYPE_PIPE) {
1270 			fdrop(fp, td);
1271 			return (EINVAL);
1272 		}
1273 		fdrop(fp, td);
1274 
1275 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1276 
1277 	case LINUX_F_DUPFD_CLOEXEC:
1278 		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
1279 	}
1280 
1281 	return (EINVAL);
1282 }
1283 
1284 int
1285 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1286 {
1287 
1288 	return (fcntl_common(td, args));
1289 }
1290 
1291 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1292 int
1293 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1294 {
1295 	struct l_flock64 linux_flock;
1296 	struct flock bsd_flock;
1297 	struct linux_fcntl_args fcntl_args;
1298 	int error;
1299 
1300 	switch (args->cmd) {
1301 	case LINUX_F_GETLK64:
1302 		error = copyin((void *)args->arg, &linux_flock,
1303 		    sizeof(linux_flock));
1304 		if (error)
1305 			return (error);
1306 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1307 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1308 		if (error)
1309 			return (error);
1310 		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1311 		return (copyout(&linux_flock, (void *)args->arg,
1312 			    sizeof(linux_flock)));
1313 
1314 	case LINUX_F_SETLK64:
1315 		error = copyin((void *)args->arg, &linux_flock,
1316 		    sizeof(linux_flock));
1317 		if (error)
1318 			return (error);
1319 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1320 		return (kern_fcntl(td, args->fd, F_SETLK,
1321 		    (intptr_t)&bsd_flock));
1322 
1323 	case LINUX_F_SETLKW64:
1324 		error = copyin((void *)args->arg, &linux_flock,
1325 		    sizeof(linux_flock));
1326 		if (error)
1327 			return (error);
1328 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1329 		return (kern_fcntl(td, args->fd, F_SETLKW,
1330 		    (intptr_t)&bsd_flock));
1331 	}
1332 
1333 	fcntl_args.fd = args->fd;
1334 	fcntl_args.cmd = args->cmd;
1335 	fcntl_args.arg = args->arg;
1336 	return (fcntl_common(td, &fcntl_args));
1337 }
1338 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1339 
1340 #ifdef LINUX_LEGACY_SYSCALLS
1341 int
1342 linux_chown(struct thread *td, struct linux_chown_args *args)
1343 {
1344 	char *path;
1345 	int error;
1346 
1347 	LCONVPATHEXIST(td, args->path, &path);
1348 
1349 	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1350 	    args->gid, 0);
1351 	LFREEPATH(path);
1352 	return (error);
1353 }
1354 #endif
1355 
1356 int
1357 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1358 {
1359 	char *path;
1360 	int error, dfd, flag;
1361 
1362 	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1363 		return (EINVAL);
1364 
1365 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1366 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1367 
1368 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1369 	    AT_SYMLINK_NOFOLLOW;
1370 	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1371 	    flag);
1372 	LFREEPATH(path);
1373 	return (error);
1374 }
1375 
1376 #ifdef LINUX_LEGACY_SYSCALLS
1377 int
1378 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1379 {
1380 	char *path;
1381 	int error;
1382 
1383 	LCONVPATHEXIST(td, args->path, &path);
1384 
1385 	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1386 	    args->gid, AT_SYMLINK_NOFOLLOW);
1387 	LFREEPATH(path);
1388 	return (error);
1389 }
1390 #endif
1391 
1392 static int
1393 convert_fadvice(int advice)
1394 {
1395 	switch (advice) {
1396 	case LINUX_POSIX_FADV_NORMAL:
1397 		return (POSIX_FADV_NORMAL);
1398 	case LINUX_POSIX_FADV_RANDOM:
1399 		return (POSIX_FADV_RANDOM);
1400 	case LINUX_POSIX_FADV_SEQUENTIAL:
1401 		return (POSIX_FADV_SEQUENTIAL);
1402 	case LINUX_POSIX_FADV_WILLNEED:
1403 		return (POSIX_FADV_WILLNEED);
1404 	case LINUX_POSIX_FADV_DONTNEED:
1405 		return (POSIX_FADV_DONTNEED);
1406 	case LINUX_POSIX_FADV_NOREUSE:
1407 		return (POSIX_FADV_NOREUSE);
1408 	default:
1409 		return (-1);
1410 	}
1411 }
1412 
1413 int
1414 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1415 {
1416 	int advice;
1417 
1418 	advice = convert_fadvice(args->advice);
1419 	if (advice == -1)
1420 		return (EINVAL);
1421 	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1422 	    advice));
1423 }
1424 
1425 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1426 int
1427 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1428 {
1429 	int advice;
1430 
1431 	advice = convert_fadvice(args->advice);
1432 	if (advice == -1)
1433 		return (EINVAL);
1434 	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1435 	    advice));
1436 }
1437 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1438 
1439 #ifdef LINUX_LEGACY_SYSCALLS
1440 int
1441 linux_pipe(struct thread *td, struct linux_pipe_args *args)
1442 {
1443 	int fildes[2];
1444 	int error;
1445 
1446 	error = kern_pipe(td, fildes, 0, NULL, NULL);
1447 	if (error != 0)
1448 		return (error);
1449 
1450 	error = copyout(fildes, args->pipefds, sizeof(fildes));
1451 	if (error != 0) {
1452 		(void)kern_close(td, fildes[0]);
1453 		(void)kern_close(td, fildes[1]);
1454 	}
1455 
1456 	return (error);
1457 }
1458 #endif
1459 
1460 int
1461 linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1462 {
1463 	int fildes[2];
1464 	int error, flags;
1465 
1466 	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1467 		return (EINVAL);
1468 
1469 	flags = 0;
1470 	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1471 		flags |= O_NONBLOCK;
1472 	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1473 		flags |= O_CLOEXEC;
1474 	error = kern_pipe(td, fildes, flags, NULL, NULL);
1475 	if (error != 0)
1476 		return (error);
1477 
1478 	error = copyout(fildes, args->pipefds, sizeof(fildes));
1479 	if (error != 0) {
1480 		(void)kern_close(td, fildes[0]);
1481 		(void)kern_close(td, fildes[1]);
1482 	}
1483 
1484 	return (error);
1485 }
1486 
1487 int
1488 linux_dup3(struct thread *td, struct linux_dup3_args *args)
1489 {
1490 	int cmd;
1491 	intptr_t newfd;
1492 
1493 	if (args->oldfd == args->newfd)
1494 		return (EINVAL);
1495 	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1496 		return (EINVAL);
1497 	if (args->flags & LINUX_O_CLOEXEC)
1498 		cmd = F_DUP2FD_CLOEXEC;
1499 	else
1500 		cmd = F_DUP2FD;
1501 
1502 	newfd = args->newfd;
1503 	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1504 }
1505 
1506 int
1507 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1508 {
1509 
1510 	/*
1511 	 * We emulate only posix_fallocate system call for which
1512 	 * mode should be 0.
1513 	 */
1514 	if (args->mode != 0)
1515 		return (ENOSYS);
1516 
1517 	return (kern_posix_fallocate(td, args->fd, args->offset,
1518 	    args->len));
1519 }
1520