linux_file.c revision 238029
1/*-
2 * Copyright (c) 1994-1995 S��ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/compat/linux/linux_file.c 238029 2012-07-02 21:01:03Z kib $");
31
32#include "opt_compat.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/capability.h>
37#include <sys/conf.h>
38#include <sys/dirent.h>
39#include <sys/fcntl.h>
40#include <sys/file.h>
41#include <sys/filedesc.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mount.h>
45#include <sys/mutex.h>
46#include <sys/namei.h>
47#include <sys/proc.h>
48#include <sys/stat.h>
49#include <sys/sx.h>
50#include <sys/syscallsubr.h>
51#include <sys/sysproto.h>
52#include <sys/tty.h>
53#include <sys/unistd.h>
54#include <sys/vnode.h>
55
56#include <security/mac/mac_framework.h>
57
58#include <ufs/ufs/extattr.h>
59#include <ufs/ufs/quota.h>
60#include <ufs/ufs/ufsmount.h>
61
62#ifdef COMPAT_LINUX32
63#include <machine/../linux32/linux.h>
64#include <machine/../linux32/linux32_proto.h>
65#else
66#include <machine/../linux/linux.h>
67#include <machine/../linux/linux_proto.h>
68#endif
69#include <compat/linux/linux_util.h>
70#include <compat/linux/linux_file.h>
71
72/* XXX */
73int	do_pipe(struct thread *td, int fildes[2], int flags);
74
75int
76linux_creat(struct thread *td, struct linux_creat_args *args)
77{
78    char *path;
79    int error;
80
81    LCONVPATHEXIST(td, args->path, &path);
82
83#ifdef DEBUG
84	if (ldebug(creat))
85		printf(ARGS(creat, "%s, %d"), path, args->mode);
86#endif
87    error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
88	args->mode);
89    LFREEPATH(path);
90    return (error);
91}
92
93
94static int
95linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
96{
97    struct proc *p = td->td_proc;
98    struct file *fp;
99    int fd;
100    int bsd_flags, error;
101
102    bsd_flags = 0;
103    switch (l_flags & LINUX_O_ACCMODE) {
104    case LINUX_O_WRONLY:
105	bsd_flags |= O_WRONLY;
106	break;
107    case LINUX_O_RDWR:
108	bsd_flags |= O_RDWR;
109	break;
110    default:
111	bsd_flags |= O_RDONLY;
112    }
113    if (l_flags & LINUX_O_NDELAY)
114	bsd_flags |= O_NONBLOCK;
115    if (l_flags & LINUX_O_APPEND)
116	bsd_flags |= O_APPEND;
117    if (l_flags & LINUX_O_SYNC)
118	bsd_flags |= O_FSYNC;
119    if (l_flags & LINUX_O_NONBLOCK)
120	bsd_flags |= O_NONBLOCK;
121    if (l_flags & LINUX_FASYNC)
122	bsd_flags |= O_ASYNC;
123    if (l_flags & LINUX_O_CREAT)
124	bsd_flags |= O_CREAT;
125    if (l_flags & LINUX_O_TRUNC)
126	bsd_flags |= O_TRUNC;
127    if (l_flags & LINUX_O_EXCL)
128	bsd_flags |= O_EXCL;
129    if (l_flags & LINUX_O_NOCTTY)
130	bsd_flags |= O_NOCTTY;
131    if (l_flags & LINUX_O_DIRECT)
132	bsd_flags |= O_DIRECT;
133    if (l_flags & LINUX_O_NOFOLLOW)
134	bsd_flags |= O_NOFOLLOW;
135    if (l_flags & LINUX_O_DIRECTORY)
136	bsd_flags |= O_DIRECTORY;
137    /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
138
139    error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
140
141    if (!error) {
142	    fd = td->td_retval[0];
143	    /*
144	     * XXX In between kern_open() and fget(), another process
145	     * having the same filedesc could use that fd without
146	     * checking below.
147	     */
148	    error = fget(td, fd, CAP_IOCTL, &fp);
149	    if (!error) {
150		    sx_slock(&proctree_lock);
151		    PROC_LOCK(p);
152		    if (!(bsd_flags & O_NOCTTY) &&
153			SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
154			    PROC_UNLOCK(p);
155			    sx_unlock(&proctree_lock);
156			    if (fp->f_type == DTYPE_VNODE)
157				    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
158					     td->td_ucred, td);
159		    } else {
160			    PROC_UNLOCK(p);
161			    sx_sunlock(&proctree_lock);
162		    }
163		    fdrop(fp, td);
164		    /*
165		     * XXX as above, fdrop()/kern_close() pair is racy.
166		     */
167		    if (error)
168			    kern_close(td, fd);
169	    }
170    }
171
172#ifdef DEBUG
173    if (ldebug(open))
174	    printf(LMSG("open returns error %d"), error);
175#endif
176    LFREEPATH(path);
177    return (error);
178}
179
180int
181linux_openat(struct thread *td, struct linux_openat_args *args)
182{
183	char *path;
184	int dfd;
185
186	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
187	if (args->flags & LINUX_O_CREAT)
188		LCONVPATH_AT(td, args->filename, &path, 1, dfd);
189	else
190		LCONVPATH_AT(td, args->filename, &path, 0, dfd);
191#ifdef DEBUG
192	if (ldebug(openat))
193		printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
194		    path, args->flags, args->mode);
195#endif
196	return (linux_common_open(td, dfd, path, args->flags, args->mode));
197}
198
199int
200linux_open(struct thread *td, struct linux_open_args *args)
201{
202    char *path;
203
204    if (args->flags & LINUX_O_CREAT)
205	LCONVPATHCREAT(td, args->path, &path);
206    else
207	LCONVPATHEXIST(td, args->path, &path);
208
209#ifdef DEBUG
210	if (ldebug(open))
211		printf(ARGS(open, "%s, 0x%x, 0x%x"),
212		    path, args->flags, args->mode);
213#endif
214
215	return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
216}
217
218int
219linux_lseek(struct thread *td, struct linux_lseek_args *args)
220{
221
222    struct lseek_args /* {
223	int fd;
224	int pad;
225	off_t offset;
226	int whence;
227    } */ tmp_args;
228    int error;
229
230#ifdef DEBUG
231	if (ldebug(lseek))
232		printf(ARGS(lseek, "%d, %ld, %d"),
233		    args->fdes, (long)args->off, args->whence);
234#endif
235    tmp_args.fd = args->fdes;
236    tmp_args.offset = (off_t)args->off;
237    tmp_args.whence = args->whence;
238    error = sys_lseek(td, &tmp_args);
239    return error;
240}
241
242int
243linux_llseek(struct thread *td, struct linux_llseek_args *args)
244{
245	struct lseek_args bsd_args;
246	int error;
247	off_t off;
248
249#ifdef DEBUG
250	if (ldebug(llseek))
251		printf(ARGS(llseek, "%d, %d:%d, %d"),
252		    args->fd, args->ohigh, args->olow, args->whence);
253#endif
254	off = (args->olow) | (((off_t) args->ohigh) << 32);
255
256	bsd_args.fd = args->fd;
257	bsd_args.offset = off;
258	bsd_args.whence = args->whence;
259
260	if ((error = sys_lseek(td, &bsd_args)))
261		return error;
262
263	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
264		return error;
265
266	td->td_retval[0] = 0;
267	return 0;
268}
269
270int
271linux_readdir(struct thread *td, struct linux_readdir_args *args)
272{
273	struct linux_getdents_args lda;
274
275	lda.fd = args->fd;
276	lda.dent = args->dent;
277	lda.count = 1;
278	return linux_getdents(td, &lda);
279}
280
281/*
282 * Note that linux_getdents(2) and linux_getdents64(2) have the same
283 * arguments. They only differ in the definition of struct dirent they
284 * operate on. We use this to common the code, with the exception of
285 * accessing struct dirent. Note that linux_readdir(2) is implemented
286 * by means of linux_getdents(2). In this case we never operate on
287 * struct dirent64 and thus don't need to handle it...
288 */
289
290struct l_dirent {
291	l_ulong		d_ino;
292	l_off_t		d_off;
293	l_ushort	d_reclen;
294	char		d_name[LINUX_NAME_MAX + 1];
295};
296
297struct l_dirent64 {
298	uint64_t	d_ino;
299	int64_t		d_off;
300	l_ushort	d_reclen;
301	u_char		d_type;
302	char		d_name[LINUX_NAME_MAX + 1];
303};
304
305/*
306 * Linux uses the last byte in the dirent buffer to store d_type,
307 * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
308 */
309#define LINUX_RECLEN(namlen)						\
310    roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),		\
311    sizeof(l_ulong))
312
313#define LINUX_RECLEN64(namlen)						\
314    roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),	\
315    sizeof(uint64_t))
316
317#define LINUX_MAXRECLEN		max(LINUX_RECLEN(LINUX_NAME_MAX),	\
318				    LINUX_RECLEN64(LINUX_NAME_MAX))
319#define	LINUX_DIRBLKSIZ		512
320
321static int
322getdents_common(struct thread *td, struct linux_getdents64_args *args,
323    int is64bit)
324{
325	struct dirent *bdp;
326	struct vnode *vp;
327	caddr_t inp, buf;		/* BSD-format */
328	int len, reclen;		/* BSD-format */
329	caddr_t outp;			/* Linux-format */
330	int resid, linuxreclen=0;	/* Linux-format */
331	caddr_t lbuf;			/* Linux-format */
332	struct file *fp;
333	struct uio auio;
334	struct iovec aiov;
335	off_t off;
336	struct l_dirent *linux_dirent;
337	struct l_dirent64 *linux_dirent64;
338	int buflen, error, eofflag, nbytes, justone;
339	u_long *cookies = NULL, *cookiep;
340	int ncookies, vfslocked;
341
342	nbytes = args->count;
343	if (nbytes == 1) {
344		/* readdir(2) case. Always struct dirent. */
345		if (is64bit)
346			return (EINVAL);
347		nbytes = sizeof(*linux_dirent);
348		justone = 1;
349	} else
350		justone = 0;
351
352	if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0)
353		return (error);
354
355	if ((fp->f_flag & FREAD) == 0) {
356		fdrop(fp, td);
357		return (EBADF);
358	}
359
360	off = foffset_lock(fp, 0);
361	vp = fp->f_vnode;
362	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
363	if (vp->v_type != VDIR) {
364		VFS_UNLOCK_GIANT(vfslocked);
365		foffset_unlock(fp, off, 0);
366		fdrop(fp, td);
367		return (EINVAL);
368	}
369
370
371	buflen = max(LINUX_DIRBLKSIZ, nbytes);
372	buflen = min(buflen, MAXBSIZE);
373	buf = malloc(buflen, M_TEMP, M_WAITOK);
374	lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
375	vn_lock(vp, LK_SHARED | LK_RETRY);
376
377	aiov.iov_base = buf;
378	aiov.iov_len = buflen;
379	auio.uio_iov = &aiov;
380	auio.uio_iovcnt = 1;
381	auio.uio_rw = UIO_READ;
382	auio.uio_segflg = UIO_SYSSPACE;
383	auio.uio_td = td;
384	auio.uio_resid = buflen;
385	auio.uio_offset = off;
386
387	if (cookies) {
388		free(cookies, M_TEMP);
389		cookies = NULL;
390	}
391
392#ifdef MAC
393	/*
394	 * Do directory search MAC check using non-cached credentials.
395	 */
396	if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
397		goto out;
398#endif /* MAC */
399	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
400		 &cookies)))
401		goto out;
402
403	inp = buf;
404	outp = (caddr_t)args->dirent;
405	resid = nbytes;
406	if ((len = buflen - auio.uio_resid) <= 0)
407		goto eof;
408
409	cookiep = cookies;
410
411	if (cookies) {
412		/*
413		 * When using cookies, the vfs has the option of reading from
414		 * a different offset than that supplied (UFS truncates the
415		 * offset to a block boundary to make sure that it never reads
416		 * partway through a directory entry, even if the directory
417		 * has been compacted).
418		 */
419		while (len > 0 && ncookies > 0 && *cookiep <= off) {
420			bdp = (struct dirent *) inp;
421			len -= bdp->d_reclen;
422			inp += bdp->d_reclen;
423			cookiep++;
424			ncookies--;
425		}
426	}
427
428	while (len > 0) {
429		if (cookiep && ncookies == 0)
430			break;
431		bdp = (struct dirent *) inp;
432		reclen = bdp->d_reclen;
433		if (reclen & 3) {
434			error = EFAULT;
435			goto out;
436		}
437
438		if (bdp->d_fileno == 0) {
439			inp += reclen;
440			if (cookiep) {
441				off = *cookiep++;
442				ncookies--;
443			} else
444				off += reclen;
445
446			len -= reclen;
447			continue;
448		}
449
450		linuxreclen = (is64bit)
451		    ? LINUX_RECLEN64(bdp->d_namlen)
452		    : LINUX_RECLEN(bdp->d_namlen);
453
454		if (reclen > len || resid < linuxreclen) {
455			outp++;
456			break;
457		}
458
459		if (justone) {
460			/* readdir(2) case. */
461			linux_dirent = (struct l_dirent*)lbuf;
462			linux_dirent->d_ino = bdp->d_fileno;
463			linux_dirent->d_off = (l_off_t)linuxreclen;
464			linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
465			strlcpy(linux_dirent->d_name, bdp->d_name,
466			    linuxreclen - offsetof(struct l_dirent, d_name));
467			error = copyout(linux_dirent, outp, linuxreclen);
468		}
469		if (is64bit) {
470			linux_dirent64 = (struct l_dirent64*)lbuf;
471			linux_dirent64->d_ino = bdp->d_fileno;
472			linux_dirent64->d_off = (cookiep)
473			    ? (l_off_t)*cookiep
474			    : (l_off_t)(off + reclen);
475			linux_dirent64->d_reclen = (l_ushort)linuxreclen;
476			linux_dirent64->d_type = bdp->d_type;
477			strlcpy(linux_dirent64->d_name, bdp->d_name,
478			    linuxreclen - offsetof(struct l_dirent64, d_name));
479			error = copyout(linux_dirent64, outp, linuxreclen);
480		} else if (!justone) {
481			linux_dirent = (struct l_dirent*)lbuf;
482			linux_dirent->d_ino = bdp->d_fileno;
483			linux_dirent->d_off = (cookiep)
484			    ? (l_off_t)*cookiep
485			    : (l_off_t)(off + reclen);
486			linux_dirent->d_reclen = (l_ushort)linuxreclen;
487			/*
488			 * Copy d_type to last byte of l_dirent buffer
489			 */
490			lbuf[linuxreclen-1] = bdp->d_type;
491			strlcpy(linux_dirent->d_name, bdp->d_name,
492			    linuxreclen - offsetof(struct l_dirent, d_name)-1);
493			error = copyout(linux_dirent, outp, linuxreclen);
494		}
495
496		if (error)
497			goto out;
498
499		inp += reclen;
500		if (cookiep) {
501			off = *cookiep++;
502			ncookies--;
503		} else
504			off += reclen;
505
506		outp += linuxreclen;
507		resid -= linuxreclen;
508		len -= reclen;
509		if (justone)
510			break;
511	}
512
513	if (outp == (caddr_t)args->dirent) {
514		nbytes = resid;
515		goto eof;
516	}
517
518	if (justone)
519		nbytes = resid + linuxreclen;
520
521eof:
522	td->td_retval[0] = nbytes - resid;
523
524out:
525	if (cookies)
526		free(cookies, M_TEMP);
527
528	VOP_UNLOCK(vp, 0);
529	VFS_UNLOCK_GIANT(vfslocked);
530	foffset_unlock(fp, off, 0);
531	fdrop(fp, td);
532	free(buf, M_TEMP);
533	free(lbuf, M_TEMP);
534	return (error);
535}
536
537int
538linux_getdents(struct thread *td, struct linux_getdents_args *args)
539{
540
541#ifdef DEBUG
542	if (ldebug(getdents))
543		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
544#endif
545
546	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
547}
548
549int
550linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
551{
552
553#ifdef DEBUG
554	if (ldebug(getdents64))
555		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
556#endif
557
558	return (getdents_common(td, args, 1));
559}
560
561/*
562 * These exist mainly for hooks for doing /compat/linux translation.
563 */
564
565int
566linux_access(struct thread *td, struct linux_access_args *args)
567{
568	char *path;
569	int error;
570
571	/* linux convention */
572	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
573		return (EINVAL);
574
575	LCONVPATHEXIST(td, args->path, &path);
576
577#ifdef DEBUG
578	if (ldebug(access))
579		printf(ARGS(access, "%s, %d"), path, args->amode);
580#endif
581	error = kern_access(td, path, UIO_SYSSPACE, args->amode);
582	LFREEPATH(path);
583
584	return (error);
585}
586
587int
588linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
589{
590	char *path;
591	int error, dfd, flag;
592
593	if (args->flag & ~LINUX_AT_EACCESS)
594		return (EINVAL);
595	/* linux convention */
596	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
597		return (EINVAL);
598
599	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
600	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
601
602#ifdef DEBUG
603	if (ldebug(access))
604		printf(ARGS(access, "%s, %d"), path, args->amode);
605#endif
606
607	flag = (args->flag & LINUX_AT_EACCESS) == 0 ? 0 : AT_EACCESS;
608	error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flag, args->amode);
609	LFREEPATH(path);
610
611	return (error);
612}
613
614int
615linux_unlink(struct thread *td, struct linux_unlink_args *args)
616{
617	char *path;
618	int error;
619	struct stat st;
620
621	LCONVPATHEXIST(td, args->path, &path);
622
623#ifdef DEBUG
624	if (ldebug(unlink))
625		printf(ARGS(unlink, "%s"), path);
626#endif
627
628	error = kern_unlink(td, path, UIO_SYSSPACE);
629	if (error == EPERM)
630		/* Introduce POSIX noncompliant behaviour of Linux */
631		if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
632			if (S_ISDIR(st.st_mode))
633				error = EISDIR;
634	LFREEPATH(path);
635	return (error);
636}
637
638int
639linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
640{
641	char *path;
642	int error, dfd;
643	struct stat st;
644
645	if (args->flag & ~LINUX_AT_REMOVEDIR)
646		return (EINVAL);
647
648	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
649	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
650
651#ifdef DEBUG
652	if (ldebug(unlinkat))
653		printf(ARGS(unlinkat, "%s"), path);
654#endif
655
656	if (args->flag & LINUX_AT_REMOVEDIR)
657		error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
658	else
659		error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
660	if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
661		/* Introduce POSIX noncompliant behaviour of Linux */
662		if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
663		    UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
664			error = EISDIR;
665	}
666	LFREEPATH(path);
667	return (error);
668}
669int
670linux_chdir(struct thread *td, struct linux_chdir_args *args)
671{
672	char *path;
673	int error;
674
675	LCONVPATHEXIST(td, args->path, &path);
676
677#ifdef DEBUG
678	if (ldebug(chdir))
679		printf(ARGS(chdir, "%s"), path);
680#endif
681	error = kern_chdir(td, path, UIO_SYSSPACE);
682	LFREEPATH(path);
683	return (error);
684}
685
686int
687linux_chmod(struct thread *td, struct linux_chmod_args *args)
688{
689	char *path;
690	int error;
691
692	LCONVPATHEXIST(td, args->path, &path);
693
694#ifdef DEBUG
695	if (ldebug(chmod))
696		printf(ARGS(chmod, "%s, %d"), path, args->mode);
697#endif
698	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
699	LFREEPATH(path);
700	return (error);
701}
702
703int
704linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
705{
706	char *path;
707	int error, dfd;
708
709	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
710	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
711
712#ifdef DEBUG
713	if (ldebug(fchmodat))
714		printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
715#endif
716
717	error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
718	LFREEPATH(path);
719	return (error);
720}
721
722int
723linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
724{
725	char *path;
726	int error;
727
728	LCONVPATHCREAT(td, args->path, &path);
729
730#ifdef DEBUG
731	if (ldebug(mkdir))
732		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
733#endif
734	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
735	LFREEPATH(path);
736	return (error);
737}
738
739int
740linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
741{
742	char *path;
743	int error, dfd;
744
745	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
746	LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
747
748#ifdef DEBUG
749	if (ldebug(mkdirat))
750		printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
751#endif
752	error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
753	LFREEPATH(path);
754	return (error);
755}
756
757int
758linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
759{
760	char *path;
761	int error;
762
763	LCONVPATHEXIST(td, args->path, &path);
764
765#ifdef DEBUG
766	if (ldebug(rmdir))
767		printf(ARGS(rmdir, "%s"), path);
768#endif
769	error = kern_rmdir(td, path, UIO_SYSSPACE);
770	LFREEPATH(path);
771	return (error);
772}
773
774int
775linux_rename(struct thread *td, struct linux_rename_args *args)
776{
777	char *from, *to;
778	int error;
779
780	LCONVPATHEXIST(td, args->from, &from);
781	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
782	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
783	if (to == NULL) {
784		LFREEPATH(from);
785		return (error);
786	}
787
788#ifdef DEBUG
789	if (ldebug(rename))
790		printf(ARGS(rename, "%s, %s"), from, to);
791#endif
792	error = kern_rename(td, from, to, UIO_SYSSPACE);
793	LFREEPATH(from);
794	LFREEPATH(to);
795	return (error);
796}
797
798int
799linux_renameat(struct thread *td, struct linux_renameat_args *args)
800{
801	char *from, *to;
802	int error, olddfd, newdfd;
803
804	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
805	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
806	LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
807	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
808	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
809	if (to == NULL) {
810		LFREEPATH(from);
811		return (error);
812	}
813
814#ifdef DEBUG
815	if (ldebug(renameat))
816		printf(ARGS(renameat, "%s, %s"), from, to);
817#endif
818	error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
819	LFREEPATH(from);
820	LFREEPATH(to);
821	return (error);
822}
823
824int
825linux_symlink(struct thread *td, struct linux_symlink_args *args)
826{
827	char *path, *to;
828	int error;
829
830	LCONVPATHEXIST(td, args->path, &path);
831	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
832	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
833	if (to == NULL) {
834		LFREEPATH(path);
835		return (error);
836	}
837
838#ifdef DEBUG
839	if (ldebug(symlink))
840		printf(ARGS(symlink, "%s, %s"), path, to);
841#endif
842	error = kern_symlink(td, path, to, UIO_SYSSPACE);
843	LFREEPATH(path);
844	LFREEPATH(to);
845	return (error);
846}
847
848int
849linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
850{
851	char *path, *to;
852	int error, dfd;
853
854	dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
855	LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
856	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
857	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
858	if (to == NULL) {
859		LFREEPATH(path);
860		return (error);
861	}
862
863#ifdef DEBUG
864	if (ldebug(symlinkat))
865		printf(ARGS(symlinkat, "%s, %s"), path, to);
866#endif
867
868	error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
869	LFREEPATH(path);
870	LFREEPATH(to);
871	return (error);
872}
873
874int
875linux_readlink(struct thread *td, struct linux_readlink_args *args)
876{
877	char *name;
878	int error;
879
880	LCONVPATHEXIST(td, args->name, &name);
881
882#ifdef DEBUG
883	if (ldebug(readlink))
884		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
885		    args->count);
886#endif
887	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
888	    args->count);
889	LFREEPATH(name);
890	return (error);
891}
892
893int
894linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
895{
896	char *name;
897	int error, dfd;
898
899	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
900	LCONVPATHEXIST_AT(td, args->path, &name, dfd);
901
902#ifdef DEBUG
903	if (ldebug(readlinkat))
904		printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
905		    args->bufsiz);
906#endif
907
908	error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
909	    UIO_USERSPACE, args->bufsiz);
910	LFREEPATH(name);
911	return (error);
912}
913
914int
915linux_truncate(struct thread *td, struct linux_truncate_args *args)
916{
917	char *path;
918	int error;
919
920	LCONVPATHEXIST(td, args->path, &path);
921
922#ifdef DEBUG
923	if (ldebug(truncate))
924		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
925#endif
926
927	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
928	LFREEPATH(path);
929	return (error);
930}
931
932int
933linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
934{
935	char *path;
936	int error;
937
938	LCONVPATHEXIST(td, args->path, &path);
939
940#ifdef DEBUG
941	if (ldebug(truncate64))
942		printf(ARGS(truncate64, "%s, %jd"), path, args->length);
943#endif
944
945	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
946	LFREEPATH(path);
947	return (error);
948}
949int
950linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
951{
952	struct ftruncate_args /* {
953		int fd;
954		int pad;
955		off_t length;
956		} */ nuap;
957
958	nuap.fd = args->fd;
959	nuap.length = args->length;
960	return (sys_ftruncate(td, &nuap));
961}
962
963int
964linux_link(struct thread *td, struct linux_link_args *args)
965{
966	char *path, *to;
967	int error;
968
969	LCONVPATHEXIST(td, args->path, &path);
970	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
971	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
972	if (to == NULL) {
973		LFREEPATH(path);
974		return (error);
975	}
976
977#ifdef DEBUG
978	if (ldebug(link))
979		printf(ARGS(link, "%s, %s"), path, to);
980#endif
981	error = kern_link(td, path, to, UIO_SYSSPACE);
982	LFREEPATH(path);
983	LFREEPATH(to);
984	return (error);
985}
986
987int
988linux_linkat(struct thread *td, struct linux_linkat_args *args)
989{
990	char *path, *to;
991	int error, olddfd, newdfd, follow;
992
993	if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
994		return (EINVAL);
995
996	olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
997	newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
998	LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
999	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
1000	error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
1001	if (to == NULL) {
1002		LFREEPATH(path);
1003		return (error);
1004	}
1005
1006#ifdef DEBUG
1007	if (ldebug(linkat))
1008		printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
1009			args->newdfd, to, args->flag);
1010#endif
1011
1012	follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
1013	    FOLLOW;
1014	error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
1015	LFREEPATH(path);
1016	LFREEPATH(to);
1017	return (error);
1018}
1019
1020int
1021linux_fdatasync(td, uap)
1022	struct thread *td;
1023	struct linux_fdatasync_args *uap;
1024{
1025	struct fsync_args bsd;
1026
1027	bsd.fd = uap->fd;
1028	return sys_fsync(td, &bsd);
1029}
1030
1031int
1032linux_pread(td, uap)
1033	struct thread *td;
1034	struct linux_pread_args *uap;
1035{
1036	struct pread_args bsd;
1037	struct vnode *vp;
1038	int error;
1039
1040	bsd.fd = uap->fd;
1041	bsd.buf = uap->buf;
1042	bsd.nbyte = uap->nbyte;
1043	bsd.offset = uap->offset;
1044
1045	error = sys_pread(td, &bsd);
1046
1047	if (error == 0) {
1048   	   	/* This seems to violate POSIX but linux does it */
1049		if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0)
1050   		   	return (error);
1051		if (vp->v_type == VDIR) {
1052   		   	vrele(vp);
1053			return (EISDIR);
1054		}
1055		vrele(vp);
1056	}
1057
1058	return (error);
1059}
1060
1061int
1062linux_pwrite(td, uap)
1063	struct thread *td;
1064	struct linux_pwrite_args *uap;
1065{
1066	struct pwrite_args bsd;
1067
1068	bsd.fd = uap->fd;
1069	bsd.buf = uap->buf;
1070	bsd.nbyte = uap->nbyte;
1071	bsd.offset = uap->offset;
1072	return sys_pwrite(td, &bsd);
1073}
1074
1075int
1076linux_mount(struct thread *td, struct linux_mount_args *args)
1077{
1078	struct ufs_args ufs;
1079	char fstypename[MFSNAMELEN];
1080	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
1081	int error;
1082	int fsflags;
1083	void *fsdata;
1084
1085	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
1086	    NULL);
1087	if (error)
1088		return (error);
1089	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
1090	if (error)
1091		return (error);
1092	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
1093	if (error)
1094		return (error);
1095
1096#ifdef DEBUG
1097	if (ldebug(mount))
1098		printf(ARGS(mount, "%s, %s, %s"),
1099		    fstypename, mntfromname, mntonname);
1100#endif
1101
1102	if (strcmp(fstypename, "ext2") == 0) {
1103		strcpy(fstypename, "ext2fs");
1104		fsdata = &ufs;
1105		ufs.fspec = mntfromname;
1106#define DEFAULT_ROOTID		-2
1107		ufs.export.ex_root = DEFAULT_ROOTID;
1108		ufs.export.ex_flags =
1109		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
1110	} else if (strcmp(fstypename, "proc") == 0) {
1111		strcpy(fstypename, "linprocfs");
1112		fsdata = NULL;
1113	} else if (strcmp(fstypename, "vfat") == 0) {
1114		strcpy(fstypename, "msdosfs");
1115		fsdata = NULL;
1116	} else {
1117		return (ENODEV);
1118	}
1119
1120	fsflags = 0;
1121
1122	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
1123		/*
1124		 * Linux SYNC flag is not included; the closest equivalent
1125		 * FreeBSD has is !ASYNC, which is our default.
1126		 */
1127		if (args->rwflag & LINUX_MS_RDONLY)
1128			fsflags |= MNT_RDONLY;
1129		if (args->rwflag & LINUX_MS_NOSUID)
1130			fsflags |= MNT_NOSUID;
1131		if (args->rwflag & LINUX_MS_NOEXEC)
1132			fsflags |= MNT_NOEXEC;
1133		if (args->rwflag & LINUX_MS_REMOUNT)
1134			fsflags |= MNT_UPDATE;
1135	}
1136
1137	if (strcmp(fstypename, "linprocfs") == 0) {
1138		error = kernel_vmount(fsflags,
1139			"fstype", fstypename,
1140			"fspath", mntonname,
1141			NULL);
1142	} else if (strcmp(fstypename, "msdosfs") == 0) {
1143		error = kernel_vmount(fsflags,
1144			"fstype", fstypename,
1145			"fspath", mntonname,
1146			"from", mntfromname,
1147			NULL);
1148	} else
1149		error = EOPNOTSUPP;
1150	return (error);
1151}
1152
1153int
1154linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1155{
1156	struct linux_umount_args args2;
1157
1158	args2.path = args->path;
1159	args2.flags = 0;
1160	return (linux_umount(td, &args2));
1161}
1162
1163int
1164linux_umount(struct thread *td, struct linux_umount_args *args)
1165{
1166	struct unmount_args bsd;
1167
1168	bsd.path = args->path;
1169	bsd.flags = args->flags;	/* XXX correct? */
1170	return (sys_unmount(td, &bsd));
1171}
1172
1173/*
1174 * fcntl family of syscalls
1175 */
1176
1177struct l_flock {
1178	l_short		l_type;
1179	l_short		l_whence;
1180	l_off_t		l_start;
1181	l_off_t		l_len;
1182	l_pid_t		l_pid;
1183}
1184#if defined(__amd64__) && defined(COMPAT_LINUX32)
1185__packed
1186#endif
1187;
1188
1189static void
1190linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1191{
1192	switch (linux_flock->l_type) {
1193	case LINUX_F_RDLCK:
1194		bsd_flock->l_type = F_RDLCK;
1195		break;
1196	case LINUX_F_WRLCK:
1197		bsd_flock->l_type = F_WRLCK;
1198		break;
1199	case LINUX_F_UNLCK:
1200		bsd_flock->l_type = F_UNLCK;
1201		break;
1202	default:
1203		bsd_flock->l_type = -1;
1204		break;
1205	}
1206	bsd_flock->l_whence = linux_flock->l_whence;
1207	bsd_flock->l_start = (off_t)linux_flock->l_start;
1208	bsd_flock->l_len = (off_t)linux_flock->l_len;
1209	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1210	bsd_flock->l_sysid = 0;
1211}
1212
1213static void
1214bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1215{
1216	switch (bsd_flock->l_type) {
1217	case F_RDLCK:
1218		linux_flock->l_type = LINUX_F_RDLCK;
1219		break;
1220	case F_WRLCK:
1221		linux_flock->l_type = LINUX_F_WRLCK;
1222		break;
1223	case F_UNLCK:
1224		linux_flock->l_type = LINUX_F_UNLCK;
1225		break;
1226	}
1227	linux_flock->l_whence = bsd_flock->l_whence;
1228	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1229	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1230	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1231}
1232
1233#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1234struct l_flock64 {
1235	l_short		l_type;
1236	l_short		l_whence;
1237	l_loff_t	l_start;
1238	l_loff_t	l_len;
1239	l_pid_t		l_pid;
1240}
1241#if defined(__amd64__) && defined(COMPAT_LINUX32)
1242__packed
1243#endif
1244;
1245
1246static void
1247linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1248{
1249	switch (linux_flock->l_type) {
1250	case LINUX_F_RDLCK:
1251		bsd_flock->l_type = F_RDLCK;
1252		break;
1253	case LINUX_F_WRLCK:
1254		bsd_flock->l_type = F_WRLCK;
1255		break;
1256	case LINUX_F_UNLCK:
1257		bsd_flock->l_type = F_UNLCK;
1258		break;
1259	default:
1260		bsd_flock->l_type = -1;
1261		break;
1262	}
1263	bsd_flock->l_whence = linux_flock->l_whence;
1264	bsd_flock->l_start = (off_t)linux_flock->l_start;
1265	bsd_flock->l_len = (off_t)linux_flock->l_len;
1266	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1267	bsd_flock->l_sysid = 0;
1268}
1269
1270static void
1271bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1272{
1273	switch (bsd_flock->l_type) {
1274	case F_RDLCK:
1275		linux_flock->l_type = LINUX_F_RDLCK;
1276		break;
1277	case F_WRLCK:
1278		linux_flock->l_type = LINUX_F_WRLCK;
1279		break;
1280	case F_UNLCK:
1281		linux_flock->l_type = LINUX_F_UNLCK;
1282		break;
1283	}
1284	linux_flock->l_whence = bsd_flock->l_whence;
1285	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1286	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1287	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1288}
1289#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1290
1291static int
1292fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
1293{
1294	struct l_flock linux_flock;
1295	struct flock bsd_flock;
1296	struct file *fp;
1297	long arg;
1298	int error, result;
1299
1300	switch (args->cmd) {
1301	case LINUX_F_DUPFD:
1302		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1303
1304	case LINUX_F_GETFD:
1305		return (kern_fcntl(td, args->fd, F_GETFD, 0));
1306
1307	case LINUX_F_SETFD:
1308		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1309
1310	case LINUX_F_GETFL:
1311		error = kern_fcntl(td, args->fd, F_GETFL, 0);
1312		result = td->td_retval[0];
1313		td->td_retval[0] = 0;
1314		if (result & O_RDONLY)
1315			td->td_retval[0] |= LINUX_O_RDONLY;
1316		if (result & O_WRONLY)
1317			td->td_retval[0] |= LINUX_O_WRONLY;
1318		if (result & O_RDWR)
1319			td->td_retval[0] |= LINUX_O_RDWR;
1320		if (result & O_NDELAY)
1321			td->td_retval[0] |= LINUX_O_NONBLOCK;
1322		if (result & O_APPEND)
1323			td->td_retval[0] |= LINUX_O_APPEND;
1324		if (result & O_FSYNC)
1325			td->td_retval[0] |= LINUX_O_SYNC;
1326		if (result & O_ASYNC)
1327			td->td_retval[0] |= LINUX_FASYNC;
1328#ifdef LINUX_O_NOFOLLOW
1329		if (result & O_NOFOLLOW)
1330			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1331#endif
1332#ifdef LINUX_O_DIRECT
1333		if (result & O_DIRECT)
1334			td->td_retval[0] |= LINUX_O_DIRECT;
1335#endif
1336		return (error);
1337
1338	case LINUX_F_SETFL:
1339		arg = 0;
1340		if (args->arg & LINUX_O_NDELAY)
1341			arg |= O_NONBLOCK;
1342		if (args->arg & LINUX_O_APPEND)
1343			arg |= O_APPEND;
1344		if (args->arg & LINUX_O_SYNC)
1345			arg |= O_FSYNC;
1346		if (args->arg & LINUX_FASYNC)
1347			arg |= O_ASYNC;
1348#ifdef LINUX_O_NOFOLLOW
1349		if (args->arg & LINUX_O_NOFOLLOW)
1350			arg |= O_NOFOLLOW;
1351#endif
1352#ifdef LINUX_O_DIRECT
1353		if (args->arg & LINUX_O_DIRECT)
1354			arg |= O_DIRECT;
1355#endif
1356		return (kern_fcntl(td, args->fd, F_SETFL, arg));
1357
1358	case LINUX_F_GETLK:
1359		error = copyin((void *)args->arg, &linux_flock,
1360		    sizeof(linux_flock));
1361		if (error)
1362			return (error);
1363		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1364		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1365		if (error)
1366			return (error);
1367		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1368		return (copyout(&linux_flock, (void *)args->arg,
1369		    sizeof(linux_flock)));
1370
1371	case LINUX_F_SETLK:
1372		error = copyin((void *)args->arg, &linux_flock,
1373		    sizeof(linux_flock));
1374		if (error)
1375			return (error);
1376		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1377		return (kern_fcntl(td, args->fd, F_SETLK,
1378		    (intptr_t)&bsd_flock));
1379
1380	case LINUX_F_SETLKW:
1381		error = copyin((void *)args->arg, &linux_flock,
1382		    sizeof(linux_flock));
1383		if (error)
1384			return (error);
1385		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1386		return (kern_fcntl(td, args->fd, F_SETLKW,
1387		     (intptr_t)&bsd_flock));
1388
1389	case LINUX_F_GETOWN:
1390		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1391
1392	case LINUX_F_SETOWN:
1393		/*
1394		 * XXX some Linux applications depend on F_SETOWN having no
1395		 * significant effect for pipes (SIGIO is not delivered for
1396		 * pipes under Linux-2.2.35 at least).
1397		 */
1398		error = fget(td, args->fd, CAP_FCNTL, &fp);
1399		if (error)
1400			return (error);
1401		if (fp->f_type == DTYPE_PIPE) {
1402			fdrop(fp, td);
1403			return (EINVAL);
1404		}
1405		fdrop(fp, td);
1406
1407		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1408	}
1409
1410	return (EINVAL);
1411}
1412
1413int
1414linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1415{
1416	struct linux_fcntl64_args args64;
1417
1418#ifdef DEBUG
1419	if (ldebug(fcntl))
1420		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1421#endif
1422
1423	args64.fd = args->fd;
1424	args64.cmd = args->cmd;
1425	args64.arg = args->arg;
1426	return (fcntl_common(td, &args64));
1427}
1428
1429#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1430int
1431linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1432{
1433	struct l_flock64 linux_flock;
1434	struct flock bsd_flock;
1435	int error;
1436
1437#ifdef DEBUG
1438	if (ldebug(fcntl64))
1439		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1440#endif
1441
1442	switch (args->cmd) {
1443	case LINUX_F_GETLK64:
1444		error = copyin((void *)args->arg, &linux_flock,
1445		    sizeof(linux_flock));
1446		if (error)
1447			return (error);
1448		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1449		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1450		if (error)
1451			return (error);
1452		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1453		return (copyout(&linux_flock, (void *)args->arg,
1454			    sizeof(linux_flock)));
1455
1456	case LINUX_F_SETLK64:
1457		error = copyin((void *)args->arg, &linux_flock,
1458		    sizeof(linux_flock));
1459		if (error)
1460			return (error);
1461		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1462		return (kern_fcntl(td, args->fd, F_SETLK,
1463		    (intptr_t)&bsd_flock));
1464
1465	case LINUX_F_SETLKW64:
1466		error = copyin((void *)args->arg, &linux_flock,
1467		    sizeof(linux_flock));
1468		if (error)
1469			return (error);
1470		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1471		return (kern_fcntl(td, args->fd, F_SETLKW,
1472		    (intptr_t)&bsd_flock));
1473	}
1474
1475	return (fcntl_common(td, args));
1476}
1477#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1478
1479int
1480linux_chown(struct thread *td, struct linux_chown_args *args)
1481{
1482	char *path;
1483	int error;
1484
1485	LCONVPATHEXIST(td, args->path, &path);
1486
1487#ifdef DEBUG
1488	if (ldebug(chown))
1489		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1490#endif
1491	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1492	LFREEPATH(path);
1493	return (error);
1494}
1495
1496int
1497linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1498{
1499	char *path;
1500	int error, dfd, flag;
1501
1502	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1503		return (EINVAL);
1504
1505	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1506	LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1507
1508#ifdef DEBUG
1509	if (ldebug(fchownat))
1510		printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
1511#endif
1512
1513	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1514	    AT_SYMLINK_NOFOLLOW;
1515	error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1516	    flag);
1517	LFREEPATH(path);
1518	return (error);
1519}
1520
1521int
1522linux_lchown(struct thread *td, struct linux_lchown_args *args)
1523{
1524	char *path;
1525	int error;
1526
1527	LCONVPATHEXIST(td, args->path, &path);
1528
1529#ifdef DEBUG
1530	if (ldebug(lchown))
1531		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1532#endif
1533	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1534	LFREEPATH(path);
1535	return (error);
1536}
1537
1538static int
1539convert_fadvice(int advice)
1540{
1541	switch (advice) {
1542	case LINUX_POSIX_FADV_NORMAL:
1543		return (POSIX_FADV_NORMAL);
1544	case LINUX_POSIX_FADV_RANDOM:
1545		return (POSIX_FADV_RANDOM);
1546	case LINUX_POSIX_FADV_SEQUENTIAL:
1547		return (POSIX_FADV_SEQUENTIAL);
1548	case LINUX_POSIX_FADV_WILLNEED:
1549		return (POSIX_FADV_WILLNEED);
1550	case LINUX_POSIX_FADV_DONTNEED:
1551		return (POSIX_FADV_DONTNEED);
1552	case LINUX_POSIX_FADV_NOREUSE:
1553		return (POSIX_FADV_NOREUSE);
1554	default:
1555		return (-1);
1556	}
1557}
1558
1559int
1560linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1561{
1562	int advice;
1563
1564	advice = convert_fadvice(args->advice);
1565	if (advice == -1)
1566		return (EINVAL);
1567	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1568	    advice));
1569}
1570
1571int
1572linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1573{
1574	int advice;
1575
1576	advice = convert_fadvice(args->advice);
1577	if (advice == -1)
1578		return (EINVAL);
1579	return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1580	    advice));
1581}
1582
1583int
1584linux_pipe(struct thread *td, struct linux_pipe_args *args)
1585{
1586	int fildes[2];
1587	int error;
1588
1589#ifdef DEBUG
1590	if (ldebug(pipe))
1591		printf(ARGS(pipe, "*"));
1592#endif
1593
1594	error = do_pipe(td, fildes, 0);
1595	if (error)
1596		return (error);
1597
1598	/* XXX: Close descriptors on error. */
1599	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1600}
1601
1602int
1603linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1604{
1605	int fildes[2];
1606	int error, flags;
1607
1608#ifdef DEBUG
1609	if (ldebug(pipe2))
1610		printf(ARGS(pipe2, "*, %d"), args->flags);
1611#endif
1612
1613	if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1614		return (EINVAL);
1615
1616	flags = 0;
1617	if ((args->flags & LINUX_O_NONBLOCK) != 0)
1618		flags |= O_NONBLOCK;
1619	if ((args->flags & LINUX_O_CLOEXEC) != 0)
1620		flags |= O_CLOEXEC;
1621	error = do_pipe(td, fildes, flags);
1622	if (error)
1623		return (error);
1624
1625	/* XXX: Close descriptors on error. */
1626	return (copyout(fildes, args->pipefds, sizeof(fildes)));
1627}
1628