linux_file.c revision 346831
19313Ssos/*-
2330997Semaste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330997Semaste *
4230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt
59313Ssos * All rights reserved.
69313Ssos *
79313Ssos * Redistribution and use in source and binary forms, with or without
89313Ssos * modification, are permitted provided that the following conditions
99313Ssos * are met:
109313Ssos * 1. Redistributions of source code must retain the above copyright
11330997Semaste *    notice, this list of conditions and the following disclaimer.
129313Ssos * 2. Redistributions in binary form must reproduce the above copyright
139313Ssos *    notice, this list of conditions and the following disclaimer in the
149313Ssos *    documentation and/or other materials provided with the distribution.
159313Ssos *
16330997Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17330997Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18330997Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19330997Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20330997Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21330997Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22330997Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23330997Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24330997Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25330997Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26330997Semaste * SUCH DAMAGE.
279313Ssos */
289313Ssos
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_file.c 346831 2019-04-28 13:45:18Z dchagin $");
31116173Sobrien
32156874Sru#include "opt_compat.h"
3331784Seivind
349313Ssos#include <sys/param.h>
359313Ssos#include <sys/systm.h>
36263233Srwatson#include <sys/capsicum.h>
3776166Smarkm#include <sys/conf.h>
3876166Smarkm#include <sys/dirent.h>
399313Ssos#include <sys/fcntl.h>
409313Ssos#include <sys/file.h>
419313Ssos#include <sys/filedesc.h>
4231561Sbde#include <sys/lock.h>
439313Ssos#include <sys/malloc.h>
4472538Sjlemon#include <sys/mount.h>
4576166Smarkm#include <sys/mutex.h>
46168014Sjulian#include <sys/namei.h>
4776166Smarkm#include <sys/proc.h>
48162201Snetchild#include <sys/stat.h>
49166085Skib#include <sys/sx.h>
50102814Siedowse#include <sys/syscallsubr.h>
5176166Smarkm#include <sys/sysproto.h>
5214331Speter#include <sys/tty.h>
53162585Snetchild#include <sys/unistd.h>
5476166Smarkm#include <sys/vnode.h>
5512458Sbde
56140214Sobrien#ifdef COMPAT_LINUX32
57140214Sobrien#include <machine/../linux32/linux.h>
58140214Sobrien#include <machine/../linux32/linux32_proto.h>
59140214Sobrien#else
6064905Smarcel#include <machine/../linux/linux.h>
6168583Smarcel#include <machine/../linux/linux_proto.h>
62133816Stjr#endif
63246085Sjhb#include <compat/linux/linux_misc.h>
6464905Smarcel#include <compat/linux/linux_util.h>
65177997Skib#include <compat/linux/linux_file.h>
669313Ssos
67315376Sdchaginstatic int	linux_common_open(struct thread *, int, char *, int, int);
68315376Sdchaginstatic int	linux_getdents_error(struct thread *, int, int);
69315376Sdchagin
70315376Sdchagin
719313Ssosint
7283366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args)
739313Ssos{
74300411Sdchagin	char *path;
75300411Sdchagin	int error;
769313Ssos
77300411Sdchagin	LCONVPATHEXIST(td, args->path, &path);
789313Ssos#ifdef DEBUG
7972543Sjlemon	if (ldebug(creat))
80102814Siedowse		printf(ARGS(creat, "%s, %d"), path, args->mode);
819313Ssos#endif
82300411Sdchagin	error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
83300411Sdchagin	    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
84300411Sdchagin	LFREEPATH(path);
85300411Sdchagin	return (error);
869313Ssos}
879313Ssos
88168014Sjulian
89168014Sjulianstatic int
90177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
919313Ssos{
92300411Sdchagin	cap_rights_t rights;
93300411Sdchagin	struct proc *p = td->td_proc;
94300411Sdchagin	struct file *fp;
95300411Sdchagin	int fd;
96300411Sdchagin	int bsd_flags, error;
9714331Speter
98300411Sdchagin	bsd_flags = 0;
99300411Sdchagin	switch (l_flags & LINUX_O_ACCMODE) {
100300411Sdchagin	case LINUX_O_WRONLY:
101300411Sdchagin		bsd_flags |= O_WRONLY;
102300411Sdchagin		break;
103300411Sdchagin	case LINUX_O_RDWR:
104300411Sdchagin		bsd_flags |= O_RDWR;
105300411Sdchagin		break;
106300411Sdchagin	default:
107300411Sdchagin		bsd_flags |= O_RDONLY;
108300411Sdchagin	}
109300411Sdchagin	if (l_flags & LINUX_O_NDELAY)
110300411Sdchagin		bsd_flags |= O_NONBLOCK;
111300411Sdchagin	if (l_flags & LINUX_O_APPEND)
112300411Sdchagin		bsd_flags |= O_APPEND;
113300411Sdchagin	if (l_flags & LINUX_O_SYNC)
114300411Sdchagin		bsd_flags |= O_FSYNC;
115300411Sdchagin	if (l_flags & LINUX_O_NONBLOCK)
116300411Sdchagin		bsd_flags |= O_NONBLOCK;
117300411Sdchagin	if (l_flags & LINUX_FASYNC)
118300411Sdchagin		bsd_flags |= O_ASYNC;
119300411Sdchagin	if (l_flags & LINUX_O_CREAT)
120300411Sdchagin		bsd_flags |= O_CREAT;
121300411Sdchagin	if (l_flags & LINUX_O_TRUNC)
122300411Sdchagin		bsd_flags |= O_TRUNC;
123300411Sdchagin	if (l_flags & LINUX_O_EXCL)
124300411Sdchagin		bsd_flags |= O_EXCL;
125300411Sdchagin	if (l_flags & LINUX_O_NOCTTY)
126300411Sdchagin		bsd_flags |= O_NOCTTY;
127300411Sdchagin	if (l_flags & LINUX_O_DIRECT)
128300411Sdchagin		bsd_flags |= O_DIRECT;
129300411Sdchagin	if (l_flags & LINUX_O_NOFOLLOW)
130300411Sdchagin		bsd_flags |= O_NOFOLLOW;
131300411Sdchagin	if (l_flags & LINUX_O_DIRECTORY)
132300411Sdchagin		bsd_flags |= O_DIRECTORY;
133300411Sdchagin	/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
1349313Ssos
135300411Sdchagin	error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
136300411Sdchagin	if (error != 0)
137300411Sdchagin		goto done;
138300411Sdchagin	if (bsd_flags & O_NOCTTY)
139300411Sdchagin		goto done;
140178036Srdivacky
141300411Sdchagin	/*
142300411Sdchagin	 * XXX In between kern_open() and fget(), another process
143300411Sdchagin	 * having the same filedesc could use that fd without
144300411Sdchagin	 * checking below.
145300411Sdchagin	*/
146300411Sdchagin	fd = td->td_retval[0];
147300411Sdchagin	if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
148300411Sdchagin		if (fp->f_type != DTYPE_VNODE) {
149300411Sdchagin			fdrop(fp, td);
150300411Sdchagin			goto done;
151300411Sdchagin		}
152300411Sdchagin		sx_slock(&proctree_lock);
153300411Sdchagin		PROC_LOCK(p);
154300411Sdchagin		if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
155300411Sdchagin			PROC_UNLOCK(p);
156300411Sdchagin			sx_sunlock(&proctree_lock);
157300411Sdchagin			/* XXXPJD: Verify if TIOCSCTTY is allowed. */
158300411Sdchagin			(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
159300411Sdchagin			    td->td_ucred, td);
160300411Sdchagin		} else {
161300411Sdchagin			PROC_UNLOCK(p);
162300411Sdchagin			sx_sunlock(&proctree_lock);
163300411Sdchagin		}
164300411Sdchagin		fdrop(fp, td);
165300411Sdchagin	}
166281726Strasz
167281726Straszdone:
16814331Speter#ifdef DEBUG
169300411Sdchagin	if (ldebug(open))
170300411Sdchagin		printf(LMSG("open returns error %d"), error);
17114331Speter#endif
172300411Sdchagin	LFREEPATH(path);
173300411Sdchagin	return (error);
1749313Ssos}
1759313Ssos
1769313Ssosint
177168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args)
178168014Sjulian{
179177997Skib	char *path;
180177997Skib	int dfd;
181168014Sjulian
182177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
183177997Skib	if (args->flags & LINUX_O_CREAT)
184177997Skib		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
185177997Skib	else
186177997Skib		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
187168014Sjulian#ifdef DEBUG
188168014Sjulian	if (ldebug(openat))
189168014Sjulian		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
190177997Skib		    path, args->flags, args->mode);
191168014Sjulian#endif
192177997Skib	return (linux_common_open(td, dfd, path, args->flags, args->mode));
193168014Sjulian}
194168014Sjulian
195168014Sjulianint
196168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args)
197168014Sjulian{
198300411Sdchagin	char *path;
199168014Sjulian
200300411Sdchagin	if (args->flags & LINUX_O_CREAT)
201300411Sdchagin		LCONVPATHCREAT(td, args->path, &path);
202300411Sdchagin	else
203300411Sdchagin		LCONVPATHEXIST(td, args->path, &path);
204168014Sjulian#ifdef DEBUG
205168014Sjulian	if (ldebug(open))
206168014Sjulian		printf(ARGS(open, "%s, 0x%x, 0x%x"),
207168014Sjulian		    path, args->flags, args->mode);
208168014Sjulian#endif
209178036Srdivacky	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
210168014Sjulian}
211168014Sjulian
212168014Sjulianint
21383366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args)
2149313Ssos{
2159313Ssos
2169313Ssos#ifdef DEBUG
21772543Sjlemon	if (ldebug(lseek))
21872543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
21983221Smarcel		    args->fdes, (long)args->off, args->whence);
2209313Ssos#endif
221315550Strasz	return (kern_lseek(td, args->fdes, args->off, args->whence));
2229313Ssos}
2239313Ssos
224283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
22514331Speterint
22683366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args)
22714331Speter{
22814331Speter	int error;
22914331Speter	off_t off;
23014331Speter
23114331Speter#ifdef DEBUG
23272543Sjlemon	if (ldebug(llseek))
23372543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
23472543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
23514331Speter#endif
23614331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
23714331Speter
238315550Strasz	error = kern_lseek(td, args->fd, off, args->whence);
239315550Strasz	if (error != 0)
240300411Sdchagin		return (error);
24114331Speter
242315550Strasz	error = copyout(td->td_retval, args->res, sizeof(off_t));
243315550Strasz	if (error != 0)
244300411Sdchagin		return (error);
24514331Speter
24683366Sjulian	td->td_retval[0] = 0;
247300411Sdchagin	return (0);
24814331Speter}
249283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
25014331Speter
25183221Smarcel/*
25283221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same
25383221Smarcel * arguments. They only differ in the definition of struct dirent they
254315376Sdchagin * operate on.
255315376Sdchagin * Note that linux_readdir(2) is a special case of linux_getdents(2)
256315376Sdchagin * where count is always equals 1, meaning that the buffer is one
257315376Sdchagin * dirent-structure in size and that the code can't handle more anyway.
258315376Sdchagin * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
259315376Sdchagin * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
260315376Sdchagin * trash user stack.
26183221Smarcel */
26283221Smarcel
263315376Sdchaginstatic int
264315376Sdchaginlinux_getdents_error(struct thread *td, int fd, int err)
265315376Sdchagin{
266315376Sdchagin	cap_rights_t rights;
267315376Sdchagin	struct vnode *vp;
268315376Sdchagin	struct file *fp;
269315376Sdchagin	int error;
270315376Sdchagin
271315376Sdchagin	/* Linux return ENOTDIR in case when fd is not a directory. */
272315376Sdchagin	error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
273315376Sdchagin	if (error != 0)
274315376Sdchagin		return (error);
275315376Sdchagin	vp = fp->f_vnode;
276315376Sdchagin	if (vp->v_type != VDIR) {
277315376Sdchagin		fdrop(fp, td);
278315376Sdchagin		return (ENOTDIR);
279315376Sdchagin	}
280315376Sdchagin	fdrop(fp, td);
281315376Sdchagin	return (err);
282315376Sdchagin}
283315376Sdchagin
28483221Smarcelstruct l_dirent {
285179651Srdivacky	l_ulong		d_ino;
28683221Smarcel	l_off_t		d_off;
28783221Smarcel	l_ushort	d_reclen;
28883221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
28983221Smarcel};
29083221Smarcel
29183221Smarcelstruct l_dirent64 {
29283221Smarcel	uint64_t	d_ino;
29383221Smarcel	int64_t		d_off;
29483221Smarcel	l_ushort	d_reclen;
29583221Smarcel	u_char		d_type;
29683221Smarcel	char		d_name[LINUX_NAME_MAX + 1];
29783221Smarcel};
29883221Smarcel
299182892Srdivacky/*
300182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type,
301182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
302182892Srdivacky */
303182892Srdivacky#define LINUX_RECLEN(namlen)						\
304298482Spfg    roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
30583221Smarcel
306182892Srdivacky#define LINUX_RECLEN64(namlen)						\
307298482Spfg    roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,		\
308182892Srdivacky    sizeof(uint64_t))
309182892Srdivacky
310315376Sdchagin/*
311315376Sdchagin * Linux l_dirent is bigger than FreeBSD dirent, thus the buffer size
312315376Sdchagin * passed to kern_getdirentries() must be smaller than the one passed
313315376Sdchagin * to linux_getdents() by certain factor.
314315376Sdchagin */
315315376Sdchagin#define	LINUX_RECLEN_RATIO(X)	X * offsetof(struct dirent, d_name) /	\
316315376Sdchagin    offsetof(struct l_dirent, d_name);
317315376Sdchagin#define	LINUX_RECLEN64_RATIO(X)	X * offsetof(struct dirent, d_name) / 	\
318315376Sdchagin    offsetof(struct l_dirent64, d_name);
319315376Sdchagin
320315376Sdchaginint
321315376Sdchaginlinux_getdents(struct thread *td, struct linux_getdents_args *args)
32214331Speter{
323111798Sdes	struct dirent *bdp;
32483221Smarcel	caddr_t inp, buf;		/* BSD-format */
32583221Smarcel	int len, reclen;		/* BSD-format */
32683221Smarcel	caddr_t outp;			/* Linux-format */
327315376Sdchagin	int resid, linuxreclen;		/* Linux-format */
328182892Srdivacky	caddr_t lbuf;			/* Linux-format */
329315376Sdchagin	long base;
330182892Srdivacky	struct l_dirent *linux_dirent;
331315376Sdchagin	int buflen, error;
332315376Sdchagin	size_t retval;
3339313Ssos
334315376Sdchagin#ifdef DEBUG
335315376Sdchagin	if (ldebug(getdents))
336315376Sdchagin		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
337315376Sdchagin#endif
338315376Sdchagin	buflen = LINUX_RECLEN_RATIO(args->count);
339315376Sdchagin	buflen = min(buflen, MAXBSIZE);
340315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
341160276Sjhb
342315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
343315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
344315376Sdchagin	if (error != 0) {
345315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
346315376Sdchagin		goto out1;
34789306Salfred	}
3489313Ssos
349315376Sdchagin	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
350315376Sdchagin
351315376Sdchagin	len = td->td_retval[0];
352315376Sdchagin	inp = buf;
353315376Sdchagin	outp = (caddr_t)args->dent;
354315376Sdchagin	resid = args->count;
355315376Sdchagin	retval = 0;
356315376Sdchagin
357315376Sdchagin	while (len > 0) {
358315376Sdchagin		bdp = (struct dirent *) inp;
359315376Sdchagin		reclen = bdp->d_reclen;
360315376Sdchagin		linuxreclen = LINUX_RECLEN(bdp->d_namlen);
361315376Sdchagin		/*
362315376Sdchagin		 * No more space in the user supplied dirent buffer.
363315376Sdchagin		 * Return EINVAL.
364315376Sdchagin		 */
365315376Sdchagin		if (resid < linuxreclen) {
366315376Sdchagin			error = EINVAL;
367315376Sdchagin			goto out;
368315376Sdchagin		}
369315376Sdchagin
370315376Sdchagin		linux_dirent = (struct l_dirent*)lbuf;
371315376Sdchagin		linux_dirent->d_ino = bdp->d_fileno;
372315376Sdchagin		linux_dirent->d_off = base + reclen;
373315376Sdchagin		linux_dirent->d_reclen = linuxreclen;
374315376Sdchagin		/*
375315376Sdchagin		 * Copy d_type to last byte of l_dirent buffer
376315376Sdchagin		 */
377315376Sdchagin		lbuf[linuxreclen - 1] = bdp->d_type;
378315376Sdchagin		strlcpy(linux_dirent->d_name, bdp->d_name,
379315376Sdchagin		    linuxreclen - offsetof(struct l_dirent, d_name)-1);
380315376Sdchagin		error = copyout(linux_dirent, outp, linuxreclen);
381315376Sdchagin		if (error != 0)
382315376Sdchagin			goto out;
383315376Sdchagin
384315376Sdchagin		inp += reclen;
385315376Sdchagin		base += reclen;
386315376Sdchagin		len -= reclen;
387315376Sdchagin
388315376Sdchagin		retval += linuxreclen;
389315376Sdchagin		outp += linuxreclen;
390315376Sdchagin		resid -= linuxreclen;
39189306Salfred	}
392315376Sdchagin	td->td_retval[0] = retval;
3939313Ssos
394315376Sdchaginout:
395320469Savg	free(lbuf, M_TEMP);
396315376Sdchaginout1:
397320469Savg	free(buf, M_TEMP);
398315376Sdchagin	return (error);
399315376Sdchagin}
4009313Ssos
401315376Sdchaginint
402315376Sdchaginlinux_getdents64(struct thread *td, struct linux_getdents64_args *args)
403315376Sdchagin{
404315376Sdchagin	struct dirent *bdp;
405315376Sdchagin	caddr_t inp, buf;		/* BSD-format */
406315376Sdchagin	int len, reclen;		/* BSD-format */
407315376Sdchagin	caddr_t outp;			/* Linux-format */
408315376Sdchagin	int resid, linuxreclen;		/* Linux-format */
409315376Sdchagin	caddr_t lbuf;			/* Linux-format */
410315376Sdchagin	long base;
411315376Sdchagin	struct l_dirent64 *linux_dirent64;
412315376Sdchagin	int buflen, error;
413315376Sdchagin	size_t retval;
414315376Sdchagin
415315376Sdchagin#ifdef DEBUG
416315376Sdchagin	if (ldebug(getdents64))
417315376Sdchagin		uprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
418315376Sdchagin#endif
419315376Sdchagin	buflen = LINUX_RECLEN64_RATIO(args->count);
42083221Smarcel	buflen = min(buflen, MAXBSIZE);
421315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
42283221Smarcel
423315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
424315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
425315376Sdchagin	if (error != 0) {
426315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
427315376Sdchagin		goto out1;
428315376Sdchagin	}
4299313Ssos
430315376Sdchagin	lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
4319313Ssos
432315376Sdchagin	len = td->td_retval[0];
43383221Smarcel	inp = buf;
43483221Smarcel	outp = (caddr_t)args->dirent;
435315376Sdchagin	resid = args->count;
436315376Sdchagin	retval = 0;
4379313Ssos
43883221Smarcel	while (len > 0) {
43983221Smarcel		bdp = (struct dirent *) inp;
44083221Smarcel		reclen = bdp->d_reclen;
441315376Sdchagin		linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
442315376Sdchagin		/*
443315376Sdchagin		 * No more space in the user supplied dirent buffer.
444315376Sdchagin		 * Return EINVAL.
445315376Sdchagin		 */
446315376Sdchagin		if (resid < linuxreclen) {
447315376Sdchagin			error = EINVAL;
44883221Smarcel			goto out;
44983221Smarcel		}
45083221Smarcel
451315376Sdchagin		linux_dirent64 = (struct l_dirent64*)lbuf;
452315376Sdchagin		linux_dirent64->d_ino = bdp->d_fileno;
453315376Sdchagin		linux_dirent64->d_off = base + reclen;
454315376Sdchagin		linux_dirent64->d_reclen = linuxreclen;
455315376Sdchagin		linux_dirent64->d_type = bdp->d_type;
456315376Sdchagin		strlcpy(linux_dirent64->d_name, bdp->d_name,
457315376Sdchagin		    linuxreclen - offsetof(struct l_dirent64, d_name));
458315376Sdchagin		error = copyout(linux_dirent64, outp, linuxreclen);
459315376Sdchagin		if (error != 0)
46083221Smarcel			goto out;
46183221Smarcel
46283221Smarcel		inp += reclen;
463315376Sdchagin		base += reclen;
464315376Sdchagin		len -= reclen;
46583221Smarcel
466315376Sdchagin		retval += linuxreclen;
46783221Smarcel		outp += linuxreclen;
46883221Smarcel		resid -= linuxreclen;
46910355Sswallace	}
470315376Sdchagin	td->td_retval[0] = retval;
4719313Ssos
4729313Ssosout:
473315376Sdchagin	free(lbuf, M_TEMP);
474315376Sdchaginout1:
475315376Sdchagin	free(buf, M_TEMP);
47683221Smarcel	return (error);
4779313Ssos}
47814331Speter
479315376Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
48083221Smarcelint
481315376Sdchaginlinux_readdir(struct thread *td, struct linux_readdir_args *args)
48283221Smarcel{
483315376Sdchagin	struct dirent *bdp;
484315376Sdchagin	caddr_t buf;			/* BSD-format */
485315376Sdchagin	int linuxreclen;		/* Linux-format */
486315376Sdchagin	caddr_t lbuf;			/* Linux-format */
487315376Sdchagin	long base;
488315376Sdchagin	struct l_dirent *linux_dirent;
489315376Sdchagin	int buflen, error;
49083221Smarcel
49183221Smarcel#ifdef DEBUG
492315376Sdchagin	if (ldebug(readdir))
493315376Sdchagin		printf(ARGS(readdir, "%d, *"), args->fd);
49483221Smarcel#endif
495315376Sdchagin	buflen = LINUX_RECLEN(LINUX_NAME_MAX);
496315376Sdchagin	buflen = LINUX_RECLEN_RATIO(buflen);
497315376Sdchagin	buf = malloc(buflen, M_TEMP, M_WAITOK);
49883221Smarcel
499315376Sdchagin	error = kern_getdirentries(td, args->fd, buf, buflen,
500315376Sdchagin	    &base, NULL, UIO_SYSSPACE);
501315376Sdchagin	if (error != 0) {
502315376Sdchagin		error = linux_getdents_error(td, args->fd, error);
503315376Sdchagin		goto out;
504315376Sdchagin	}
505315376Sdchagin	if (td->td_retval[0] == 0)
506315376Sdchagin		goto out;
50783221Smarcel
508315376Sdchagin	lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
50983221Smarcel
510315376Sdchagin	bdp = (struct dirent *) buf;
511315376Sdchagin	linuxreclen = LINUX_RECLEN(bdp->d_namlen);
51283221Smarcel
513315376Sdchagin	linux_dirent = (struct l_dirent*)lbuf;
514315376Sdchagin	linux_dirent->d_ino = bdp->d_fileno;
515315376Sdchagin	linux_dirent->d_off = linuxreclen;
516315376Sdchagin	linux_dirent->d_reclen = bdp->d_namlen;
517315376Sdchagin	strlcpy(linux_dirent->d_name, bdp->d_name,
518315376Sdchagin	    linuxreclen - offsetof(struct l_dirent, d_name));
519315376Sdchagin	error = copyout(linux_dirent, args->dent, linuxreclen);
520315376Sdchagin	if (error == 0)
521315376Sdchagin		td->td_retval[0] = linuxreclen;
522315376Sdchagin
523320469Savg	free(lbuf, M_TEMP);
524315376Sdchaginout:
525320469Savg	free(buf, M_TEMP);
526315376Sdchagin	return (error);
52783221Smarcel}
528315376Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
52983221Smarcel
530315376Sdchagin
53114331Speter/*
53214331Speter * These exist mainly for hooks for doing /compat/linux translation.
53314331Speter */
53414331Speter
53514331Speterint
53683366Sjulianlinux_access(struct thread *td, struct linux_access_args *args)
53714331Speter{
538102814Siedowse	char *path;
539102814Siedowse	int error;
54014331Speter
541346816Sdchagin	/* Linux convention. */
542227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
543162585Snetchild		return (EINVAL);
544162585Snetchild
545102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
54614331Speter
54714331Speter#ifdef DEBUG
54872543Sjlemon	if (ldebug(access))
549227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
55014331Speter#endif
551274476Skib	error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
552274476Skib	    args->amode);
553102814Siedowse	LFREEPATH(path);
554162585Snetchild
555102814Siedowse	return (error);
55614331Speter}
55714331Speter
55814331Speterint
559177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args)
560177997Skib{
561177997Skib	char *path;
562283428Sdchagin	int error, dfd;
563177997Skib
564346816Sdchagin	/* Linux convention. */
565227691Sed	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
566177997Skib		return (EINVAL);
567177997Skib
568177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
569177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
570177997Skib
571177997Skib#ifdef DEBUG
572346831Sdchagin	if (ldebug(faccessat))
573227691Sed		printf(ARGS(access, "%s, %d"), path, args->amode);
574177997Skib#endif
575177997Skib
576283428Sdchagin	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
577177997Skib	LFREEPATH(path);
578177997Skib
579177997Skib	return (error);
580177997Skib}
581177997Skib
582177997Skibint
58383366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args)
58414331Speter{
585102814Siedowse	char *path;
586102814Siedowse	int error;
587162201Snetchild	struct stat st;
58814331Speter
589102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
59014331Speter
59114331Speter#ifdef DEBUG
59272543Sjlemon	if (ldebug(unlink))
593102814Siedowse		printf(ARGS(unlink, "%s"), path);
59414331Speter#endif
59514331Speter
596274476Skib	error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
597274476Skib	if (error == EPERM) {
598162201Snetchild		/* Introduce POSIX noncompliant behaviour of Linux */
599274476Skib		if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
600274476Skib		    NULL) == 0) {
601162201Snetchild			if (S_ISDIR(st.st_mode))
602162201Snetchild				error = EISDIR;
603274476Skib		}
604274476Skib	}
605102814Siedowse	LFREEPATH(path);
606102814Siedowse	return (error);
60714331Speter}
60814331Speter
60914331Speterint
610177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
611177997Skib{
612177997Skib	char *path;
613177997Skib	int error, dfd;
614177997Skib	struct stat st;
615177997Skib
616177997Skib	if (args->flag & ~LINUX_AT_REMOVEDIR)
617177997Skib		return (EINVAL);
618177997Skib
619177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
620177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
621177997Skib
622177997Skib#ifdef DEBUG
623177997Skib	if (ldebug(unlinkat))
624177997Skib		printf(ARGS(unlinkat, "%s"), path);
625177997Skib#endif
626177997Skib
627177997Skib	if (args->flag & LINUX_AT_REMOVEDIR)
628177997Skib		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
629177997Skib	else
630202113Smckusick		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
631177997Skib	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
632177997Skib		/* Introduce POSIX noncompliant behaviour of Linux */
633177997Skib		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
634274476Skib		    UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
635177997Skib			error = EISDIR;
636177997Skib	}
637177997Skib	LFREEPATH(path);
638177997Skib	return (error);
639177997Skib}
640177997Skibint
64183366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args)
64214331Speter{
643102814Siedowse	char *path;
644102814Siedowse	int error;
64514331Speter
646102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
64714331Speter
64814331Speter#ifdef DEBUG
64972543Sjlemon	if (ldebug(chdir))
650102814Siedowse		printf(ARGS(chdir, "%s"), path);
65114331Speter#endif
652102814Siedowse	error = kern_chdir(td, path, UIO_SYSSPACE);
653102814Siedowse	LFREEPATH(path);
654102814Siedowse	return (error);
65514331Speter}
65614331Speter
65714331Speterint
65883366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args)
65914331Speter{
660102814Siedowse	char *path;
661102814Siedowse	int error;
66214331Speter
663102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
66414331Speter
66514331Speter#ifdef DEBUG
66672543Sjlemon	if (ldebug(chmod))
667102814Siedowse		printf(ARGS(chmod, "%s, %d"), path, args->mode);
66814331Speter#endif
669274476Skib	error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
670274476Skib	    args->mode, 0);
671102814Siedowse	LFREEPATH(path);
672102814Siedowse	return (error);
67314331Speter}
67414331Speter
67514331Speterint
676177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
677177997Skib{
678177997Skib	char *path;
679177997Skib	int error, dfd;
680177997Skib
681177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
682177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
683177997Skib
684177997Skib#ifdef DEBUG
685177997Skib	if (ldebug(fchmodat))
686177997Skib		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
687177997Skib#endif
688177997Skib
689177997Skib	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
690177997Skib	LFREEPATH(path);
691177997Skib	return (error);
692177997Skib}
693177997Skib
694177997Skibint
69583366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args)
69614331Speter{
697102814Siedowse	char *path;
698102814Siedowse	int error;
69914331Speter
700102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
70114331Speter
70214331Speter#ifdef DEBUG
70372543Sjlemon	if (ldebug(mkdir))
704102814Siedowse		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
70514331Speter#endif
706274476Skib	error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
707102814Siedowse	LFREEPATH(path);
708102814Siedowse	return (error);
70914331Speter}
71014331Speter
71114331Speterint
712177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
713177997Skib{
714177997Skib	char *path;
715177997Skib	int error, dfd;
716177997Skib
717177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
718177997Skib	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
719177997Skib
720177997Skib#ifdef DEBUG
721177997Skib	if (ldebug(mkdirat))
722177997Skib		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
723177997Skib#endif
724177997Skib	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
725177997Skib	LFREEPATH(path);
726177997Skib	return (error);
727177997Skib}
728177997Skib
729177997Skibint
73083366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args)
73114331Speter{
732102814Siedowse	char *path;
733102814Siedowse	int error;
73414331Speter
735102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
73614331Speter
73714331Speter#ifdef DEBUG
73872543Sjlemon	if (ldebug(rmdir))
739102814Siedowse		printf(ARGS(rmdir, "%s"), path);
74014331Speter#endif
741274476Skib	error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
742102814Siedowse	LFREEPATH(path);
743102814Siedowse	return (error);
74414331Speter}
74514331Speter
74614331Speterint
74783366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args)
74814331Speter{
749102814Siedowse	char *from, *to;
750102814Siedowse	int error;
75114331Speter
752102814Siedowse	LCONVPATHEXIST(td, args->from, &from);
753102814Siedowse	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
754177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
755102814Siedowse	if (to == NULL) {
756102814Siedowse		LFREEPATH(from);
757102814Siedowse		return (error);
758102814Siedowse	}
75914331Speter
76014331Speter#ifdef DEBUG
76172543Sjlemon	if (ldebug(rename))
762102814Siedowse		printf(ARGS(rename, "%s, %s"), from, to);
76314331Speter#endif
764274476Skib	error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
765102814Siedowse	LFREEPATH(from);
766102814Siedowse	LFREEPATH(to);
767102814Siedowse	return (error);
76814331Speter}
76914331Speter
77014331Speterint
771177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args)
772177997Skib{
773177997Skib	char *from, *to;
774177997Skib	int error, olddfd, newdfd;
775177997Skib
776177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
777177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
778177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
779177997Skib	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
780177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
781177997Skib	if (to == NULL) {
782177997Skib		LFREEPATH(from);
783177997Skib		return (error);
784177997Skib	}
785177997Skib
786177997Skib#ifdef DEBUG
787177997Skib	if (ldebug(renameat))
788177997Skib		printf(ARGS(renameat, "%s, %s"), from, to);
789177997Skib#endif
790177997Skib	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
791177997Skib	LFREEPATH(from);
792177997Skib	LFREEPATH(to);
793177997Skib	return (error);
794177997Skib}
795177997Skib
796177997Skibint
79783366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args)
79814331Speter{
799102814Siedowse	char *path, *to;
800102814Siedowse	int error;
80114331Speter
802102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
803102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
804177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
805102814Siedowse	if (to == NULL) {
806102814Siedowse		LFREEPATH(path);
807102814Siedowse		return (error);
808102814Siedowse	}
80914331Speter
81014331Speter#ifdef DEBUG
81172543Sjlemon	if (ldebug(symlink))
812102814Siedowse		printf(ARGS(symlink, "%s, %s"), path, to);
81314331Speter#endif
814274476Skib	error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
815102814Siedowse	LFREEPATH(path);
816102814Siedowse	LFREEPATH(to);
817102814Siedowse	return (error);
81814331Speter}
81914331Speter
82014331Speterint
821177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
822177997Skib{
823177997Skib	char *path, *to;
824177997Skib	int error, dfd;
825177997Skib
826177997Skib	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
827319573Sdchagin	LCONVPATHEXIST(td, args->oldname, &path);
828177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
829177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
830177997Skib	if (to == NULL) {
831177997Skib		LFREEPATH(path);
832177997Skib		return (error);
833177997Skib	}
834177997Skib
835177997Skib#ifdef DEBUG
836177997Skib	if (ldebug(symlinkat))
837177997Skib		printf(ARGS(symlinkat, "%s, %s"), path, to);
838177997Skib#endif
839177997Skib
840177997Skib	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
841177997Skib	LFREEPATH(path);
842177997Skib	LFREEPATH(to);
843177997Skib	return (error);
844177997Skib}
845177997Skib
846177997Skibint
84783366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args)
84814331Speter{
849102814Siedowse	char *name;
850102814Siedowse	int error;
85114331Speter
852102814Siedowse	LCONVPATHEXIST(td, args->name, &name);
85314331Speter
85414331Speter#ifdef DEBUG
85572543Sjlemon	if (ldebug(readlink))
856102814Siedowse		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
857102814Siedowse		    args->count);
85814331Speter#endif
859274476Skib	error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
860274476Skib	    args->buf, UIO_USERSPACE, args->count);
861102814Siedowse	LFREEPATH(name);
862102814Siedowse	return (error);
86314331Speter}
86414331Speter
86514331Speterint
866177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
867177997Skib{
868177997Skib	char *name;
869177997Skib	int error, dfd;
870177997Skib
871177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
872177997Skib	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
873177997Skib
874177997Skib#ifdef DEBUG
875177997Skib	if (ldebug(readlinkat))
876177997Skib		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
877177997Skib		    args->bufsiz);
878177997Skib#endif
879177997Skib
880177997Skib	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
881177997Skib	    UIO_USERSPACE, args->bufsiz);
882177997Skib	LFREEPATH(name);
883177997Skib	return (error);
884177997Skib}
885178439Srdivacky
886177997Skibint
88783366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args)
88814331Speter{
889102814Siedowse	char *path;
890102814Siedowse	int error;
89114331Speter
892102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
89314331Speter
89414331Speter#ifdef DEBUG
89572543Sjlemon	if (ldebug(truncate))
896102814Siedowse		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
89714331Speter#endif
89814331Speter
899102814Siedowse	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
900102814Siedowse	LFREEPATH(path);
901102814Siedowse	return (error);
90214331Speter}
90314331Speter
904283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
90549662Smarcelint
906178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args)
907178439Srdivacky{
908178439Srdivacky	char *path;
909178439Srdivacky	int error;
910178439Srdivacky
911178439Srdivacky	LCONVPATHEXIST(td, args->path, &path);
912178439Srdivacky
913178439Srdivacky#ifdef DEBUG
914178439Srdivacky	if (ldebug(truncate64))
915178439Srdivacky		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
916178439Srdivacky#endif
917178439Srdivacky
918178439Srdivacky	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
919178439Srdivacky	LFREEPATH(path);
920178439Srdivacky	return (error);
921178439Srdivacky}
922283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
923283415Sdchagin
924178439Srdivackyint
925156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
926156842Snetchild{
927300411Sdchagin
928315548Strasz	return (kern_ftruncate(td, args->fd, args->length));
929156842Snetchild}
930156842Snetchild
931156842Snetchildint
93283366Sjulianlinux_link(struct thread *td, struct linux_link_args *args)
93349662Smarcel{
934102814Siedowse	char *path, *to;
935102814Siedowse	int error;
93649662Smarcel
937102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
938102814Siedowse	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
939177997Skib	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
940102814Siedowse	if (to == NULL) {
941102814Siedowse		LFREEPATH(path);
942102814Siedowse		return (error);
943102814Siedowse	}
94449662Smarcel
94549662Smarcel#ifdef DEBUG
94672543Sjlemon	if (ldebug(link))
947102814Siedowse		printf(ARGS(link, "%s, %s"), path, to);
94849662Smarcel#endif
949274476Skib	error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
950274476Skib	    FOLLOW);
951102814Siedowse	LFREEPATH(path);
952102814Siedowse	LFREEPATH(to);
953102814Siedowse	return (error);
95449662Smarcel}
95549788Smarcel
95653713Smarcelint
957177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args)
958177997Skib{
959177997Skib	char *path, *to;
960227693Sed	int error, olddfd, newdfd, follow;
961177997Skib
962227693Sed	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
963177997Skib		return (EINVAL);
964177997Skib
965177997Skib	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
966177997Skib	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
967177997Skib	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
968177997Skib	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
969177997Skib	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
970177997Skib	if (to == NULL) {
971177997Skib		LFREEPATH(path);
972177997Skib		return (error);
973177997Skib	}
974177997Skib
975177997Skib#ifdef DEBUG
976177997Skib	if (ldebug(linkat))
977177997Skib		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
978227693Sed			args->newdfd, to, args->flag);
979177997Skib#endif
980177997Skib
981227693Sed	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
982227693Sed	    FOLLOW;
983227693Sed	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
984177997Skib	LFREEPATH(path);
985177997Skib	LFREEPATH(to);
986177997Skib	return (error);
987177997Skib}
988177997Skib
989177997Skibint
99083366Sjulianlinux_fdatasync(td, uap)
99183366Sjulian	struct thread *td;
99253713Smarcel	struct linux_fdatasync_args *uap;
99353713Smarcel{
99453713Smarcel
995304987Skib	return (kern_fsync(td, uap->fd, false));
99653713Smarcel}
99763285Smarcel
99863285Smarcelint
999315553Straszlinux_pread(struct thread *td, struct linux_pread_args *uap)
100063285Smarcel{
1001255219Spjd	cap_rights_t rights;
1002162585Snetchild	struct vnode *vp;
1003162585Snetchild	int error;
100463285Smarcel
1005315553Strasz	error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
1006162585Snetchild	if (error == 0) {
1007346816Sdchagin		/* This seems to violate POSIX but Linux does it. */
1008255219Spjd		error = fgetvp(td, uap->fd,
1009255219Spjd		    cap_rights_init(&rights, CAP_PREAD), &vp);
1010255219Spjd		if (error != 0)
1011247602Spjd			return (error);
1012162585Snetchild		if (vp->v_type == VDIR) {
1013247602Spjd			vrele(vp);
1014162585Snetchild			return (EISDIR);
1015162585Snetchild		}
1016162585Snetchild		vrele(vp);
1017162585Snetchild	}
1018162585Snetchild	return (error);
101963285Smarcel}
102063285Smarcel
102163285Smarcelint
1022315553Straszlinux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
102363285Smarcel{
102463285Smarcel
1025315553Strasz	return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
102663285Smarcel}
102772538Sjlemon
102872538Sjlemonint
1029314909Smmokhilinux_preadv(struct thread *td, struct linux_preadv_args *uap)
1030314909Smmokhi{
1031314909Smmokhi	struct uio *auio;
1032314909Smmokhi	int error;
1033314909Smmokhi	off_t offset;
1034314909Smmokhi
1035314909Smmokhi	/*
1036314909Smmokhi	 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
1037314909Smmokhi	 * pos_l and pos_h, respectively, contain the
1038314909Smmokhi	 * low order and high order 32 bits of offset.
1039314909Smmokhi	 */
1040314909Smmokhi	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
1041314909Smmokhi	    (sizeof(offset) * 4)) | uap->pos_l;
1042314909Smmokhi	if (offset < 0)
1043314909Smmokhi		return (EINVAL);
1044314909Smmokhi#ifdef COMPAT_LINUX32
1045314909Smmokhi	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1046314909Smmokhi#else
1047314909Smmokhi	error = copyinuio(uap->vec, uap->vlen, &auio);
1048314909Smmokhi#endif
1049314909Smmokhi	if (error != 0)
1050314909Smmokhi		return (error);
1051314909Smmokhi	error = kern_preadv(td, uap->fd, auio, offset);
1052314909Smmokhi	free(auio, M_IOV);
1053314909Smmokhi	return (error);
1054314909Smmokhi}
1055314909Smmokhi
1056314909Smmokhiint
1057314909Smmokhilinux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
1058314909Smmokhi{
1059314909Smmokhi	struct uio *auio;
1060314909Smmokhi	int error;
1061314909Smmokhi	off_t offset;
1062314909Smmokhi
1063314909Smmokhi	/*
1064314909Smmokhi	 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
1065314909Smmokhi	 * pos_l and pos_h, respectively, contain the
1066314909Smmokhi	 * low order and high order 32 bits of offset.
1067314909Smmokhi	 */
1068314909Smmokhi	offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
1069314909Smmokhi	    (sizeof(offset) * 4)) | uap->pos_l;
1070314909Smmokhi	if (offset < 0)
1071314909Smmokhi		return (EINVAL);
1072314909Smmokhi#ifdef COMPAT_LINUX32
1073314909Smmokhi	error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1074314909Smmokhi#else
1075314909Smmokhi	error = copyinuio(uap->vec, uap->vlen, &auio);
1076314909Smmokhi#endif
1077314909Smmokhi	if (error != 0)
1078314909Smmokhi		return (error);
1079314909Smmokhi	error = kern_pwritev(td, uap->fd, auio, offset);
1080314909Smmokhi	free(auio, M_IOV);
1081314909Smmokhi	return (error);
1082314909Smmokhi}
1083314909Smmokhi
1084314909Smmokhiint
108583366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args)
108672538Sjlemon{
1087111798Sdes	char fstypename[MFSNAMELEN];
1088111798Sdes	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
108973286Sadrian	int error;
109073286Sadrian	int fsflags;
109172538Sjlemon
1092111798Sdes	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
109373286Sadrian	    NULL);
109472538Sjlemon	if (error)
1095111798Sdes		return (error);
1096127057Stjr	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
109772538Sjlemon	if (error)
1098111798Sdes		return (error);
1099127057Stjr	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
110072538Sjlemon	if (error)
1101111798Sdes		return (error);
110272538Sjlemon
110372538Sjlemon#ifdef DEBUG
110472538Sjlemon	if (ldebug(mount))
110572538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
110672538Sjlemon		    fstypename, mntfromname, mntonname);
110772538Sjlemon#endif
110872538Sjlemon
110972538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
1110127059Stjr		strcpy(fstypename, "ext2fs");
111172538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
1112127059Stjr		strcpy(fstypename, "linprocfs");
1113190445Sambrisko	} else if (strcmp(fstypename, "vfat") == 0) {
1114190445Sambrisko		strcpy(fstypename, "msdosfs");
111572538Sjlemon	}
111672538Sjlemon
111773286Sadrian	fsflags = 0;
111872538Sjlemon
111972538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
112072538Sjlemon		/*
112172538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
112272538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
112372538Sjlemon		 */
112472538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
1125111798Sdes			fsflags |= MNT_RDONLY;
112672538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
1127111798Sdes			fsflags |= MNT_NOSUID;
112872538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
1129111798Sdes			fsflags |= MNT_NOEXEC;
113072538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
1131111798Sdes			fsflags |= MNT_UPDATE;
113272538Sjlemon	}
113372538Sjlemon
1134281689Strasz	error = kernel_vmount(fsflags,
1135281689Strasz	    "fstype", fstypename,
1136281689Strasz	    "fspath", mntonname,
1137281689Strasz	    "from", mntfromname,
1138281689Strasz	    NULL);
1139127059Stjr	return (error);
114072538Sjlemon}
114172538Sjlemon
1142283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
114372538Sjlemonint
114483366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args)
114572538Sjlemon{
114683221Smarcel	struct linux_umount_args args2;
114772538Sjlemon
114872538Sjlemon	args2.path = args->path;
114972538Sjlemon	args2.flags = 0;
115083366Sjulian	return (linux_umount(td, &args2));
115172538Sjlemon}
1152283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
115372538Sjlemon
115472538Sjlemonint
115583366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args)
115672538Sjlemon{
115772538Sjlemon	struct unmount_args bsd;
115872538Sjlemon
115972538Sjlemon	bsd.path = args->path;
116072538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
1161225617Skmacy	return (sys_unmount(td, &bsd));
116272538Sjlemon}
116383221Smarcel
116483221Smarcel/*
116583221Smarcel * fcntl family of syscalls
116683221Smarcel */
116783221Smarcel
116883221Smarcelstruct l_flock {
116983221Smarcel	l_short		l_type;
117083221Smarcel	l_short		l_whence;
117183221Smarcel	l_off_t		l_start;
117283221Smarcel	l_off_t		l_len;
117383221Smarcel	l_pid_t		l_pid;
1174133816Stjr}
1175140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1176133816Stjr__packed
1177133816Stjr#endif
1178133816Stjr;
117983221Smarcel
118083221Smarcelstatic void
118183221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
118283221Smarcel{
118383221Smarcel	switch (linux_flock->l_type) {
118483221Smarcel	case LINUX_F_RDLCK:
118583221Smarcel		bsd_flock->l_type = F_RDLCK;
118683221Smarcel		break;
118783221Smarcel	case LINUX_F_WRLCK:
118883221Smarcel		bsd_flock->l_type = F_WRLCK;
118983221Smarcel		break;
119083221Smarcel	case LINUX_F_UNLCK:
119183221Smarcel		bsd_flock->l_type = F_UNLCK;
119283221Smarcel		break;
119383221Smarcel	default:
119483221Smarcel		bsd_flock->l_type = -1;
119583221Smarcel		break;
119683221Smarcel	}
119783221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
119883221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
119983221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
120083221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1201177633Sdfr	bsd_flock->l_sysid = 0;
120283221Smarcel}
120383221Smarcel
120483221Smarcelstatic void
120583221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
120683221Smarcel{
120783221Smarcel	switch (bsd_flock->l_type) {
120883221Smarcel	case F_RDLCK:
120983221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
121083221Smarcel		break;
121183221Smarcel	case F_WRLCK:
121283221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
121383221Smarcel		break;
121483221Smarcel	case F_UNLCK:
121583221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
121683221Smarcel		break;
121783221Smarcel	}
121883221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
121983221Smarcel	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
122083221Smarcel	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
122183221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
122283221Smarcel}
122383221Smarcel
1224140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
122583221Smarcelstruct l_flock64 {
122683221Smarcel	l_short		l_type;
122783221Smarcel	l_short		l_whence;
122883221Smarcel	l_loff_t	l_start;
122983221Smarcel	l_loff_t	l_len;
123083221Smarcel	l_pid_t		l_pid;
1231133816Stjr}
1232140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32)
1233133816Stjr__packed
1234133816Stjr#endif
1235133816Stjr;
123683221Smarcel
123783221Smarcelstatic void
123883221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
123983221Smarcel{
124083221Smarcel	switch (linux_flock->l_type) {
124183221Smarcel	case LINUX_F_RDLCK:
124283221Smarcel		bsd_flock->l_type = F_RDLCK;
124383221Smarcel		break;
124483221Smarcel	case LINUX_F_WRLCK:
124583221Smarcel		bsd_flock->l_type = F_WRLCK;
124683221Smarcel		break;
124783221Smarcel	case LINUX_F_UNLCK:
124883221Smarcel		bsd_flock->l_type = F_UNLCK;
124983221Smarcel		break;
125083221Smarcel	default:
125183221Smarcel		bsd_flock->l_type = -1;
125283221Smarcel		break;
125383221Smarcel	}
125483221Smarcel	bsd_flock->l_whence = linux_flock->l_whence;
125583221Smarcel	bsd_flock->l_start = (off_t)linux_flock->l_start;
125683221Smarcel	bsd_flock->l_len = (off_t)linux_flock->l_len;
125783221Smarcel	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1258177633Sdfr	bsd_flock->l_sysid = 0;
125983221Smarcel}
126083221Smarcel
126183221Smarcelstatic void
126283221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
126383221Smarcel{
126483221Smarcel	switch (bsd_flock->l_type) {
126583221Smarcel	case F_RDLCK:
126683221Smarcel		linux_flock->l_type = LINUX_F_RDLCK;
126783221Smarcel		break;
126883221Smarcel	case F_WRLCK:
126983221Smarcel		linux_flock->l_type = LINUX_F_WRLCK;
127083221Smarcel		break;
127183221Smarcel	case F_UNLCK:
127283221Smarcel		linux_flock->l_type = LINUX_F_UNLCK;
127383221Smarcel		break;
127483221Smarcel	}
127583221Smarcel	linux_flock->l_whence = bsd_flock->l_whence;
127683221Smarcel	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
127783221Smarcel	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
127883221Smarcel	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
127983221Smarcel}
1280133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
128183221Smarcel
128283221Smarcelstatic int
1283283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args)
128483221Smarcel{
1285107680Siedowse	struct l_flock linux_flock;
1286107680Siedowse	struct flock bsd_flock;
1287255219Spjd	cap_rights_t rights;
128883221Smarcel	struct file *fp;
1289102872Siedowse	long arg;
129083221Smarcel	int error, result;
129183221Smarcel
129283221Smarcel	switch (args->cmd) {
129383221Smarcel	case LINUX_F_DUPFD:
1294102872Siedowse		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
129583221Smarcel
129683221Smarcel	case LINUX_F_GETFD:
1297102872Siedowse		return (kern_fcntl(td, args->fd, F_GETFD, 0));
129883221Smarcel
129983221Smarcel	case LINUX_F_SETFD:
1300102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
130183221Smarcel
130283221Smarcel	case LINUX_F_GETFL:
1303102872Siedowse		error = kern_fcntl(td, args->fd, F_GETFL, 0);
130483366Sjulian		result = td->td_retval[0];
130583366Sjulian		td->td_retval[0] = 0;
130683221Smarcel		if (result & O_RDONLY)
130783366Sjulian			td->td_retval[0] |= LINUX_O_RDONLY;
130883221Smarcel		if (result & O_WRONLY)
130983366Sjulian			td->td_retval[0] |= LINUX_O_WRONLY;
131083221Smarcel		if (result & O_RDWR)
131183366Sjulian			td->td_retval[0] |= LINUX_O_RDWR;
131283221Smarcel		if (result & O_NDELAY)
131383366Sjulian			td->td_retval[0] |= LINUX_O_NONBLOCK;
131483221Smarcel		if (result & O_APPEND)
131583366Sjulian			td->td_retval[0] |= LINUX_O_APPEND;
131683221Smarcel		if (result & O_FSYNC)
131783366Sjulian			td->td_retval[0] |= LINUX_O_SYNC;
131883221Smarcel		if (result & O_ASYNC)
131983366Sjulian			td->td_retval[0] |= LINUX_FASYNC;
1320144987Smdodd#ifdef LINUX_O_NOFOLLOW
1321144987Smdodd		if (result & O_NOFOLLOW)
1322144987Smdodd			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1323144987Smdodd#endif
1324144987Smdodd#ifdef LINUX_O_DIRECT
1325144987Smdodd		if (result & O_DIRECT)
1326144987Smdodd			td->td_retval[0] |= LINUX_O_DIRECT;
1327144987Smdodd#endif
132883221Smarcel		return (error);
132983221Smarcel
133083221Smarcel	case LINUX_F_SETFL:
1331102872Siedowse		arg = 0;
133283221Smarcel		if (args->arg & LINUX_O_NDELAY)
1333102872Siedowse			arg |= O_NONBLOCK;
133483221Smarcel		if (args->arg & LINUX_O_APPEND)
1335102872Siedowse			arg |= O_APPEND;
133683221Smarcel		if (args->arg & LINUX_O_SYNC)
1337102872Siedowse			arg |= O_FSYNC;
133883221Smarcel		if (args->arg & LINUX_FASYNC)
1339102872Siedowse			arg |= O_ASYNC;
1340144987Smdodd#ifdef LINUX_O_NOFOLLOW
1341144987Smdodd		if (args->arg & LINUX_O_NOFOLLOW)
1342144987Smdodd			arg |= O_NOFOLLOW;
1343144987Smdodd#endif
1344144987Smdodd#ifdef LINUX_O_DIRECT
1345144987Smdodd		if (args->arg & LINUX_O_DIRECT)
1346144987Smdodd			arg |= O_DIRECT;
1347144987Smdodd#endif
1348102872Siedowse		return (kern_fcntl(td, args->fd, F_SETFL, arg));
134983221Smarcel
1350107680Siedowse	case LINUX_F_GETLK:
1351111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1352107680Siedowse		    sizeof(linux_flock));
1353107680Siedowse		if (error)
1354107680Siedowse			return (error);
1355107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1356107680Siedowse		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1357107680Siedowse		if (error)
1358107680Siedowse			return (error);
1359107680Siedowse		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1360111797Sdes		return (copyout(&linux_flock, (void *)args->arg,
1361107680Siedowse		    sizeof(linux_flock)));
1362107680Siedowse
1363107680Siedowse	case LINUX_F_SETLK:
1364111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1365107680Siedowse		    sizeof(linux_flock));
1366107680Siedowse		if (error)
1367107680Siedowse			return (error);
1368107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1369107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLK,
1370107680Siedowse		    (intptr_t)&bsd_flock));
1371107680Siedowse
1372107680Siedowse	case LINUX_F_SETLKW:
1373111797Sdes		error = copyin((void *)args->arg, &linux_flock,
1374107680Siedowse		    sizeof(linux_flock));
1375107680Siedowse		if (error)
1376107680Siedowse			return (error);
1377107680Siedowse		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1378107680Siedowse		return (kern_fcntl(td, args->fd, F_SETLKW,
1379107680Siedowse		     (intptr_t)&bsd_flock));
1380107680Siedowse
138183221Smarcel	case LINUX_F_GETOWN:
1382102872Siedowse		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
138383221Smarcel
138483221Smarcel	case LINUX_F_SETOWN:
138583221Smarcel		/*
138683221Smarcel		 * XXX some Linux applications depend on F_SETOWN having no
138783221Smarcel		 * significant effect for pipes (SIGIO is not delivered for
138883221Smarcel		 * pipes under Linux-2.2.35 at least).
138983221Smarcel		 */
1390255219Spjd		error = fget(td, args->fd,
1391255219Spjd		    cap_rights_init(&rights, 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));
1401283439Sdchagin
1402283439Sdchagin	case LINUX_F_DUPFD_CLOEXEC:
1403283439Sdchagin		return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
140483221Smarcel	}
140583221Smarcel
140683221Smarcel	return (EINVAL);
140783221Smarcel}
140883221Smarcel
140983221Smarcelint
141083366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args)
141183221Smarcel{
141283221Smarcel
141383221Smarcel#ifdef DEBUG
141483221Smarcel	if (ldebug(fcntl))
141583221Smarcel		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
141683221Smarcel#endif
141783221Smarcel
1418283415Sdchagin	return (fcntl_common(td, args));
141983221Smarcel}
142083221Smarcel
1421140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
142283221Smarcelint
142383366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
142483221Smarcel{
142583221Smarcel	struct l_flock64 linux_flock;
1426102872Siedowse	struct flock bsd_flock;
1427283415Sdchagin	struct linux_fcntl_args fcntl_args;
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
1468283415Sdchagin	fcntl_args.fd = args->fd;
1469283415Sdchagin	fcntl_args.cmd = args->cmd;
1470283415Sdchagin	fcntl_args.arg = args->arg;
1471283415Sdchagin	return (fcntl_common(td, &fcntl_args));
147283221Smarcel}
1473133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
147485022Smarcel
147585022Smarcelint
147685022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args)
147785022Smarcel{
1478102814Siedowse	char *path;
1479102814Siedowse	int error;
148085022Smarcel
1481102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
148285022Smarcel
148385022Smarcel#ifdef DEBUG
148485022Smarcel	if (ldebug(chown))
1485102814Siedowse		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
148685022Smarcel#endif
1487274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1488274476Skib	    args->gid, 0);
1489102814Siedowse	LFREEPATH(path);
1490102814Siedowse	return (error);
149185022Smarcel}
149285022Smarcel
149385022Smarcelint
1494177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1495177997Skib{
1496177997Skib	char *path;
1497227693Sed	int error, dfd, flag;
1498177997Skib
1499177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1500177997Skib		return (EINVAL);
1501177997Skib
1502177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1503177997Skib	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1504177997Skib
1505177997Skib#ifdef DEBUG
1506177997Skib	if (ldebug(fchownat))
1507177997Skib		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1508177997Skib#endif
1509177997Skib
1510227693Sed	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1511177997Skib	    AT_SYMLINK_NOFOLLOW;
1512177997Skib	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1513227693Sed	    flag);
1514177997Skib	LFREEPATH(path);
1515177997Skib	return (error);
1516177997Skib}
1517177997Skib
1518177997Skibint
151985022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args)
152085022Smarcel{
1521102814Siedowse	char *path;
1522102814Siedowse	int error;
152385022Smarcel
1524102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
152585022Smarcel
152685022Smarcel#ifdef DEBUG
152785022Smarcel	if (ldebug(lchown))
1528102814Siedowse		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
152985022Smarcel#endif
1530274476Skib	error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1531274476Skib	    args->gid, AT_SYMLINK_NOFOLLOW);
1532102814Siedowse	LFREEPATH(path);
1533102814Siedowse	return (error);
153485022Smarcel}
1535228957Sjhb
1536228957Sjhbstatic int
1537228957Sjhbconvert_fadvice(int advice)
1538228957Sjhb{
1539228957Sjhb	switch (advice) {
1540228957Sjhb	case LINUX_POSIX_FADV_NORMAL:
1541228957Sjhb		return (POSIX_FADV_NORMAL);
1542228957Sjhb	case LINUX_POSIX_FADV_RANDOM:
1543228957Sjhb		return (POSIX_FADV_RANDOM);
1544228957Sjhb	case LINUX_POSIX_FADV_SEQUENTIAL:
1545228957Sjhb		return (POSIX_FADV_SEQUENTIAL);
1546228957Sjhb	case LINUX_POSIX_FADV_WILLNEED:
1547228957Sjhb		return (POSIX_FADV_WILLNEED);
1548228957Sjhb	case LINUX_POSIX_FADV_DONTNEED:
1549228957Sjhb		return (POSIX_FADV_DONTNEED);
1550228957Sjhb	case LINUX_POSIX_FADV_NOREUSE:
1551228957Sjhb		return (POSIX_FADV_NOREUSE);
1552228957Sjhb	default:
1553228957Sjhb		return (-1);
1554228957Sjhb	}
1555228957Sjhb}
1556228957Sjhb
1557228957Sjhbint
1558228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1559228957Sjhb{
1560228957Sjhb	int advice;
1561228957Sjhb
1562228957Sjhb	advice = convert_fadvice(args->advice);
1563228957Sjhb	if (advice == -1)
1564228957Sjhb		return (EINVAL);
1565228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1566228957Sjhb	    advice));
1567228957Sjhb}
1568228957Sjhb
1569283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1570228957Sjhbint
1571228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1572228957Sjhb{
1573228957Sjhb	int advice;
1574228957Sjhb
1575228957Sjhb	advice = convert_fadvice(args->advice);
1576228957Sjhb	if (advice == -1)
1577228957Sjhb		return (EINVAL);
1578228957Sjhb	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1579228957Sjhb	    advice));
1580228957Sjhb}
1581283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1582234352Sjkim
1583234352Sjkimint
1584234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args)
1585234352Sjkim{
1586234352Sjkim	int fildes[2];
1587234352Sjkim	int error;
1588234352Sjkim
1589234352Sjkim#ifdef DEBUG
1590234352Sjkim	if (ldebug(pipe))
1591234352Sjkim		printf(ARGS(pipe, "*"));
1592234352Sjkim#endif
1593234352Sjkim
1594286021Sed	error = kern_pipe(td, fildes, 0, NULL, NULL);
1595315538Strasz	if (error != 0)
1596234352Sjkim		return (error);
1597234352Sjkim
1598315538Strasz	error = copyout(fildes, args->pipefds, sizeof(fildes));
1599315538Strasz	if (error != 0) {
1600315538Strasz		(void)kern_close(td, fildes[0]);
1601315538Strasz		(void)kern_close(td, fildes[1]);
1602315538Strasz	}
1603315538Strasz
1604315538Strasz	return (error);
1605234352Sjkim}
1606234352Sjkim
1607234352Sjkimint
1608234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1609234352Sjkim{
1610234352Sjkim	int fildes[2];
1611234352Sjkim	int error, flags;
1612234352Sjkim
1613234352Sjkim#ifdef DEBUG
1614234352Sjkim	if (ldebug(pipe2))
1615234352Sjkim		printf(ARGS(pipe2, "*, %d"), args->flags);
1616234352Sjkim#endif
1617234352Sjkim
1618234352Sjkim	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1619234352Sjkim		return (EINVAL);
1620234352Sjkim
1621234352Sjkim	flags = 0;
1622234352Sjkim	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1623234352Sjkim		flags |= O_NONBLOCK;
1624234352Sjkim	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1625234352Sjkim		flags |= O_CLOEXEC;
1626286021Sed	error = kern_pipe(td, fildes, flags, NULL, NULL);
1627315538Strasz	if (error != 0)
1628234352Sjkim		return (error);
1629234352Sjkim
1630315538Strasz	error = copyout(fildes, args->pipefds, sizeof(fildes));
1631315538Strasz	if (error != 0) {
1632315538Strasz		(void)kern_close(td, fildes[0]);
1633315538Strasz		(void)kern_close(td, fildes[1]);
1634315538Strasz	}
1635315538Strasz
1636315538Strasz	return (error);
1637234352Sjkim}
1638283399Sdchagin
1639283399Sdchaginint
1640283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args)
1641283399Sdchagin{
1642283399Sdchagin	int cmd;
1643283399Sdchagin	intptr_t newfd;
1644283399Sdchagin
1645283399Sdchagin	if (args->oldfd == args->newfd)
1646283399Sdchagin		return (EINVAL);
1647283399Sdchagin	if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1648283399Sdchagin		return (EINVAL);
1649283399Sdchagin	if (args->flags & LINUX_O_CLOEXEC)
1650283399Sdchagin		cmd = F_DUP2FD_CLOEXEC;
1651283399Sdchagin	else
1652283399Sdchagin		cmd = F_DUP2FD;
1653283399Sdchagin
1654283399Sdchagin	newfd = args->newfd;
1655283399Sdchagin	return (kern_fcntl(td, args->oldfd, cmd, newfd));
1656283399Sdchagin}
1657283465Sdchagin
1658283465Sdchaginint
1659283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1660283465Sdchagin{
1661283465Sdchagin
1662283465Sdchagin	/*
1663283465Sdchagin	 * We emulate only posix_fallocate system call for which
1664283465Sdchagin	 * mode should be 0.
1665283465Sdchagin	 */
1666283465Sdchagin	if (args->mode != 0)
1667283465Sdchagin		return (ENOSYS);
1668283465Sdchagin
1669283465Sdchagin	return (kern_posix_fallocate(td, args->fd, args->offset,
1670283465Sdchagin	    args->len));
1671283465Sdchagin}
1672