linux_file.c revision 319573
19313Ssos/*-
2230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
9111798Sdes *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
1597748Sschweikh *    derived from this software without specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos */
289313Ssos
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_file.c 319573 2017-06-04 19:56:21Z dchagin $");
31116173Sobrien
32156874Sru#include "opt_compat.h"
3331784Seivind
349313Ssos#include <sys/param.h>
359313Ssos#include <sys/systm.h>
36263233Srwatson#include <sys/capsicum.h>
3776166Smarkm#include <sys/conf.h>
3876166Smarkm#include <sys/dirent.h>
399313Ssos#include <sys/fcntl.h>
409313Ssos#include <sys/file.h>
419313Ssos#include <sys/filedesc.h>
4231561Sbde#include <sys/lock.h>
439313Ssos#include <sys/malloc.h>
4472538Sjlemon#include <sys/mount.h>
4576166Smarkm#include <sys/mutex.h>
46168014Sjulian#include <sys/namei.h>
4776166Smarkm#include <sys/proc.h>
48162201Snetchild#include <sys/stat.h>
49166085Skib#include <sys/sx.h>
50102814Siedowse#include <sys/syscallsubr.h>
5176166Smarkm#include <sys/sysproto.h>
5214331Speter#include <sys/tty.h>
53162585Snetchild#include <sys/unistd.h>
5476166Smarkm#include <sys/vnode.h>
5512458Sbde
56140214Sobrien#ifdef COMPAT_LINUX32
57140214Sobrien#include <machine/../linux32/linux.h>
58140214Sobrien#include <machine/../linux32/linux32_proto.h>
59140214Sobrien#else
6064905Smarcel#include <machine/../linux/linux.h>
6168583Smarcel#include <machine/../linux/linux_proto.h>
62133816Stjr#endif
63246085Sjhb#include <compat/linux/linux_misc.h>
6464905Smarcel#include <compat/linux/linux_util.h>
65177997Skib#include <compat/linux/linux_file.h>
669313Ssos
67315376Sdchaginstatic int	linux_common_open(struct thread *, int, char *, int, int);
68315376Sdchaginstatic int	linux_getdents_error(struct thread *, int, int);
69315376Sdchagin
70315376Sdchagin
719313Ssosint
7283366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args)
739313Ssos{
74300411Sdchagin	char *path;
75300411Sdchagin	int error;
769313Ssos
77300411Sdchagin	LCONVPATHEXIST(td, args->path, &path);
789313Ssos#ifdef DEBUG
7972543Sjlemon	if (ldebug(creat))
80102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
819313Ssos#endif
82300411Sdchagin	error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
83300411Sdchagin	    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
84300411Sdchagin	LFREEPATH(path);
85300411Sdchagin	return (error);
869313Ssos}
879313Ssos
88168014Sjulian
89168014Sjulianstatic int
90177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
919313Ssos{
92300411Sdchagin	cap_rights_t rights;
93300411Sdchagin	struct proc *p = td->td_proc;
94300411Sdchagin	struct file *fp;
95300411Sdchagin	int fd;
96300411Sdchagin	int bsd_flags, error;
9714331Speter
98300411Sdchagin	bsd_flags = 0;
99300411Sdchagin	switch (l_flags & LINUX_O_ACCMODE) {
100300411Sdchagin	case LINUX_O_WRONLY:
101300411Sdchagin		bsd_flags |= O_WRONLY;
102300411Sdchagin		break;
103300411Sdchagin	case LINUX_O_RDWR:
104300411Sdchagin		bsd_flags |= O_RDWR;
105300411Sdchagin		break;
106300411Sdchagin	default:
107300411Sdchagin		bsd_flags |= O_RDONLY;
108300411Sdchagin	}
109300411Sdchagin	if (l_flags & LINUX_O_NDELAY)
110300411Sdchagin		bsd_flags |= O_NONBLOCK;
111300411Sdchagin	if (l_flags & LINUX_O_APPEND)
112300411Sdchagin		bsd_flags |= O_APPEND;
113300411Sdchagin	if (l_flags & LINUX_O_SYNC)
114300411Sdchagin		bsd_flags |= O_FSYNC;
115300411Sdchagin	if (l_flags & LINUX_O_NONBLOCK)
116300411Sdchagin		bsd_flags |= O_NONBLOCK;
117300411Sdchagin	if (l_flags & LINUX_FASYNC)
118300411Sdchagin		bsd_flags |= O_ASYNC;
119300411Sdchagin	if (l_flags & LINUX_O_CREAT)
120300411Sdchagin		bsd_flags |= O_CREAT;
121300411Sdchagin	if (l_flags & LINUX_O_TRUNC)
122300411Sdchagin		bsd_flags |= O_TRUNC;
123300411Sdchagin	if (l_flags & LINUX_O_EXCL)
124300411Sdchagin		bsd_flags |= O_EXCL;
125300411Sdchagin	if (l_flags & LINUX_O_NOCTTY)
126300411Sdchagin		bsd_flags |= O_NOCTTY;
127300411Sdchagin	if (l_flags & LINUX_O_DIRECT)
128300411Sdchagin		bsd_flags |= O_DIRECT;
129300411Sdchagin	if (l_flags & LINUX_O_NOFOLLOW)
130300411Sdchagin		bsd_flags |= O_NOFOLLOW;
131300411Sdchagin	if (l_flags & LINUX_O_DIRECTORY)
132300411Sdchagin		bsd_flags |= O_DIRECTORY;
133300411Sdchagin	/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1349313Ssos
135300411Sdchagin	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
136300411Sdchagin	if (error != 0)
137300411Sdchagin		goto done;
138300411Sdchagin	if (bsd_flags & O_NOCTTY)
139300411Sdchagin		goto done;
140178036Srdivacky
141300411Sdchagin	/*
142300411Sdchagin	 * XXX In between kern_open() and fget(), another process
143300411Sdchagin	 * having the same filedesc could use that fd without
144300411Sdchagin	 * checking below.
145300411Sdchagin	*/
146300411Sdchagin	fd = td->td_retval[0];
147300411Sdchagin	if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
148300411Sdchagin		if (fp->f_type != DTYPE_VNODE) {
149300411Sdchagin			fdrop(fp, td);
150300411Sdchagin			goto done;
151300411Sdchagin		}
152300411Sdchagin		sx_slock(&proctree_lock);
153300411Sdchagin		PROC_LOCK(p);
154300411Sdchagin		if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
155300411Sdchagin			PROC_UNLOCK(p);
156300411Sdchagin			sx_sunlock(&proctree_lock);
157300411Sdchagin			/* XXXPJD: Verify if TIOCSCTTY is allowed. */
158300411Sdchagin			(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
159300411Sdchagin			    td->td_ucred, td);
160300411Sdchagin		} else {
161300411Sdchagin			PROC_UNLOCK(p);
162300411Sdchagin			sx_sunlock(&proctree_lock);
163300411Sdchagin		}
164300411Sdchagin		fdrop(fp, td);
165300411Sdchagin	}
166281726Strasz
167281726Straszdone:
16814331Speter#ifdef DEBUG
169300411Sdchagin	if (ldebug(open))
170300411Sdchagin		printf(LMSG("open returns error %d"), error);
17114331Speter#endif
172300411Sdchagin	LFREEPATH(path);
173300411Sdchagin	return (error);
1749313Ssos}
1759313Ssos
1769313Ssosint
177168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args)
178168014Sjulian{
179177997Skib	char *path;
180177997Skib	int dfd;
181168014Sjulian
182177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
183177997Skib	if (args->flags & LINUX_O_CREAT)
184177997Skib		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
185177997Skib	else
186177997Skib		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
187168014Sjulian#ifdef DEBUG
188168014Sjulian	if (ldebug(openat))
189168014Sjulian		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
190177997Skib		    path, args->flags, args->mode);
191168014Sjulian#endif
192177997Skib	return (linux_common_open(td, dfd, path, args->flags, args->mode));
193168014Sjulian}
194168014Sjulian
195168014Sjulianint
196168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args)
197168014Sjulian{
198300411Sdchagin	char *path;
199168014Sjulian
200300411Sdchagin	if (args->flags & LINUX_O_CREAT)
201300411Sdchagin		LCONVPATHCREAT(td, args->path, &path);
202300411Sdchagin	else
203300411Sdchagin		LCONVPATHEXIST(td, args->path, &path);
204168014Sjulian#ifdef DEBUG
205168014Sjulian	if (ldebug(open))
206168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
207168014Sjulian		    path, args->flags, args->mode);
208168014Sjulian#endif
209178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
210168014Sjulian}
211168014Sjulian
212168014Sjulianint
21383366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2149313Ssos{
2159313Ssos
2169313Ssos#ifdef DEBUG
21772543Sjlemon	if (ldebug(lseek))
21872543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
21983221Smarcel		    args->fdes, (long)args->off, args->whence);
2209313Ssos#endif
221315550Strasz	return (kern_lseek(td, args->fdes, args->off, args->whence));
2229313Ssos}
2239313Ssos
224283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
22514331Speterint
22683366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
22714331Speter{
22814331Speter	int error;
22914331Speter	off_t off;
23014331Speter
23114331Speter#ifdef DEBUG
23272543Sjlemon	if (ldebug(llseek))
23372543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
23472543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
23514331Speter#endif
23614331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
23714331Speter
238315550Strasz	error = kern_lseek(td, args->fd, off, args->whence);
239315550Strasz	if (error != 0)
240300411Sdchagin		return (error);
24114331Speter
242315550Strasz	error = copyout(td->td_retval, args->res, sizeof(off_t));
243315550Strasz	if (error != 0)
244300411Sdchagin		return (error);
24514331Speter
24683366Sjulian	td->td_retval[0] = 0;
247300411Sdchagin	return (0);
24814331Speter}
249283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
25014331Speter
25183221Smarcel/*
25283221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
25383221Smarcel * arguments. They only differ in the definition of struct dirent they
254315376Sdchagin * operate on.
255315376Sdchagin * Note that linux_readdir(2) is a special case of linux_getdents(2)
256315376Sdchagin * where count is always equals 1, meaning that the buffer is one
257315376Sdchagin * dirent-structure in size and that the code can't handle more anyway.
258315376Sdchagin * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
259315376Sdchagin * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
260315376Sdchagin * trash user stack.
26183221Smarcel */
26283221Smarcel
263315376Sdchaginstatic int
264315376Sdchaginlinux_getdents_error(struct thread *td, int fd, int err)
265315376Sdchagin{
266315376Sdchagin	cap_rights_t rights;
267315376Sdchagin	struct vnode *vp;
268315376Sdchagin	struct file *fp;
269315376Sdchagin	int error;
270315376Sdchagin
271315376Sdchagin	/* Linux return ENOTDIR in case when fd is not a directory. */
272315376Sdchagin	error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
273315376Sdchagin	if (error != 0)
274315376Sdchagin		return (error);
275315376Sdchagin	vp = fp->f_vnode;
276315376Sdchagin	if (vp->v_type != VDIR) {
277315376Sdchagin		fdrop(fp, td);
278315376Sdchagin		return (ENOTDIR);
279315376Sdchagin	}
280315376Sdchagin	fdrop(fp, td);
281315376Sdchagin	return (err);
282315376Sdchagin}
283315376Sdchagin
28483221Smarcelstruct l_dirent {
285179651Srdivacky	l_ulong		d_ino;
28683221Smarcel	l_off_t		d_off;
28783221Smarcel	l_ushort	d_reclen;
28883221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
28983221Smarcel};
29083221Smarcel
29183221Smarcelstruct l_dirent64 {
29283221Smarcel	uint64_t	d_ino;
29383221Smarcel	int64_t		d_off;
29483221Smarcel	l_ushort	d_reclen;
29583221Smarcel	u_char		d_type;
29683221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29783221Smarcel};
29883221Smarcel
299182892Srdivacky/*
300182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
301182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
302182892Srdivacky */
303182892Srdivacky#define LINUX_RECLEN(namlen)						\
304298482Spfg    roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
30583221Smarcel
306182892Srdivacky#define LINUX_RECLEN64(namlen)						\
307298482Spfg    roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
308182892Srdivacky    sizeof(uint64_t))
309182892Srdivacky
31083221Smarcel#define	LINUX_DIRBLKSIZ		512
31183221Smarcel
312315376Sdchagin/*
313315376Sdchagin * Linux l_dirent is bigger than FreeBSD dirent, thus the buffer size
314315376Sdchagin * passed to kern_getdirentries() must be smaller than the one passed
315315376Sdchagin * to linux_getdents() by certain factor.
316315376Sdchagin */
317315376Sdchagin#define	LINUX_RECLEN_RATIO(X)	X * offsetof(struct dirent, d_name) /	\
318315376Sdchagin    offsetof(struct l_dirent, d_name);
319315376Sdchagin#define	LINUX_RECLEN64_RATIO(X)	X * offsetof(struct dirent, d_name) / 	\
320315376Sdchagin    offsetof(struct l_dirent64, d_name);
321315376Sdchagin
322315376Sdchaginint
323315376Sdchaginlinux_getdents(struct thread *td, struct linux_getdents_args *args)
32414331Speter{
325111798Sdes	struct dirent *bdp;
32683221Smarcel	caddr_t inp, buf;		/* BSD-format */
32783221Smarcel	int len, reclen;		/* BSD-format */
32883221Smarcel	caddr_t outp;			/* Linux-format */
329315376Sdchagin	int resid, linuxreclen;		/* Linux-format */
330182892Srdivacky	caddr_t lbuf;			/* Linux-format */
331315376Sdchagin	long base;
332182892Srdivacky	struct l_dirent *linux_dirent;
333315376Sdchagin	int buflen, error;
334315376Sdchagin	size_t retval;
3359313Ssos
336315376Sdchagin#ifdef DEBUG
337315376Sdchagin	if (ldebug(getdents))
338315376Sdchagin		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
339315376Sdchagin#endif
340315376Sdchagin	buflen = LINUX_RECLEN_RATIO(args->count);
341315376Sdchagin	buflen = min(buflen, MAXBSIZE);
342315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
343160276Sjhb
344315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
345315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
346315376Sdchagin	if (error != 0) {
347315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
348315376Sdchagin		goto out1;
34989306Salfred	}
3509313Ssos
351315376Sdchagin	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
352315376Sdchagin
353315376Sdchagin	len = td->td_retval[0];
354315376Sdchagin	inp = buf;
355315376Sdchagin	outp = (caddr_t)args->dent;
356315376Sdchagin	resid = args->count;
357315376Sdchagin	retval = 0;
358315376Sdchagin
359315376Sdchagin	while (len > 0) {
360315376Sdchagin		bdp = (struct dirent *) inp;
361315376Sdchagin		reclen = bdp->d_reclen;
362315376Sdchagin		linuxreclen = LINUX_RECLEN(bdp->d_namlen);
363315376Sdchagin		/*
364315376Sdchagin		 * No more space in the user supplied dirent buffer.
365315376Sdchagin		 * Return EINVAL.
366315376Sdchagin		 */
367315376Sdchagin		if (resid < linuxreclen) {
368315376Sdchagin			error = EINVAL;
369315376Sdchagin			goto out;
370315376Sdchagin		}
371315376Sdchagin
372315376Sdchagin		linux_dirent = (struct l_dirent*)lbuf;
373315376Sdchagin		linux_dirent->d_ino = bdp->d_fileno;
374315376Sdchagin		linux_dirent->d_off = base + reclen;
375315376Sdchagin		linux_dirent->d_reclen = linuxreclen;
376315376Sdchagin		/*
377315376Sdchagin		 * Copy d_type to last byte of l_dirent buffer
378315376Sdchagin		 */
379315376Sdchagin		lbuf[linuxreclen - 1] = bdp->d_type;
380315376Sdchagin		strlcpy(linux_dirent->d_name, bdp->d_name,
381315376Sdchagin		    linuxreclen - offsetof(struct l_dirent, d_name)-1);
382315376Sdchagin		error = copyout(linux_dirent, outp, linuxreclen);
383315376Sdchagin		if (error != 0)
384315376Sdchagin			goto out;
385315376Sdchagin
386315376Sdchagin		inp += reclen;
387315376Sdchagin		base += reclen;
388315376Sdchagin		len -= reclen;
389315376Sdchagin
390315376Sdchagin		retval += linuxreclen;
391315376Sdchagin		outp += linuxreclen;
392315376Sdchagin		resid -= linuxreclen;
39389306Salfred	}
394315376Sdchagin	td->td_retval[0] = retval;
3959313Ssos
396315376Sdchaginout:
397315376Sdchagin	free(lbuf, M_LINUX);
398315376Sdchaginout1:
399315376Sdchagin	free(buf, M_LINUX);
400315376Sdchagin	return (error);
401315376Sdchagin}
4029313Ssos
403315376Sdchaginint
404315376Sdchaginlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
405315376Sdchagin{
406315376Sdchagin	struct dirent *bdp;
407315376Sdchagin	caddr_t inp, buf;		/* BSD-format */
408315376Sdchagin	int len, reclen;		/* BSD-format */
409315376Sdchagin	caddr_t outp;			/* Linux-format */
410315376Sdchagin	int resid, linuxreclen;		/* Linux-format */
411315376Sdchagin	caddr_t lbuf;			/* Linux-format */
412315376Sdchagin	long base;
413315376Sdchagin	struct l_dirent64 *linux_dirent64;
414315376Sdchagin	int buflen, error;
415315376Sdchagin	size_t retval;
416315376Sdchagin
417315376Sdchagin#ifdef DEBUG
418315376Sdchagin	if (ldebug(getdents64))
419315376Sdchagin		uprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
420315376Sdchagin#endif
421315376Sdchagin	buflen = LINUX_RECLEN64_RATIO(args->count);
42283221Smarcel	buflen = min(buflen, MAXBSIZE);
423315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
42483221Smarcel
425315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
426315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
427315376Sdchagin	if (error != 0) {
428315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
429315376Sdchagin		goto out1;
430315376Sdchagin	}
4319313Ssos
432315376Sdchagin	lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
4339313Ssos
434315376Sdchagin	len = td->td_retval[0];
43583221Smarcel	inp = buf;
43683221Smarcel	outp = (caddr_t)args->dirent;
437315376Sdchagin	resid = args->count;
438315376Sdchagin	retval = 0;
4399313Ssos
44083221Smarcel	while (len > 0) {
44183221Smarcel		bdp = (struct dirent *) inp;
44283221Smarcel		reclen = bdp->d_reclen;
443315376Sdchagin		linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
444315376Sdchagin		/*
445315376Sdchagin		 * No more space in the user supplied dirent buffer.
446315376Sdchagin		 * Return EINVAL.
447315376Sdchagin		 */
448315376Sdchagin		if (resid < linuxreclen) {
449315376Sdchagin			error = EINVAL;
45083221Smarcel			goto out;
45183221Smarcel		}
45283221Smarcel
453315376Sdchagin		linux_dirent64 = (struct l_dirent64*)lbuf;
454315376Sdchagin		linux_dirent64->d_ino = bdp->d_fileno;
455315376Sdchagin		linux_dirent64->d_off = base + reclen;
456315376Sdchagin		linux_dirent64->d_reclen = linuxreclen;
457315376Sdchagin		linux_dirent64->d_type = bdp->d_type;
458315376Sdchagin		strlcpy(linux_dirent64->d_name, bdp->d_name,
459315376Sdchagin		    linuxreclen - offsetof(struct l_dirent64, d_name));
460315376Sdchagin		error = copyout(linux_dirent64, outp, linuxreclen);
461315376Sdchagin		if (error != 0)
46283221Smarcel			goto out;
46383221Smarcel
46483221Smarcel		inp += reclen;
465315376Sdchagin		base += reclen;
466315376Sdchagin		len -= reclen;
46783221Smarcel
468315376Sdchagin		retval += linuxreclen;
46983221Smarcel		outp += linuxreclen;
47083221Smarcel		resid -= linuxreclen;
47110355Sswallace	}
472315376Sdchagin	td->td_retval[0] = retval;
4739313Ssos
4749313Ssosout:
475315376Sdchagin	free(lbuf, M_TEMP);
476315376Sdchaginout1:
477315376Sdchagin	free(buf, M_TEMP);
47883221Smarcel	return (error);
4799313Ssos}
48014331Speter
481315376Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
48283221Smarcelint
483315376Sdchaginlinux_readdir(struct thread *td, struct linux_readdir_args *args)
48483221Smarcel{
485315376Sdchagin	struct dirent *bdp;
486315376Sdchagin	caddr_t buf;			/* BSD-format */
487315376Sdchagin	int linuxreclen;		/* Linux-format */
488315376Sdchagin	caddr_t lbuf;			/* Linux-format */
489315376Sdchagin	long base;
490315376Sdchagin	struct l_dirent *linux_dirent;
491315376Sdchagin	int buflen, error;
49283221Smarcel
49383221Smarcel#ifdef DEBUG
494315376Sdchagin	if (ldebug(readdir))
495315376Sdchagin		printf(ARGS(readdir, "%d, *"), args->fd);
49683221Smarcel#endif
497315376Sdchagin	buflen = LINUX_RECLEN(LINUX_NAME_MAX);
498315376Sdchagin	buflen = LINUX_RECLEN_RATIO(buflen);
499315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
50083221Smarcel
501315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
502315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
503315376Sdchagin	if (error != 0) {
504315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
505315376Sdchagin		goto out;
506315376Sdchagin	}
507315376Sdchagin	if (td->td_retval[0] == 0)
508315376Sdchagin		goto out;
50983221Smarcel
510315376Sdchagin	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
51183221Smarcel
512315376Sdchagin	bdp = (struct dirent *) buf;
513315376Sdchagin	linuxreclen = LINUX_RECLEN(bdp->d_namlen);
51483221Smarcel
515315376Sdchagin	linux_dirent = (struct l_dirent*)lbuf;
516315376Sdchagin	linux_dirent->d_ino = bdp->d_fileno;
517315376Sdchagin	linux_dirent->d_off = linuxreclen;
518315376Sdchagin	linux_dirent->d_reclen = bdp->d_namlen;
519315376Sdchagin	strlcpy(linux_dirent->d_name, bdp->d_name,
520315376Sdchagin	    linuxreclen - offsetof(struct l_dirent, d_name));
521315376Sdchagin	error = copyout(linux_dirent, args->dent, linuxreclen);
522315376Sdchagin	if (error == 0)
523315376Sdchagin		td->td_retval[0] = linuxreclen;
524315376Sdchagin
525315376Sdchagin	free(lbuf, M_LINUX);
526315376Sdchaginout:
527315376Sdchagin	free(buf, M_LINUX);
528315376Sdchagin	return (error);
52983221Smarcel}
530315376Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
53183221Smarcel
532315376Sdchagin
53314331Speter/*
53414331Speter * These exist mainly for hooks for doing /compat/linux translation.
53514331Speter */
53614331Speter
53714331Speterint
53883366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
53914331Speter{
540102814Siedowse	char *path;
541102814Siedowse	int error;
54214331Speter
543162585Snetchild	/* linux convention */
544227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
545162585Snetchild		return (EINVAL);
546162585Snetchild
547102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
54814331Speter
54914331Speter#ifdef DEBUG
55072543Sjlemon	if (ldebug(access))
551227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
55214331Speter#endif
553274476Skib	error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
554274476Skib	    args->amode);
555102814Siedowse	LFREEPATH(path);
556162585Snetchild
557102814Siedowse	return (error);
55814331Speter}
55914331Speter
56014331Speterint
561177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
562177997Skib{
563177997Skib	char *path;
564283428Sdchagin	int error, dfd;
565177997Skib
566177997Skib	/* linux convention */
567227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
568177997Skib		return (EINVAL);
569177997Skib
570177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
571177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
572177997Skib
573177997Skib#ifdef DEBUG
574177997Skib	if (ldebug(access))
575227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
576177997Skib#endif
577177997Skib
578283428Sdchagin	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
579177997Skib	LFREEPATH(path);
580177997Skib
581177997Skib	return (error);
582177997Skib}
583177997Skib
584177997Skibint
58583366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
58614331Speter{
587102814Siedowse	char *path;
588102814Siedowse	int error;
589162201Snetchild	struct stat st;
59014331Speter
591102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
59214331Speter
59314331Speter#ifdef DEBUG
59472543Sjlemon	if (ldebug(unlink))
595102814Siedowse		printf(ARGS(unlink, "%s"), path);
59614331Speter#endif
59714331Speter
598274476Skib	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
599274476Skib	if (error == EPERM) {
600162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
601274476Skib		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
602274476Skib		    NULL) == 0) {
603162201Snetchild			if (S_ISDIR(st.st_mode))
604162201Snetchild				error = EISDIR;
605274476Skib		}
606274476Skib	}
607102814Siedowse	LFREEPATH(path);
608102814Siedowse	return (error);
60914331Speter}
61014331Speter
61114331Speterint
612177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
613177997Skib{
614177997Skib	char *path;
615177997Skib	int error, dfd;
616177997Skib	struct stat st;
617177997Skib
618177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
619177997Skib		return (EINVAL);
620177997Skib
621177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
622177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
623177997Skib
624177997Skib#ifdef DEBUG
625177997Skib	if (ldebug(unlinkat))
626177997Skib		printf(ARGS(unlinkat, "%s"), path);
627177997Skib#endif
628177997Skib
629177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
630177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
631177997Skib	else
632202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
633177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
634177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
635177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
636274476Skib		    UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
637177997Skib			error = EISDIR;
638177997Skib	}
639177997Skib	LFREEPATH(path);
640177997Skib	return (error);
641177997Skib}
642177997Skibint
64383366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
64414331Speter{
645102814Siedowse	char *path;
646102814Siedowse	int error;
64714331Speter
648102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
64914331Speter
65014331Speter#ifdef DEBUG
65172543Sjlemon	if (ldebug(chdir))
652102814Siedowse		printf(ARGS(chdir, "%s"), path);
65314331Speter#endif
654102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
655102814Siedowse	LFREEPATH(path);
656102814Siedowse	return (error);
65714331Speter}
65814331Speter
65914331Speterint
66083366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
66114331Speter{
662102814Siedowse	char *path;
663102814Siedowse	int error;
66414331Speter
665102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
66614331Speter
66714331Speter#ifdef DEBUG
66872543Sjlemon	if (ldebug(chmod))
669102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
67014331Speter#endif
671274476Skib	error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
672274476Skib	    args->mode, 0);
673102814Siedowse	LFREEPATH(path);
674102814Siedowse	return (error);
67514331Speter}
67614331Speter
67714331Speterint
678177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
679177997Skib{
680177997Skib	char *path;
681177997Skib	int error, dfd;
682177997Skib
683177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
684177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
685177997Skib
686177997Skib#ifdef DEBUG
687177997Skib	if (ldebug(fchmodat))
688177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
689177997Skib#endif
690177997Skib
691177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
692177997Skib	LFREEPATH(path);
693177997Skib	return (error);
694177997Skib}
695177997Skib
696177997Skibint
69783366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
69814331Speter{
699102814Siedowse	char *path;
700102814Siedowse	int error;
70114331Speter
702102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
70314331Speter
70414331Speter#ifdef DEBUG
70572543Sjlemon	if (ldebug(mkdir))
706102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
70714331Speter#endif
708274476Skib	error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
709102814Siedowse	LFREEPATH(path);
710102814Siedowse	return (error);
71114331Speter}
71214331Speter
71314331Speterint
714177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
715177997Skib{
716177997Skib	char *path;
717177997Skib	int error, dfd;
718177997Skib
719177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
720177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
721177997Skib
722177997Skib#ifdef DEBUG
723177997Skib	if (ldebug(mkdirat))
724177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
725177997Skib#endif
726177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
727177997Skib	LFREEPATH(path);
728177997Skib	return (error);
729177997Skib}
730177997Skib
731177997Skibint
73283366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
73314331Speter{
734102814Siedowse	char *path;
735102814Siedowse	int error;
73614331Speter
737102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
73814331Speter
73914331Speter#ifdef DEBUG
74072543Sjlemon	if (ldebug(rmdir))
741102814Siedowse		printf(ARGS(rmdir, "%s"), path);
74214331Speter#endif
743274476Skib	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
744102814Siedowse	LFREEPATH(path);
745102814Siedowse	return (error);
74614331Speter}
74714331Speter
74814331Speterint
74983366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
75014331Speter{
751102814Siedowse	char *from, *to;
752102814Siedowse	int error;
75314331Speter
754102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
755102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
756177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
757102814Siedowse	if (to == NULL) {
758102814Siedowse		LFREEPATH(from);
759102814Siedowse		return (error);
760102814Siedowse	}
76114331Speter
76214331Speter#ifdef DEBUG
76372543Sjlemon	if (ldebug(rename))
764102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
76514331Speter#endif
766274476Skib	error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
767102814Siedowse	LFREEPATH(from);
768102814Siedowse	LFREEPATH(to);
769102814Siedowse	return (error);
77014331Speter}
77114331Speter
77214331Speterint
773177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
774177997Skib{
775177997Skib	char *from, *to;
776177997Skib	int error, olddfd, newdfd;
777177997Skib
778177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
779177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
780177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
781177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
782177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
783177997Skib	if (to == NULL) {
784177997Skib		LFREEPATH(from);
785177997Skib		return (error);
786177997Skib	}
787177997Skib
788177997Skib#ifdef DEBUG
789177997Skib	if (ldebug(renameat))
790177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
791177997Skib#endif
792177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
793177997Skib	LFREEPATH(from);
794177997Skib	LFREEPATH(to);
795177997Skib	return (error);
796177997Skib}
797177997Skib
798177997Skibint
79983366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
80014331Speter{
801102814Siedowse	char *path, *to;
802102814Siedowse	int error;
80314331Speter
804102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
805102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
806177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
807102814Siedowse	if (to == NULL) {
808102814Siedowse		LFREEPATH(path);
809102814Siedowse		return (error);
810102814Siedowse	}
81114331Speter
81214331Speter#ifdef DEBUG
81372543Sjlemon	if (ldebug(symlink))
814102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
81514331Speter#endif
816274476Skib	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
817102814Siedowse	LFREEPATH(path);
818102814Siedowse	LFREEPATH(to);
819102814Siedowse	return (error);
82014331Speter}
82114331Speter
82214331Speterint
823177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
824177997Skib{
825177997Skib	char *path, *to;
826177997Skib	int error, dfd;
827177997Skib
828177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
829319573Sdchagin	LCONVPATHEXIST(td, args->oldname, &path);
830177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
831177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
832177997Skib	if (to == NULL) {
833177997Skib		LFREEPATH(path);
834177997Skib		return (error);
835177997Skib	}
836177997Skib
837177997Skib#ifdef DEBUG
838177997Skib	if (ldebug(symlinkat))
839177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
840177997Skib#endif
841177997Skib
842177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
843177997Skib	LFREEPATH(path);
844177997Skib	LFREEPATH(to);
845177997Skib	return (error);
846177997Skib}
847177997Skib
848177997Skibint
84983366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
85014331Speter{
851102814Siedowse	char *name;
852102814Siedowse	int error;
85314331Speter
854102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
85514331Speter
85614331Speter#ifdef DEBUG
85772543Sjlemon	if (ldebug(readlink))
858102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
859102814Siedowse		    args->count);
86014331Speter#endif
861274476Skib	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
862274476Skib	    args->buf, UIO_USERSPACE, args->count);
863102814Siedowse	LFREEPATH(name);
864102814Siedowse	return (error);
86514331Speter}
86614331Speter
86714331Speterint
868177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
869177997Skib{
870177997Skib	char *name;
871177997Skib	int error, dfd;
872177997Skib
873177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
874177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
875177997Skib
876177997Skib#ifdef DEBUG
877177997Skib	if (ldebug(readlinkat))
878177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
879177997Skib		    args->bufsiz);
880177997Skib#endif
881177997Skib
882177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
883177997Skib	    UIO_USERSPACE, args->bufsiz);
884177997Skib	LFREEPATH(name);
885177997Skib	return (error);
886177997Skib}
887178439Srdivacky
888177997Skibint
88983366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
89014331Speter{
891102814Siedowse	char *path;
892102814Siedowse	int error;
89314331Speter
894102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
89514331Speter
89614331Speter#ifdef DEBUG
89772543Sjlemon	if (ldebug(truncate))
898102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
89914331Speter#endif
90014331Speter
901102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
902102814Siedowse	LFREEPATH(path);
903102814Siedowse	return (error);
90414331Speter}
90514331Speter
906283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
90749662Smarcelint
908178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args)
909178439Srdivacky{
910178439Srdivacky	char *path;
911178439Srdivacky	int error;
912178439Srdivacky
913178439Srdivacky	LCONVPATHEXIST(td, args->path, &path);
914178439Srdivacky
915178439Srdivacky#ifdef DEBUG
916178439Srdivacky	if (ldebug(truncate64))
917178439Srdivacky		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
918178439Srdivacky#endif
919178439Srdivacky
920178439Srdivacky	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
921178439Srdivacky	LFREEPATH(path);
922178439Srdivacky	return (error);
923178439Srdivacky}
924283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
925283415Sdchagin
926178439Srdivackyint
927156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
928156842Snetchild{
929300411Sdchagin
930315548Strasz	return (kern_ftruncate(td, args->fd, args->length));
931156842Snetchild}
932156842Snetchild
933156842Snetchildint
93483366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
93549662Smarcel{
936102814Siedowse	char *path, *to;
937102814Siedowse	int error;
93849662Smarcel
939102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
940102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
941177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
942102814Siedowse	if (to == NULL) {
943102814Siedowse		LFREEPATH(path);
944102814Siedowse		return (error);
945102814Siedowse	}
94649662Smarcel
94749662Smarcel#ifdef DEBUG
94872543Sjlemon	if (ldebug(link))
949102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
95049662Smarcel#endif
951274476Skib	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
952274476Skib	    FOLLOW);
953102814Siedowse	LFREEPATH(path);
954102814Siedowse	LFREEPATH(to);
955102814Siedowse	return (error);
95649662Smarcel}
95749788Smarcel
95853713Smarcelint
959177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
960177997Skib{
961177997Skib	char *path, *to;
962227693Sed	int error, olddfd, newdfd, follow;
963177997Skib
964227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
965177997Skib		return (EINVAL);
966177997Skib
967177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
968177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
969177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
970177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
971177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
972177997Skib	if (to == NULL) {
973177997Skib		LFREEPATH(path);
974177997Skib		return (error);
975177997Skib	}
976177997Skib
977177997Skib#ifdef DEBUG
978177997Skib	if (ldebug(linkat))
979177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
980227693Sed			args->newdfd, to, args->flag);
981177997Skib#endif
982177997Skib
983227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
984227693Sed	    FOLLOW;
985227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
986177997Skib	LFREEPATH(path);
987177997Skib	LFREEPATH(to);
988177997Skib	return (error);
989177997Skib}
990177997Skib
991177997Skibint
99283366Sjulianlinux_fdatasync(td, uap)
99383366Sjulian	struct thread *td;
99453713Smarcel	struct linux_fdatasync_args *uap;
99553713Smarcel{
99653713Smarcel
997304987Skib	return (kern_fsync(td, uap->fd, false));
99853713Smarcel}
99963285Smarcel
100063285Smarcelint
1001315553Straszlinux_pread(struct thread *td, struct linux_pread_args *uap)
100263285Smarcel{
1003255219Spjd	cap_rights_t rights;
1004162585Snetchild	struct vnode *vp;
1005162585Snetchild	int error;
100663285Smarcel
1007315553Strasz	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
1008162585Snetchild	if (error == 0) {
1009247602Spjd		/* This seems to violate POSIX but linux does it */
1010255219Spjd		error = fgetvp(td, uap->fd,
1011255219Spjd		    cap_rights_init(&rights, CAP_PREAD), &vp);
1012255219Spjd		if (error != 0)
1013247602Spjd			return (error);
1014162585Snetchild		if (vp->v_type == VDIR) {
1015247602Spjd			vrele(vp);
1016162585Snetchild			return (EISDIR);
1017162585Snetchild		}
1018162585Snetchild		vrele(vp);
1019162585Snetchild	}
1020162585Snetchild	return (error);
102163285Smarcel}
102263285Smarcel
102363285Smarcelint
1024315553Straszlinux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
102563285Smarcel{
102663285Smarcel
1027315553Strasz	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
102863285Smarcel}
102972538Sjlemon
103072538Sjlemonint
1031314909Smmokhilinux_preadv(struct thread *td, struct linux_preadv_args *uap)
1032314909Smmokhi{
1033314909Smmokhi	struct uio *auio;
1034314909Smmokhi	int error;
1035314909Smmokhi	off_t offset;
1036314909Smmokhi
1037314909Smmokhi	/*
1038314909Smmokhi	 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
1039314909Smmokhi	 * pos_l and pos_h, respectively, contain the
1040314909Smmokhi	 * low order and high order 32 bits of offset.
1041314909Smmokhi	 */
1042314909Smmokhi	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
1043314909Smmokhi	    (sizeof(offset) * 4)) | uap->pos_l;
1044314909Smmokhi	if (offset < 0)
1045314909Smmokhi		return (EINVAL);
1046314909Smmokhi#ifdef COMPAT_LINUX32
1047314909Smmokhi	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1048314909Smmokhi#else
1049314909Smmokhi	error = copyinuio(uap->vec, uap->vlen, &auio);
1050314909Smmokhi#endif
1051314909Smmokhi	if (error != 0)
1052314909Smmokhi		return (error);
1053314909Smmokhi	error = kern_preadv(td, uap->fd, auio, offset);
1054314909Smmokhi	free(auio, M_IOV);
1055314909Smmokhi	return (error);
1056314909Smmokhi}
1057314909Smmokhi
1058314909Smmokhiint
1059314909Smmokhilinux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
1060314909Smmokhi{
1061314909Smmokhi	struct uio *auio;
1062314909Smmokhi	int error;
1063314909Smmokhi	off_t offset;
1064314909Smmokhi
1065314909Smmokhi	/*
1066314909Smmokhi	 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
1067314909Smmokhi	 * pos_l and pos_h, respectively, contain the
1068314909Smmokhi	 * low order and high order 32 bits of offset.
1069314909Smmokhi	 */
1070314909Smmokhi	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
1071314909Smmokhi	    (sizeof(offset) * 4)) | uap->pos_l;
1072314909Smmokhi	if (offset < 0)
1073314909Smmokhi		return (EINVAL);
1074314909Smmokhi#ifdef COMPAT_LINUX32
1075314909Smmokhi	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1076314909Smmokhi#else
1077314909Smmokhi	error = copyinuio(uap->vec, uap->vlen, &auio);
1078314909Smmokhi#endif
1079314909Smmokhi	if (error != 0)
1080314909Smmokhi		return (error);
1081314909Smmokhi	error = kern_pwritev(td, uap->fd, auio, offset);
1082314909Smmokhi	free(auio, M_IOV);
1083314909Smmokhi	return (error);
1084314909Smmokhi}
1085314909Smmokhi
1086314909Smmokhiint
108783366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
108872538Sjlemon{
1089111798Sdes	char fstypename[MFSNAMELEN];
1090111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
109173286Sadrian	int error;
109273286Sadrian	int fsflags;
109372538Sjlemon
1094111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
109573286Sadrian	    NULL);
109672538Sjlemon	if (error)
1097111798Sdes		return (error);
1098127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
109972538Sjlemon	if (error)
1100111798Sdes		return (error);
1101127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
110272538Sjlemon	if (error)
1103111798Sdes		return (error);
110472538Sjlemon
110572538Sjlemon#ifdef DEBUG
110672538Sjlemon	if (ldebug(mount))
110772538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
110872538Sjlemon		    fstypename, mntfromname, mntonname);
110972538Sjlemon#endif
111072538Sjlemon
111172538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1112127059Stjr		strcpy(fstypename, "ext2fs");
111372538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1114127059Stjr		strcpy(fstypename, "linprocfs");
1115190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1116190445Sambrisko		strcpy(fstypename, "msdosfs");
111772538Sjlemon	}
111872538Sjlemon
111973286Sadrian	fsflags = 0;
112072538Sjlemon
112172538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
112272538Sjlemon		/*
112372538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
112472538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
112572538Sjlemon		 */
112672538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1127111798Sdes			fsflags |= MNT_RDONLY;
112872538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1129111798Sdes			fsflags |= MNT_NOSUID;
113072538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1131111798Sdes			fsflags |= MNT_NOEXEC;
113272538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1133111798Sdes			fsflags |= MNT_UPDATE;
113472538Sjlemon	}
113572538Sjlemon
1136281689Strasz	error = kernel_vmount(fsflags,
1137281689Strasz	    "fstype", fstypename,
1138281689Strasz	    "fspath", mntonname,
1139281689Strasz	    "from", mntfromname,
1140281689Strasz	    NULL);
1141127059Stjr	return (error);
114272538Sjlemon}
114372538Sjlemon
1144283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
114572538Sjlemonint
114683366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
114772538Sjlemon{
114883221Smarcel	struct linux_umount_args args2;
114972538Sjlemon
115072538Sjlemon	args2.path = args->path;
115172538Sjlemon	args2.flags = 0;
115283366Sjulian	return (linux_umount(td, &args2));
115372538Sjlemon}
1154283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
115572538Sjlemon
115672538Sjlemonint
115783366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
115872538Sjlemon{
115972538Sjlemon	struct unmount_args bsd;
116072538Sjlemon
116172538Sjlemon	bsd.path = args->path;
116272538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1163225617Skmacy	return (sys_unmount(td, &bsd));
116472538Sjlemon}
116583221Smarcel
116683221Smarcel/*
116783221Smarcel * fcntl family of syscalls
116883221Smarcel */
116983221Smarcel
117083221Smarcelstruct l_flock {
117183221Smarcel	l_short		l_type;
117283221Smarcel	l_short		l_whence;
117383221Smarcel	l_off_t		l_start;
117483221Smarcel	l_off_t		l_len;
117583221Smarcel	l_pid_t		l_pid;
1176133816Stjr}
1177140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1178133816Stjr__packed
1179133816Stjr#endif
1180133816Stjr;
118183221Smarcel
118283221Smarcelstatic void
118383221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
118483221Smarcel{
118583221Smarcel	switch (linux_flock->l_type) {
118683221Smarcel	case LINUX_F_RDLCK:
118783221Smarcel		bsd_flock->l_type = F_RDLCK;
118883221Smarcel		break;
118983221Smarcel	case LINUX_F_WRLCK:
119083221Smarcel		bsd_flock->l_type = F_WRLCK;
119183221Smarcel		break;
119283221Smarcel	case LINUX_F_UNLCK:
119383221Smarcel		bsd_flock->l_type = F_UNLCK;
119483221Smarcel		break;
119583221Smarcel	default:
119683221Smarcel		bsd_flock->l_type = -1;
119783221Smarcel		break;
119883221Smarcel	}
119983221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
120083221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
120183221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
120283221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1203177633Sdfr	bsd_flock->l_sysid = 0;
120483221Smarcel}
120583221Smarcel
120683221Smarcelstatic void
120783221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
120883221Smarcel{
120983221Smarcel	switch (bsd_flock->l_type) {
121083221Smarcel	case F_RDLCK:
121183221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
121283221Smarcel		break;
121383221Smarcel	case F_WRLCK:
121483221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
121583221Smarcel		break;
121683221Smarcel	case F_UNLCK:
121783221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
121883221Smarcel		break;
121983221Smarcel	}
122083221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
122183221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
122283221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
122383221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
122483221Smarcel}
122583221Smarcel
1226140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
122783221Smarcelstruct l_flock64 {
122883221Smarcel	l_short		l_type;
122983221Smarcel	l_short		l_whence;
123083221Smarcel	l_loff_t	l_start;
123183221Smarcel	l_loff_t	l_len;
123283221Smarcel	l_pid_t		l_pid;
1233133816Stjr}
1234140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1235133816Stjr__packed
1236133816Stjr#endif
1237133816Stjr;
123883221Smarcel
123983221Smarcelstatic void
124083221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
124183221Smarcel{
124283221Smarcel	switch (linux_flock->l_type) {
124383221Smarcel	case LINUX_F_RDLCK:
124483221Smarcel		bsd_flock->l_type = F_RDLCK;
124583221Smarcel		break;
124683221Smarcel	case LINUX_F_WRLCK:
124783221Smarcel		bsd_flock->l_type = F_WRLCK;
124883221Smarcel		break;
124983221Smarcel	case LINUX_F_UNLCK:
125083221Smarcel		bsd_flock->l_type = F_UNLCK;
125183221Smarcel		break;
125283221Smarcel	default:
125383221Smarcel		bsd_flock->l_type = -1;
125483221Smarcel		break;
125583221Smarcel	}
125683221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
125783221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
125883221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
125983221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1260177633Sdfr	bsd_flock->l_sysid = 0;
126183221Smarcel}
126283221Smarcel
126383221Smarcelstatic void
126483221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
126583221Smarcel{
126683221Smarcel	switch (bsd_flock->l_type) {
126783221Smarcel	case F_RDLCK:
126883221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
126983221Smarcel		break;
127083221Smarcel	case F_WRLCK:
127183221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
127283221Smarcel		break;
127383221Smarcel	case F_UNLCK:
127483221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
127583221Smarcel		break;
127683221Smarcel	}
127783221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
127883221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
127983221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
128083221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
128183221Smarcel}
1282133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
128383221Smarcel
128483221Smarcelstatic int
1285283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args)
128683221Smarcel{
1287107680Siedowse	struct l_flock linux_flock;
1288107680Siedowse	struct flock bsd_flock;
1289255219Spjd	cap_rights_t rights;
129083221Smarcel	struct file *fp;
1291102872Siedowse	long arg;
129283221Smarcel	int error, result;
129383221Smarcel
129483221Smarcel	switch (args->cmd) {
129583221Smarcel	case LINUX_F_DUPFD:
1296102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
129783221Smarcel
129883221Smarcel	case LINUX_F_GETFD:
1299102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
130083221Smarcel
130183221Smarcel	case LINUX_F_SETFD:
1302102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
130383221Smarcel
130483221Smarcel	case LINUX_F_GETFL:
1305102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
130683366Sjulian		result = td->td_retval[0];
130783366Sjulian		td->td_retval[0] = 0;
130883221Smarcel		if (result & O_RDONLY)
130983366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
131083221Smarcel		if (result & O_WRONLY)
131183366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
131283221Smarcel		if (result & O_RDWR)
131383366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
131483221Smarcel		if (result & O_NDELAY)
131583366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
131683221Smarcel		if (result & O_APPEND)
131783366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
131883221Smarcel		if (result & O_FSYNC)
131983366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
132083221Smarcel		if (result & O_ASYNC)
132183366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1322144987Smdodd#ifdef LINUX_O_NOFOLLOW
1323144987Smdodd		if (result & O_NOFOLLOW)
1324144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1325144987Smdodd#endif
1326144987Smdodd#ifdef LINUX_O_DIRECT
1327144987Smdodd		if (result & O_DIRECT)
1328144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1329144987Smdodd#endif
133083221Smarcel		return (error);
133183221Smarcel
133283221Smarcel	case LINUX_F_SETFL:
1333102872Siedowse		arg = 0;
133483221Smarcel		if (args->arg & LINUX_O_NDELAY)
1335102872Siedowse			arg |= O_NONBLOCK;
133683221Smarcel		if (args->arg & LINUX_O_APPEND)
1337102872Siedowse			arg |= O_APPEND;
133883221Smarcel		if (args->arg & LINUX_O_SYNC)
1339102872Siedowse			arg |= O_FSYNC;
134083221Smarcel		if (args->arg & LINUX_FASYNC)
1341102872Siedowse			arg |= O_ASYNC;
1342144987Smdodd#ifdef LINUX_O_NOFOLLOW
1343144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1344144987Smdodd			arg |= O_NOFOLLOW;
1345144987Smdodd#endif
1346144987Smdodd#ifdef LINUX_O_DIRECT
1347144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1348144987Smdodd			arg |= O_DIRECT;
1349144987Smdodd#endif
1350102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
135183221Smarcel
1352107680Siedowse	case LINUX_F_GETLK:
1353111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1354107680Siedowse		    sizeof(linux_flock));
1355107680Siedowse		if (error)
1356107680Siedowse			return (error);
1357107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1358107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1359107680Siedowse		if (error)
1360107680Siedowse			return (error);
1361107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1362111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1363107680Siedowse		    sizeof(linux_flock)));
1364107680Siedowse
1365107680Siedowse	case LINUX_F_SETLK:
1366111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1367107680Siedowse		    sizeof(linux_flock));
1368107680Siedowse		if (error)
1369107680Siedowse			return (error);
1370107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1371107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1372107680Siedowse		    (intptr_t)&bsd_flock));
1373107680Siedowse
1374107680Siedowse	case LINUX_F_SETLKW:
1375111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1376107680Siedowse		    sizeof(linux_flock));
1377107680Siedowse		if (error)
1378107680Siedowse			return (error);
1379107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1380107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1381107680Siedowse		     (intptr_t)&bsd_flock));
1382107680Siedowse
138383221Smarcel	case LINUX_F_GETOWN:
1384102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
138583221Smarcel
138683221Smarcel	case LINUX_F_SETOWN:
138783221Smarcel		/*
138883221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
138983221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
139083221Smarcel		 * pipes under Linux-2.2.35 at least).
139183221Smarcel		 */
1392255219Spjd		error = fget(td, args->fd,
1393255219Spjd		    cap_rights_init(&rights, CAP_FCNTL), &fp);
139489319Salfred		if (error)
139589319Salfred			return (error);
139689306Salfred		if (fp->f_type == DTYPE_PIPE) {
139789306Salfred			fdrop(fp, td);
139883221Smarcel			return (EINVAL);
139989306Salfred		}
140089306Salfred		fdrop(fp, td);
140183221Smarcel
1402102872Siedowse		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1403283439Sdchagin
1404283439Sdchagin	case LINUX_F_DUPFD_CLOEXEC:
1405283439Sdchagin		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
140683221Smarcel	}
140783221Smarcel
140883221Smarcel	return (EINVAL);
140983221Smarcel}
141083221Smarcel
141183221Smarcelint
141283366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
141383221Smarcel{
141483221Smarcel
141583221Smarcel#ifdef DEBUG
141683221Smarcel	if (ldebug(fcntl))
141783221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
141883221Smarcel#endif
141983221Smarcel
1420283415Sdchagin	return (fcntl_common(td, args));
142183221Smarcel}
142283221Smarcel
1423140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
142483221Smarcelint
142583366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
142683221Smarcel{
142783221Smarcel	struct l_flock64 linux_flock;
1428102872Siedowse	struct flock bsd_flock;
1429283415Sdchagin	struct linux_fcntl_args fcntl_args;
143083221Smarcel	int error;
143183221Smarcel
143283221Smarcel#ifdef DEBUG
143383221Smarcel	if (ldebug(fcntl64))
143483221Smarcel		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
143583221Smarcel#endif
143683221Smarcel
143783221Smarcel	switch (args->cmd) {
143899687Srobert	case LINUX_F_GETLK64:
1439111797Sdes		error = copyin((void *)args->arg, &linux_flock,
144083221Smarcel		    sizeof(linux_flock));
144183221Smarcel		if (error)
144283221Smarcel			return (error);
1443102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1444102872Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
144583221Smarcel		if (error)
144683221Smarcel			return (error);
1447102872Siedowse		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1448111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1449111797Sdes			    sizeof(linux_flock)));
145083221Smarcel
145199687Srobert	case LINUX_F_SETLK64:
1452111797Sdes		error = copyin((void *)args->arg, &linux_flock,
145383221Smarcel		    sizeof(linux_flock));
145483221Smarcel		if (error)
145583221Smarcel			return (error);
1456102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1457102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1458102872Siedowse		    (intptr_t)&bsd_flock));
145983221Smarcel
146099687Srobert	case LINUX_F_SETLKW64:
1461111797Sdes		error = copyin((void *)args->arg, &linux_flock,
146283221Smarcel		    sizeof(linux_flock));
146383221Smarcel		if (error)
146483221Smarcel			return (error);
1465102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1466102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1467102872Siedowse		    (intptr_t)&bsd_flock));
146883221Smarcel	}
146983221Smarcel
1470283415Sdchagin	fcntl_args.fd = args->fd;
1471283415Sdchagin	fcntl_args.cmd = args->cmd;
1472283415Sdchagin	fcntl_args.arg = args->arg;
1473283415Sdchagin	return (fcntl_common(td, &fcntl_args));
147483221Smarcel}
1475133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
147685022Smarcel
147785022Smarcelint
147885022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
147985022Smarcel{
1480102814Siedowse	char *path;
1481102814Siedowse	int error;
148285022Smarcel
1483102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
148485022Smarcel
148585022Smarcel#ifdef DEBUG
148685022Smarcel	if (ldebug(chown))
1487102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
148885022Smarcel#endif
1489274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1490274476Skib	    args->gid, 0);
1491102814Siedowse	LFREEPATH(path);
1492102814Siedowse	return (error);
149385022Smarcel}
149485022Smarcel
149585022Smarcelint
1496177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1497177997Skib{
1498177997Skib	char *path;
1499227693Sed	int error, dfd, flag;
1500177997Skib
1501177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1502177997Skib		return (EINVAL);
1503177997Skib
1504177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1505177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1506177997Skib
1507177997Skib#ifdef DEBUG
1508177997Skib	if (ldebug(fchownat))
1509177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1510177997Skib#endif
1511177997Skib
1512227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1513177997Skib	    AT_SYMLINK_NOFOLLOW;
1514177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1515227693Sed	    flag);
1516177997Skib	LFREEPATH(path);
1517177997Skib	return (error);
1518177997Skib}
1519177997Skib
1520177997Skibint
152185022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
152285022Smarcel{
1523102814Siedowse	char *path;
1524102814Siedowse	int error;
152585022Smarcel
1526102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
152785022Smarcel
152885022Smarcel#ifdef DEBUG
152985022Smarcel	if (ldebug(lchown))
1530102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
153185022Smarcel#endif
1532274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1533274476Skib	    args->gid, AT_SYMLINK_NOFOLLOW);
1534102814Siedowse	LFREEPATH(path);
1535102814Siedowse	return (error);
153685022Smarcel}
1537228957Sjhb
1538228957Sjhbstatic int
1539228957Sjhbconvert_fadvice(int advice)
1540228957Sjhb{
1541228957Sjhb	switch (advice) {
1542228957Sjhb	case LINUX_POSIX_FADV_NORMAL:
1543228957Sjhb		return (POSIX_FADV_NORMAL);
1544228957Sjhb	case LINUX_POSIX_FADV_RANDOM:
1545228957Sjhb		return (POSIX_FADV_RANDOM);
1546228957Sjhb	case LINUX_POSIX_FADV_SEQUENTIAL:
1547228957Sjhb		return (POSIX_FADV_SEQUENTIAL);
1548228957Sjhb	case LINUX_POSIX_FADV_WILLNEED:
1549228957Sjhb		return (POSIX_FADV_WILLNEED);
1550228957Sjhb	case LINUX_POSIX_FADV_DONTNEED:
1551228957Sjhb		return (POSIX_FADV_DONTNEED);
1552228957Sjhb	case LINUX_POSIX_FADV_NOREUSE:
1553228957Sjhb		return (POSIX_FADV_NOREUSE);
1554228957Sjhb	default:
1555228957Sjhb		return (-1);
1556228957Sjhb	}
1557228957Sjhb}
1558228957Sjhb
1559228957Sjhbint
1560228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1561228957Sjhb{
1562228957Sjhb	int advice;
1563228957Sjhb
1564228957Sjhb	advice = convert_fadvice(args->advice);
1565228957Sjhb	if (advice == -1)
1566228957Sjhb		return (EINVAL);
1567228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1568228957Sjhb	    advice));
1569228957Sjhb}
1570228957Sjhb
1571283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1572228957Sjhbint
1573228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1574228957Sjhb{
1575228957Sjhb	int advice;
1576228957Sjhb
1577228957Sjhb	advice = convert_fadvice(args->advice);
1578228957Sjhb	if (advice == -1)
1579228957Sjhb		return (EINVAL);
1580228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1581228957Sjhb	    advice));
1582228957Sjhb}
1583283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1584234352Sjkim
1585234352Sjkimint
1586234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args)
1587234352Sjkim{
1588234352Sjkim	int fildes[2];
1589234352Sjkim	int error;
1590234352Sjkim
1591234352Sjkim#ifdef DEBUG
1592234352Sjkim	if (ldebug(pipe))
1593234352Sjkim		printf(ARGS(pipe, "*"));
1594234352Sjkim#endif
1595234352Sjkim
1596286021Sed	error = kern_pipe(td, fildes, 0, NULL, NULL);
1597315538Strasz	if (error != 0)
1598234352Sjkim		return (error);
1599234352Sjkim
1600315538Strasz	error = copyout(fildes, args->pipefds, sizeof(fildes));
1601315538Strasz	if (error != 0) {
1602315538Strasz		(void)kern_close(td, fildes[0]);
1603315538Strasz		(void)kern_close(td, fildes[1]);
1604315538Strasz	}
1605315538Strasz
1606315538Strasz	return (error);
1607234352Sjkim}
1608234352Sjkim
1609234352Sjkimint
1610234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1611234352Sjkim{
1612234352Sjkim	int fildes[2];
1613234352Sjkim	int error, flags;
1614234352Sjkim
1615234352Sjkim#ifdef DEBUG
1616234352Sjkim	if (ldebug(pipe2))
1617234352Sjkim		printf(ARGS(pipe2, "*, %d"), args->flags);
1618234352Sjkim#endif
1619234352Sjkim
1620234352Sjkim	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1621234352Sjkim		return (EINVAL);
1622234352Sjkim
1623234352Sjkim	flags = 0;
1624234352Sjkim	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1625234352Sjkim		flags |= O_NONBLOCK;
1626234352Sjkim	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1627234352Sjkim		flags |= O_CLOEXEC;
1628286021Sed	error = kern_pipe(td, fildes, flags, NULL, NULL);
1629315538Strasz	if (error != 0)
1630234352Sjkim		return (error);
1631234352Sjkim
1632315538Strasz	error = copyout(fildes, args->pipefds, sizeof(fildes));
1633315538Strasz	if (error != 0) {
1634315538Strasz		(void)kern_close(td, fildes[0]);
1635315538Strasz		(void)kern_close(td, fildes[1]);
1636315538Strasz	}
1637315538Strasz
1638315538Strasz	return (error);
1639234352Sjkim}
1640283399Sdchagin
1641283399Sdchaginint
1642283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args)
1643283399Sdchagin{
1644283399Sdchagin	int cmd;
1645283399Sdchagin	intptr_t newfd;
1646283399Sdchagin
1647283399Sdchagin	if (args->oldfd == args->newfd)
1648283399Sdchagin		return (EINVAL);
1649283399Sdchagin	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1650283399Sdchagin		return (EINVAL);
1651283399Sdchagin	if (args->flags & LINUX_O_CLOEXEC)
1652283399Sdchagin		cmd = F_DUP2FD_CLOEXEC;
1653283399Sdchagin	else
1654283399Sdchagin		cmd = F_DUP2FD;
1655283399Sdchagin
1656283399Sdchagin	newfd = args->newfd;
1657283399Sdchagin	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1658283399Sdchagin}
1659283465Sdchagin
1660283465Sdchaginint
1661283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1662283465Sdchagin{
1663283465Sdchagin
1664283465Sdchagin	/*
1665283465Sdchagin	 * We emulate only posix_fallocate system call for which
1666283465Sdchagin	 * mode should be 0.
1667283465Sdchagin	 */
1668283465Sdchagin	if (args->mode != 0)
1669283465Sdchagin		return (ENOSYS);
1670283465Sdchagin
1671283465Sdchagin	return (kern_posix_fallocate(td, args->fd, args->offset,
1672283465Sdchagin	    args->len));
1673283465Sdchagin}
1674