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