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