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