xref: /freebsd/sys/compat/linux/linux_file.c (revision c950e612873480cd06b61cae2cc024675d6cacd4)
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 	struct linux_renameat2_args renameat2_args = {
690 	    .olddfd = args->olddfd,
691 	    .oldname = args->oldname,
692 	    .newdfd = args->newdfd,
693 	    .newname = args->newname,
694 	    .flags = 0
695 	};
696 
697 	return (linux_renameat2(td, &renameat2_args));
698 }
699 
700 int
701 linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
702 {
703 	char *from, *to;
704 	int error, olddfd, newdfd;
705 
706 	if (args->flags != 0) {
707 		linux_msg(td, "renameat2 unsupported flags 0x%x\n",
708 		    args->flags);
709 		return (EINVAL);
710 	}
711 
712 	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
713 	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
714 	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
715 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
716 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
717 	if (to == NULL) {
718 		LFREEPATH(from);
719 		return (error);
720 	}
721 
722 	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
723 	LFREEPATH(from);
724 	LFREEPATH(to);
725 	return (error);
726 }
727 
728 #ifdef LINUX_LEGACY_SYSCALLS
729 int
730 linux_symlink(struct thread *td, struct linux_symlink_args *args)
731 {
732 	char *path, *to;
733 	int error;
734 
735 	LCONVPATHEXIST(td, args->path, &path);
736 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
737 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
738 	if (to == NULL) {
739 		LFREEPATH(path);
740 		return (error);
741 	}
742 
743 	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
744 	LFREEPATH(path);
745 	LFREEPATH(to);
746 	return (error);
747 }
748 #endif
749 
750 int
751 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
752 {
753 	char *path, *to;
754 	int error, dfd;
755 
756 	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
757 	LCONVPATHEXIST(td, args->oldname, &path);
758 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
759 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
760 	if (to == NULL) {
761 		LFREEPATH(path);
762 		return (error);
763 	}
764 
765 	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
766 	LFREEPATH(path);
767 	LFREEPATH(to);
768 	return (error);
769 }
770 
771 #ifdef LINUX_LEGACY_SYSCALLS
772 int
773 linux_readlink(struct thread *td, struct linux_readlink_args *args)
774 {
775 	char *name;
776 	int error;
777 
778 	LCONVPATHEXIST(td, args->name, &name);
779 
780 	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
781 	    args->buf, UIO_USERSPACE, args->count);
782 	LFREEPATH(name);
783 	return (error);
784 }
785 #endif
786 
787 int
788 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
789 {
790 	char *name;
791 	int error, dfd;
792 
793 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
794 	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
795 
796 	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
797 	    UIO_USERSPACE, args->bufsiz);
798 	LFREEPATH(name);
799 	return (error);
800 }
801 
802 int
803 linux_truncate(struct thread *td, struct linux_truncate_args *args)
804 {
805 	char *path;
806 	int error;
807 
808 	LCONVPATHEXIST(td, args->path, &path);
809 
810 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
811 	LFREEPATH(path);
812 	return (error);
813 }
814 
815 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
816 int
817 linux_truncate64(struct thread *td, struct linux_truncate64_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 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
829 
830 int
831 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
832 {
833 
834 	return (kern_ftruncate(td, args->fd, args->length));
835 }
836 
837 #ifdef LINUX_LEGACY_SYSCALLS
838 int
839 linux_link(struct thread *td, struct linux_link_args *args)
840 {
841 	char *path, *to;
842 	int error;
843 
844 	LCONVPATHEXIST(td, args->path, &path);
845 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
846 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
847 	if (to == NULL) {
848 		LFREEPATH(path);
849 		return (error);
850 	}
851 
852 	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
853 	    FOLLOW);
854 	LFREEPATH(path);
855 	LFREEPATH(to);
856 	return (error);
857 }
858 #endif
859 
860 int
861 linux_linkat(struct thread *td, struct linux_linkat_args *args)
862 {
863 	char *path, *to;
864 	int error, olddfd, newdfd, follow;
865 
866 	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
867 		return (EINVAL);
868 
869 	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
870 	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
871 	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
872 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
873 	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
874 	if (to == NULL) {
875 		LFREEPATH(path);
876 		return (error);
877 	}
878 
879 	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
880 	    FOLLOW;
881 	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
882 	LFREEPATH(path);
883 	LFREEPATH(to);
884 	return (error);
885 }
886 
887 int
888 linux_fdatasync(td, uap)
889 	struct thread *td;
890 	struct linux_fdatasync_args *uap;
891 {
892 
893 	return (kern_fsync(td, uap->fd, false));
894 }
895 
896 int
897 linux_pread(struct thread *td, struct linux_pread_args *uap)
898 {
899 	struct vnode *vp;
900 	int error;
901 
902 	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
903 	if (error == 0) {
904 		/* This seems to violate POSIX but Linux does it. */
905 		error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
906 		if (error != 0)
907 			return (error);
908 		if (vp->v_type == VDIR) {
909 			vrele(vp);
910 			return (EISDIR);
911 		}
912 		vrele(vp);
913 	}
914 	return (error);
915 }
916 
917 int
918 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
919 {
920 
921 	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
922 }
923 
924 int
925 linux_preadv(struct thread *td, struct linux_preadv_args *uap)
926 {
927 	struct uio *auio;
928 	int error;
929 	off_t offset;
930 
931 	/*
932 	 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
933 	 * pos_l and pos_h, respectively, contain the
934 	 * low order and high order 32 bits of offset.
935 	 */
936 	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
937 	    (sizeof(offset) * 4)) | uap->pos_l;
938 	if (offset < 0)
939 		return (EINVAL);
940 #ifdef COMPAT_LINUX32
941 	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
942 #else
943 	error = copyinuio(uap->vec, uap->vlen, &auio);
944 #endif
945 	if (error != 0)
946 		return (error);
947 	error = kern_preadv(td, uap->fd, auio, offset);
948 	free(auio, M_IOV);
949 	return (error);
950 }
951 
952 int
953 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
954 {
955 	struct uio *auio;
956 	int error;
957 	off_t offset;
958 
959 	/*
960 	 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
961 	 * pos_l and pos_h, respectively, contain the
962 	 * low order and high order 32 bits of offset.
963 	 */
964 	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
965 	    (sizeof(offset) * 4)) | uap->pos_l;
966 	if (offset < 0)
967 		return (EINVAL);
968 #ifdef COMPAT_LINUX32
969 	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
970 #else
971 	error = copyinuio(uap->vec, uap->vlen, &auio);
972 #endif
973 	if (error != 0)
974 		return (error);
975 	error = kern_pwritev(td, uap->fd, auio, offset);
976 	free(auio, M_IOV);
977 	return (error);
978 }
979 
980 int
981 linux_mount(struct thread *td, struct linux_mount_args *args)
982 {
983 	char fstypename[MFSNAMELEN];
984 	char *mntonname, *mntfromname;
985 	int error, fsflags;
986 
987 	mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
988 	mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
989 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
990 	    NULL);
991 	if (error != 0)
992 		goto out;
993 	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
994 	if (error != 0)
995 		goto out;
996 	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
997 	if (error != 0)
998 		goto out;
999 
1000 	if (strcmp(fstypename, "ext2") == 0) {
1001 		strcpy(fstypename, "ext2fs");
1002 	} else if (strcmp(fstypename, "proc") == 0) {
1003 		strcpy(fstypename, "linprocfs");
1004 	} else if (strcmp(fstypename, "vfat") == 0) {
1005 		strcpy(fstypename, "msdosfs");
1006 	}
1007 
1008 	fsflags = 0;
1009 
1010 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
1011 		/*
1012 		 * Linux SYNC flag is not included; the closest equivalent
1013 		 * FreeBSD has is !ASYNC, which is our default.
1014 		 */
1015 		if (args->rwflag & LINUX_MS_RDONLY)
1016 			fsflags |= MNT_RDONLY;
1017 		if (args->rwflag & LINUX_MS_NOSUID)
1018 			fsflags |= MNT_NOSUID;
1019 		if (args->rwflag & LINUX_MS_NOEXEC)
1020 			fsflags |= MNT_NOEXEC;
1021 		if (args->rwflag & LINUX_MS_REMOUNT)
1022 			fsflags |= MNT_UPDATE;
1023 	}
1024 
1025 	error = kernel_vmount(fsflags,
1026 	    "fstype", fstypename,
1027 	    "fspath", mntonname,
1028 	    "from", mntfromname,
1029 	    NULL);
1030 out:
1031 	free(mntonname, M_TEMP);
1032 	free(mntfromname, M_TEMP);
1033 	return (error);
1034 }
1035 
1036 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1037 int
1038 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1039 {
1040 	struct linux_umount_args args2;
1041 
1042 	args2.path = args->path;
1043 	args2.flags = 0;
1044 	return (linux_umount(td, &args2));
1045 }
1046 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1047 
1048 #ifdef LINUX_LEGACY_SYSCALLS
1049 int
1050 linux_umount(struct thread *td, struct linux_umount_args *args)
1051 {
1052 	struct unmount_args bsd;
1053 
1054 	bsd.path = args->path;
1055 	bsd.flags = args->flags;	/* XXX correct? */
1056 	return (sys_unmount(td, &bsd));
1057 }
1058 #endif
1059 
1060 /*
1061  * fcntl family of syscalls
1062  */
1063 
1064 struct l_flock {
1065 	l_short		l_type;
1066 	l_short		l_whence;
1067 	l_off_t		l_start;
1068 	l_off_t		l_len;
1069 	l_pid_t		l_pid;
1070 }
1071 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1072 __packed
1073 #endif
1074 ;
1075 
1076 static void
1077 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1078 {
1079 	switch (linux_flock->l_type) {
1080 	case LINUX_F_RDLCK:
1081 		bsd_flock->l_type = F_RDLCK;
1082 		break;
1083 	case LINUX_F_WRLCK:
1084 		bsd_flock->l_type = F_WRLCK;
1085 		break;
1086 	case LINUX_F_UNLCK:
1087 		bsd_flock->l_type = F_UNLCK;
1088 		break;
1089 	default:
1090 		bsd_flock->l_type = -1;
1091 		break;
1092 	}
1093 	bsd_flock->l_whence = linux_flock->l_whence;
1094 	bsd_flock->l_start = (off_t)linux_flock->l_start;
1095 	bsd_flock->l_len = (off_t)linux_flock->l_len;
1096 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1097 	bsd_flock->l_sysid = 0;
1098 }
1099 
1100 static void
1101 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1102 {
1103 	switch (bsd_flock->l_type) {
1104 	case F_RDLCK:
1105 		linux_flock->l_type = LINUX_F_RDLCK;
1106 		break;
1107 	case F_WRLCK:
1108 		linux_flock->l_type = LINUX_F_WRLCK;
1109 		break;
1110 	case F_UNLCK:
1111 		linux_flock->l_type = LINUX_F_UNLCK;
1112 		break;
1113 	}
1114 	linux_flock->l_whence = bsd_flock->l_whence;
1115 	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1116 	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1117 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1118 }
1119 
1120 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1121 struct l_flock64 {
1122 	l_short		l_type;
1123 	l_short		l_whence;
1124 	l_loff_t	l_start;
1125 	l_loff_t	l_len;
1126 	l_pid_t		l_pid;
1127 }
1128 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1129 __packed
1130 #endif
1131 ;
1132 
1133 static void
1134 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1135 {
1136 	switch (linux_flock->l_type) {
1137 	case LINUX_F_RDLCK:
1138 		bsd_flock->l_type = F_RDLCK;
1139 		break;
1140 	case LINUX_F_WRLCK:
1141 		bsd_flock->l_type = F_WRLCK;
1142 		break;
1143 	case LINUX_F_UNLCK:
1144 		bsd_flock->l_type = F_UNLCK;
1145 		break;
1146 	default:
1147 		bsd_flock->l_type = -1;
1148 		break;
1149 	}
1150 	bsd_flock->l_whence = linux_flock->l_whence;
1151 	bsd_flock->l_start = (off_t)linux_flock->l_start;
1152 	bsd_flock->l_len = (off_t)linux_flock->l_len;
1153 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1154 	bsd_flock->l_sysid = 0;
1155 }
1156 
1157 static void
1158 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1159 {
1160 	switch (bsd_flock->l_type) {
1161 	case F_RDLCK:
1162 		linux_flock->l_type = LINUX_F_RDLCK;
1163 		break;
1164 	case F_WRLCK:
1165 		linux_flock->l_type = LINUX_F_WRLCK;
1166 		break;
1167 	case F_UNLCK:
1168 		linux_flock->l_type = LINUX_F_UNLCK;
1169 		break;
1170 	}
1171 	linux_flock->l_whence = bsd_flock->l_whence;
1172 	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1173 	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1174 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1175 }
1176 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1177 
1178 static int
1179 fcntl_common(struct thread *td, struct linux_fcntl_args *args)
1180 {
1181 	struct l_flock linux_flock;
1182 	struct flock bsd_flock;
1183 	struct file *fp;
1184 	long arg;
1185 	int error, result;
1186 
1187 	switch (args->cmd) {
1188 	case LINUX_F_DUPFD:
1189 		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1190 
1191 	case LINUX_F_GETFD:
1192 		return (kern_fcntl(td, args->fd, F_GETFD, 0));
1193 
1194 	case LINUX_F_SETFD:
1195 		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1196 
1197 	case LINUX_F_GETFL:
1198 		error = kern_fcntl(td, args->fd, F_GETFL, 0);
1199 		result = td->td_retval[0];
1200 		td->td_retval[0] = 0;
1201 		if (result & O_RDONLY)
1202 			td->td_retval[0] |= LINUX_O_RDONLY;
1203 		if (result & O_WRONLY)
1204 			td->td_retval[0] |= LINUX_O_WRONLY;
1205 		if (result & O_RDWR)
1206 			td->td_retval[0] |= LINUX_O_RDWR;
1207 		if (result & O_NDELAY)
1208 			td->td_retval[0] |= LINUX_O_NONBLOCK;
1209 		if (result & O_APPEND)
1210 			td->td_retval[0] |= LINUX_O_APPEND;
1211 		if (result & O_FSYNC)
1212 			td->td_retval[0] |= LINUX_O_SYNC;
1213 		if (result & O_ASYNC)
1214 			td->td_retval[0] |= LINUX_FASYNC;
1215 #ifdef LINUX_O_NOFOLLOW
1216 		if (result & O_NOFOLLOW)
1217 			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1218 #endif
1219 #ifdef LINUX_O_DIRECT
1220 		if (result & O_DIRECT)
1221 			td->td_retval[0] |= LINUX_O_DIRECT;
1222 #endif
1223 		return (error);
1224 
1225 	case LINUX_F_SETFL:
1226 		arg = 0;
1227 		if (args->arg & LINUX_O_NDELAY)
1228 			arg |= O_NONBLOCK;
1229 		if (args->arg & LINUX_O_APPEND)
1230 			arg |= O_APPEND;
1231 		if (args->arg & LINUX_O_SYNC)
1232 			arg |= O_FSYNC;
1233 		if (args->arg & LINUX_FASYNC)
1234 			arg |= O_ASYNC;
1235 #ifdef LINUX_O_NOFOLLOW
1236 		if (args->arg & LINUX_O_NOFOLLOW)
1237 			arg |= O_NOFOLLOW;
1238 #endif
1239 #ifdef LINUX_O_DIRECT
1240 		if (args->arg & LINUX_O_DIRECT)
1241 			arg |= O_DIRECT;
1242 #endif
1243 		return (kern_fcntl(td, args->fd, F_SETFL, arg));
1244 
1245 	case LINUX_F_GETLK:
1246 		error = copyin((void *)args->arg, &linux_flock,
1247 		    sizeof(linux_flock));
1248 		if (error)
1249 			return (error);
1250 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1251 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1252 		if (error)
1253 			return (error);
1254 		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1255 		return (copyout(&linux_flock, (void *)args->arg,
1256 		    sizeof(linux_flock)));
1257 
1258 	case LINUX_F_SETLK:
1259 		error = copyin((void *)args->arg, &linux_flock,
1260 		    sizeof(linux_flock));
1261 		if (error)
1262 			return (error);
1263 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1264 		return (kern_fcntl(td, args->fd, F_SETLK,
1265 		    (intptr_t)&bsd_flock));
1266 
1267 	case LINUX_F_SETLKW:
1268 		error = copyin((void *)args->arg, &linux_flock,
1269 		    sizeof(linux_flock));
1270 		if (error)
1271 			return (error);
1272 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1273 		return (kern_fcntl(td, args->fd, F_SETLKW,
1274 		     (intptr_t)&bsd_flock));
1275 
1276 	case LINUX_F_GETOWN:
1277 		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1278 
1279 	case LINUX_F_SETOWN:
1280 		/*
1281 		 * XXX some Linux applications depend on F_SETOWN having no
1282 		 * significant effect for pipes (SIGIO is not delivered for
1283 		 * pipes under Linux-2.2.35 at least).
1284 		 */
1285 		error = fget(td, args->fd,
1286 		    &cap_fcntl_rights, &fp);
1287 		if (error)
1288 			return (error);
1289 		if (fp->f_type == DTYPE_PIPE) {
1290 			fdrop(fp, td);
1291 			return (EINVAL);
1292 		}
1293 		fdrop(fp, td);
1294 
1295 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1296 
1297 	case LINUX_F_DUPFD_CLOEXEC:
1298 		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
1299 	}
1300 
1301 	return (EINVAL);
1302 }
1303 
1304 int
1305 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1306 {
1307 
1308 	return (fcntl_common(td, args));
1309 }
1310 
1311 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1312 int
1313 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1314 {
1315 	struct l_flock64 linux_flock;
1316 	struct flock bsd_flock;
1317 	struct linux_fcntl_args fcntl_args;
1318 	int error;
1319 
1320 	switch (args->cmd) {
1321 	case LINUX_F_GETLK64:
1322 		error = copyin((void *)args->arg, &linux_flock,
1323 		    sizeof(linux_flock));
1324 		if (error)
1325 			return (error);
1326 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1327 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1328 		if (error)
1329 			return (error);
1330 		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1331 		return (copyout(&linux_flock, (void *)args->arg,
1332 			    sizeof(linux_flock)));
1333 
1334 	case LINUX_F_SETLK64:
1335 		error = copyin((void *)args->arg, &linux_flock,
1336 		    sizeof(linux_flock));
1337 		if (error)
1338 			return (error);
1339 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1340 		return (kern_fcntl(td, args->fd, F_SETLK,
1341 		    (intptr_t)&bsd_flock));
1342 
1343 	case LINUX_F_SETLKW64:
1344 		error = copyin((void *)args->arg, &linux_flock,
1345 		    sizeof(linux_flock));
1346 		if (error)
1347 			return (error);
1348 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1349 		return (kern_fcntl(td, args->fd, F_SETLKW,
1350 		    (intptr_t)&bsd_flock));
1351 	}
1352 
1353 	fcntl_args.fd = args->fd;
1354 	fcntl_args.cmd = args->cmd;
1355 	fcntl_args.arg = args->arg;
1356 	return (fcntl_common(td, &fcntl_args));
1357 }
1358 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1359 
1360 #ifdef LINUX_LEGACY_SYSCALLS
1361 int
1362 linux_chown(struct thread *td, struct linux_chown_args *args)
1363 {
1364 	char *path;
1365 	int error;
1366 
1367 	LCONVPATHEXIST(td, args->path, &path);
1368 
1369 	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1370 	    args->gid, 0);
1371 	LFREEPATH(path);
1372 	return (error);
1373 }
1374 #endif
1375 
1376 int
1377 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1378 {
1379 	char *path;
1380 	int error, dfd, flag;
1381 
1382 	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1383 		return (EINVAL);
1384 
1385 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1386 	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1387 
1388 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1389 	    AT_SYMLINK_NOFOLLOW;
1390 	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1391 	    flag);
1392 	LFREEPATH(path);
1393 	return (error);
1394 }
1395 
1396 #ifdef LINUX_LEGACY_SYSCALLS
1397 int
1398 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1399 {
1400 	char *path;
1401 	int error;
1402 
1403 	LCONVPATHEXIST(td, args->path, &path);
1404 
1405 	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1406 	    args->gid, AT_SYMLINK_NOFOLLOW);
1407 	LFREEPATH(path);
1408 	return (error);
1409 }
1410 #endif
1411 
1412 static int
1413 convert_fadvice(int advice)
1414 {
1415 	switch (advice) {
1416 	case LINUX_POSIX_FADV_NORMAL:
1417 		return (POSIX_FADV_NORMAL);
1418 	case LINUX_POSIX_FADV_RANDOM:
1419 		return (POSIX_FADV_RANDOM);
1420 	case LINUX_POSIX_FADV_SEQUENTIAL:
1421 		return (POSIX_FADV_SEQUENTIAL);
1422 	case LINUX_POSIX_FADV_WILLNEED:
1423 		return (POSIX_FADV_WILLNEED);
1424 	case LINUX_POSIX_FADV_DONTNEED:
1425 		return (POSIX_FADV_DONTNEED);
1426 	case LINUX_POSIX_FADV_NOREUSE:
1427 		return (POSIX_FADV_NOREUSE);
1428 	default:
1429 		return (-1);
1430 	}
1431 }
1432 
1433 int
1434 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1435 {
1436 	int advice;
1437 
1438 	advice = convert_fadvice(args->advice);
1439 	if (advice == -1)
1440 		return (EINVAL);
1441 	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1442 	    advice));
1443 }
1444 
1445 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1446 int
1447 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1448 {
1449 	int advice;
1450 
1451 	advice = convert_fadvice(args->advice);
1452 	if (advice == -1)
1453 		return (EINVAL);
1454 	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1455 	    advice));
1456 }
1457 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1458 
1459 #ifdef LINUX_LEGACY_SYSCALLS
1460 int
1461 linux_pipe(struct thread *td, struct linux_pipe_args *args)
1462 {
1463 	int fildes[2];
1464 	int error;
1465 
1466 	error = kern_pipe(td, fildes, 0, NULL, NULL);
1467 	if (error != 0)
1468 		return (error);
1469 
1470 	error = copyout(fildes, args->pipefds, sizeof(fildes));
1471 	if (error != 0) {
1472 		(void)kern_close(td, fildes[0]);
1473 		(void)kern_close(td, fildes[1]);
1474 	}
1475 
1476 	return (error);
1477 }
1478 #endif
1479 
1480 int
1481 linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1482 {
1483 	int fildes[2];
1484 	int error, flags;
1485 
1486 	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1487 		return (EINVAL);
1488 
1489 	flags = 0;
1490 	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1491 		flags |= O_NONBLOCK;
1492 	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1493 		flags |= O_CLOEXEC;
1494 	error = kern_pipe(td, fildes, flags, 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 
1507 int
1508 linux_dup3(struct thread *td, struct linux_dup3_args *args)
1509 {
1510 	int cmd;
1511 	intptr_t newfd;
1512 
1513 	if (args->oldfd == args->newfd)
1514 		return (EINVAL);
1515 	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1516 		return (EINVAL);
1517 	if (args->flags & LINUX_O_CLOEXEC)
1518 		cmd = F_DUP2FD_CLOEXEC;
1519 	else
1520 		cmd = F_DUP2FD;
1521 
1522 	newfd = args->newfd;
1523 	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1524 }
1525 
1526 int
1527 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1528 {
1529 
1530 	/*
1531 	 * We emulate only posix_fallocate system call for which
1532 	 * mode should be 0.
1533 	 */
1534 	if (args->mode != 0)
1535 		return (ENOSYS);
1536 
1537 	return (kern_posix_fallocate(td, args->fd, args->offset,
1538 	    args->len));
1539 }
1540