linux_file.c revision 304987
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 304987 2016-08-29 06:32:30Z kib $");
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
56163606Srwatson#include <security/mac/mac_framework.h>
57163606Srwatson
58140214Sobrien#ifdef COMPAT_LINUX32
59140214Sobrien#include <machine/../linux32/linux.h>
60140214Sobrien#include <machine/../linux32/linux32_proto.h>
61140214Sobrien#else
6264905Smarcel#include <machine/../linux/linux.h>
6368583Smarcel#include <machine/../linux/linux_proto.h>
64133816Stjr#endif
65246085Sjhb#include <compat/linux/linux_misc.h>
6664905Smarcel#include <compat/linux/linux_util.h>
67177997Skib#include <compat/linux/linux_file.h>
689313Ssos
699313Ssosint
7083366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args)
719313Ssos{
72300411Sdchagin	char *path;
73300411Sdchagin	int error;
749313Ssos
75300411Sdchagin	LCONVPATHEXIST(td, args->path, &path);
769313Ssos#ifdef DEBUG
7772543Sjlemon	if (ldebug(creat))
78102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
799313Ssos#endif
80300411Sdchagin	error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
81300411Sdchagin	    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
82300411Sdchagin	LFREEPATH(path);
83300411Sdchagin	return (error);
849313Ssos}
859313Ssos
86168014Sjulian
87168014Sjulianstatic int
88177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
899313Ssos{
90300411Sdchagin	cap_rights_t rights;
91300411Sdchagin	struct proc *p = td->td_proc;
92300411Sdchagin	struct file *fp;
93300411Sdchagin	int fd;
94300411Sdchagin	int bsd_flags, error;
9514331Speter
96300411Sdchagin	bsd_flags = 0;
97300411Sdchagin	switch (l_flags & LINUX_O_ACCMODE) {
98300411Sdchagin	case LINUX_O_WRONLY:
99300411Sdchagin		bsd_flags |= O_WRONLY;
100300411Sdchagin		break;
101300411Sdchagin	case LINUX_O_RDWR:
102300411Sdchagin		bsd_flags |= O_RDWR;
103300411Sdchagin		break;
104300411Sdchagin	default:
105300411Sdchagin		bsd_flags |= O_RDONLY;
106300411Sdchagin	}
107300411Sdchagin	if (l_flags & LINUX_O_NDELAY)
108300411Sdchagin		bsd_flags |= O_NONBLOCK;
109300411Sdchagin	if (l_flags & LINUX_O_APPEND)
110300411Sdchagin		bsd_flags |= O_APPEND;
111300411Sdchagin	if (l_flags & LINUX_O_SYNC)
112300411Sdchagin		bsd_flags |= O_FSYNC;
113300411Sdchagin	if (l_flags & LINUX_O_NONBLOCK)
114300411Sdchagin		bsd_flags |= O_NONBLOCK;
115300411Sdchagin	if (l_flags & LINUX_FASYNC)
116300411Sdchagin		bsd_flags |= O_ASYNC;
117300411Sdchagin	if (l_flags & LINUX_O_CREAT)
118300411Sdchagin		bsd_flags |= O_CREAT;
119300411Sdchagin	if (l_flags & LINUX_O_TRUNC)
120300411Sdchagin		bsd_flags |= O_TRUNC;
121300411Sdchagin	if (l_flags & LINUX_O_EXCL)
122300411Sdchagin		bsd_flags |= O_EXCL;
123300411Sdchagin	if (l_flags & LINUX_O_NOCTTY)
124300411Sdchagin		bsd_flags |= O_NOCTTY;
125300411Sdchagin	if (l_flags & LINUX_O_DIRECT)
126300411Sdchagin		bsd_flags |= O_DIRECT;
127300411Sdchagin	if (l_flags & LINUX_O_NOFOLLOW)
128300411Sdchagin		bsd_flags |= O_NOFOLLOW;
129300411Sdchagin	if (l_flags & LINUX_O_DIRECTORY)
130300411Sdchagin		bsd_flags |= O_DIRECTORY;
131300411Sdchagin	/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1329313Ssos
133300411Sdchagin	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
134300411Sdchagin	if (error != 0)
135300411Sdchagin		goto done;
136300411Sdchagin	if (bsd_flags & O_NOCTTY)
137300411Sdchagin		goto done;
138178036Srdivacky
139300411Sdchagin	/*
140300411Sdchagin	 * XXX In between kern_open() and fget(), another process
141300411Sdchagin	 * having the same filedesc could use that fd without
142300411Sdchagin	 * checking below.
143300411Sdchagin	*/
144300411Sdchagin	fd = td->td_retval[0];
145300411Sdchagin	if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
146300411Sdchagin		if (fp->f_type != DTYPE_VNODE) {
147300411Sdchagin			fdrop(fp, td);
148300411Sdchagin			goto done;
149300411Sdchagin		}
150300411Sdchagin		sx_slock(&proctree_lock);
151300411Sdchagin		PROC_LOCK(p);
152300411Sdchagin		if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
153300411Sdchagin			PROC_UNLOCK(p);
154300411Sdchagin			sx_sunlock(&proctree_lock);
155300411Sdchagin			/* XXXPJD: Verify if TIOCSCTTY is allowed. */
156300411Sdchagin			(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
157300411Sdchagin			    td->td_ucred, td);
158300411Sdchagin		} else {
159300411Sdchagin			PROC_UNLOCK(p);
160300411Sdchagin			sx_sunlock(&proctree_lock);
161300411Sdchagin		}
162300411Sdchagin		fdrop(fp, td);
163300411Sdchagin	}
164281726Strasz
165281726Straszdone:
16614331Speter#ifdef DEBUG
167300411Sdchagin	if (ldebug(open))
168300411Sdchagin		printf(LMSG("open returns error %d"), error);
16914331Speter#endif
170300411Sdchagin	LFREEPATH(path);
171300411Sdchagin	return (error);
1729313Ssos}
1739313Ssos
1749313Ssosint
175168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args)
176168014Sjulian{
177177997Skib	char *path;
178177997Skib	int dfd;
179168014Sjulian
180177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
181177997Skib	if (args->flags & LINUX_O_CREAT)
182177997Skib		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
183177997Skib	else
184177997Skib		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
185168014Sjulian#ifdef DEBUG
186168014Sjulian	if (ldebug(openat))
187168014Sjulian		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
188177997Skib		    path, args->flags, args->mode);
189168014Sjulian#endif
190177997Skib	return (linux_common_open(td, dfd, path, args->flags, args->mode));
191168014Sjulian}
192168014Sjulian
193168014Sjulianint
194168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args)
195168014Sjulian{
196300411Sdchagin	char *path;
197168014Sjulian
198300411Sdchagin	if (args->flags & LINUX_O_CREAT)
199300411Sdchagin		LCONVPATHCREAT(td, args->path, &path);
200300411Sdchagin	else
201300411Sdchagin		LCONVPATHEXIST(td, args->path, &path);
202168014Sjulian#ifdef DEBUG
203168014Sjulian	if (ldebug(open))
204168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
205168014Sjulian		    path, args->flags, args->mode);
206168014Sjulian#endif
207178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
208168014Sjulian}
209168014Sjulian
210168014Sjulianint
21183366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2129313Ssos{
213300411Sdchagin	struct lseek_args /* {
214300411Sdchagin		int fd;
215300411Sdchagin		int pad;
216300411Sdchagin		off_t offset;
217300411Sdchagin		int whence;
218300411Sdchagin	} */ tmp_args;
219300411Sdchagin	int error;
2209313Ssos
2219313Ssos#ifdef DEBUG
22272543Sjlemon	if (ldebug(lseek))
22372543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
22483221Smarcel		    args->fdes, (long)args->off, args->whence);
2259313Ssos#endif
226300411Sdchagin	tmp_args.fd = args->fdes;
227300411Sdchagin	tmp_args.offset = (off_t)args->off;
228300411Sdchagin	tmp_args.whence = args->whence;
229300411Sdchagin	error = sys_lseek(td, &tmp_args);
230300411Sdchagin	return (error);
2319313Ssos}
2329313Ssos
233283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
23414331Speterint
23583366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
23614331Speter{
23714331Speter	struct lseek_args bsd_args;
23814331Speter	int error;
23914331Speter	off_t off;
24014331Speter
24114331Speter#ifdef DEBUG
24272543Sjlemon	if (ldebug(llseek))
24372543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
24472543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
24514331Speter#endif
24614331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
24714331Speter
24814331Speter	bsd_args.fd = args->fd;
24914331Speter	bsd_args.offset = off;
25014331Speter	bsd_args.whence = args->whence;
25114331Speter
252225617Skmacy	if ((error = sys_lseek(td, &bsd_args)))
253300411Sdchagin		return (error);
25414331Speter
255111797Sdes	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
256300411Sdchagin		return (error);
25714331Speter
25883366Sjulian	td->td_retval[0] = 0;
259300411Sdchagin	return (0);
26014331Speter}
26114331Speter
2629313Ssosint
26383366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args)
2649313Ssos{
26514331Speter	struct linux_getdents_args lda;
26614331Speter
26714331Speter	lda.fd = args->fd;
26814331Speter	lda.dent = args->dent;
26914331Speter	lda.count = 1;
270300411Sdchagin	return (linux_getdents(td, &lda));
27114331Speter}
272283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
27314331Speter
27483221Smarcel/*
27583221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
27683221Smarcel * arguments. They only differ in the definition of struct dirent they
27783221Smarcel * operate on. We use this to common the code, with the exception of
27883221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented
27983221Smarcel * by means of linux_getdents(2). In this case we never operate on
28083221Smarcel * struct dirent64 and thus don't need to handle it...
28183221Smarcel */
28283221Smarcel
28383221Smarcelstruct l_dirent {
284179651Srdivacky	l_ulong		d_ino;
28583221Smarcel	l_off_t		d_off;
28683221Smarcel	l_ushort	d_reclen;
28783221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
28883221Smarcel};
28983221Smarcel
29083221Smarcelstruct l_dirent64 {
29183221Smarcel	uint64_t	d_ino;
29283221Smarcel	int64_t		d_off;
29383221Smarcel	l_ushort	d_reclen;
29483221Smarcel	u_char		d_type;
29583221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29683221Smarcel};
29783221Smarcel
298182892Srdivacky/*
299182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
300182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
301182892Srdivacky */
302182892Srdivacky#define LINUX_RECLEN(namlen)						\
303298482Spfg    roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
30483221Smarcel
305182892Srdivacky#define LINUX_RECLEN64(namlen)						\
306298482Spfg    roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
307182892Srdivacky    sizeof(uint64_t))
308182892Srdivacky
309182892Srdivacky#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
310182892Srdivacky				    LINUX_RECLEN64(LINUX_NAME_MAX))
31183221Smarcel#define	LINUX_DIRBLKSIZ		512
31283221Smarcel
31383221Smarcelstatic int
31483366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args,
31583221Smarcel    int is64bit)
31614331Speter{
317111798Sdes	struct dirent *bdp;
31883221Smarcel	struct vnode *vp;
31983221Smarcel	caddr_t inp, buf;		/* BSD-format */
32083221Smarcel	int len, reclen;		/* BSD-format */
32183221Smarcel	caddr_t outp;			/* Linux-format */
32283221Smarcel	int resid, linuxreclen=0;	/* Linux-format */
323182892Srdivacky	caddr_t lbuf;			/* Linux-format */
324255219Spjd	cap_rights_t rights;
32583221Smarcel	struct file *fp;
32683221Smarcel	struct uio auio;
32783221Smarcel	struct iovec aiov;
32883221Smarcel	off_t off;
329182892Srdivacky	struct l_dirent *linux_dirent;
330182892Srdivacky	struct l_dirent64 *linux_dirent64;
33183221Smarcel	int buflen, error, eofflag, nbytes, justone;
33283221Smarcel	u_long *cookies = NULL, *cookiep;
333241896Skib	int ncookies;
3349313Ssos
335160276Sjhb	nbytes = args->count;
336160276Sjhb	if (nbytes == 1) {
337160276Sjhb		/* readdir(2) case. Always struct dirent. */
338160276Sjhb		if (is64bit)
339160276Sjhb			return (EINVAL);
340188572Snetchild		nbytes = sizeof(*linux_dirent);
341160276Sjhb		justone = 1;
342160276Sjhb	} else
343160276Sjhb		justone = 0;
344160276Sjhb
345284446Smjg	error = getvnode(td, args->fd, cap_rights_init(&rights, CAP_READ), &fp);
346255219Spjd	if (error != 0)
34783221Smarcel		return (error);
3489313Ssos
34989306Salfred	if ((fp->f_flag & FREAD) == 0) {
35089306Salfred		fdrop(fp, td);
35183221Smarcel		return (EBADF);
35289306Salfred	}
3539313Ssos
354238029Skib	off = foffset_lock(fp, 0);
355116678Sphk	vp = fp->f_vnode;
35689306Salfred	if (vp->v_type != VDIR) {
357238029Skib		foffset_unlock(fp, off, 0);
35889306Salfred		fdrop(fp, td);
35983221Smarcel		return (EINVAL);
36089306Salfred	}
3619313Ssos
3629313Ssos
36383221Smarcel	buflen = max(LINUX_DIRBLKSIZ, nbytes);
36483221Smarcel	buflen = min(buflen, MAXBSIZE);
365283427Sdchagin	buf = malloc(buflen, M_LINUX, M_WAITOK);
366283427Sdchagin	lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO);
367188588Sjhb	vn_lock(vp, LK_SHARED | LK_RETRY);
36883221Smarcel
36983221Smarcel	aiov.iov_base = buf;
37083221Smarcel	aiov.iov_len = buflen;
37183221Smarcel	auio.uio_iov = &aiov;
37283221Smarcel	auio.uio_iovcnt = 1;
37383221Smarcel	auio.uio_rw = UIO_READ;
37483221Smarcel	auio.uio_segflg = UIO_SYSSPACE;
37583366Sjulian	auio.uio_td = td;
37683221Smarcel	auio.uio_resid = buflen;
37783221Smarcel	auio.uio_offset = off;
3789313Ssos
379101189Srwatson#ifdef MAC
380101189Srwatson	/*
381101189Srwatson	 * Do directory search MAC check using non-cached credentials.
382101189Srwatson	 */
383172930Srwatson	if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
384101189Srwatson		goto out;
385101189Srwatson#endif /* MAC */
38683221Smarcel	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
38783221Smarcel		 &cookies)))
38883221Smarcel		goto out;
3899313Ssos
39083221Smarcel	inp = buf;
39183221Smarcel	outp = (caddr_t)args->dirent;
39283221Smarcel	resid = nbytes;
39383221Smarcel	if ((len = buflen - auio.uio_resid) <= 0)
39483221Smarcel		goto eof;
3959313Ssos
39683221Smarcel	cookiep = cookies;
39724654Sdfr
39883221Smarcel	if (cookies) {
39983221Smarcel		/*
40083221Smarcel		 * When using cookies, the vfs has the option of reading from
40183221Smarcel		 * a different offset than that supplied (UFS truncates the
40283221Smarcel		 * offset to a block boundary to make sure that it never reads
40383221Smarcel		 * partway through a directory entry, even if the directory
40483221Smarcel		 * has been compacted).
40583221Smarcel		 */
40683221Smarcel		while (len > 0 && ncookies > 0 && *cookiep <= off) {
40783221Smarcel			bdp = (struct dirent *) inp;
40883221Smarcel			len -= bdp->d_reclen;
40983221Smarcel			inp += bdp->d_reclen;
41083221Smarcel			cookiep++;
41183221Smarcel			ncookies--;
41283221Smarcel		}
41324654Sdfr	}
41424654Sdfr
41583221Smarcel	while (len > 0) {
41683221Smarcel		if (cookiep && ncookies == 0)
41783221Smarcel			break;
41883221Smarcel		bdp = (struct dirent *) inp;
41983221Smarcel		reclen = bdp->d_reclen;
42083221Smarcel		if (reclen & 3) {
42183221Smarcel			error = EFAULT;
42283221Smarcel			goto out;
42383221Smarcel		}
42483221Smarcel
42583221Smarcel		if (bdp->d_fileno == 0) {
42683221Smarcel			inp += reclen;
42783221Smarcel			if (cookiep) {
42883221Smarcel				off = *cookiep++;
42983221Smarcel				ncookies--;
43083221Smarcel			} else
43183221Smarcel				off += reclen;
43283221Smarcel
43383221Smarcel			len -= reclen;
43483221Smarcel			continue;
43583221Smarcel		}
43683221Smarcel
43783221Smarcel		linuxreclen = (is64bit)
438182892Srdivacky		    ? LINUX_RECLEN64(bdp->d_namlen)
439182892Srdivacky		    : LINUX_RECLEN(bdp->d_namlen);
44083221Smarcel
44183221Smarcel		if (reclen > len || resid < linuxreclen) {
44283221Smarcel			outp++;
44383221Smarcel			break;
44483221Smarcel		}
44583221Smarcel
44683221Smarcel		if (justone) {
44783221Smarcel			/* readdir(2) case. */
448182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
449182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
450182892Srdivacky			linux_dirent->d_off = (l_off_t)linuxreclen;
451182892Srdivacky			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
452182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
453182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name));
454182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
45583221Smarcel		}
456182892Srdivacky		if (is64bit) {
457182892Srdivacky			linux_dirent64 = (struct l_dirent64*)lbuf;
458182892Srdivacky			linux_dirent64->d_ino = bdp->d_fileno;
459182892Srdivacky			linux_dirent64->d_off = (cookiep)
460182892Srdivacky			    ? (l_off_t)*cookiep
461182892Srdivacky			    : (l_off_t)(off + reclen);
462182892Srdivacky			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
463182892Srdivacky			linux_dirent64->d_type = bdp->d_type;
464182892Srdivacky			strlcpy(linux_dirent64->d_name, bdp->d_name,
465182892Srdivacky			    linuxreclen - offsetof(struct l_dirent64, d_name));
466182892Srdivacky			error = copyout(linux_dirent64, outp, linuxreclen);
467182892Srdivacky		} else if (!justone) {
468182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
469182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
470182892Srdivacky			linux_dirent->d_off = (cookiep)
471182892Srdivacky			    ? (l_off_t)*cookiep
472182892Srdivacky			    : (l_off_t)(off + reclen);
473182892Srdivacky			linux_dirent->d_reclen = (l_ushort)linuxreclen;
474182892Srdivacky			/*
475182892Srdivacky			 * Copy d_type to last byte of l_dirent buffer
476182892Srdivacky			 */
477182892Srdivacky			lbuf[linuxreclen-1] = bdp->d_type;
478182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
479182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
480182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
481182892Srdivacky		}
482182892Srdivacky
48383221Smarcel		if (error)
48483221Smarcel			goto out;
48583221Smarcel
48683221Smarcel		inp += reclen;
48783221Smarcel		if (cookiep) {
48883221Smarcel			off = *cookiep++;
48983221Smarcel			ncookies--;
49083221Smarcel		} else
49183221Smarcel			off += reclen;
49283221Smarcel
49383221Smarcel		outp += linuxreclen;
49483221Smarcel		resid -= linuxreclen;
49583221Smarcel		len -= reclen;
49683221Smarcel		if (justone)
49783221Smarcel			break;
49810355Sswallace	}
4999313Ssos
500217578Skib	if (outp == (caddr_t)args->dirent) {
501217578Skib		nbytes = resid;
502217578Skib		goto eof;
503217578Skib	}
5049313Ssos
50583221Smarcel	if (justone)
50683221Smarcel		nbytes = resid + linuxreclen;
50710355Sswallace
5089313Ssoseof:
50983366Sjulian	td->td_retval[0] = nbytes - resid;
51083221Smarcel
5119313Ssosout:
512247764Seadler	free(cookies, M_TEMP);
51383221Smarcel
514175294Sattilio	VOP_UNLOCK(vp, 0);
515238029Skib	foffset_unlock(fp, off, 0);
51689306Salfred	fdrop(fp, td);
517283427Sdchagin	free(buf, M_LINUX);
518283427Sdchagin	free(lbuf, M_LINUX);
51983221Smarcel	return (error);
5209313Ssos}
52114331Speter
52283221Smarcelint
52383366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args)
52483221Smarcel{
52583221Smarcel
52683221Smarcel#ifdef DEBUG
52783221Smarcel	if (ldebug(getdents))
52883221Smarcel		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
52983221Smarcel#endif
53083221Smarcel
53183366Sjulian	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
53283221Smarcel}
53383221Smarcel
53483221Smarcelint
53583366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
53683221Smarcel{
53783221Smarcel
53883221Smarcel#ifdef DEBUG
53983221Smarcel	if (ldebug(getdents64))
54083221Smarcel		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
54183221Smarcel#endif
54283221Smarcel
54383366Sjulian	return (getdents_common(td, args, 1));
54483221Smarcel}
54583221Smarcel
54614331Speter/*
54714331Speter * These exist mainly for hooks for doing /compat/linux translation.
54814331Speter */
54914331Speter
55014331Speterint
55183366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
55214331Speter{
553102814Siedowse	char *path;
554102814Siedowse	int error;
55514331Speter
556162585Snetchild	/* linux convention */
557227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
558162585Snetchild		return (EINVAL);
559162585Snetchild
560102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
56114331Speter
56214331Speter#ifdef DEBUG
56372543Sjlemon	if (ldebug(access))
564227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
56514331Speter#endif
566274476Skib	error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
567274476Skib	    args->amode);
568102814Siedowse	LFREEPATH(path);
569162585Snetchild
570102814Siedowse	return (error);
57114331Speter}
57214331Speter
57314331Speterint
574177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
575177997Skib{
576177997Skib	char *path;
577283428Sdchagin	int error, dfd;
578177997Skib
579177997Skib	/* linux convention */
580227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
581177997Skib		return (EINVAL);
582177997Skib
583177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
584177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
585177997Skib
586177997Skib#ifdef DEBUG
587177997Skib	if (ldebug(access))
588227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
589177997Skib#endif
590177997Skib
591283428Sdchagin	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
592177997Skib	LFREEPATH(path);
593177997Skib
594177997Skib	return (error);
595177997Skib}
596177997Skib
597177997Skibint
59883366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
59914331Speter{
600102814Siedowse	char *path;
601102814Siedowse	int error;
602162201Snetchild	struct stat st;
60314331Speter
604102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
60514331Speter
60614331Speter#ifdef DEBUG
60772543Sjlemon	if (ldebug(unlink))
608102814Siedowse		printf(ARGS(unlink, "%s"), path);
60914331Speter#endif
61014331Speter
611274476Skib	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
612274476Skib	if (error == EPERM) {
613162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
614274476Skib		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
615274476Skib		    NULL) == 0) {
616162201Snetchild			if (S_ISDIR(st.st_mode))
617162201Snetchild				error = EISDIR;
618274476Skib		}
619274476Skib	}
620102814Siedowse	LFREEPATH(path);
621102814Siedowse	return (error);
62214331Speter}
62314331Speter
62414331Speterint
625177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
626177997Skib{
627177997Skib	char *path;
628177997Skib	int error, dfd;
629177997Skib	struct stat st;
630177997Skib
631177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
632177997Skib		return (EINVAL);
633177997Skib
634177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
635177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
636177997Skib
637177997Skib#ifdef DEBUG
638177997Skib	if (ldebug(unlinkat))
639177997Skib		printf(ARGS(unlinkat, "%s"), path);
640177997Skib#endif
641177997Skib
642177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
643177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
644177997Skib	else
645202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
646177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
647177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
648177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
649274476Skib		    UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
650177997Skib			error = EISDIR;
651177997Skib	}
652177997Skib	LFREEPATH(path);
653177997Skib	return (error);
654177997Skib}
655177997Skibint
65683366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
65714331Speter{
658102814Siedowse	char *path;
659102814Siedowse	int error;
66014331Speter
661102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
66214331Speter
66314331Speter#ifdef DEBUG
66472543Sjlemon	if (ldebug(chdir))
665102814Siedowse		printf(ARGS(chdir, "%s"), path);
66614331Speter#endif
667102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
668102814Siedowse	LFREEPATH(path);
669102814Siedowse	return (error);
67014331Speter}
67114331Speter
67214331Speterint
67383366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
67414331Speter{
675102814Siedowse	char *path;
676102814Siedowse	int error;
67714331Speter
678102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
67914331Speter
68014331Speter#ifdef DEBUG
68172543Sjlemon	if (ldebug(chmod))
682102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
68314331Speter#endif
684274476Skib	error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
685274476Skib	    args->mode, 0);
686102814Siedowse	LFREEPATH(path);
687102814Siedowse	return (error);
68814331Speter}
68914331Speter
69014331Speterint
691177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
692177997Skib{
693177997Skib	char *path;
694177997Skib	int error, dfd;
695177997Skib
696177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
697177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
698177997Skib
699177997Skib#ifdef DEBUG
700177997Skib	if (ldebug(fchmodat))
701177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
702177997Skib#endif
703177997Skib
704177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
705177997Skib	LFREEPATH(path);
706177997Skib	return (error);
707177997Skib}
708177997Skib
709177997Skibint
71083366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
71114331Speter{
712102814Siedowse	char *path;
713102814Siedowse	int error;
71414331Speter
715102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
71614331Speter
71714331Speter#ifdef DEBUG
71872543Sjlemon	if (ldebug(mkdir))
719102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
72014331Speter#endif
721274476Skib	error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
722102814Siedowse	LFREEPATH(path);
723102814Siedowse	return (error);
72414331Speter}
72514331Speter
72614331Speterint
727177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
728177997Skib{
729177997Skib	char *path;
730177997Skib	int error, dfd;
731177997Skib
732177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
733177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
734177997Skib
735177997Skib#ifdef DEBUG
736177997Skib	if (ldebug(mkdirat))
737177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
738177997Skib#endif
739177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
740177997Skib	LFREEPATH(path);
741177997Skib	return (error);
742177997Skib}
743177997Skib
744177997Skibint
74583366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
74614331Speter{
747102814Siedowse	char *path;
748102814Siedowse	int error;
74914331Speter
750102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
75114331Speter
75214331Speter#ifdef DEBUG
75372543Sjlemon	if (ldebug(rmdir))
754102814Siedowse		printf(ARGS(rmdir, "%s"), path);
75514331Speter#endif
756274476Skib	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
757102814Siedowse	LFREEPATH(path);
758102814Siedowse	return (error);
75914331Speter}
76014331Speter
76114331Speterint
76283366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
76314331Speter{
764102814Siedowse	char *from, *to;
765102814Siedowse	int error;
76614331Speter
767102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
768102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
769177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
770102814Siedowse	if (to == NULL) {
771102814Siedowse		LFREEPATH(from);
772102814Siedowse		return (error);
773102814Siedowse	}
77414331Speter
77514331Speter#ifdef DEBUG
77672543Sjlemon	if (ldebug(rename))
777102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
77814331Speter#endif
779274476Skib	error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
780102814Siedowse	LFREEPATH(from);
781102814Siedowse	LFREEPATH(to);
782102814Siedowse	return (error);
78314331Speter}
78414331Speter
78514331Speterint
786177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
787177997Skib{
788177997Skib	char *from, *to;
789177997Skib	int error, olddfd, newdfd;
790177997Skib
791177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
792177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
793177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
794177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
795177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
796177997Skib	if (to == NULL) {
797177997Skib		LFREEPATH(from);
798177997Skib		return (error);
799177997Skib	}
800177997Skib
801177997Skib#ifdef DEBUG
802177997Skib	if (ldebug(renameat))
803177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
804177997Skib#endif
805177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
806177997Skib	LFREEPATH(from);
807177997Skib	LFREEPATH(to);
808177997Skib	return (error);
809177997Skib}
810177997Skib
811177997Skibint
81283366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
81314331Speter{
814102814Siedowse	char *path, *to;
815102814Siedowse	int error;
81614331Speter
817102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
818102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
819177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
820102814Siedowse	if (to == NULL) {
821102814Siedowse		LFREEPATH(path);
822102814Siedowse		return (error);
823102814Siedowse	}
82414331Speter
82514331Speter#ifdef DEBUG
82672543Sjlemon	if (ldebug(symlink))
827102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
82814331Speter#endif
829274476Skib	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
830102814Siedowse	LFREEPATH(path);
831102814Siedowse	LFREEPATH(to);
832102814Siedowse	return (error);
83314331Speter}
83414331Speter
83514331Speterint
836177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
837177997Skib{
838177997Skib	char *path, *to;
839177997Skib	int error, dfd;
840177997Skib
841177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
842177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
843177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
844177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
845177997Skib	if (to == NULL) {
846177997Skib		LFREEPATH(path);
847177997Skib		return (error);
848177997Skib	}
849177997Skib
850177997Skib#ifdef DEBUG
851177997Skib	if (ldebug(symlinkat))
852177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
853177997Skib#endif
854177997Skib
855177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
856177997Skib	LFREEPATH(path);
857177997Skib	LFREEPATH(to);
858177997Skib	return (error);
859177997Skib}
860177997Skib
861177997Skibint
86283366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
86314331Speter{
864102814Siedowse	char *name;
865102814Siedowse	int error;
86614331Speter
867102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
86814331Speter
86914331Speter#ifdef DEBUG
87072543Sjlemon	if (ldebug(readlink))
871102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
872102814Siedowse		    args->count);
87314331Speter#endif
874274476Skib	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
875274476Skib	    args->buf, UIO_USERSPACE, args->count);
876102814Siedowse	LFREEPATH(name);
877102814Siedowse	return (error);
87814331Speter}
87914331Speter
88014331Speterint
881177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
882177997Skib{
883177997Skib	char *name;
884177997Skib	int error, dfd;
885177997Skib
886177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
887177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
888177997Skib
889177997Skib#ifdef DEBUG
890177997Skib	if (ldebug(readlinkat))
891177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
892177997Skib		    args->bufsiz);
893177997Skib#endif
894177997Skib
895177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
896177997Skib	    UIO_USERSPACE, args->bufsiz);
897177997Skib	LFREEPATH(name);
898177997Skib	return (error);
899177997Skib}
900178439Srdivacky
901177997Skibint
90283366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
90314331Speter{
904102814Siedowse	char *path;
905102814Siedowse	int error;
90614331Speter
907102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
90814331Speter
90914331Speter#ifdef DEBUG
91072543Sjlemon	if (ldebug(truncate))
911102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
91214331Speter#endif
91314331Speter
914102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
915102814Siedowse	LFREEPATH(path);
916102814Siedowse	return (error);
91714331Speter}
91814331Speter
919283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
92049662Smarcelint
921178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args)
922178439Srdivacky{
923178439Srdivacky	char *path;
924178439Srdivacky	int error;
925178439Srdivacky
926178439Srdivacky	LCONVPATHEXIST(td, args->path, &path);
927178439Srdivacky
928178439Srdivacky#ifdef DEBUG
929178439Srdivacky	if (ldebug(truncate64))
930178439Srdivacky		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
931178439Srdivacky#endif
932178439Srdivacky
933178439Srdivacky	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
934178439Srdivacky	LFREEPATH(path);
935178439Srdivacky	return (error);
936178439Srdivacky}
937283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
938283415Sdchagin
939178439Srdivackyint
940156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
941156842Snetchild{
942156842Snetchild	struct ftruncate_args /* {
943156842Snetchild		int fd;
944156842Snetchild		int pad;
945156842Snetchild		off_t length;
946156842Snetchild		} */ nuap;
947300411Sdchagin
948156842Snetchild	nuap.fd = args->fd;
949156842Snetchild	nuap.length = args->length;
950225617Skmacy	return (sys_ftruncate(td, &nuap));
951156842Snetchild}
952156842Snetchild
953156842Snetchildint
95483366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
95549662Smarcel{
956102814Siedowse	char *path, *to;
957102814Siedowse	int error;
95849662Smarcel
959102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
960102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
961177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
962102814Siedowse	if (to == NULL) {
963102814Siedowse		LFREEPATH(path);
964102814Siedowse		return (error);
965102814Siedowse	}
96649662Smarcel
96749662Smarcel#ifdef DEBUG
96872543Sjlemon	if (ldebug(link))
969102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
97049662Smarcel#endif
971274476Skib	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
972274476Skib	    FOLLOW);
973102814Siedowse	LFREEPATH(path);
974102814Siedowse	LFREEPATH(to);
975102814Siedowse	return (error);
97649662Smarcel}
97749788Smarcel
97853713Smarcelint
979177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
980177997Skib{
981177997Skib	char *path, *to;
982227693Sed	int error, olddfd, newdfd, follow;
983177997Skib
984227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
985177997Skib		return (EINVAL);
986177997Skib
987177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
988177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
989177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
990177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
991177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
992177997Skib	if (to == NULL) {
993177997Skib		LFREEPATH(path);
994177997Skib		return (error);
995177997Skib	}
996177997Skib
997177997Skib#ifdef DEBUG
998177997Skib	if (ldebug(linkat))
999177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
1000227693Sed			args->newdfd, to, args->flag);
1001177997Skib#endif
1002177997Skib
1003227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
1004227693Sed	    FOLLOW;
1005227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
1006177997Skib	LFREEPATH(path);
1007177997Skib	LFREEPATH(to);
1008177997Skib	return (error);
1009177997Skib}
1010177997Skib
1011177997Skibint
101283366Sjulianlinux_fdatasync(td, uap)
101383366Sjulian	struct thread *td;
101453713Smarcel	struct linux_fdatasync_args *uap;
101553713Smarcel{
101653713Smarcel
1017304987Skib	return (kern_fsync(td, uap->fd, false));
101853713Smarcel}
101963285Smarcel
102063285Smarcelint
102183366Sjulianlinux_pread(td, uap)
102283366Sjulian	struct thread *td;
102363285Smarcel	struct linux_pread_args *uap;
102463285Smarcel{
102563285Smarcel	struct pread_args bsd;
1026255219Spjd	cap_rights_t rights;
1027162585Snetchild	struct vnode *vp;
1028162585Snetchild	int error;
102963285Smarcel
103063285Smarcel	bsd.fd = uap->fd;
103163285Smarcel	bsd.buf = uap->buf;
103263285Smarcel	bsd.nbyte = uap->nbyte;
103363285Smarcel	bsd.offset = uap->offset;
1034225617Skmacy	error = sys_pread(td, &bsd);
1035162585Snetchild	if (error == 0) {
1036247602Spjd		/* This seems to violate POSIX but linux does it */
1037255219Spjd		error = fgetvp(td, uap->fd,
1038255219Spjd		    cap_rights_init(&rights, CAP_PREAD), &vp);
1039255219Spjd		if (error != 0)
1040247602Spjd			return (error);
1041162585Snetchild		if (vp->v_type == VDIR) {
1042247602Spjd			vrele(vp);
1043162585Snetchild			return (EISDIR);
1044162585Snetchild		}
1045162585Snetchild		vrele(vp);
1046162585Snetchild	}
1047162585Snetchild	return (error);
104863285Smarcel}
104963285Smarcel
105063285Smarcelint
105183366Sjulianlinux_pwrite(td, uap)
105283366Sjulian	struct thread *td;
105363285Smarcel	struct linux_pwrite_args *uap;
105463285Smarcel{
105563285Smarcel	struct pwrite_args bsd;
105663285Smarcel
105763285Smarcel	bsd.fd = uap->fd;
105863285Smarcel	bsd.buf = uap->buf;
105963285Smarcel	bsd.nbyte = uap->nbyte;
106063285Smarcel	bsd.offset = uap->offset;
1061300411Sdchagin	return (sys_pwrite(td, &bsd));
106263285Smarcel}
106372538Sjlemon
106472538Sjlemonint
106583366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
106672538Sjlemon{
1067111798Sdes	char fstypename[MFSNAMELEN];
1068111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
106973286Sadrian	int error;
107073286Sadrian	int fsflags;
107172538Sjlemon
1072111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
107373286Sadrian	    NULL);
107472538Sjlemon	if (error)
1075111798Sdes		return (error);
1076127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
107772538Sjlemon	if (error)
1078111798Sdes		return (error);
1079127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
108072538Sjlemon	if (error)
1081111798Sdes		return (error);
108272538Sjlemon
108372538Sjlemon#ifdef DEBUG
108472538Sjlemon	if (ldebug(mount))
108572538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
108672538Sjlemon		    fstypename, mntfromname, mntonname);
108772538Sjlemon#endif
108872538Sjlemon
108972538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1090127059Stjr		strcpy(fstypename, "ext2fs");
109172538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1092127059Stjr		strcpy(fstypename, "linprocfs");
1093190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1094190445Sambrisko		strcpy(fstypename, "msdosfs");
109572538Sjlemon	}
109672538Sjlemon
109773286Sadrian	fsflags = 0;
109872538Sjlemon
109972538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
110072538Sjlemon		/*
110172538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
110272538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
110372538Sjlemon		 */
110472538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1105111798Sdes			fsflags |= MNT_RDONLY;
110672538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1107111798Sdes			fsflags |= MNT_NOSUID;
110872538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1109111798Sdes			fsflags |= MNT_NOEXEC;
111072538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1111111798Sdes			fsflags |= MNT_UPDATE;
111272538Sjlemon	}
111372538Sjlemon
1114281689Strasz	error = kernel_vmount(fsflags,
1115281689Strasz	    "fstype", fstypename,
1116281689Strasz	    "fspath", mntonname,
1117281689Strasz	    "from", mntfromname,
1118281689Strasz	    NULL);
1119127059Stjr	return (error);
112072538Sjlemon}
112172538Sjlemon
1122283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
112372538Sjlemonint
112483366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
112572538Sjlemon{
112683221Smarcel	struct linux_umount_args args2;
112772538Sjlemon
112872538Sjlemon	args2.path = args->path;
112972538Sjlemon	args2.flags = 0;
113083366Sjulian	return (linux_umount(td, &args2));
113172538Sjlemon}
1132283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
113372538Sjlemon
113472538Sjlemonint
113583366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
113672538Sjlemon{
113772538Sjlemon	struct unmount_args bsd;
113872538Sjlemon
113972538Sjlemon	bsd.path = args->path;
114072538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1141225617Skmacy	return (sys_unmount(td, &bsd));
114272538Sjlemon}
114383221Smarcel
114483221Smarcel/*
114583221Smarcel * fcntl family of syscalls
114683221Smarcel */
114783221Smarcel
114883221Smarcelstruct l_flock {
114983221Smarcel	l_short		l_type;
115083221Smarcel	l_short		l_whence;
115183221Smarcel	l_off_t		l_start;
115283221Smarcel	l_off_t		l_len;
115383221Smarcel	l_pid_t		l_pid;
1154133816Stjr}
1155140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1156133816Stjr__packed
1157133816Stjr#endif
1158133816Stjr;
115983221Smarcel
116083221Smarcelstatic void
116183221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
116283221Smarcel{
116383221Smarcel	switch (linux_flock->l_type) {
116483221Smarcel	case LINUX_F_RDLCK:
116583221Smarcel		bsd_flock->l_type = F_RDLCK;
116683221Smarcel		break;
116783221Smarcel	case LINUX_F_WRLCK:
116883221Smarcel		bsd_flock->l_type = F_WRLCK;
116983221Smarcel		break;
117083221Smarcel	case LINUX_F_UNLCK:
117183221Smarcel		bsd_flock->l_type = F_UNLCK;
117283221Smarcel		break;
117383221Smarcel	default:
117483221Smarcel		bsd_flock->l_type = -1;
117583221Smarcel		break;
117683221Smarcel	}
117783221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
117883221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
117983221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
118083221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1181177633Sdfr	bsd_flock->l_sysid = 0;
118283221Smarcel}
118383221Smarcel
118483221Smarcelstatic void
118583221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
118683221Smarcel{
118783221Smarcel	switch (bsd_flock->l_type) {
118883221Smarcel	case F_RDLCK:
118983221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
119083221Smarcel		break;
119183221Smarcel	case F_WRLCK:
119283221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
119383221Smarcel		break;
119483221Smarcel	case F_UNLCK:
119583221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
119683221Smarcel		break;
119783221Smarcel	}
119883221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
119983221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
120083221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
120183221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
120283221Smarcel}
120383221Smarcel
1204140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
120583221Smarcelstruct l_flock64 {
120683221Smarcel	l_short		l_type;
120783221Smarcel	l_short		l_whence;
120883221Smarcel	l_loff_t	l_start;
120983221Smarcel	l_loff_t	l_len;
121083221Smarcel	l_pid_t		l_pid;
1211133816Stjr}
1212140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1213133816Stjr__packed
1214133816Stjr#endif
1215133816Stjr;
121683221Smarcel
121783221Smarcelstatic void
121883221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
121983221Smarcel{
122083221Smarcel	switch (linux_flock->l_type) {
122183221Smarcel	case LINUX_F_RDLCK:
122283221Smarcel		bsd_flock->l_type = F_RDLCK;
122383221Smarcel		break;
122483221Smarcel	case LINUX_F_WRLCK:
122583221Smarcel		bsd_flock->l_type = F_WRLCK;
122683221Smarcel		break;
122783221Smarcel	case LINUX_F_UNLCK:
122883221Smarcel		bsd_flock->l_type = F_UNLCK;
122983221Smarcel		break;
123083221Smarcel	default:
123183221Smarcel		bsd_flock->l_type = -1;
123283221Smarcel		break;
123383221Smarcel	}
123483221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
123583221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
123683221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
123783221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1238177633Sdfr	bsd_flock->l_sysid = 0;
123983221Smarcel}
124083221Smarcel
124183221Smarcelstatic void
124283221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
124383221Smarcel{
124483221Smarcel	switch (bsd_flock->l_type) {
124583221Smarcel	case F_RDLCK:
124683221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
124783221Smarcel		break;
124883221Smarcel	case F_WRLCK:
124983221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
125083221Smarcel		break;
125183221Smarcel	case F_UNLCK:
125283221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
125383221Smarcel		break;
125483221Smarcel	}
125583221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
125683221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
125783221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
125883221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
125983221Smarcel}
1260133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
126183221Smarcel
126283221Smarcelstatic int
1263283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args)
126483221Smarcel{
1265107680Siedowse	struct l_flock linux_flock;
1266107680Siedowse	struct flock bsd_flock;
1267255219Spjd	cap_rights_t rights;
126883221Smarcel	struct file *fp;
1269102872Siedowse	long arg;
127083221Smarcel	int error, result;
127183221Smarcel
127283221Smarcel	switch (args->cmd) {
127383221Smarcel	case LINUX_F_DUPFD:
1274102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
127583221Smarcel
127683221Smarcel	case LINUX_F_GETFD:
1277102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
127883221Smarcel
127983221Smarcel	case LINUX_F_SETFD:
1280102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
128183221Smarcel
128283221Smarcel	case LINUX_F_GETFL:
1283102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
128483366Sjulian		result = td->td_retval[0];
128583366Sjulian		td->td_retval[0] = 0;
128683221Smarcel		if (result & O_RDONLY)
128783366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
128883221Smarcel		if (result & O_WRONLY)
128983366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
129083221Smarcel		if (result & O_RDWR)
129183366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
129283221Smarcel		if (result & O_NDELAY)
129383366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
129483221Smarcel		if (result & O_APPEND)
129583366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
129683221Smarcel		if (result & O_FSYNC)
129783366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
129883221Smarcel		if (result & O_ASYNC)
129983366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1300144987Smdodd#ifdef LINUX_O_NOFOLLOW
1301144987Smdodd		if (result & O_NOFOLLOW)
1302144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1303144987Smdodd#endif
1304144987Smdodd#ifdef LINUX_O_DIRECT
1305144987Smdodd		if (result & O_DIRECT)
1306144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1307144987Smdodd#endif
130883221Smarcel		return (error);
130983221Smarcel
131083221Smarcel	case LINUX_F_SETFL:
1311102872Siedowse		arg = 0;
131283221Smarcel		if (args->arg & LINUX_O_NDELAY)
1313102872Siedowse			arg |= O_NONBLOCK;
131483221Smarcel		if (args->arg & LINUX_O_APPEND)
1315102872Siedowse			arg |= O_APPEND;
131683221Smarcel		if (args->arg & LINUX_O_SYNC)
1317102872Siedowse			arg |= O_FSYNC;
131883221Smarcel		if (args->arg & LINUX_FASYNC)
1319102872Siedowse			arg |= O_ASYNC;
1320144987Smdodd#ifdef LINUX_O_NOFOLLOW
1321144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1322144987Smdodd			arg |= O_NOFOLLOW;
1323144987Smdodd#endif
1324144987Smdodd#ifdef LINUX_O_DIRECT
1325144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1326144987Smdodd			arg |= O_DIRECT;
1327144987Smdodd#endif
1328102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
132983221Smarcel
1330107680Siedowse	case LINUX_F_GETLK:
1331111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1332107680Siedowse		    sizeof(linux_flock));
1333107680Siedowse		if (error)
1334107680Siedowse			return (error);
1335107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1336107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1337107680Siedowse		if (error)
1338107680Siedowse			return (error);
1339107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1340111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1341107680Siedowse		    sizeof(linux_flock)));
1342107680Siedowse
1343107680Siedowse	case LINUX_F_SETLK:
1344111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1345107680Siedowse		    sizeof(linux_flock));
1346107680Siedowse		if (error)
1347107680Siedowse			return (error);
1348107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1349107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1350107680Siedowse		    (intptr_t)&bsd_flock));
1351107680Siedowse
1352107680Siedowse	case LINUX_F_SETLKW:
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		return (kern_fcntl(td, args->fd, F_SETLKW,
1359107680Siedowse		     (intptr_t)&bsd_flock));
1360107680Siedowse
136183221Smarcel	case LINUX_F_GETOWN:
1362102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
136383221Smarcel
136483221Smarcel	case LINUX_F_SETOWN:
136583221Smarcel		/*
136683221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
136783221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
136883221Smarcel		 * pipes under Linux-2.2.35 at least).
136983221Smarcel		 */
1370255219Spjd		error = fget(td, args->fd,
1371255219Spjd		    cap_rights_init(&rights, CAP_FCNTL), &fp);
137289319Salfred		if (error)
137389319Salfred			return (error);
137489306Salfred		if (fp->f_type == DTYPE_PIPE) {
137589306Salfred			fdrop(fp, td);
137683221Smarcel			return (EINVAL);
137789306Salfred		}
137889306Salfred		fdrop(fp, td);
137983221Smarcel
1380102872Siedowse		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1381283439Sdchagin
1382283439Sdchagin	case LINUX_F_DUPFD_CLOEXEC:
1383283439Sdchagin		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
138483221Smarcel	}
138583221Smarcel
138683221Smarcel	return (EINVAL);
138783221Smarcel}
138883221Smarcel
138983221Smarcelint
139083366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
139183221Smarcel{
139283221Smarcel
139383221Smarcel#ifdef DEBUG
139483221Smarcel	if (ldebug(fcntl))
139583221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
139683221Smarcel#endif
139783221Smarcel
1398283415Sdchagin	return (fcntl_common(td, args));
139983221Smarcel}
140083221Smarcel
1401140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
140283221Smarcelint
140383366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
140483221Smarcel{
140583221Smarcel	struct l_flock64 linux_flock;
1406102872Siedowse	struct flock bsd_flock;
1407283415Sdchagin	struct linux_fcntl_args fcntl_args;
140883221Smarcel	int error;
140983221Smarcel
141083221Smarcel#ifdef DEBUG
141183221Smarcel	if (ldebug(fcntl64))
141283221Smarcel		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
141383221Smarcel#endif
141483221Smarcel
141583221Smarcel	switch (args->cmd) {
141699687Srobert	case LINUX_F_GETLK64:
1417111797Sdes		error = copyin((void *)args->arg, &linux_flock,
141883221Smarcel		    sizeof(linux_flock));
141983221Smarcel		if (error)
142083221Smarcel			return (error);
1421102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1422102872Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
142383221Smarcel		if (error)
142483221Smarcel			return (error);
1425102872Siedowse		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1426111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1427111797Sdes			    sizeof(linux_flock)));
142883221Smarcel
142999687Srobert	case LINUX_F_SETLK64:
1430111797Sdes		error = copyin((void *)args->arg, &linux_flock,
143183221Smarcel		    sizeof(linux_flock));
143283221Smarcel		if (error)
143383221Smarcel			return (error);
1434102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1435102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1436102872Siedowse		    (intptr_t)&bsd_flock));
143783221Smarcel
143899687Srobert	case LINUX_F_SETLKW64:
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		return (kern_fcntl(td, args->fd, F_SETLKW,
1445102872Siedowse		    (intptr_t)&bsd_flock));
144683221Smarcel	}
144783221Smarcel
1448283415Sdchagin	fcntl_args.fd = args->fd;
1449283415Sdchagin	fcntl_args.cmd = args->cmd;
1450283415Sdchagin	fcntl_args.arg = args->arg;
1451283415Sdchagin	return (fcntl_common(td, &fcntl_args));
145283221Smarcel}
1453133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
145485022Smarcel
145585022Smarcelint
145685022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
145785022Smarcel{
1458102814Siedowse	char *path;
1459102814Siedowse	int error;
146085022Smarcel
1461102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
146285022Smarcel
146385022Smarcel#ifdef DEBUG
146485022Smarcel	if (ldebug(chown))
1465102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
146685022Smarcel#endif
1467274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1468274476Skib	    args->gid, 0);
1469102814Siedowse	LFREEPATH(path);
1470102814Siedowse	return (error);
147185022Smarcel}
147285022Smarcel
147385022Smarcelint
1474177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1475177997Skib{
1476177997Skib	char *path;
1477227693Sed	int error, dfd, flag;
1478177997Skib
1479177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1480177997Skib		return (EINVAL);
1481177997Skib
1482177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1483177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1484177997Skib
1485177997Skib#ifdef DEBUG
1486177997Skib	if (ldebug(fchownat))
1487177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1488177997Skib#endif
1489177997Skib
1490227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1491177997Skib	    AT_SYMLINK_NOFOLLOW;
1492177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1493227693Sed	    flag);
1494177997Skib	LFREEPATH(path);
1495177997Skib	return (error);
1496177997Skib}
1497177997Skib
1498177997Skibint
149985022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
150085022Smarcel{
1501102814Siedowse	char *path;
1502102814Siedowse	int error;
150385022Smarcel
1504102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
150585022Smarcel
150685022Smarcel#ifdef DEBUG
150785022Smarcel	if (ldebug(lchown))
1508102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
150985022Smarcel#endif
1510274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1511274476Skib	    args->gid, AT_SYMLINK_NOFOLLOW);
1512102814Siedowse	LFREEPATH(path);
1513102814Siedowse	return (error);
151485022Smarcel}
1515228957Sjhb
1516228957Sjhbstatic int
1517228957Sjhbconvert_fadvice(int advice)
1518228957Sjhb{
1519228957Sjhb	switch (advice) {
1520228957Sjhb	case LINUX_POSIX_FADV_NORMAL:
1521228957Sjhb		return (POSIX_FADV_NORMAL);
1522228957Sjhb	case LINUX_POSIX_FADV_RANDOM:
1523228957Sjhb		return (POSIX_FADV_RANDOM);
1524228957Sjhb	case LINUX_POSIX_FADV_SEQUENTIAL:
1525228957Sjhb		return (POSIX_FADV_SEQUENTIAL);
1526228957Sjhb	case LINUX_POSIX_FADV_WILLNEED:
1527228957Sjhb		return (POSIX_FADV_WILLNEED);
1528228957Sjhb	case LINUX_POSIX_FADV_DONTNEED:
1529228957Sjhb		return (POSIX_FADV_DONTNEED);
1530228957Sjhb	case LINUX_POSIX_FADV_NOREUSE:
1531228957Sjhb		return (POSIX_FADV_NOREUSE);
1532228957Sjhb	default:
1533228957Sjhb		return (-1);
1534228957Sjhb	}
1535228957Sjhb}
1536228957Sjhb
1537228957Sjhbint
1538228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1539228957Sjhb{
1540228957Sjhb	int advice;
1541228957Sjhb
1542228957Sjhb	advice = convert_fadvice(args->advice);
1543228957Sjhb	if (advice == -1)
1544228957Sjhb		return (EINVAL);
1545228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1546228957Sjhb	    advice));
1547228957Sjhb}
1548228957Sjhb
1549283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1550228957Sjhbint
1551228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1552228957Sjhb{
1553228957Sjhb	int advice;
1554228957Sjhb
1555228957Sjhb	advice = convert_fadvice(args->advice);
1556228957Sjhb	if (advice == -1)
1557228957Sjhb		return (EINVAL);
1558228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1559228957Sjhb	    advice));
1560228957Sjhb}
1561283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1562234352Sjkim
1563234352Sjkimint
1564234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args)
1565234352Sjkim{
1566234352Sjkim	int fildes[2];
1567234352Sjkim	int error;
1568234352Sjkim
1569234352Sjkim#ifdef DEBUG
1570234352Sjkim	if (ldebug(pipe))
1571234352Sjkim		printf(ARGS(pipe, "*"));
1572234352Sjkim#endif
1573234352Sjkim
1574286021Sed	error = kern_pipe(td, fildes, 0, NULL, NULL);
1575234352Sjkim	if (error)
1576234352Sjkim		return (error);
1577234352Sjkim
1578234352Sjkim	/* XXX: Close descriptors on error. */
1579234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1580234352Sjkim}
1581234352Sjkim
1582234352Sjkimint
1583234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1584234352Sjkim{
1585234352Sjkim	int fildes[2];
1586234352Sjkim	int error, flags;
1587234352Sjkim
1588234352Sjkim#ifdef DEBUG
1589234352Sjkim	if (ldebug(pipe2))
1590234352Sjkim		printf(ARGS(pipe2, "*, %d"), args->flags);
1591234352Sjkim#endif
1592234352Sjkim
1593234352Sjkim	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1594234352Sjkim		return (EINVAL);
1595234352Sjkim
1596234352Sjkim	flags = 0;
1597234352Sjkim	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1598234352Sjkim		flags |= O_NONBLOCK;
1599234352Sjkim	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1600234352Sjkim		flags |= O_CLOEXEC;
1601286021Sed	error = kern_pipe(td, fildes, flags, NULL, NULL);
1602234352Sjkim	if (error)
1603234352Sjkim		return (error);
1604234352Sjkim
1605234352Sjkim	/* XXX: Close descriptors on error. */
1606234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1607234352Sjkim}
1608283399Sdchagin
1609283399Sdchaginint
1610283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args)
1611283399Sdchagin{
1612283399Sdchagin	int cmd;
1613283399Sdchagin	intptr_t newfd;
1614283399Sdchagin
1615283399Sdchagin	if (args->oldfd == args->newfd)
1616283399Sdchagin		return (EINVAL);
1617283399Sdchagin	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1618283399Sdchagin		return (EINVAL);
1619283399Sdchagin	if (args->flags & LINUX_O_CLOEXEC)
1620283399Sdchagin		cmd = F_DUP2FD_CLOEXEC;
1621283399Sdchagin	else
1622283399Sdchagin		cmd = F_DUP2FD;
1623283399Sdchagin
1624283399Sdchagin	newfd = args->newfd;
1625283399Sdchagin	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1626283399Sdchagin}
1627283465Sdchagin
1628283465Sdchaginint
1629283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1630283465Sdchagin{
1631283465Sdchagin
1632283465Sdchagin	/*
1633283465Sdchagin	 * We emulate only posix_fallocate system call for which
1634283465Sdchagin	 * mode should be 0.
1635283465Sdchagin	 */
1636283465Sdchagin	if (args->mode != 0)
1637283465Sdchagin		return (ENOSYS);
1638283465Sdchagin
1639283465Sdchagin	return (kern_posix_fallocate(td, args->fd, args->offset,
1640283465Sdchagin	    args->len));
1641283465Sdchagin}
1642