linux_file.c revision 246085
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 246085 2013-01-29 18:41:30Z jhb $");
31116173Sobrien
32156874Sru#include "opt_compat.h"
3331784Seivind
349313Ssos#include <sys/param.h>
359313Ssos#include <sys/systm.h>
36224778Srwatson#include <sys/capability.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
5872538Sjlemon#include <ufs/ufs/extattr.h>
5972538Sjlemon#include <ufs/ufs/quota.h>
6072538Sjlemon#include <ufs/ufs/ufsmount.h>
6172538Sjlemon
62140214Sobrien#ifdef COMPAT_LINUX32
63140214Sobrien#include <machine/../linux32/linux.h>
64140214Sobrien#include <machine/../linux32/linux32_proto.h>
65140214Sobrien#else
6664905Smarcel#include <machine/../linux/linux.h>
6768583Smarcel#include <machine/../linux/linux_proto.h>
68133816Stjr#endif
69246085Sjhb#include <compat/linux/linux_misc.h>
7064905Smarcel#include <compat/linux/linux_util.h>
71177997Skib#include <compat/linux/linux_file.h>
729313Ssos
73234352Sjkim/* XXX */
74234352Sjkimint	do_pipe(struct thread *td, int fildes[2], int flags);
75234352Sjkim
769313Ssosint
7783366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args)
789313Ssos{
79102814Siedowse    char *path;
80102814Siedowse    int error;
819313Ssos
82102814Siedowse    LCONVPATHEXIST(td, args->path, &path);
8314331Speter
849313Ssos#ifdef DEBUG
8572543Sjlemon	if (ldebug(creat))
86102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
879313Ssos#endif
88102814Siedowse    error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
89102814Siedowse	args->mode);
90102814Siedowse    LFREEPATH(path);
91102814Siedowse    return (error);
929313Ssos}
939313Ssos
94168014Sjulian
95168014Sjulianstatic int
96177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
979313Ssos{
9883382Sjhb    struct proc *p = td->td_proc;
99166085Skib    struct file *fp;
100166085Skib    int fd;
101102814Siedowse    int bsd_flags, error;
10214331Speter
103102814Siedowse    bsd_flags = 0;
104168014Sjulian    switch (l_flags & LINUX_O_ACCMODE) {
105168014Sjulian    case LINUX_O_WRONLY:
106102814Siedowse	bsd_flags |= O_WRONLY;
107168014Sjulian	break;
108168014Sjulian    case LINUX_O_RDWR:
109102814Siedowse	bsd_flags |= O_RDWR;
110168014Sjulian	break;
111168014Sjulian    default:
112168014Sjulian	bsd_flags |= O_RDONLY;
113168014Sjulian    }
114168014Sjulian    if (l_flags & LINUX_O_NDELAY)
115102814Siedowse	bsd_flags |= O_NONBLOCK;
116168014Sjulian    if (l_flags & LINUX_O_APPEND)
117102814Siedowse	bsd_flags |= O_APPEND;
118168014Sjulian    if (l_flags & LINUX_O_SYNC)
119102814Siedowse	bsd_flags |= O_FSYNC;
120168014Sjulian    if (l_flags & LINUX_O_NONBLOCK)
121102814Siedowse	bsd_flags |= O_NONBLOCK;
122168014Sjulian    if (l_flags & LINUX_FASYNC)
123102814Siedowse	bsd_flags |= O_ASYNC;
124168014Sjulian    if (l_flags & LINUX_O_CREAT)
125102814Siedowse	bsd_flags |= O_CREAT;
126168014Sjulian    if (l_flags & LINUX_O_TRUNC)
127102814Siedowse	bsd_flags |= O_TRUNC;
128168014Sjulian    if (l_flags & LINUX_O_EXCL)
129102814Siedowse	bsd_flags |= O_EXCL;
130168014Sjulian    if (l_flags & LINUX_O_NOCTTY)
131102814Siedowse	bsd_flags |= O_NOCTTY;
132168014Sjulian    if (l_flags & LINUX_O_DIRECT)
133166085Skib	bsd_flags |= O_DIRECT;
134168014Sjulian    if (l_flags & LINUX_O_NOFOLLOW)
135166085Skib	bsd_flags |= O_NOFOLLOW;
136205423Sed    if (l_flags & LINUX_O_DIRECTORY)
137205423Sed	bsd_flags |= O_DIRECTORY;
138166085Skib    /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1399313Ssos
140178036Srdivacky    error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
141178036Srdivacky
142166085Skib    if (!error) {
143166085Skib	    fd = td->td_retval[0];
144166085Skib	    /*
145166085Skib	     * XXX In between kern_open() and fget(), another process
146166085Skib	     * having the same filedesc could use that fd without
147166085Skib	     * checking below.
148166085Skib	     */
149224778Srwatson	    error = fget(td, fd, CAP_IOCTL, &fp);
150166085Skib	    if (!error) {
151166085Skib		    sx_slock(&proctree_lock);
152166085Skib		    PROC_LOCK(p);
153166085Skib		    if (!(bsd_flags & O_NOCTTY) &&
154166085Skib			SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
155166085Skib			    PROC_UNLOCK(p);
156166085Skib			    sx_unlock(&proctree_lock);
157166085Skib			    if (fp->f_type == DTYPE_VNODE)
158166085Skib				    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
159166085Skib					     td->td_ucred, td);
160166085Skib		    } else {
161166085Skib			    PROC_UNLOCK(p);
162166085Skib			    sx_sunlock(&proctree_lock);
163166085Skib		    }
164166085Skib		    fdrop(fp, td);
165166085Skib		    /*
166166085Skib		     * XXX as above, fdrop()/kern_close() pair is racy.
167166085Skib		     */
168166085Skib		    if (error)
169166085Skib			    kern_close(td, fd);
170166085Skib	    }
171166085Skib    }
1729313Ssos
17314331Speter#ifdef DEBUG
174166085Skib    if (ldebug(open))
175166085Skib	    printf(LMSG("open returns error %d"), error);
17614331Speter#endif
177177997Skib    LFREEPATH(path);
178177997Skib    return (error);
1799313Ssos}
1809313Ssos
1819313Ssosint
182168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args)
183168014Sjulian{
184177997Skib	char *path;
185177997Skib	int dfd;
186168014Sjulian
187177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
188177997Skib	if (args->flags & LINUX_O_CREAT)
189177997Skib		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
190177997Skib	else
191177997Skib		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
192168014Sjulian#ifdef DEBUG
193168014Sjulian	if (ldebug(openat))
194168014Sjulian		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
195177997Skib		    path, args->flags, args->mode);
196168014Sjulian#endif
197177997Skib	return (linux_common_open(td, dfd, path, args->flags, args->mode));
198168014Sjulian}
199168014Sjulian
200168014Sjulianint
201168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args)
202168014Sjulian{
203168014Sjulian    char *path;
204168014Sjulian
205168014Sjulian    if (args->flags & LINUX_O_CREAT)
206168014Sjulian	LCONVPATHCREAT(td, args->path, &path);
207168014Sjulian    else
208168014Sjulian	LCONVPATHEXIST(td, args->path, &path);
209168014Sjulian
210168014Sjulian#ifdef DEBUG
211168014Sjulian	if (ldebug(open))
212168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
213168014Sjulian		    path, args->flags, args->mode);
214168014Sjulian#endif
215168014Sjulian
216178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
217168014Sjulian}
218168014Sjulian
219168014Sjulianint
22083366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2219313Ssos{
2229313Ssos
22312858Speter    struct lseek_args /* {
22412858Speter	int fd;
2259313Ssos	int pad;
22612858Speter	off_t offset;
2279313Ssos	int whence;
22812858Speter    } */ tmp_args;
2299313Ssos    int error;
2309313Ssos
2319313Ssos#ifdef DEBUG
23272543Sjlemon	if (ldebug(lseek))
23372543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
23483221Smarcel		    args->fdes, (long)args->off, args->whence);
2359313Ssos#endif
23612858Speter    tmp_args.fd = args->fdes;
23712858Speter    tmp_args.offset = (off_t)args->off;
2389313Ssos    tmp_args.whence = args->whence;
239225617Skmacy    error = sys_lseek(td, &tmp_args);
2409313Ssos    return error;
2419313Ssos}
2429313Ssos
24314331Speterint
24483366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
24514331Speter{
24614331Speter	struct lseek_args bsd_args;
24714331Speter	int error;
24814331Speter	off_t off;
24914331Speter
25014331Speter#ifdef DEBUG
25172543Sjlemon	if (ldebug(llseek))
25272543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
25372543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
25414331Speter#endif
25514331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
25614331Speter
25714331Speter	bsd_args.fd = args->fd;
25814331Speter	bsd_args.offset = off;
25914331Speter	bsd_args.whence = args->whence;
26014331Speter
261225617Skmacy	if ((error = sys_lseek(td, &bsd_args)))
26214331Speter		return error;
26314331Speter
264111797Sdes	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
26514331Speter		return error;
26614331Speter
26783366Sjulian	td->td_retval[0] = 0;
26814331Speter	return 0;
26914331Speter}
27014331Speter
2719313Ssosint
27283366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args)
2739313Ssos{
27414331Speter	struct linux_getdents_args lda;
27514331Speter
27614331Speter	lda.fd = args->fd;
27714331Speter	lda.dent = args->dent;
27814331Speter	lda.count = 1;
27983366Sjulian	return linux_getdents(td, &lda);
28014331Speter}
28114331Speter
28283221Smarcel/*
28383221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
28483221Smarcel * arguments. They only differ in the definition of struct dirent they
28583221Smarcel * operate on. We use this to common the code, with the exception of
28683221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented
28783221Smarcel * by means of linux_getdents(2). In this case we never operate on
28883221Smarcel * struct dirent64 and thus don't need to handle it...
28983221Smarcel */
29083221Smarcel
29183221Smarcelstruct l_dirent {
292179651Srdivacky	l_ulong		d_ino;
29383221Smarcel	l_off_t		d_off;
29483221Smarcel	l_ushort	d_reclen;
29583221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29683221Smarcel};
29783221Smarcel
29883221Smarcelstruct l_dirent64 {
29983221Smarcel	uint64_t	d_ino;
30083221Smarcel	int64_t		d_off;
30183221Smarcel	l_ushort	d_reclen;
30283221Smarcel	u_char		d_type;
30383221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
30483221Smarcel};
30583221Smarcel
306182892Srdivacky/*
307182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
308182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
309182892Srdivacky */
310182892Srdivacky#define LINUX_RECLEN(namlen)						\
311182892Srdivacky    roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),		\
312182892Srdivacky    sizeof(l_ulong))
31383221Smarcel
314182892Srdivacky#define LINUX_RECLEN64(namlen)						\
315182892Srdivacky    roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),	\
316182892Srdivacky    sizeof(uint64_t))
317182892Srdivacky
318182892Srdivacky#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
319182892Srdivacky				    LINUX_RECLEN64(LINUX_NAME_MAX))
32083221Smarcel#define	LINUX_DIRBLKSIZ		512
32183221Smarcel
32283221Smarcelstatic int
32383366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args,
32483221Smarcel    int is64bit)
32514331Speter{
326111798Sdes	struct dirent *bdp;
32783221Smarcel	struct vnode *vp;
32883221Smarcel	caddr_t inp, buf;		/* BSD-format */
32983221Smarcel	int len, reclen;		/* BSD-format */
33083221Smarcel	caddr_t outp;			/* Linux-format */
33183221Smarcel	int resid, linuxreclen=0;	/* Linux-format */
332182892Srdivacky	caddr_t lbuf;			/* Linux-format */
33383221Smarcel	struct file *fp;
33483221Smarcel	struct uio auio;
33583221Smarcel	struct iovec aiov;
33683221Smarcel	off_t off;
337182892Srdivacky	struct l_dirent *linux_dirent;
338182892Srdivacky	struct l_dirent64 *linux_dirent64;
33983221Smarcel	int buflen, error, eofflag, nbytes, justone;
34083221Smarcel	u_long *cookies = NULL, *cookiep;
341241896Skib	int ncookies;
3429313Ssos
343160276Sjhb	nbytes = args->count;
344160276Sjhb	if (nbytes == 1) {
345160276Sjhb		/* readdir(2) case. Always struct dirent. */
346160276Sjhb		if (is64bit)
347160276Sjhb			return (EINVAL);
348188572Snetchild		nbytes = sizeof(*linux_dirent);
349160276Sjhb		justone = 1;
350160276Sjhb	} else
351160276Sjhb		justone = 0;
352160276Sjhb
353224778Srwatson	if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0)
35483221Smarcel		return (error);
3559313Ssos
35689306Salfred	if ((fp->f_flag & FREAD) == 0) {
35789306Salfred		fdrop(fp, td);
35883221Smarcel		return (EBADF);
35989306Salfred	}
3609313Ssos
361238029Skib	off = foffset_lock(fp, 0);
362116678Sphk	vp = fp->f_vnode;
36389306Salfred	if (vp->v_type != VDIR) {
364238029Skib		foffset_unlock(fp, off, 0);
36589306Salfred		fdrop(fp, td);
36683221Smarcel		return (EINVAL);
36789306Salfred	}
3689313Ssos
3699313Ssos
37083221Smarcel	buflen = max(LINUX_DIRBLKSIZ, nbytes);
37183221Smarcel	buflen = min(buflen, MAXBSIZE);
372111119Simp	buf = malloc(buflen, M_TEMP, M_WAITOK);
373182892Srdivacky	lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
374188588Sjhb	vn_lock(vp, LK_SHARED | LK_RETRY);
37583221Smarcel
37683221Smarcel	aiov.iov_base = buf;
37783221Smarcel	aiov.iov_len = buflen;
37883221Smarcel	auio.uio_iov = &aiov;
37983221Smarcel	auio.uio_iovcnt = 1;
38083221Smarcel	auio.uio_rw = UIO_READ;
38183221Smarcel	auio.uio_segflg = UIO_SYSSPACE;
38283366Sjulian	auio.uio_td = td;
38383221Smarcel	auio.uio_resid = buflen;
38483221Smarcel	auio.uio_offset = off;
3859313Ssos
386101189Srwatson#ifdef MAC
387101189Srwatson	/*
388101189Srwatson	 * Do directory search MAC check using non-cached credentials.
389101189Srwatson	 */
390172930Srwatson	if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
391101189Srwatson		goto out;
392101189Srwatson#endif /* MAC */
39383221Smarcel	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
39483221Smarcel		 &cookies)))
39583221Smarcel		goto out;
3969313Ssos
39783221Smarcel	inp = buf;
39883221Smarcel	outp = (caddr_t)args->dirent;
39983221Smarcel	resid = nbytes;
40083221Smarcel	if ((len = buflen - auio.uio_resid) <= 0)
40183221Smarcel		goto eof;
4029313Ssos
40383221Smarcel	cookiep = cookies;
40424654Sdfr
40583221Smarcel	if (cookies) {
40683221Smarcel		/*
40783221Smarcel		 * When using cookies, the vfs has the option of reading from
40883221Smarcel		 * a different offset than that supplied (UFS truncates the
40983221Smarcel		 * offset to a block boundary to make sure that it never reads
41083221Smarcel		 * partway through a directory entry, even if the directory
41183221Smarcel		 * has been compacted).
41283221Smarcel		 */
41383221Smarcel		while (len > 0 && ncookies > 0 && *cookiep <= off) {
41483221Smarcel			bdp = (struct dirent *) inp;
41583221Smarcel			len -= bdp->d_reclen;
41683221Smarcel			inp += bdp->d_reclen;
41783221Smarcel			cookiep++;
41883221Smarcel			ncookies--;
41983221Smarcel		}
42024654Sdfr	}
42124654Sdfr
42283221Smarcel	while (len > 0) {
42383221Smarcel		if (cookiep && ncookies == 0)
42483221Smarcel			break;
42583221Smarcel		bdp = (struct dirent *) inp;
42683221Smarcel		reclen = bdp->d_reclen;
42783221Smarcel		if (reclen & 3) {
42883221Smarcel			error = EFAULT;
42983221Smarcel			goto out;
43083221Smarcel		}
43183221Smarcel
43283221Smarcel		if (bdp->d_fileno == 0) {
43383221Smarcel			inp += reclen;
43483221Smarcel			if (cookiep) {
43583221Smarcel				off = *cookiep++;
43683221Smarcel				ncookies--;
43783221Smarcel			} else
43883221Smarcel				off += reclen;
43983221Smarcel
44083221Smarcel			len -= reclen;
44183221Smarcel			continue;
44283221Smarcel		}
44383221Smarcel
44483221Smarcel		linuxreclen = (is64bit)
445182892Srdivacky		    ? LINUX_RECLEN64(bdp->d_namlen)
446182892Srdivacky		    : LINUX_RECLEN(bdp->d_namlen);
44783221Smarcel
44883221Smarcel		if (reclen > len || resid < linuxreclen) {
44983221Smarcel			outp++;
45083221Smarcel			break;
45183221Smarcel		}
45283221Smarcel
45383221Smarcel		if (justone) {
45483221Smarcel			/* readdir(2) case. */
455182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
456182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
457182892Srdivacky			linux_dirent->d_off = (l_off_t)linuxreclen;
458182892Srdivacky			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
459182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
460182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name));
461182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
46283221Smarcel		}
463182892Srdivacky		if (is64bit) {
464182892Srdivacky			linux_dirent64 = (struct l_dirent64*)lbuf;
465182892Srdivacky			linux_dirent64->d_ino = bdp->d_fileno;
466182892Srdivacky			linux_dirent64->d_off = (cookiep)
467182892Srdivacky			    ? (l_off_t)*cookiep
468182892Srdivacky			    : (l_off_t)(off + reclen);
469182892Srdivacky			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
470182892Srdivacky			linux_dirent64->d_type = bdp->d_type;
471182892Srdivacky			strlcpy(linux_dirent64->d_name, bdp->d_name,
472182892Srdivacky			    linuxreclen - offsetof(struct l_dirent64, d_name));
473182892Srdivacky			error = copyout(linux_dirent64, outp, linuxreclen);
474182892Srdivacky		} else if (!justone) {
475182892Srdivacky			linux_dirent = (struct l_dirent*)lbuf;
476182892Srdivacky			linux_dirent->d_ino = bdp->d_fileno;
477182892Srdivacky			linux_dirent->d_off = (cookiep)
478182892Srdivacky			    ? (l_off_t)*cookiep
479182892Srdivacky			    : (l_off_t)(off + reclen);
480182892Srdivacky			linux_dirent->d_reclen = (l_ushort)linuxreclen;
481182892Srdivacky			/*
482182892Srdivacky			 * Copy d_type to last byte of l_dirent buffer
483182892Srdivacky			 */
484182892Srdivacky			lbuf[linuxreclen-1] = bdp->d_type;
485182892Srdivacky			strlcpy(linux_dirent->d_name, bdp->d_name,
486182892Srdivacky			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
487182892Srdivacky			error = copyout(linux_dirent, outp, linuxreclen);
488182892Srdivacky		}
489182892Srdivacky
49083221Smarcel		if (error)
49183221Smarcel			goto out;
49283221Smarcel
49383221Smarcel		inp += reclen;
49483221Smarcel		if (cookiep) {
49583221Smarcel			off = *cookiep++;
49683221Smarcel			ncookies--;
49783221Smarcel		} else
49883221Smarcel			off += reclen;
49983221Smarcel
50083221Smarcel		outp += linuxreclen;
50183221Smarcel		resid -= linuxreclen;
50283221Smarcel		len -= reclen;
50383221Smarcel		if (justone)
50483221Smarcel			break;
50510355Sswallace	}
5069313Ssos
507217578Skib	if (outp == (caddr_t)args->dirent) {
508217578Skib		nbytes = resid;
509217578Skib		goto eof;
510217578Skib	}
5119313Ssos
51283221Smarcel	if (justone)
51383221Smarcel		nbytes = resid + linuxreclen;
51410355Sswallace
5159313Ssoseof:
51683366Sjulian	td->td_retval[0] = nbytes - resid;
51783221Smarcel
5189313Ssosout:
51983221Smarcel	if (cookies)
52083221Smarcel		free(cookies, M_TEMP);
52183221Smarcel
522175294Sattilio	VOP_UNLOCK(vp, 0);
523238029Skib	foffset_unlock(fp, off, 0);
52489306Salfred	fdrop(fp, td);
52583221Smarcel	free(buf, M_TEMP);
526182892Srdivacky	free(lbuf, M_TEMP);
52783221Smarcel	return (error);
5289313Ssos}
52914331Speter
53083221Smarcelint
53183366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args)
53283221Smarcel{
53383221Smarcel
53483221Smarcel#ifdef DEBUG
53583221Smarcel	if (ldebug(getdents))
53683221Smarcel		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
53783221Smarcel#endif
53883221Smarcel
53983366Sjulian	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
54083221Smarcel}
54183221Smarcel
54283221Smarcelint
54383366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
54483221Smarcel{
54583221Smarcel
54683221Smarcel#ifdef DEBUG
54783221Smarcel	if (ldebug(getdents64))
54883221Smarcel		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
54983221Smarcel#endif
55083221Smarcel
55183366Sjulian	return (getdents_common(td, args, 1));
55283221Smarcel}
55383221Smarcel
55414331Speter/*
55514331Speter * These exist mainly for hooks for doing /compat/linux translation.
55614331Speter */
55714331Speter
55814331Speterint
55983366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
56014331Speter{
561102814Siedowse	char *path;
562102814Siedowse	int error;
56314331Speter
564162585Snetchild	/* linux convention */
565227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
566162585Snetchild		return (EINVAL);
567162585Snetchild
568102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
56914331Speter
57014331Speter#ifdef DEBUG
57172543Sjlemon	if (ldebug(access))
572227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
57314331Speter#endif
574227691Sed	error = kern_access(td, path, UIO_SYSSPACE, args->amode);
575102814Siedowse	LFREEPATH(path);
576162585Snetchild
577102814Siedowse	return (error);
57814331Speter}
57914331Speter
58014331Speterint
581177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
582177997Skib{
583177997Skib	char *path;
584227693Sed	int error, dfd, flag;
585177997Skib
586227693Sed	if (args->flag & ~LINUX_AT_EACCESS)
587227693Sed		return (EINVAL);
588177997Skib	/* linux convention */
589227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
590177997Skib		return (EINVAL);
591177997Skib
592177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
593177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
594177997Skib
595177997Skib#ifdef DEBUG
596177997Skib	if (ldebug(access))
597227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
598177997Skib#endif
599177997Skib
600227693Sed	flag = (args->flag & LINUX_AT_EACCESS) == 0 ? 0 : AT_EACCESS;
601227693Sed	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flag, args->amode);
602177997Skib	LFREEPATH(path);
603177997Skib
604177997Skib	return (error);
605177997Skib}
606177997Skib
607177997Skibint
60883366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
60914331Speter{
610102814Siedowse	char *path;
611102814Siedowse	int error;
612162201Snetchild	struct stat st;
61314331Speter
614102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
61514331Speter
61614331Speter#ifdef DEBUG
61772543Sjlemon	if (ldebug(unlink))
618102814Siedowse		printf(ARGS(unlink, "%s"), path);
61914331Speter#endif
62014331Speter
621102814Siedowse	error = kern_unlink(td, path, UIO_SYSSPACE);
622162201Snetchild	if (error == EPERM)
623162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
624162201Snetchild		if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
625162201Snetchild			if (S_ISDIR(st.st_mode))
626162201Snetchild				error = EISDIR;
627102814Siedowse	LFREEPATH(path);
628102814Siedowse	return (error);
62914331Speter}
63014331Speter
63114331Speterint
632177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
633177997Skib{
634177997Skib	char *path;
635177997Skib	int error, dfd;
636177997Skib	struct stat st;
637177997Skib
638177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
639177997Skib		return (EINVAL);
640177997Skib
641177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
642177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
643177997Skib
644177997Skib#ifdef DEBUG
645177997Skib	if (ldebug(unlinkat))
646177997Skib		printf(ARGS(unlinkat, "%s"), path);
647177997Skib#endif
648177997Skib
649177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
650177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
651177997Skib	else
652202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
653177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
654177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
655177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
656177997Skib		    UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
657177997Skib			error = EISDIR;
658177997Skib	}
659177997Skib	LFREEPATH(path);
660177997Skib	return (error);
661177997Skib}
662177997Skibint
66383366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
66414331Speter{
665102814Siedowse	char *path;
666102814Siedowse	int error;
66714331Speter
668102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
66914331Speter
67014331Speter#ifdef DEBUG
67172543Sjlemon	if (ldebug(chdir))
672102814Siedowse		printf(ARGS(chdir, "%s"), path);
67314331Speter#endif
674102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
675102814Siedowse	LFREEPATH(path);
676102814Siedowse	return (error);
67714331Speter}
67814331Speter
67914331Speterint
68083366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
68114331Speter{
682102814Siedowse	char *path;
683102814Siedowse	int error;
68414331Speter
685102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
68614331Speter
68714331Speter#ifdef DEBUG
68872543Sjlemon	if (ldebug(chmod))
689102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
69014331Speter#endif
691102814Siedowse	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
692102814Siedowse	LFREEPATH(path);
693102814Siedowse	return (error);
69414331Speter}
69514331Speter
69614331Speterint
697177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
698177997Skib{
699177997Skib	char *path;
700177997Skib	int error, dfd;
701177997Skib
702177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
703177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
704177997Skib
705177997Skib#ifdef DEBUG
706177997Skib	if (ldebug(fchmodat))
707177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
708177997Skib#endif
709177997Skib
710177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
711177997Skib	LFREEPATH(path);
712177997Skib	return (error);
713177997Skib}
714177997Skib
715177997Skibint
71683366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
71714331Speter{
718102814Siedowse	char *path;
719102814Siedowse	int error;
72014331Speter
721102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
72214331Speter
72314331Speter#ifdef DEBUG
72472543Sjlemon	if (ldebug(mkdir))
725102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
72614331Speter#endif
727102814Siedowse	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
728102814Siedowse	LFREEPATH(path);
729102814Siedowse	return (error);
73014331Speter}
73114331Speter
73214331Speterint
733177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
734177997Skib{
735177997Skib	char *path;
736177997Skib	int error, dfd;
737177997Skib
738177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
739177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
740177997Skib
741177997Skib#ifdef DEBUG
742177997Skib	if (ldebug(mkdirat))
743177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
744177997Skib#endif
745177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
746177997Skib	LFREEPATH(path);
747177997Skib	return (error);
748177997Skib}
749177997Skib
750177997Skibint
75183366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
75214331Speter{
753102814Siedowse	char *path;
754102814Siedowse	int error;
75514331Speter
756102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
75714331Speter
75814331Speter#ifdef DEBUG
75972543Sjlemon	if (ldebug(rmdir))
760102814Siedowse		printf(ARGS(rmdir, "%s"), path);
76114331Speter#endif
762102814Siedowse	error = kern_rmdir(td, path, UIO_SYSSPACE);
763102814Siedowse	LFREEPATH(path);
764102814Siedowse	return (error);
76514331Speter}
76614331Speter
76714331Speterint
76883366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
76914331Speter{
770102814Siedowse	char *from, *to;
771102814Siedowse	int error;
77214331Speter
773102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
774102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
775177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
776102814Siedowse	if (to == NULL) {
777102814Siedowse		LFREEPATH(from);
778102814Siedowse		return (error);
779102814Siedowse	}
78014331Speter
78114331Speter#ifdef DEBUG
78272543Sjlemon	if (ldebug(rename))
783102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
78414331Speter#endif
785102814Siedowse	error = kern_rename(td, from, to, UIO_SYSSPACE);
786102814Siedowse	LFREEPATH(from);
787102814Siedowse	LFREEPATH(to);
788102814Siedowse	return (error);
78914331Speter}
79014331Speter
79114331Speterint
792177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
793177997Skib{
794177997Skib	char *from, *to;
795177997Skib	int error, olddfd, newdfd;
796177997Skib
797177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
798177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
799177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
800177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
801177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
802177997Skib	if (to == NULL) {
803177997Skib		LFREEPATH(from);
804177997Skib		return (error);
805177997Skib	}
806177997Skib
807177997Skib#ifdef DEBUG
808177997Skib	if (ldebug(renameat))
809177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
810177997Skib#endif
811177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
812177997Skib	LFREEPATH(from);
813177997Skib	LFREEPATH(to);
814177997Skib	return (error);
815177997Skib}
816177997Skib
817177997Skibint
81883366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
81914331Speter{
820102814Siedowse	char *path, *to;
821102814Siedowse	int error;
82214331Speter
823102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
824102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
825177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
826102814Siedowse	if (to == NULL) {
827102814Siedowse		LFREEPATH(path);
828102814Siedowse		return (error);
829102814Siedowse	}
83014331Speter
83114331Speter#ifdef DEBUG
83272543Sjlemon	if (ldebug(symlink))
833102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
83414331Speter#endif
835102814Siedowse	error = kern_symlink(td, path, to, UIO_SYSSPACE);
836102814Siedowse	LFREEPATH(path);
837102814Siedowse	LFREEPATH(to);
838102814Siedowse	return (error);
83914331Speter}
84014331Speter
84114331Speterint
842177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
843177997Skib{
844177997Skib	char *path, *to;
845177997Skib	int error, dfd;
846177997Skib
847177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
848177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
849177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
850177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
851177997Skib	if (to == NULL) {
852177997Skib		LFREEPATH(path);
853177997Skib		return (error);
854177997Skib	}
855177997Skib
856177997Skib#ifdef DEBUG
857177997Skib	if (ldebug(symlinkat))
858177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
859177997Skib#endif
860177997Skib
861177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
862177997Skib	LFREEPATH(path);
863177997Skib	LFREEPATH(to);
864177997Skib	return (error);
865177997Skib}
866177997Skib
867177997Skibint
86883366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
86914331Speter{
870102814Siedowse	char *name;
871102814Siedowse	int error;
87214331Speter
873102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
87414331Speter
87514331Speter#ifdef DEBUG
87672543Sjlemon	if (ldebug(readlink))
877102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
878102814Siedowse		    args->count);
87914331Speter#endif
880102814Siedowse	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
881102814Siedowse	    args->count);
882102814Siedowse	LFREEPATH(name);
883102814Siedowse	return (error);
88414331Speter}
88514331Speter
88614331Speterint
887177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
888177997Skib{
889177997Skib	char *name;
890177997Skib	int error, dfd;
891177997Skib
892177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
893177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
894177997Skib
895177997Skib#ifdef DEBUG
896177997Skib	if (ldebug(readlinkat))
897177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
898177997Skib		    args->bufsiz);
899177997Skib#endif
900177997Skib
901177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
902177997Skib	    UIO_USERSPACE, args->bufsiz);
903177997Skib	LFREEPATH(name);
904177997Skib	return (error);
905177997Skib}
906178439Srdivacky
907177997Skibint
90883366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
90914331Speter{
910102814Siedowse	char *path;
911102814Siedowse	int error;
91214331Speter
913102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
91414331Speter
91514331Speter#ifdef DEBUG
91672543Sjlemon	if (ldebug(truncate))
917102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
91814331Speter#endif
91914331Speter
920102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
921102814Siedowse	LFREEPATH(path);
922102814Siedowse	return (error);
92314331Speter}
92414331Speter
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}
942178439Srdivackyint
943156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
944156842Snetchild{
945156842Snetchild	struct ftruncate_args /* {
946156842Snetchild		int fd;
947156842Snetchild		int pad;
948156842Snetchild		off_t length;
949156842Snetchild		} */ nuap;
950156842Snetchild
951156842Snetchild	nuap.fd = args->fd;
952156842Snetchild	nuap.length = args->length;
953225617Skmacy	return (sys_ftruncate(td, &nuap));
954156842Snetchild}
955156842Snetchild
956156842Snetchildint
95783366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
95849662Smarcel{
959102814Siedowse	char *path, *to;
960102814Siedowse	int error;
96149662Smarcel
962102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
963102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
964177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
965102814Siedowse	if (to == NULL) {
966102814Siedowse		LFREEPATH(path);
967102814Siedowse		return (error);
968102814Siedowse	}
96949662Smarcel
97049662Smarcel#ifdef DEBUG
97172543Sjlemon	if (ldebug(link))
972102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
97349662Smarcel#endif
974102814Siedowse	error = kern_link(td, path, to, UIO_SYSSPACE);
975102814Siedowse	LFREEPATH(path);
976102814Siedowse	LFREEPATH(to);
977102814Siedowse	return (error);
97849662Smarcel}
97949788Smarcel
98053713Smarcelint
981177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
982177997Skib{
983177997Skib	char *path, *to;
984227693Sed	int error, olddfd, newdfd, follow;
985177997Skib
986227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
987177997Skib		return (EINVAL);
988177997Skib
989177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
990177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
991177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
992177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
993177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
994177997Skib	if (to == NULL) {
995177997Skib		LFREEPATH(path);
996177997Skib		return (error);
997177997Skib	}
998177997Skib
999177997Skib#ifdef DEBUG
1000177997Skib	if (ldebug(linkat))
1001177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
1002227693Sed			args->newdfd, to, args->flag);
1003177997Skib#endif
1004177997Skib
1005227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
1006227693Sed	    FOLLOW;
1007227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
1008177997Skib	LFREEPATH(path);
1009177997Skib	LFREEPATH(to);
1010177997Skib	return (error);
1011177997Skib}
1012177997Skib
1013177997Skibint
101483366Sjulianlinux_fdatasync(td, uap)
101583366Sjulian	struct thread *td;
101653713Smarcel	struct linux_fdatasync_args *uap;
101753713Smarcel{
101853713Smarcel	struct fsync_args bsd;
101953713Smarcel
102053713Smarcel	bsd.fd = uap->fd;
1021225617Skmacy	return sys_fsync(td, &bsd);
102253713Smarcel}
102363285Smarcel
102463285Smarcelint
102583366Sjulianlinux_pread(td, uap)
102683366Sjulian	struct thread *td;
102763285Smarcel	struct linux_pread_args *uap;
102863285Smarcel{
102963285Smarcel	struct pread_args bsd;
1030162585Snetchild	struct vnode *vp;
1031162585Snetchild	int error;
103263285Smarcel
103363285Smarcel	bsd.fd = uap->fd;
103463285Smarcel	bsd.buf = uap->buf;
103563285Smarcel	bsd.nbyte = uap->nbyte;
103663285Smarcel	bsd.offset = uap->offset;
1037162585Snetchild
1038225617Skmacy	error = sys_pread(td, &bsd);
1039162585Snetchild
1040162585Snetchild	if (error == 0) {
1041162585Snetchild   	   	/* This seems to violate POSIX but linux does it */
1042224778Srwatson		if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0)
1043162585Snetchild   		   	return (error);
1044162585Snetchild		if (vp->v_type == VDIR) {
1045162585Snetchild   		   	vrele(vp);
1046162585Snetchild			return (EISDIR);
1047162585Snetchild		}
1048162585Snetchild		vrele(vp);
1049162585Snetchild	}
1050162585Snetchild
1051162585Snetchild	return (error);
105263285Smarcel}
105363285Smarcel
105463285Smarcelint
105583366Sjulianlinux_pwrite(td, uap)
105683366Sjulian	struct thread *td;
105763285Smarcel	struct linux_pwrite_args *uap;
105863285Smarcel{
105963285Smarcel	struct pwrite_args bsd;
106063285Smarcel
106163285Smarcel	bsd.fd = uap->fd;
106263285Smarcel	bsd.buf = uap->buf;
106363285Smarcel	bsd.nbyte = uap->nbyte;
106463285Smarcel	bsd.offset = uap->offset;
1065225617Skmacy	return sys_pwrite(td, &bsd);
106663285Smarcel}
106772538Sjlemon
106872538Sjlemonint
106983366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
107072538Sjlemon{
107172538Sjlemon	struct ufs_args ufs;
1072111798Sdes	char fstypename[MFSNAMELEN];
1073111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
107473286Sadrian	int error;
107573286Sadrian	int fsflags;
107673286Sadrian	void *fsdata;
107772538Sjlemon
1078111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
107973286Sadrian	    NULL);
108072538Sjlemon	if (error)
1081111798Sdes		return (error);
1082127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
108372538Sjlemon	if (error)
1084111798Sdes		return (error);
1085127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
108672538Sjlemon	if (error)
1087111798Sdes		return (error);
108872538Sjlemon
108972538Sjlemon#ifdef DEBUG
109072538Sjlemon	if (ldebug(mount))
109172538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
109272538Sjlemon		    fstypename, mntfromname, mntonname);
109372538Sjlemon#endif
109472538Sjlemon
109572538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1096127059Stjr		strcpy(fstypename, "ext2fs");
109773286Sadrian		fsdata = &ufs;
109872538Sjlemon		ufs.fspec = mntfromname;
109972538Sjlemon#define DEFAULT_ROOTID		-2
110072538Sjlemon		ufs.export.ex_root = DEFAULT_ROOTID;
110172538Sjlemon		ufs.export.ex_flags =
110272538Sjlemon		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
110372538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1104127059Stjr		strcpy(fstypename, "linprocfs");
110573286Sadrian		fsdata = NULL;
1106190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1107190445Sambrisko		strcpy(fstypename, "msdosfs");
1108190445Sambrisko		fsdata = NULL;
110972538Sjlemon	} else {
111072538Sjlemon		return (ENODEV);
111172538Sjlemon	}
111272538Sjlemon
111373286Sadrian	fsflags = 0;
111472538Sjlemon
111572538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
111672538Sjlemon		/*
111772538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
111872538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
111972538Sjlemon		 */
112072538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1121111798Sdes			fsflags |= MNT_RDONLY;
112272538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1123111798Sdes			fsflags |= MNT_NOSUID;
112472538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1125111798Sdes			fsflags |= MNT_NOEXEC;
112672538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1127111798Sdes			fsflags |= MNT_UPDATE;
112872538Sjlemon	}
112972538Sjlemon
1130127059Stjr	if (strcmp(fstypename, "linprocfs") == 0) {
1131132708Sphk		error = kernel_vmount(fsflags,
1132132708Sphk			"fstype", fstypename,
1133132708Sphk			"fspath", mntonname,
1134132708Sphk			NULL);
1135190445Sambrisko	} else if (strcmp(fstypename, "msdosfs") == 0) {
1136190445Sambrisko		error = kernel_vmount(fsflags,
1137190445Sambrisko			"fstype", fstypename,
1138190445Sambrisko			"fspath", mntonname,
1139190445Sambrisko			"from", mntfromname,
1140190445Sambrisko			NULL);
1141127059Stjr	} else
1142138353Sphk		error = EOPNOTSUPP;
1143127059Stjr	return (error);
114472538Sjlemon}
114572538Sjlemon
114672538Sjlemonint
114783366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
114872538Sjlemon{
114983221Smarcel	struct linux_umount_args args2;
115072538Sjlemon
115172538Sjlemon	args2.path = args->path;
115272538Sjlemon	args2.flags = 0;
115383366Sjulian	return (linux_umount(td, &args2));
115472538Sjlemon}
115572538Sjlemon
115672538Sjlemonint
115783366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
115872538Sjlemon{
115972538Sjlemon	struct unmount_args bsd;
116072538Sjlemon
116172538Sjlemon	bsd.path = args->path;
116272538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1163225617Skmacy	return (sys_unmount(td, &bsd));
116472538Sjlemon}
116583221Smarcel
116683221Smarcel/*
116783221Smarcel * fcntl family of syscalls
116883221Smarcel */
116983221Smarcel
117083221Smarcelstruct l_flock {
117183221Smarcel	l_short		l_type;
117283221Smarcel	l_short		l_whence;
117383221Smarcel	l_off_t		l_start;
117483221Smarcel	l_off_t		l_len;
117583221Smarcel	l_pid_t		l_pid;
1176133816Stjr}
1177140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1178133816Stjr__packed
1179133816Stjr#endif
1180133816Stjr;
118183221Smarcel
118283221Smarcelstatic void
118383221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
118483221Smarcel{
118583221Smarcel	switch (linux_flock->l_type) {
118683221Smarcel	case LINUX_F_RDLCK:
118783221Smarcel		bsd_flock->l_type = F_RDLCK;
118883221Smarcel		break;
118983221Smarcel	case LINUX_F_WRLCK:
119083221Smarcel		bsd_flock->l_type = F_WRLCK;
119183221Smarcel		break;
119283221Smarcel	case LINUX_F_UNLCK:
119383221Smarcel		bsd_flock->l_type = F_UNLCK;
119483221Smarcel		break;
119583221Smarcel	default:
119683221Smarcel		bsd_flock->l_type = -1;
119783221Smarcel		break;
119883221Smarcel	}
119983221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
120083221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
120183221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
120283221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1203177633Sdfr	bsd_flock->l_sysid = 0;
120483221Smarcel}
120583221Smarcel
120683221Smarcelstatic void
120783221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
120883221Smarcel{
120983221Smarcel	switch (bsd_flock->l_type) {
121083221Smarcel	case F_RDLCK:
121183221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
121283221Smarcel		break;
121383221Smarcel	case F_WRLCK:
121483221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
121583221Smarcel		break;
121683221Smarcel	case F_UNLCK:
121783221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
121883221Smarcel		break;
121983221Smarcel	}
122083221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
122183221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
122283221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
122383221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
122483221Smarcel}
122583221Smarcel
1226140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
122783221Smarcelstruct l_flock64 {
122883221Smarcel	l_short		l_type;
122983221Smarcel	l_short		l_whence;
123083221Smarcel	l_loff_t	l_start;
123183221Smarcel	l_loff_t	l_len;
123283221Smarcel	l_pid_t		l_pid;
1233133816Stjr}
1234140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1235133816Stjr__packed
1236133816Stjr#endif
1237133816Stjr;
123883221Smarcel
123983221Smarcelstatic void
124083221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
124183221Smarcel{
124283221Smarcel	switch (linux_flock->l_type) {
124383221Smarcel	case LINUX_F_RDLCK:
124483221Smarcel		bsd_flock->l_type = F_RDLCK;
124583221Smarcel		break;
124683221Smarcel	case LINUX_F_WRLCK:
124783221Smarcel		bsd_flock->l_type = F_WRLCK;
124883221Smarcel		break;
124983221Smarcel	case LINUX_F_UNLCK:
125083221Smarcel		bsd_flock->l_type = F_UNLCK;
125183221Smarcel		break;
125283221Smarcel	default:
125383221Smarcel		bsd_flock->l_type = -1;
125483221Smarcel		break;
125583221Smarcel	}
125683221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
125783221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
125883221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
125983221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1260177633Sdfr	bsd_flock->l_sysid = 0;
126183221Smarcel}
126283221Smarcel
126383221Smarcelstatic void
126483221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
126583221Smarcel{
126683221Smarcel	switch (bsd_flock->l_type) {
126783221Smarcel	case F_RDLCK:
126883221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
126983221Smarcel		break;
127083221Smarcel	case F_WRLCK:
127183221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
127283221Smarcel		break;
127383221Smarcel	case F_UNLCK:
127483221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
127583221Smarcel		break;
127683221Smarcel	}
127783221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
127883221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
127983221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
128083221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
128183221Smarcel}
1282133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
128383221Smarcel
128483221Smarcelstatic int
128583366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args)
128683221Smarcel{
1287107680Siedowse	struct l_flock linux_flock;
1288107680Siedowse	struct flock bsd_flock;
128983221Smarcel	struct file *fp;
1290102872Siedowse	long arg;
129183221Smarcel	int error, result;
129283221Smarcel
129383221Smarcel	switch (args->cmd) {
129483221Smarcel	case LINUX_F_DUPFD:
1295102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
129683221Smarcel
129783221Smarcel	case LINUX_F_GETFD:
1298102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
129983221Smarcel
130083221Smarcel	case LINUX_F_SETFD:
1301102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
130283221Smarcel
130383221Smarcel	case LINUX_F_GETFL:
1304102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
130583366Sjulian		result = td->td_retval[0];
130683366Sjulian		td->td_retval[0] = 0;
130783221Smarcel		if (result & O_RDONLY)
130883366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
130983221Smarcel		if (result & O_WRONLY)
131083366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
131183221Smarcel		if (result & O_RDWR)
131283366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
131383221Smarcel		if (result & O_NDELAY)
131483366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
131583221Smarcel		if (result & O_APPEND)
131683366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
131783221Smarcel		if (result & O_FSYNC)
131883366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
131983221Smarcel		if (result & O_ASYNC)
132083366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1321144987Smdodd#ifdef LINUX_O_NOFOLLOW
1322144987Smdodd		if (result & O_NOFOLLOW)
1323144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1324144987Smdodd#endif
1325144987Smdodd#ifdef LINUX_O_DIRECT
1326144987Smdodd		if (result & O_DIRECT)
1327144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1328144987Smdodd#endif
132983221Smarcel		return (error);
133083221Smarcel
133183221Smarcel	case LINUX_F_SETFL:
1332102872Siedowse		arg = 0;
133383221Smarcel		if (args->arg & LINUX_O_NDELAY)
1334102872Siedowse			arg |= O_NONBLOCK;
133583221Smarcel		if (args->arg & LINUX_O_APPEND)
1336102872Siedowse			arg |= O_APPEND;
133783221Smarcel		if (args->arg & LINUX_O_SYNC)
1338102872Siedowse			arg |= O_FSYNC;
133983221Smarcel		if (args->arg & LINUX_FASYNC)
1340102872Siedowse			arg |= O_ASYNC;
1341144987Smdodd#ifdef LINUX_O_NOFOLLOW
1342144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1343144987Smdodd			arg |= O_NOFOLLOW;
1344144987Smdodd#endif
1345144987Smdodd#ifdef LINUX_O_DIRECT
1346144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1347144987Smdodd			arg |= O_DIRECT;
1348144987Smdodd#endif
1349102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
135083221Smarcel
1351107680Siedowse	case LINUX_F_GETLK:
1352111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1353107680Siedowse		    sizeof(linux_flock));
1354107680Siedowse		if (error)
1355107680Siedowse			return (error);
1356107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1357107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1358107680Siedowse		if (error)
1359107680Siedowse			return (error);
1360107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1361111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1362107680Siedowse		    sizeof(linux_flock)));
1363107680Siedowse
1364107680Siedowse	case LINUX_F_SETLK:
1365111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1366107680Siedowse		    sizeof(linux_flock));
1367107680Siedowse		if (error)
1368107680Siedowse			return (error);
1369107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1370107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1371107680Siedowse		    (intptr_t)&bsd_flock));
1372107680Siedowse
1373107680Siedowse	case LINUX_F_SETLKW:
1374111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1375107680Siedowse		    sizeof(linux_flock));
1376107680Siedowse		if (error)
1377107680Siedowse			return (error);
1378107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1379107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1380107680Siedowse		     (intptr_t)&bsd_flock));
1381107680Siedowse
138283221Smarcel	case LINUX_F_GETOWN:
1383102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
138483221Smarcel
138583221Smarcel	case LINUX_F_SETOWN:
138683221Smarcel		/*
138783221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
138883221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
138983221Smarcel		 * pipes under Linux-2.2.35 at least).
139083221Smarcel		 */
1391224778Srwatson		error = fget(td, args->fd, CAP_FCNTL, &fp);
139289319Salfred		if (error)
139389319Salfred			return (error);
139489306Salfred		if (fp->f_type == DTYPE_PIPE) {
139589306Salfred			fdrop(fp, td);
139683221Smarcel			return (EINVAL);
139789306Salfred		}
139889306Salfred		fdrop(fp, td);
139983221Smarcel
1400102872Siedowse		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
140183221Smarcel	}
140283221Smarcel
140383221Smarcel	return (EINVAL);
140483221Smarcel}
140583221Smarcel
140683221Smarcelint
140783366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
140883221Smarcel{
140983221Smarcel	struct linux_fcntl64_args args64;
141083221Smarcel
141183221Smarcel#ifdef DEBUG
141283221Smarcel	if (ldebug(fcntl))
141383221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
141483221Smarcel#endif
141583221Smarcel
141683221Smarcel	args64.fd = args->fd;
141783221Smarcel	args64.cmd = args->cmd;
141883221Smarcel	args64.arg = args->arg;
141983366Sjulian	return (fcntl_common(td, &args64));
142083221Smarcel}
142183221Smarcel
1422140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
142383221Smarcelint
142483366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
142583221Smarcel{
142683221Smarcel	struct l_flock64 linux_flock;
1427102872Siedowse	struct flock bsd_flock;
142883221Smarcel	int error;
142983221Smarcel
143083221Smarcel#ifdef DEBUG
143183221Smarcel	if (ldebug(fcntl64))
143283221Smarcel		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
143383221Smarcel#endif
143483221Smarcel
143583221Smarcel	switch (args->cmd) {
143699687Srobert	case LINUX_F_GETLK64:
1437111797Sdes		error = copyin((void *)args->arg, &linux_flock,
143883221Smarcel		    sizeof(linux_flock));
143983221Smarcel		if (error)
144083221Smarcel			return (error);
1441102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1442102872Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
144383221Smarcel		if (error)
144483221Smarcel			return (error);
1445102872Siedowse		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1446111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1447111797Sdes			    sizeof(linux_flock)));
144883221Smarcel
144999687Srobert	case LINUX_F_SETLK64:
1450111797Sdes		error = copyin((void *)args->arg, &linux_flock,
145183221Smarcel		    sizeof(linux_flock));
145283221Smarcel		if (error)
145383221Smarcel			return (error);
1454102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1455102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1456102872Siedowse		    (intptr_t)&bsd_flock));
145783221Smarcel
145899687Srobert	case LINUX_F_SETLKW64:
1459111797Sdes		error = copyin((void *)args->arg, &linux_flock,
146083221Smarcel		    sizeof(linux_flock));
146183221Smarcel		if (error)
146283221Smarcel			return (error);
1463102872Siedowse		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1464102872Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1465102872Siedowse		    (intptr_t)&bsd_flock));
146683221Smarcel	}
146783221Smarcel
146883366Sjulian	return (fcntl_common(td, args));
146983221Smarcel}
1470133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
147185022Smarcel
147285022Smarcelint
147385022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
147485022Smarcel{
1475102814Siedowse	char *path;
1476102814Siedowse	int error;
147785022Smarcel
1478102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
147985022Smarcel
148085022Smarcel#ifdef DEBUG
148185022Smarcel	if (ldebug(chown))
1482102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
148385022Smarcel#endif
1484102814Siedowse	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1485102814Siedowse	LFREEPATH(path);
1486102814Siedowse	return (error);
148785022Smarcel}
148885022Smarcel
148985022Smarcelint
1490177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1491177997Skib{
1492177997Skib	char *path;
1493227693Sed	int error, dfd, flag;
1494177997Skib
1495177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1496177997Skib		return (EINVAL);
1497177997Skib
1498177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1499177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1500177997Skib
1501177997Skib#ifdef DEBUG
1502177997Skib	if (ldebug(fchownat))
1503177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1504177997Skib#endif
1505177997Skib
1506227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1507177997Skib	    AT_SYMLINK_NOFOLLOW;
1508177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1509227693Sed	    flag);
1510177997Skib	LFREEPATH(path);
1511177997Skib	return (error);
1512177997Skib}
1513177997Skib
1514177997Skibint
151585022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
151685022Smarcel{
1517102814Siedowse	char *path;
1518102814Siedowse	int error;
151985022Smarcel
1520102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
152185022Smarcel
152285022Smarcel#ifdef DEBUG
152385022Smarcel	if (ldebug(lchown))
1524102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
152585022Smarcel#endif
1526102814Siedowse	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1527102814Siedowse	LFREEPATH(path);
1528102814Siedowse	return (error);
152985022Smarcel}
1530228957Sjhb
1531228957Sjhbstatic int
1532228957Sjhbconvert_fadvice(int advice)
1533228957Sjhb{
1534228957Sjhb	switch (advice) {
1535228957Sjhb	case LINUX_POSIX_FADV_NORMAL:
1536228957Sjhb		return (POSIX_FADV_NORMAL);
1537228957Sjhb	case LINUX_POSIX_FADV_RANDOM:
1538228957Sjhb		return (POSIX_FADV_RANDOM);
1539228957Sjhb	case LINUX_POSIX_FADV_SEQUENTIAL:
1540228957Sjhb		return (POSIX_FADV_SEQUENTIAL);
1541228957Sjhb	case LINUX_POSIX_FADV_WILLNEED:
1542228957Sjhb		return (POSIX_FADV_WILLNEED);
1543228957Sjhb	case LINUX_POSIX_FADV_DONTNEED:
1544228957Sjhb		return (POSIX_FADV_DONTNEED);
1545228957Sjhb	case LINUX_POSIX_FADV_NOREUSE:
1546228957Sjhb		return (POSIX_FADV_NOREUSE);
1547228957Sjhb	default:
1548228957Sjhb		return (-1);
1549228957Sjhb	}
1550228957Sjhb}
1551228957Sjhb
1552228957Sjhbint
1553228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1554228957Sjhb{
1555228957Sjhb	int advice;
1556228957Sjhb
1557228957Sjhb	advice = convert_fadvice(args->advice);
1558228957Sjhb	if (advice == -1)
1559228957Sjhb		return (EINVAL);
1560228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1561228957Sjhb	    advice));
1562228957Sjhb}
1563228957Sjhb
1564228957Sjhbint
1565228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1566228957Sjhb{
1567228957Sjhb	int advice;
1568228957Sjhb
1569228957Sjhb	advice = convert_fadvice(args->advice);
1570228957Sjhb	if (advice == -1)
1571228957Sjhb		return (EINVAL);
1572228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1573228957Sjhb	    advice));
1574228957Sjhb}
1575234352Sjkim
1576234352Sjkimint
1577234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args)
1578234352Sjkim{
1579234352Sjkim	int fildes[2];
1580234352Sjkim	int error;
1581234352Sjkim
1582234352Sjkim#ifdef DEBUG
1583234352Sjkim	if (ldebug(pipe))
1584234352Sjkim		printf(ARGS(pipe, "*"));
1585234352Sjkim#endif
1586234352Sjkim
1587234352Sjkim	error = do_pipe(td, fildes, 0);
1588234352Sjkim	if (error)
1589234352Sjkim		return (error);
1590234352Sjkim
1591234352Sjkim	/* XXX: Close descriptors on error. */
1592234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1593234352Sjkim}
1594234352Sjkim
1595234352Sjkimint
1596234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1597234352Sjkim{
1598234352Sjkim	int fildes[2];
1599234352Sjkim	int error, flags;
1600234352Sjkim
1601234352Sjkim#ifdef DEBUG
1602234352Sjkim	if (ldebug(pipe2))
1603234352Sjkim		printf(ARGS(pipe2, "*, %d"), args->flags);
1604234352Sjkim#endif
1605234352Sjkim
1606234352Sjkim	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1607234352Sjkim		return (EINVAL);
1608234352Sjkim
1609234352Sjkim	flags = 0;
1610234352Sjkim	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1611234352Sjkim		flags |= O_NONBLOCK;
1612234352Sjkim	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1613234352Sjkim		flags |= O_CLOEXEC;
1614234352Sjkim	error = do_pipe(td, fildes, flags);
1615234352Sjkim	if (error)
1616234352Sjkim		return (error);
1617234352Sjkim
1618234352Sjkim	/* XXX: Close descriptors on error. */
1619234352Sjkim	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1620234352Sjkim}
1621