linux_file.c revision 298482
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: head/sys/compat/linux/linux_file.c 298482 2016-04-22 16:57:42Z pfg $");
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{
72102814Siedowse    char *path;
73102814Siedowse    int error;
749313Ssos
75102814Siedowse    LCONVPATHEXIST(td, args->path, &path);
7614331Speter
779313Ssos#ifdef DEBUG
7872543Sjlemon	if (ldebug(creat))
79102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
809313Ssos#endif
81274476Skib    error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
82274476Skib	O_WRONLY | O_CREAT | O_TRUNC, args->mode);
83102814Siedowse    LFREEPATH(path);
84102814Siedowse    return (error);
859313Ssos}
869313Ssos
87168014Sjulian
88168014Sjulianstatic int
89177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
909313Ssos{
91255219Spjd    cap_rights_t rights;
9283382Sjhb    struct proc *p = td->td_proc;
93166085Skib    struct file *fp;
94166085Skib    int fd;
95102814Siedowse    int bsd_flags, error;
9614331Speter
97102814Siedowse    bsd_flags = 0;
98168014Sjulian    switch (l_flags & LINUX_O_ACCMODE) {
99168014Sjulian    case LINUX_O_WRONLY:
100102814Siedowse	bsd_flags |= O_WRONLY;
101168014Sjulian	break;
102168014Sjulian    case LINUX_O_RDWR:
103102814Siedowse	bsd_flags |= O_RDWR;
104168014Sjulian	break;
105168014Sjulian    default:
106168014Sjulian	bsd_flags |= O_RDONLY;
107168014Sjulian    }
108168014Sjulian    if (l_flags & LINUX_O_NDELAY)
109102814Siedowse	bsd_flags |= O_NONBLOCK;
110168014Sjulian    if (l_flags & LINUX_O_APPEND)
111102814Siedowse	bsd_flags |= O_APPEND;
112168014Sjulian    if (l_flags & LINUX_O_SYNC)
113102814Siedowse	bsd_flags |= O_FSYNC;
114168014Sjulian    if (l_flags & LINUX_O_NONBLOCK)
115102814Siedowse	bsd_flags |= O_NONBLOCK;
116168014Sjulian    if (l_flags & LINUX_FASYNC)
117102814Siedowse	bsd_flags |= O_ASYNC;
118168014Sjulian    if (l_flags & LINUX_O_CREAT)
119102814Siedowse	bsd_flags |= O_CREAT;
120168014Sjulian    if (l_flags & LINUX_O_TRUNC)
121102814Siedowse	bsd_flags |= O_TRUNC;
122168014Sjulian    if (l_flags & LINUX_O_EXCL)
123102814Siedowse	bsd_flags |= O_EXCL;
124168014Sjulian    if (l_flags & LINUX_O_NOCTTY)
125102814Siedowse	bsd_flags |= O_NOCTTY;
126168014Sjulian    if (l_flags & LINUX_O_DIRECT)
127166085Skib	bsd_flags |= O_DIRECT;
128168014Sjulian    if (l_flags & LINUX_O_NOFOLLOW)
129166085Skib	bsd_flags |= O_NOFOLLOW;
130205423Sed    if (l_flags & LINUX_O_DIRECTORY)
131205423Sed	bsd_flags |= O_DIRECTORY;
132166085Skib    /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1339313Ssos
134178036Srdivacky    error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
135281726Strasz    if (error != 0)
136281726Strasz	    goto done;
137178036Srdivacky
138281726Strasz    if (bsd_flags & O_NOCTTY)
139281726Strasz	    goto done;
140281726Strasz
141281726Strasz    /*
142281726Strasz     * XXX In between kern_open() and fget(), another process
143281726Strasz     * having the same filedesc could use that fd without
144281726Strasz     * checking below.
145281726Strasz     */
146281726Strasz    fd = td->td_retval[0];
147281726Strasz    if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
148281726Strasz	    if (fp->f_type != DTYPE_VNODE) {
149166085Skib		    fdrop(fp, td);
150281726Strasz		    goto done;
151166085Skib	    }
152281726Strasz	    sx_slock(&proctree_lock);
153281726Strasz	    PROC_LOCK(p);
154281726Strasz	    if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
155281726Strasz		    PROC_UNLOCK(p);
156281726Strasz		    sx_sunlock(&proctree_lock);
157281726Strasz		    /* XXXPJD: Verify if TIOCSCTTY is allowed. */
158281726Strasz		    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
159281726Strasz			td->td_ucred, td);
160281726Strasz	    } else {
161281726Strasz		    PROC_UNLOCK(p);
162281726Strasz		    sx_sunlock(&proctree_lock);
163281726Strasz	    }
164281728Strasz	    fdrop(fp, td);
165166085Skib    }
1669313Ssos
167281726Straszdone:
16814331Speter#ifdef DEBUG
169166085Skib    if (ldebug(open))
170166085Skib	    printf(LMSG("open returns error %d"), error);
17114331Speter#endif
172177997Skib    LFREEPATH(path);
173177997Skib    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{
198168014Sjulian    char *path;
199168014Sjulian
200168014Sjulian    if (args->flags & LINUX_O_CREAT)
201168014Sjulian	LCONVPATHCREAT(td, args->path, &path);
202168014Sjulian    else
203168014Sjulian	LCONVPATHEXIST(td, args->path, &path);
204168014Sjulian
205168014Sjulian#ifdef DEBUG
206168014Sjulian	if (ldebug(open))
207168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
208168014Sjulian		    path, args->flags, args->mode);
209168014Sjulian#endif
210168014Sjulian
211178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
212168014Sjulian}
213168014Sjulian
214168014Sjulianint
21583366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2169313Ssos{
2179313Ssos
21812858Speter    struct lseek_args /* {
21912858Speter	int fd;
2209313Ssos	int pad;
22112858Speter	off_t offset;
2229313Ssos	int whence;
22312858Speter    } */ tmp_args;
2249313Ssos    int error;
2259313Ssos
2269313Ssos#ifdef DEBUG
22772543Sjlemon	if (ldebug(lseek))
22872543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
22983221Smarcel		    args->fdes, (long)args->off, args->whence);
2309313Ssos#endif
23112858Speter    tmp_args.fd = args->fdes;
23212858Speter    tmp_args.offset = (off_t)args->off;
2339313Ssos    tmp_args.whence = args->whence;
234225617Skmacy    error = sys_lseek(td, &tmp_args);
2359313Ssos    return error;
2369313Ssos}
2379313Ssos
238283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
23914331Speterint
24083366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
24114331Speter{
24214331Speter	struct lseek_args bsd_args;
24314331Speter	int error;
24414331Speter	off_t off;
24514331Speter
24614331Speter#ifdef DEBUG
24772543Sjlemon	if (ldebug(llseek))
24872543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
24972543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
25014331Speter#endif
25114331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
25214331Speter
25314331Speter	bsd_args.fd = args->fd;
25414331Speter	bsd_args.offset = off;
25514331Speter	bsd_args.whence = args->whence;
25614331Speter
257225617Skmacy	if ((error = sys_lseek(td, &bsd_args)))
25814331Speter		return error;
25914331Speter
260111797Sdes	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
26114331Speter		return error;
26214331Speter
26383366Sjulian	td->td_retval[0] = 0;
26414331Speter	return 0;
26514331Speter}
26614331Speter
2679313Ssosint
26883366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args)
2699313Ssos{
27014331Speter	struct linux_getdents_args lda;
27114331Speter
27214331Speter	lda.fd = args->fd;
27314331Speter	lda.dent = args->dent;
27414331Speter	lda.count = 1;
27583366Sjulian	return linux_getdents(td, &lda);
27614331Speter}
277283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
27814331Speter
27983221Smarcel/*
28083221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
28183221Smarcel * arguments. They only differ in the definition of struct dirent they
28283221Smarcel * operate on. We use this to common the code, with the exception of
28383221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented
28483221Smarcel * by means of linux_getdents(2). In this case we never operate on
28583221Smarcel * struct dirent64 and thus don't need to handle it...
28683221Smarcel */
28783221Smarcel
28883221Smarcelstruct l_dirent {
289179651Srdivacky	l_ulong		d_ino;
29083221Smarcel	l_off_t		d_off;
29183221Smarcel	l_ushort	d_reclen;
29283221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29383221Smarcel};
29483221Smarcel
29583221Smarcelstruct l_dirent64 {
29683221Smarcel	uint64_t	d_ino;
29783221Smarcel	int64_t		d_off;
29883221Smarcel	l_ushort	d_reclen;
29983221Smarcel	u_char		d_type;
30083221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
30183221Smarcel};
30283221Smarcel
303182892Srdivacky/*
304182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
305182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
306182892Srdivacky */
307182892Srdivacky#define LINUX_RECLEN(namlen)						\
308298482Spfg    roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
30983221Smarcel
310182892Srdivacky#define LINUX_RECLEN64(namlen)						\
311298482Spfg    roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
312182892Srdivacky    sizeof(uint64_t))
313182892Srdivacky
314182892Srdivacky#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
315182892Srdivacky				    LINUX_RECLEN64(LINUX_NAME_MAX))
31683221Smarcel#define	LINUX_DIRBLKSIZ		512
31783221Smarcel
31883221Smarcelstatic int
31983366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args,
32083221Smarcel    int is64bit)
32114331Speter{
322111798Sdes	struct dirent *bdp;
32383221Smarcel	struct vnode *vp;
32483221Smarcel	caddr_t inp, buf;		/* BSD-format */
32583221Smarcel	int len, reclen;		/* BSD-format */
32683221Smarcel	caddr_t outp;			/* Linux-format */
32783221Smarcel	int resid, linuxreclen=0;	/* Linux-format */
328182892Srdivacky	caddr_t lbuf;			/* Linux-format */
329255219Spjd	cap_rights_t rights;
33083221Smarcel	struct file *fp;
33183221Smarcel	struct uio auio;
33283221Smarcel	struct iovec aiov;
33383221Smarcel	off_t off;
334182892Srdivacky	struct l_dirent *linux_dirent;
335182892Srdivacky	struct l_dirent64 *linux_dirent64;
33683221Smarcel	int buflen, error, eofflag, nbytes, justone;
33783221Smarcel	u_long *cookies = NULL, *cookiep;
338241896Skib	int ncookies;
3399313Ssos
340160276Sjhb	nbytes = args->count;
341160276Sjhb	if (nbytes == 1) {
342160276Sjhb		/* readdir(2) case. Always struct dirent. */
343160276Sjhb		if (is64bit)
344160276Sjhb			return (EINVAL);
345188572Snetchild		nbytes = sizeof(*linux_dirent);
346160276Sjhb		justone = 1;
347160276Sjhb	} else
348160276Sjhb		justone = 0;
349160276Sjhb
350284446Smjg	error = getvnode(td, args->fd, cap_rights_init(&rights, CAP_READ), &fp);
351255219Spjd	if (error != 0)
35283221Smarcel		return (error);
3539313Ssos
35489306Salfred	if ((fp->f_flag & FREAD) == 0) {
35589306Salfred		fdrop(fp, td);
35683221Smarcel		return (EBADF);
35789306Salfred	}
3589313Ssos
359238029Skib	off = foffset_lock(fp, 0);
360116678Sphk	vp = fp->f_vnode;
36189306Salfred	if (vp->v_type != VDIR) {
362238029Skib		foffset_unlock(fp, off, 0);
36389306Salfred		fdrop(fp, td);
36483221Smarcel		return (EINVAL);
36589306Salfred	}
3669313Ssos
3679313Ssos
36883221Smarcel	buflen = max(LINUX_DIRBLKSIZ, nbytes);
36983221Smarcel	buflen = min(buflen, MAXBSIZE);
370283427Sdchagin	buf = malloc(buflen, M_LINUX, M_WAITOK);
371283427Sdchagin	lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO);
372188588Sjhb	vn_lock(vp, LK_SHARED | LK_RETRY);
37383221Smarcel
37483221Smarcel	aiov.iov_base = buf;
37583221Smarcel	aiov.iov_len = buflen;
37683221Smarcel	auio.uio_iov = &aiov;
37783221Smarcel	auio.uio_iovcnt = 1;
37883221Smarcel	auio.uio_rw = UIO_READ;
37983221Smarcel	auio.uio_segflg = UIO_SYSSPACE;
38083366Sjulian	auio.uio_td = td;
38183221Smarcel	auio.uio_resid = buflen;
38283221Smarcel	auio.uio_offset = off;
3839313Ssos
384101189Srwatson#ifdef MAC
385101189Srwatson	/*
386101189Srwatson	 * Do directory search MAC check using non-cached credentials.
387101189Srwatson	 */
388172930Srwatson	if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
389101189Srwatson		goto out;
390101189Srwatson#endif /* MAC */
39183221Smarcel	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
39283221Smarcel		 &cookies)))
39383221Smarcel		goto out;
3949313Ssos
39583221Smarcel	inp = buf;
39683221Smarcel	outp = (caddr_t)args->dirent;
39783221Smarcel	resid = nbytes;
39883221Smarcel	if ((len = buflen - auio.uio_resid) <= 0)
39983221Smarcel		goto eof;
4009313Ssos
40183221Smarcel	cookiep = cookies;
40224654Sdfr
40383221Smarcel	if (cookies) {
40483221Smarcel		/*
40583221Smarcel		 * When using cookies, the vfs has the option of reading from
40683221Smarcel		 * a different offset than that supplied (UFS truncates the
40783221Smarcel		 * offset to a block boundary to make sure that it never reads
40883221Smarcel		 * partway through a directory entry, even if the directory
40983221Smarcel		 * has been compacted).
41083221Smarcel		 */
41183221Smarcel		while (len > 0 && ncookies > 0 && *cookiep <= off) {
41283221Smarcel			bdp = (struct dirent *) inp;
41383221Smarcel			len -= bdp->d_reclen;
41483221Smarcel			inp += bdp->d_reclen;
41583221Smarcel			cookiep++;
41683221Smarcel			ncookies--;
41783221Smarcel		}
41824654Sdfr	}
41924654Sdfr
42083221Smarcel	while (len > 0) {
42183221Smarcel		if (cookiep && ncookies == 0)
42283221Smarcel			break;
42383221Smarcel		bdp = (struct dirent *) inp;
42483221Smarcel		reclen = bdp->d_reclen;
42583221Smarcel		if (reclen & 3) {
42683221Smarcel			error = EFAULT;
42783221Smarcel			goto out;
42883221Smarcel		}
42983221Smarcel
43083221Smarcel		if (bdp->d_fileno == 0) {
43183221Smarcel			inp += reclen;
43283221Smarcel			if (cookiep) {
43383221Smarcel				off = *cookiep++;
43483221Smarcel				ncookies--;
43583221Smarcel			} else
43683221Smarcel				off += reclen;
43783221Smarcel
43883221Smarcel			len -= reclen;
43983221Smarcel			continue;
44083221Smarcel		}
44183221Smarcel
44283221Smarcel		linuxreclen = (is64bit)
443182892Srdivacky		    ? LINUX_RECLEN64(bdp->d_namlen)
444182892Srdivacky		    : LINUX_RECLEN(bdp->d_namlen);
44583221Smarcel
44683221Smarcel		if (reclen > len || resid < linuxreclen) {
44783221Smarcel			outp++;
44883221Smarcel			break;
44983221Smarcel		}
45083221Smarcel
45183221Smarcel		if (justone) {
45283221Smarcel			/* readdir(2) case. */
453182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
454182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
455182892Srdivacky			linux_dirent->d_off = (l_off_t)linuxreclen;
456182892Srdivacky			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
457182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
458182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name));
459182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
46083221Smarcel		}
461182892Srdivacky		if (is64bit) {
462182892Srdivacky			linux_dirent64 = (struct l_dirent64*)lbuf;
463182892Srdivacky			linux_dirent64->d_ino = bdp->d_fileno;
464182892Srdivacky			linux_dirent64->d_off = (cookiep)
465182892Srdivacky			    ? (l_off_t)*cookiep
466182892Srdivacky			    : (l_off_t)(off + reclen);
467182892Srdivacky			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
468182892Srdivacky			linux_dirent64->d_type = bdp->d_type;
469182892Srdivacky			strlcpy(linux_dirent64->d_name, bdp->d_name,
470182892Srdivacky			    linuxreclen - offsetof(struct l_dirent64, d_name));
471182892Srdivacky			error = copyout(linux_dirent64, outp, linuxreclen);
472182892Srdivacky		} else if (!justone) {
473182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
474182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
475182892Srdivacky			linux_dirent->d_off = (cookiep)
476182892Srdivacky			    ? (l_off_t)*cookiep
477182892Srdivacky			    : (l_off_t)(off + reclen);
478182892Srdivacky			linux_dirent->d_reclen = (l_ushort)linuxreclen;
479182892Srdivacky			/*
480182892Srdivacky			 * Copy d_type to last byte of l_dirent buffer
481182892Srdivacky			 */
482182892Srdivacky			lbuf[linuxreclen-1] = bdp->d_type;
483182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
484182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
485182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
486182892Srdivacky		}
487182892Srdivacky
48883221Smarcel		if (error)
48983221Smarcel			goto out;
49083221Smarcel
49183221Smarcel		inp += reclen;
49283221Smarcel		if (cookiep) {
49383221Smarcel			off = *cookiep++;
49483221Smarcel			ncookies--;
49583221Smarcel		} else
49683221Smarcel			off += reclen;
49783221Smarcel
49883221Smarcel		outp += linuxreclen;
49983221Smarcel		resid -= linuxreclen;
50083221Smarcel		len -= reclen;
50183221Smarcel		if (justone)
50283221Smarcel			break;
50310355Sswallace	}
5049313Ssos
505217578Skib	if (outp == (caddr_t)args->dirent) {
506217578Skib		nbytes = resid;
507217578Skib		goto eof;
508217578Skib	}
5099313Ssos
51083221Smarcel	if (justone)
51183221Smarcel		nbytes = resid + linuxreclen;
51210355Sswallace
5139313Ssoseof:
51483366Sjulian	td->td_retval[0] = nbytes - resid;
51583221Smarcel
5169313Ssosout:
517247764Seadler	free(cookies, M_TEMP);
51883221Smarcel
519175294Sattilio	VOP_UNLOCK(vp, 0);
520238029Skib	foffset_unlock(fp, off, 0);
52189306Salfred	fdrop(fp, td);
522283427Sdchagin	free(buf, M_LINUX);
523283427Sdchagin	free(lbuf, M_LINUX);
52483221Smarcel	return (error);
5259313Ssos}
52614331Speter
52783221Smarcelint
52883366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args)
52983221Smarcel{
53083221Smarcel
53183221Smarcel#ifdef DEBUG
53283221Smarcel	if (ldebug(getdents))
53383221Smarcel		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
53483221Smarcel#endif
53583221Smarcel
53683366Sjulian	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
53783221Smarcel}
53883221Smarcel
53983221Smarcelint
54083366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
54183221Smarcel{
54283221Smarcel
54383221Smarcel#ifdef DEBUG
54483221Smarcel	if (ldebug(getdents64))
54583221Smarcel		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
54683221Smarcel#endif
54783221Smarcel
54883366Sjulian	return (getdents_common(td, args, 1));
54983221Smarcel}
55083221Smarcel
55114331Speter/*
55214331Speter * These exist mainly for hooks for doing /compat/linux translation.
55314331Speter */
55414331Speter
55514331Speterint
55683366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
55714331Speter{
558102814Siedowse	char *path;
559102814Siedowse	int error;
56014331Speter
561162585Snetchild	/* linux convention */
562227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
563162585Snetchild		return (EINVAL);
564162585Snetchild
565102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
56614331Speter
56714331Speter#ifdef DEBUG
56872543Sjlemon	if (ldebug(access))
569227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
57014331Speter#endif
571274476Skib	error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
572274476Skib	    args->amode);
573102814Siedowse	LFREEPATH(path);
574162585Snetchild
575102814Siedowse	return (error);
57614331Speter}
57714331Speter
57814331Speterint
579177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
580177997Skib{
581177997Skib	char *path;
582283428Sdchagin	int error, dfd;
583177997Skib
584177997Skib	/* linux convention */
585227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
586177997Skib		return (EINVAL);
587177997Skib
588177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
589177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
590177997Skib
591177997Skib#ifdef DEBUG
592177997Skib	if (ldebug(access))
593227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
594177997Skib#endif
595177997Skib
596283428Sdchagin	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
597177997Skib	LFREEPATH(path);
598177997Skib
599177997Skib	return (error);
600177997Skib}
601177997Skib
602177997Skibint
60383366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
60414331Speter{
605102814Siedowse	char *path;
606102814Siedowse	int error;
607162201Snetchild	struct stat st;
60814331Speter
609102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
61014331Speter
61114331Speter#ifdef DEBUG
61272543Sjlemon	if (ldebug(unlink))
613102814Siedowse		printf(ARGS(unlink, "%s"), path);
61414331Speter#endif
61514331Speter
616274476Skib	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
617274476Skib	if (error == EPERM) {
618162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
619274476Skib		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
620274476Skib		    NULL) == 0) {
621162201Snetchild			if (S_ISDIR(st.st_mode))
622162201Snetchild				error = EISDIR;
623274476Skib		}
624274476Skib	}
625102814Siedowse	LFREEPATH(path);
626102814Siedowse	return (error);
62714331Speter}
62814331Speter
62914331Speterint
630177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
631177997Skib{
632177997Skib	char *path;
633177997Skib	int error, dfd;
634177997Skib	struct stat st;
635177997Skib
636177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
637177997Skib		return (EINVAL);
638177997Skib
639177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
640177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
641177997Skib
642177997Skib#ifdef DEBUG
643177997Skib	if (ldebug(unlinkat))
644177997Skib		printf(ARGS(unlinkat, "%s"), path);
645177997Skib#endif
646177997Skib
647177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
648177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
649177997Skib	else
650202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
651177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
652177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
653177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
654274476Skib		    UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
655177997Skib			error = EISDIR;
656177997Skib	}
657177997Skib	LFREEPATH(path);
658177997Skib	return (error);
659177997Skib}
660177997Skibint
66183366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
66214331Speter{
663102814Siedowse	char *path;
664102814Siedowse	int error;
66514331Speter
666102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
66714331Speter
66814331Speter#ifdef DEBUG
66972543Sjlemon	if (ldebug(chdir))
670102814Siedowse		printf(ARGS(chdir, "%s"), path);
67114331Speter#endif
672102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
673102814Siedowse	LFREEPATH(path);
674102814Siedowse	return (error);
67514331Speter}
67614331Speter
67714331Speterint
67883366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
67914331Speter{
680102814Siedowse	char *path;
681102814Siedowse	int error;
68214331Speter
683102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
68414331Speter
68514331Speter#ifdef DEBUG
68672543Sjlemon	if (ldebug(chmod))
687102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
68814331Speter#endif
689274476Skib	error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
690274476Skib	    args->mode, 0);
691102814Siedowse	LFREEPATH(path);
692102814Siedowse	return (error);
69314331Speter}
69414331Speter
69514331Speterint
696177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
697177997Skib{
698177997Skib	char *path;
699177997Skib	int error, dfd;
700177997Skib
701177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
702177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
703177997Skib
704177997Skib#ifdef DEBUG
705177997Skib	if (ldebug(fchmodat))
706177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
707177997Skib#endif
708177997Skib
709177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
710177997Skib	LFREEPATH(path);
711177997Skib	return (error);
712177997Skib}
713177997Skib
714177997Skibint
71583366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
71614331Speter{
717102814Siedowse	char *path;
718102814Siedowse	int error;
71914331Speter
720102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
72114331Speter
72214331Speter#ifdef DEBUG
72372543Sjlemon	if (ldebug(mkdir))
724102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
72514331Speter#endif
726274476Skib	error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
727102814Siedowse	LFREEPATH(path);
728102814Siedowse	return (error);
72914331Speter}
73014331Speter
73114331Speterint
732177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
733177997Skib{
734177997Skib	char *path;
735177997Skib	int error, dfd;
736177997Skib
737177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
738177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
739177997Skib
740177997Skib#ifdef DEBUG
741177997Skib	if (ldebug(mkdirat))
742177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
743177997Skib#endif
744177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
745177997Skib	LFREEPATH(path);
746177997Skib	return (error);
747177997Skib}
748177997Skib
749177997Skibint
75083366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
75114331Speter{
752102814Siedowse	char *path;
753102814Siedowse	int error;
75414331Speter
755102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
75614331Speter
75714331Speter#ifdef DEBUG
75872543Sjlemon	if (ldebug(rmdir))
759102814Siedowse		printf(ARGS(rmdir, "%s"), path);
76014331Speter#endif
761274476Skib	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
762102814Siedowse	LFREEPATH(path);
763102814Siedowse	return (error);
76414331Speter}
76514331Speter
76614331Speterint
76783366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
76814331Speter{
769102814Siedowse	char *from, *to;
770102814Siedowse	int error;
77114331Speter
772102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
773102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
774177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
775102814Siedowse	if (to == NULL) {
776102814Siedowse		LFREEPATH(from);
777102814Siedowse		return (error);
778102814Siedowse	}
77914331Speter
78014331Speter#ifdef DEBUG
78172543Sjlemon	if (ldebug(rename))
782102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
78314331Speter#endif
784274476Skib	error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
785102814Siedowse	LFREEPATH(from);
786102814Siedowse	LFREEPATH(to);
787102814Siedowse	return (error);
78814331Speter}
78914331Speter
79014331Speterint
791177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
792177997Skib{
793177997Skib	char *from, *to;
794177997Skib	int error, olddfd, newdfd;
795177997Skib
796177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
797177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
798177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
799177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
800177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
801177997Skib	if (to == NULL) {
802177997Skib		LFREEPATH(from);
803177997Skib		return (error);
804177997Skib	}
805177997Skib
806177997Skib#ifdef DEBUG
807177997Skib	if (ldebug(renameat))
808177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
809177997Skib#endif
810177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
811177997Skib	LFREEPATH(from);
812177997Skib	LFREEPATH(to);
813177997Skib	return (error);
814177997Skib}
815177997Skib
816177997Skibint
81783366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
81814331Speter{
819102814Siedowse	char *path, *to;
820102814Siedowse	int error;
82114331Speter
822102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
823102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
824177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
825102814Siedowse	if (to == NULL) {
826102814Siedowse		LFREEPATH(path);
827102814Siedowse		return (error);
828102814Siedowse	}
82914331Speter
83014331Speter#ifdef DEBUG
83172543Sjlemon	if (ldebug(symlink))
832102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
83314331Speter#endif
834274476Skib	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
835102814Siedowse	LFREEPATH(path);
836102814Siedowse	LFREEPATH(to);
837102814Siedowse	return (error);
83814331Speter}
83914331Speter
84014331Speterint
841177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
842177997Skib{
843177997Skib	char *path, *to;
844177997Skib	int error, dfd;
845177997Skib
846177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
847177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
848177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
849177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
850177997Skib	if (to == NULL) {
851177997Skib		LFREEPATH(path);
852177997Skib		return (error);
853177997Skib	}
854177997Skib
855177997Skib#ifdef DEBUG
856177997Skib	if (ldebug(symlinkat))
857177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
858177997Skib#endif
859177997Skib
860177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
861177997Skib	LFREEPATH(path);
862177997Skib	LFREEPATH(to);
863177997Skib	return (error);
864177997Skib}
865177997Skib
866177997Skibint
86783366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
86814331Speter{
869102814Siedowse	char *name;
870102814Siedowse	int error;
87114331Speter
872102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
87314331Speter
87414331Speter#ifdef DEBUG
87572543Sjlemon	if (ldebug(readlink))
876102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
877102814Siedowse		    args->count);
87814331Speter#endif
879274476Skib	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
880274476Skib	    args->buf, UIO_USERSPACE, args->count);
881102814Siedowse	LFREEPATH(name);
882102814Siedowse	return (error);
88314331Speter}
88414331Speter
88514331Speterint
886177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
887177997Skib{
888177997Skib	char *name;
889177997Skib	int error, dfd;
890177997Skib
891177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
892177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
893177997Skib
894177997Skib#ifdef DEBUG
895177997Skib	if (ldebug(readlinkat))
896177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
897177997Skib		    args->bufsiz);
898177997Skib#endif
899177997Skib
900177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
901177997Skib	    UIO_USERSPACE, args->bufsiz);
902177997Skib	LFREEPATH(name);
903177997Skib	return (error);
904177997Skib}
905178439Srdivacky
906177997Skibint
90783366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
90814331Speter{
909102814Siedowse	char *path;
910102814Siedowse	int error;
91114331Speter
912102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
91314331Speter
91414331Speter#ifdef DEBUG
91572543Sjlemon	if (ldebug(truncate))
916102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
91714331Speter#endif
91814331Speter
919102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
920102814Siedowse	LFREEPATH(path);
921102814Siedowse	return (error);
92214331Speter}
92314331Speter
924283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
92549662Smarcelint
926178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args)
927178439Srdivacky{
928178439Srdivacky	char *path;
929178439Srdivacky	int error;
930178439Srdivacky
931178439Srdivacky	LCONVPATHEXIST(td, args->path, &path);
932178439Srdivacky
933178439Srdivacky#ifdef DEBUG
934178439Srdivacky	if (ldebug(truncate64))
935178439Srdivacky		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
936178439Srdivacky#endif
937178439Srdivacky
938178439Srdivacky	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
939178439Srdivacky	LFREEPATH(path);
940178439Srdivacky	return (error);
941178439Srdivacky}
942283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
943283415Sdchagin
944178439Srdivackyint
945156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
946156842Snetchild{
947156842Snetchild	struct ftruncate_args /* {
948156842Snetchild		int fd;
949156842Snetchild		int pad;
950156842Snetchild		off_t length;
951156842Snetchild		} */ nuap;
952156842Snetchild
953156842Snetchild	nuap.fd = args->fd;
954156842Snetchild	nuap.length = args->length;
955225617Skmacy	return (sys_ftruncate(td, &nuap));
956156842Snetchild}
957156842Snetchild
958156842Snetchildint
95983366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
96049662Smarcel{
961102814Siedowse	char *path, *to;
962102814Siedowse	int error;
96349662Smarcel
964102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
965102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
966177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
967102814Siedowse	if (to == NULL) {
968102814Siedowse		LFREEPATH(path);
969102814Siedowse		return (error);
970102814Siedowse	}
97149662Smarcel
97249662Smarcel#ifdef DEBUG
97372543Sjlemon	if (ldebug(link))
974102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
97549662Smarcel#endif
976274476Skib	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
977274476Skib	    FOLLOW);
978102814Siedowse	LFREEPATH(path);
979102814Siedowse	LFREEPATH(to);
980102814Siedowse	return (error);
98149662Smarcel}
98249788Smarcel
98353713Smarcelint
984177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
985177997Skib{
986177997Skib	char *path, *to;
987227693Sed	int error, olddfd, newdfd, follow;
988177997Skib
989227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
990177997Skib		return (EINVAL);
991177997Skib
992177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
993177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
994177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
995177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
996177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
997177997Skib	if (to == NULL) {
998177997Skib		LFREEPATH(path);
999177997Skib		return (error);
1000177997Skib	}
1001177997Skib
1002177997Skib#ifdef DEBUG
1003177997Skib	if (ldebug(linkat))
1004177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
1005227693Sed			args->newdfd, to, args->flag);
1006177997Skib#endif
1007177997Skib
1008227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
1009227693Sed	    FOLLOW;
1010227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
1011177997Skib	LFREEPATH(path);
1012177997Skib	LFREEPATH(to);
1013177997Skib	return (error);
1014177997Skib}
1015177997Skib
1016177997Skibint
101783366Sjulianlinux_fdatasync(td, uap)
101883366Sjulian	struct thread *td;
101953713Smarcel	struct linux_fdatasync_args *uap;
102053713Smarcel{
102153713Smarcel	struct fsync_args bsd;
102253713Smarcel
102353713Smarcel	bsd.fd = uap->fd;
1024225617Skmacy	return sys_fsync(td, &bsd);
102553713Smarcel}
102663285Smarcel
102763285Smarcelint
102883366Sjulianlinux_pread(td, uap)
102983366Sjulian	struct thread *td;
103063285Smarcel	struct linux_pread_args *uap;
103163285Smarcel{
103263285Smarcel	struct pread_args bsd;
1033255219Spjd	cap_rights_t rights;
1034162585Snetchild	struct vnode *vp;
1035162585Snetchild	int error;
103663285Smarcel
103763285Smarcel	bsd.fd = uap->fd;
103863285Smarcel	bsd.buf = uap->buf;
103963285Smarcel	bsd.nbyte = uap->nbyte;
104063285Smarcel	bsd.offset = uap->offset;
1041162585Snetchild
1042225617Skmacy	error = sys_pread(td, &bsd);
1043162585Snetchild
1044162585Snetchild	if (error == 0) {
1045247602Spjd		/* This seems to violate POSIX but linux does it */
1046255219Spjd		error = fgetvp(td, uap->fd,
1047255219Spjd		    cap_rights_init(&rights, CAP_PREAD), &vp);
1048255219Spjd		if (error != 0)
1049247602Spjd			return (error);
1050162585Snetchild		if (vp->v_type == VDIR) {
1051247602Spjd			vrele(vp);
1052162585Snetchild			return (EISDIR);
1053162585Snetchild		}
1054162585Snetchild		vrele(vp);
1055162585Snetchild	}
1056162585Snetchild
1057162585Snetchild	return (error);
105863285Smarcel}
105963285Smarcel
106063285Smarcelint
106183366Sjulianlinux_pwrite(td, uap)
106283366Sjulian	struct thread *td;
106363285Smarcel	struct linux_pwrite_args *uap;
106463285Smarcel{
106563285Smarcel	struct pwrite_args bsd;
106663285Smarcel
106763285Smarcel	bsd.fd = uap->fd;
106863285Smarcel	bsd.buf = uap->buf;
106963285Smarcel	bsd.nbyte = uap->nbyte;
107063285Smarcel	bsd.offset = uap->offset;
1071225617Skmacy	return sys_pwrite(td, &bsd);
107263285Smarcel}
107372538Sjlemon
107472538Sjlemonint
107583366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
107672538Sjlemon{
1077111798Sdes	char fstypename[MFSNAMELEN];
1078111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
107973286Sadrian	int error;
108073286Sadrian	int fsflags;
108172538Sjlemon
1082111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
108373286Sadrian	    NULL);
108472538Sjlemon	if (error)
1085111798Sdes		return (error);
1086127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
108772538Sjlemon	if (error)
1088111798Sdes		return (error);
1089127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
109072538Sjlemon	if (error)
1091111798Sdes		return (error);
109272538Sjlemon
109372538Sjlemon#ifdef DEBUG
109472538Sjlemon	if (ldebug(mount))
109572538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
109672538Sjlemon		    fstypename, mntfromname, mntonname);
109772538Sjlemon#endif
109872538Sjlemon
109972538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1100127059Stjr		strcpy(fstypename, "ext2fs");
110172538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1102127059Stjr		strcpy(fstypename, "linprocfs");
1103190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1104190445Sambrisko		strcpy(fstypename, "msdosfs");
110572538Sjlemon	}
110672538Sjlemon
110773286Sadrian	fsflags = 0;
110872538Sjlemon
110972538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
111072538Sjlemon		/*
111172538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
111272538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
111372538Sjlemon		 */
111472538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1115111798Sdes			fsflags |= MNT_RDONLY;
111672538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1117111798Sdes			fsflags |= MNT_NOSUID;
111872538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1119111798Sdes			fsflags |= MNT_NOEXEC;
112072538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1121111798Sdes			fsflags |= MNT_UPDATE;
112272538Sjlemon	}
112372538Sjlemon
1124281689Strasz	error = kernel_vmount(fsflags,
1125281689Strasz	    "fstype", fstypename,
1126281689Strasz	    "fspath", mntonname,
1127281689Strasz	    "from", mntfromname,
1128281689Strasz	    NULL);
1129127059Stjr	return (error);
113072538Sjlemon}
113172538Sjlemon
1132283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
113372538Sjlemonint
113483366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
113572538Sjlemon{
113683221Smarcel	struct linux_umount_args args2;
113772538Sjlemon
113872538Sjlemon	args2.path = args->path;
113972538Sjlemon	args2.flags = 0;
114083366Sjulian	return (linux_umount(td, &args2));
114172538Sjlemon}
1142283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
114372538Sjlemon
114472538Sjlemonint
114583366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
114672538Sjlemon{
114772538Sjlemon	struct unmount_args bsd;
114872538Sjlemon
114972538Sjlemon	bsd.path = args->path;
115072538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1151225617Skmacy	return (sys_unmount(td, &bsd));
115272538Sjlemon}
115383221Smarcel
115483221Smarcel/*
115583221Smarcel * fcntl family of syscalls
115683221Smarcel */
115783221Smarcel
115883221Smarcelstruct l_flock {
115983221Smarcel	l_short		l_type;
116083221Smarcel	l_short		l_whence;
116183221Smarcel	l_off_t		l_start;
116283221Smarcel	l_off_t		l_len;
116383221Smarcel	l_pid_t		l_pid;
1164133816Stjr}
1165140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1166133816Stjr__packed
1167133816Stjr#endif
1168133816Stjr;
116983221Smarcel
117083221Smarcelstatic void
117183221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
117283221Smarcel{
117383221Smarcel	switch (linux_flock->l_type) {
117483221Smarcel	case LINUX_F_RDLCK:
117583221Smarcel		bsd_flock->l_type = F_RDLCK;
117683221Smarcel		break;
117783221Smarcel	case LINUX_F_WRLCK:
117883221Smarcel		bsd_flock->l_type = F_WRLCK;
117983221Smarcel		break;
118083221Smarcel	case LINUX_F_UNLCK:
118183221Smarcel		bsd_flock->l_type = F_UNLCK;
118283221Smarcel		break;
118383221Smarcel	default:
118483221Smarcel		bsd_flock->l_type = -1;
118583221Smarcel		break;
118683221Smarcel	}
118783221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
118883221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
118983221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
119083221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1191177633Sdfr	bsd_flock->l_sysid = 0;
119283221Smarcel}
119383221Smarcel
119483221Smarcelstatic void
119583221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
119683221Smarcel{
119783221Smarcel	switch (bsd_flock->l_type) {
119883221Smarcel	case F_RDLCK:
119983221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
120083221Smarcel		break;
120183221Smarcel	case F_WRLCK:
120283221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
120383221Smarcel		break;
120483221Smarcel	case F_UNLCK:
120583221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
120683221Smarcel		break;
120783221Smarcel	}
120883221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
120983221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
121083221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
121183221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
121283221Smarcel}
121383221Smarcel
1214140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
121583221Smarcelstruct l_flock64 {
121683221Smarcel	l_short		l_type;
121783221Smarcel	l_short		l_whence;
121883221Smarcel	l_loff_t	l_start;
121983221Smarcel	l_loff_t	l_len;
122083221Smarcel	l_pid_t		l_pid;
1221133816Stjr}
1222140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1223133816Stjr__packed
1224133816Stjr#endif
1225133816Stjr;
122683221Smarcel
122783221Smarcelstatic void
122883221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
122983221Smarcel{
123083221Smarcel	switch (linux_flock->l_type) {
123183221Smarcel	case LINUX_F_RDLCK:
123283221Smarcel		bsd_flock->l_type = F_RDLCK;
123383221Smarcel		break;
123483221Smarcel	case LINUX_F_WRLCK:
123583221Smarcel		bsd_flock->l_type = F_WRLCK;
123683221Smarcel		break;
123783221Smarcel	case LINUX_F_UNLCK:
123883221Smarcel		bsd_flock->l_type = F_UNLCK;
123983221Smarcel		break;
124083221Smarcel	default:
124183221Smarcel		bsd_flock->l_type = -1;
124283221Smarcel		break;
124383221Smarcel	}
124483221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
124583221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
124683221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
124783221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1248177633Sdfr	bsd_flock->l_sysid = 0;
124983221Smarcel}
125083221Smarcel
125183221Smarcelstatic void
125283221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
125383221Smarcel{
125483221Smarcel	switch (bsd_flock->l_type) {
125583221Smarcel	case F_RDLCK:
125683221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
125783221Smarcel		break;
125883221Smarcel	case F_WRLCK:
125983221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
126083221Smarcel		break;
126183221Smarcel	case F_UNLCK:
126283221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
126383221Smarcel		break;
126483221Smarcel	}
126583221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
126683221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
126783221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
126883221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
126983221Smarcel}
1270133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
127183221Smarcel
127283221Smarcelstatic int
1273283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args)
127483221Smarcel{
1275107680Siedowse	struct l_flock linux_flock;
1276107680Siedowse	struct flock bsd_flock;
1277255219Spjd	cap_rights_t rights;
127883221Smarcel	struct file *fp;
1279102872Siedowse	long arg;
128083221Smarcel	int error, result;
128183221Smarcel
128283221Smarcel	switch (args->cmd) {
128383221Smarcel	case LINUX_F_DUPFD:
1284102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
128583221Smarcel
128683221Smarcel	case LINUX_F_GETFD:
1287102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
128883221Smarcel
128983221Smarcel	case LINUX_F_SETFD:
1290102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
129183221Smarcel
129283221Smarcel	case LINUX_F_GETFL:
1293102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
129483366Sjulian		result = td->td_retval[0];
129583366Sjulian		td->td_retval[0] = 0;
129683221Smarcel		if (result & O_RDONLY)
129783366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
129883221Smarcel		if (result & O_WRONLY)
129983366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
130083221Smarcel		if (result & O_RDWR)
130183366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
130283221Smarcel		if (result & O_NDELAY)
130383366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
130483221Smarcel		if (result & O_APPEND)
130583366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
130683221Smarcel		if (result & O_FSYNC)
130783366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
130883221Smarcel		if (result & O_ASYNC)
130983366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1310144987Smdodd#ifdef LINUX_O_NOFOLLOW
1311144987Smdodd		if (result & O_NOFOLLOW)
1312144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1313144987Smdodd#endif
1314144987Smdodd#ifdef LINUX_O_DIRECT
1315144987Smdodd		if (result & O_DIRECT)
1316144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1317144987Smdodd#endif
131883221Smarcel		return (error);
131983221Smarcel
132083221Smarcel	case LINUX_F_SETFL:
1321102872Siedowse		arg = 0;
132283221Smarcel		if (args->arg & LINUX_O_NDELAY)
1323102872Siedowse			arg |= O_NONBLOCK;
132483221Smarcel		if (args->arg & LINUX_O_APPEND)
1325102872Siedowse			arg |= O_APPEND;
132683221Smarcel		if (args->arg & LINUX_O_SYNC)
1327102872Siedowse			arg |= O_FSYNC;
132883221Smarcel		if (args->arg & LINUX_FASYNC)
1329102872Siedowse			arg |= O_ASYNC;
1330144987Smdodd#ifdef LINUX_O_NOFOLLOW
1331144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1332144987Smdodd			arg |= O_NOFOLLOW;
1333144987Smdodd#endif
1334144987Smdodd#ifdef LINUX_O_DIRECT
1335144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1336144987Smdodd			arg |= O_DIRECT;
1337144987Smdodd#endif
1338102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
133983221Smarcel
1340107680Siedowse	case LINUX_F_GETLK:
1341111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1342107680Siedowse		    sizeof(linux_flock));
1343107680Siedowse		if (error)
1344107680Siedowse			return (error);
1345107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1346107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1347107680Siedowse		if (error)
1348107680Siedowse			return (error);
1349107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1350111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1351107680Siedowse		    sizeof(linux_flock)));
1352107680Siedowse
1353107680Siedowse	case LINUX_F_SETLK:
1354111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1355107680Siedowse		    sizeof(linux_flock));
1356107680Siedowse		if (error)
1357107680Siedowse			return (error);
1358107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1359107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1360107680Siedowse		    (intptr_t)&bsd_flock));
1361107680Siedowse
1362107680Siedowse	case LINUX_F_SETLKW:
1363111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1364107680Siedowse		    sizeof(linux_flock));
1365107680Siedowse		if (error)
1366107680Siedowse			return (error);
1367107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1368107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1369107680Siedowse		     (intptr_t)&bsd_flock));
1370107680Siedowse
137183221Smarcel	case LINUX_F_GETOWN:
1372102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
137383221Smarcel
137483221Smarcel	case LINUX_F_SETOWN:
137583221Smarcel		/*
137683221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
137783221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
137883221Smarcel		 * pipes under Linux-2.2.35 at least).
137983221Smarcel		 */
1380255219Spjd		error = fget(td, args->fd,
1381255219Spjd		    cap_rights_init(&rights, CAP_FCNTL), &fp);
138289319Salfred		if (error)
138389319Salfred			return (error);
138489306Salfred		if (fp->f_type == DTYPE_PIPE) {
138589306Salfred			fdrop(fp, td);
138683221Smarcel			return (EINVAL);
138789306Salfred		}
138889306Salfred		fdrop(fp, td);
138983221Smarcel
1390102872Siedowse		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1391283439Sdchagin
1392283439Sdchagin	case LINUX_F_DUPFD_CLOEXEC:
1393283439Sdchagin		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
139483221Smarcel	}
139583221Smarcel
139683221Smarcel	return (EINVAL);
139783221Smarcel}
139883221Smarcel
139983221Smarcelint
140083366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
140183221Smarcel{
140283221Smarcel
140383221Smarcel#ifdef DEBUG
140483221Smarcel	if (ldebug(fcntl))
140583221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
140683221Smarcel#endif
140783221Smarcel
1408283415Sdchagin	return (fcntl_common(td, args));
140983221Smarcel}
141083221Smarcel
1411140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
141283221Smarcelint
141383366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
141483221Smarcel{
141583221Smarcel	struct l_flock64 linux_flock;
1416102872Siedowse	struct flock bsd_flock;
1417283415Sdchagin	struct linux_fcntl_args fcntl_args;
141883221Smarcel	int error;
141983221Smarcel
142083221Smarcel#ifdef DEBUG
142183221Smarcel	if (ldebug(fcntl64))
142283221Smarcel		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
142383221Smarcel#endif
142483221Smarcel
142583221Smarcel	switch (args->cmd) {
142699687Srobert	case LINUX_F_GETLK64:
1427111797Sdes		error = copyin((void *)args->arg, &linux_flock,
142883221Smarcel		    sizeof(linux_flock));
142983221Smarcel		if (error)
143083221Smarcel			return (error);
1431102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1432102872Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
143383221Smarcel		if (error)
143483221Smarcel			return (error);
1435102872Siedowse		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1436111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1437111797Sdes			    sizeof(linux_flock)));
143883221Smarcel
143999687Srobert	case LINUX_F_SETLK64:
1440111797Sdes		error = copyin((void *)args->arg, &linux_flock,
144183221Smarcel		    sizeof(linux_flock));
144283221Smarcel		if (error)
144383221Smarcel			return (error);
1444102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1445102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1446102872Siedowse		    (intptr_t)&bsd_flock));
144783221Smarcel
144899687Srobert	case LINUX_F_SETLKW64:
1449111797Sdes		error = copyin((void *)args->arg, &linux_flock,
145083221Smarcel		    sizeof(linux_flock));
145183221Smarcel		if (error)
145283221Smarcel			return (error);
1453102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1454102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1455102872Siedowse		    (intptr_t)&bsd_flock));
145683221Smarcel	}
145783221Smarcel
1458283415Sdchagin	fcntl_args.fd = args->fd;
1459283415Sdchagin	fcntl_args.cmd = args->cmd;
1460283415Sdchagin	fcntl_args.arg = args->arg;
1461283415Sdchagin	return (fcntl_common(td, &fcntl_args));
146283221Smarcel}
1463133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
146485022Smarcel
146585022Smarcelint
146685022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
146785022Smarcel{
1468102814Siedowse	char *path;
1469102814Siedowse	int error;
147085022Smarcel
1471102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
147285022Smarcel
147385022Smarcel#ifdef DEBUG
147485022Smarcel	if (ldebug(chown))
1475102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
147685022Smarcel#endif
1477274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1478274476Skib	    args->gid, 0);
1479102814Siedowse	LFREEPATH(path);
1480102814Siedowse	return (error);
148185022Smarcel}
148285022Smarcel
148385022Smarcelint
1484177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1485177997Skib{
1486177997Skib	char *path;
1487227693Sed	int error, dfd, flag;
1488177997Skib
1489177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1490177997Skib		return (EINVAL);
1491177997Skib
1492177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1493177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1494177997Skib
1495177997Skib#ifdef DEBUG
1496177997Skib	if (ldebug(fchownat))
1497177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1498177997Skib#endif
1499177997Skib
1500227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1501177997Skib	    AT_SYMLINK_NOFOLLOW;
1502177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1503227693Sed	    flag);
1504177997Skib	LFREEPATH(path);
1505177997Skib	return (error);
1506177997Skib}
1507177997Skib
1508177997Skibint
150985022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
151085022Smarcel{
1511102814Siedowse	char *path;
1512102814Siedowse	int error;
151385022Smarcel
1514102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
151585022Smarcel
151685022Smarcel#ifdef DEBUG
151785022Smarcel	if (ldebug(lchown))
1518102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
151985022Smarcel#endif
1520274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1521274476Skib	    args->gid, AT_SYMLINK_NOFOLLOW);
1522102814Siedowse	LFREEPATH(path);
1523102814Siedowse	return (error);
152485022Smarcel}
1525228957Sjhb
1526228957Sjhbstatic int
1527228957Sjhbconvert_fadvice(int advice)
1528228957Sjhb{
1529228957Sjhb	switch (advice) {
1530228957Sjhb	case LINUX_POSIX_FADV_NORMAL:
1531228957Sjhb		return (POSIX_FADV_NORMAL);
1532228957Sjhb	case LINUX_POSIX_FADV_RANDOM:
1533228957Sjhb		return (POSIX_FADV_RANDOM);
1534228957Sjhb	case LINUX_POSIX_FADV_SEQUENTIAL:
1535228957Sjhb		return (POSIX_FADV_SEQUENTIAL);
1536228957Sjhb	case LINUX_POSIX_FADV_WILLNEED:
1537228957Sjhb		return (POSIX_FADV_WILLNEED);
1538228957Sjhb	case LINUX_POSIX_FADV_DONTNEED:
1539228957Sjhb		return (POSIX_FADV_DONTNEED);
1540228957Sjhb	case LINUX_POSIX_FADV_NOREUSE:
1541228957Sjhb		return (POSIX_FADV_NOREUSE);
1542228957Sjhb	default:
1543228957Sjhb		return (-1);
1544228957Sjhb	}
1545228957Sjhb}
1546228957Sjhb
1547228957Sjhbint
1548228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1549228957Sjhb{
1550228957Sjhb	int advice;
1551228957Sjhb
1552228957Sjhb	advice = convert_fadvice(args->advice);
1553228957Sjhb	if (advice == -1)
1554228957Sjhb		return (EINVAL);
1555228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1556228957Sjhb	    advice));
1557228957Sjhb}
1558228957Sjhb
1559283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1560228957Sjhbint
1561228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1562228957Sjhb{
1563228957Sjhb	int advice;
1564228957Sjhb
1565228957Sjhb	advice = convert_fadvice(args->advice);
1566228957Sjhb	if (advice == -1)
1567228957Sjhb		return (EINVAL);
1568228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1569228957Sjhb	    advice));
1570228957Sjhb}
1571283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1572234352Sjkim
1573234352Sjkimint
1574234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args)
1575234352Sjkim{
1576234352Sjkim	int fildes[2];
1577234352Sjkim	int error;
1578234352Sjkim
1579234352Sjkim#ifdef DEBUG
1580234352Sjkim	if (ldebug(pipe))
1581234352Sjkim		printf(ARGS(pipe, "*"));
1582234352Sjkim#endif
1583234352Sjkim
1584286021Sed	error = kern_pipe(td, fildes, 0, NULL, NULL);
1585234352Sjkim	if (error)
1586234352Sjkim		return (error);
1587234352Sjkim
1588234352Sjkim	/* XXX: Close descriptors on error. */
1589234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1590234352Sjkim}
1591234352Sjkim
1592234352Sjkimint
1593234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1594234352Sjkim{
1595234352Sjkim	int fildes[2];
1596234352Sjkim	int error, flags;
1597234352Sjkim
1598234352Sjkim#ifdef DEBUG
1599234352Sjkim	if (ldebug(pipe2))
1600234352Sjkim		printf(ARGS(pipe2, "*, %d"), args->flags);
1601234352Sjkim#endif
1602234352Sjkim
1603234352Sjkim	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1604234352Sjkim		return (EINVAL);
1605234352Sjkim
1606234352Sjkim	flags = 0;
1607234352Sjkim	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1608234352Sjkim		flags |= O_NONBLOCK;
1609234352Sjkim	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1610234352Sjkim		flags |= O_CLOEXEC;
1611286021Sed	error = kern_pipe(td, fildes, flags, NULL, NULL);
1612234352Sjkim	if (error)
1613234352Sjkim		return (error);
1614234352Sjkim
1615234352Sjkim	/* XXX: Close descriptors on error. */
1616234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1617234352Sjkim}
1618283399Sdchagin
1619283399Sdchaginint
1620283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args)
1621283399Sdchagin{
1622283399Sdchagin	int cmd;
1623283399Sdchagin	intptr_t newfd;
1624283399Sdchagin
1625283399Sdchagin	if (args->oldfd == args->newfd)
1626283399Sdchagin		return (EINVAL);
1627283399Sdchagin	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1628283399Sdchagin		return (EINVAL);
1629283399Sdchagin	if (args->flags & LINUX_O_CLOEXEC)
1630283399Sdchagin		cmd = F_DUP2FD_CLOEXEC;
1631283399Sdchagin	else
1632283399Sdchagin		cmd = F_DUP2FD;
1633283399Sdchagin
1634283399Sdchagin	newfd = args->newfd;
1635283399Sdchagin	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1636283399Sdchagin}
1637283465Sdchagin
1638283465Sdchaginint
1639283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1640283465Sdchagin{
1641283465Sdchagin
1642283465Sdchagin	/*
1643283465Sdchagin	 * We emulate only posix_fallocate system call for which
1644283465Sdchagin	 * mode should be 0.
1645283465Sdchagin	 */
1646283465Sdchagin	if (args->mode != 0)
1647283465Sdchagin		return (ENOSYS);
1648283465Sdchagin
1649283465Sdchagin	return (kern_posix_fallocate(td, args->fd, args->offset,
1650283465Sdchagin	    args->len));
1651283465Sdchagin}
1652