linux_file.c revision 91140
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 withough 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 * $FreeBSD: head/sys/compat/linux/linux_file.c 91140 2002-02-23 11:12:57Z tanimura $
29 */
30
31#include "opt_compat.h"
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/conf.h>
36#include <sys/dirent.h>
37#include <sys/fcntl.h>
38#include <sys/file.h>
39#include <sys/filedesc.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/mount.h>
43#include <sys/mutex.h>
44#include <sys/proc.h>
45#include <sys/sysproto.h>
46#include <sys/tty.h>
47#include <sys/vnode.h>
48
49#include <ufs/ufs/extattr.h>
50#include <ufs/ufs/quota.h>
51#include <ufs/ufs/ufsmount.h>
52
53#include <machine/../linux/linux.h>
54#include <machine/../linux/linux_proto.h>
55#include <compat/linux/linux_util.h>
56
57#ifndef __alpha__
58int
59linux_creat(struct thread *td, struct linux_creat_args *args)
60{
61    struct open_args /* {
62	char *path;
63	int flags;
64	int mode;
65    } */ bsd_open_args;
66    caddr_t sg;
67
68    sg = stackgap_init();
69    CHECKALTCREAT(td, &sg, args->path);
70
71#ifdef DEBUG
72	if (ldebug(creat))
73		printf(ARGS(creat, "%s, %d"), args->path, args->mode);
74#endif
75    bsd_open_args.path = args->path;
76    bsd_open_args.mode = args->mode;
77    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
78    return open(td, &bsd_open_args);
79}
80#endif /*!__alpha__*/
81
82int
83linux_open(struct thread *td, struct linux_open_args *args)
84{
85    struct open_args /* {
86	char *path;
87	int flags;
88	int mode;
89    } */ bsd_open_args;
90    struct proc *p = td->td_proc;
91    int error;
92    caddr_t sg;
93
94    sg = stackgap_init();
95
96    if (args->flags & LINUX_O_CREAT)
97	CHECKALTCREAT(td, &sg, args->path);
98    else
99	CHECKALTEXIST(td, &sg, args->path);
100
101#ifdef DEBUG
102	if (ldebug(open))
103		printf(ARGS(open, "%s, 0x%x, 0x%x"),
104		    args->path, args->flags, args->mode);
105#endif
106    bsd_open_args.flags = 0;
107    if (args->flags & LINUX_O_RDONLY)
108	bsd_open_args.flags |= O_RDONLY;
109    if (args->flags & LINUX_O_WRONLY)
110	bsd_open_args.flags |= O_WRONLY;
111    if (args->flags & LINUX_O_RDWR)
112	bsd_open_args.flags |= O_RDWR;
113    if (args->flags & LINUX_O_NDELAY)
114	bsd_open_args.flags |= O_NONBLOCK;
115    if (args->flags & LINUX_O_APPEND)
116	bsd_open_args.flags |= O_APPEND;
117    if (args->flags & LINUX_O_SYNC)
118	bsd_open_args.flags |= O_FSYNC;
119    if (args->flags & LINUX_O_NONBLOCK)
120	bsd_open_args.flags |= O_NONBLOCK;
121    if (args->flags & LINUX_FASYNC)
122	bsd_open_args.flags |= O_ASYNC;
123    if (args->flags & LINUX_O_CREAT)
124	bsd_open_args.flags |= O_CREAT;
125    if (args->flags & LINUX_O_TRUNC)
126	bsd_open_args.flags |= O_TRUNC;
127    if (args->flags & LINUX_O_EXCL)
128	bsd_open_args.flags |= O_EXCL;
129    if (args->flags & LINUX_O_NOCTTY)
130	bsd_open_args.flags |= O_NOCTTY;
131    bsd_open_args.path = args->path;
132    bsd_open_args.mode = args->mode;
133
134    error = open(td, &bsd_open_args);
135    PROC_LOCK(p);
136    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
137	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
138	struct file *fp;
139
140	error = fget(td, td->td_retval[0], &fp);
141	PROC_UNLOCK(p);
142	if (!error) {
143		if (fp->f_type == DTYPE_VNODE)
144			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td);
145	    fdrop(fp, td);
146	}
147    } else {
148	PROC_UNLOCK(p);
149#ifdef DEBUG
150	if (ldebug(open))
151		printf(LMSG("open returns error %d"), error);
152#endif
153    }
154    return error;
155}
156
157int
158linux_lseek(struct thread *td, struct linux_lseek_args *args)
159{
160
161    struct lseek_args /* {
162	int fd;
163	int pad;
164	off_t offset;
165	int whence;
166    } */ tmp_args;
167    int error;
168
169#ifdef DEBUG
170	if (ldebug(lseek))
171		printf(ARGS(lseek, "%d, %ld, %d"),
172		    args->fdes, (long)args->off, args->whence);
173#endif
174    tmp_args.fd = args->fdes;
175    tmp_args.offset = (off_t)args->off;
176    tmp_args.whence = args->whence;
177    error = lseek(td, &tmp_args);
178    return error;
179}
180
181#ifndef __alpha__
182int
183linux_llseek(struct thread *td, struct linux_llseek_args *args)
184{
185	struct lseek_args bsd_args;
186	int error;
187	off_t off;
188
189#ifdef DEBUG
190	if (ldebug(llseek))
191		printf(ARGS(llseek, "%d, %d:%d, %d"),
192		    args->fd, args->ohigh, args->olow, args->whence);
193#endif
194	off = (args->olow) | (((off_t) args->ohigh) << 32);
195
196	bsd_args.fd = args->fd;
197	bsd_args.offset = off;
198	bsd_args.whence = args->whence;
199
200	if ((error = lseek(td, &bsd_args)))
201		return error;
202
203	if ((error = copyout(td->td_retval, (caddr_t)args->res, sizeof (off_t))))
204		return error;
205
206	td->td_retval[0] = 0;
207	return 0;
208}
209#endif /*!__alpha__*/
210
211#ifndef __alpha__
212int
213linux_readdir(struct thread *td, struct linux_readdir_args *args)
214{
215	struct linux_getdents_args lda;
216
217	lda.fd = args->fd;
218	lda.dent = args->dent;
219	lda.count = 1;
220	return linux_getdents(td, &lda);
221}
222#endif /*!__alpha__*/
223
224/*
225 * Note that linux_getdents(2) and linux_getdents64(2) have the same
226 * arguments. They only differ in the definition of struct dirent they
227 * operate on. We use this to common the code, with the exception of
228 * accessing struct dirent. Note that linux_readdir(2) is implemented
229 * by means of linux_getdents(2). In this case we never operate on
230 * struct dirent64 and thus don't need to handle it...
231 */
232
233struct l_dirent {
234	l_long		d_ino;
235	l_off_t		d_off;
236	l_ushort	d_reclen;
237	char		d_name[LINUX_NAME_MAX + 1];
238};
239
240struct l_dirent64 {
241	uint64_t	d_ino;
242	int64_t		d_off;
243	l_ushort	d_reclen;
244	u_char		d_type;
245	char		d_name[LINUX_NAME_MAX + 1];
246};
247
248#define LINUX_RECLEN(de,namlen) \
249    ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
250
251#define	LINUX_DIRBLKSIZ		512
252
253static int
254getdents_common(struct thread *td, struct linux_getdents64_args *args,
255    int is64bit)
256{
257	register struct dirent *bdp;
258	struct vnode *vp;
259	caddr_t inp, buf;		/* BSD-format */
260	int len, reclen;		/* BSD-format */
261	caddr_t outp;			/* Linux-format */
262	int resid, linuxreclen=0;	/* Linux-format */
263	struct file *fp;
264	struct uio auio;
265	struct iovec aiov;
266	struct vattr va;
267	off_t off;
268	struct l_dirent linux_dirent;
269	struct l_dirent64 linux_dirent64;
270	int buflen, error, eofflag, nbytes, justone;
271	u_long *cookies = NULL, *cookiep;
272	int ncookies;
273
274	if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
275		return (error);
276
277	if ((fp->f_flag & FREAD) == 0) {
278		fdrop(fp, td);
279		return (EBADF);
280	}
281
282	vp = (struct vnode *) fp->f_data;
283	if (vp->v_type != VDIR) {
284		fdrop(fp, td);
285		return (EINVAL);
286	}
287
288	if ((error = VOP_GETATTR(vp, &va, td->td_proc->p_ucred, td))) {
289		fdrop(fp, td);
290		return (error);
291	}
292
293	nbytes = args->count;
294	if (nbytes == 1) {
295		/* readdir(2) case. Always struct dirent. */
296		if (is64bit) {
297			fdrop(fp, td);
298			return (EINVAL);
299		}
300		nbytes = sizeof(linux_dirent);
301		justone = 1;
302	} else
303		justone = 0;
304
305	off = fp->f_offset;
306
307	buflen = max(LINUX_DIRBLKSIZ, nbytes);
308	buflen = min(buflen, MAXBSIZE);
309	buf = malloc(buflen, M_TEMP, M_WAITOK);
310	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
311
312again:
313	aiov.iov_base = buf;
314	aiov.iov_len = buflen;
315	auio.uio_iov = &aiov;
316	auio.uio_iovcnt = 1;
317	auio.uio_rw = UIO_READ;
318	auio.uio_segflg = UIO_SYSSPACE;
319	auio.uio_td = td;
320	auio.uio_resid = buflen;
321	auio.uio_offset = off;
322
323	if (cookies) {
324		free(cookies, M_TEMP);
325		cookies = NULL;
326	}
327
328	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
329		 &cookies)))
330		goto out;
331
332	inp = buf;
333	outp = (caddr_t)args->dirent;
334	resid = nbytes;
335	if ((len = buflen - auio.uio_resid) <= 0)
336		goto eof;
337
338	cookiep = cookies;
339
340	if (cookies) {
341		/*
342		 * When using cookies, the vfs has the option of reading from
343		 * a different offset than that supplied (UFS truncates the
344		 * offset to a block boundary to make sure that it never reads
345		 * partway through a directory entry, even if the directory
346		 * has been compacted).
347		 */
348		while (len > 0 && ncookies > 0 && *cookiep <= off) {
349			bdp = (struct dirent *) inp;
350			len -= bdp->d_reclen;
351			inp += bdp->d_reclen;
352			cookiep++;
353			ncookies--;
354		}
355	}
356
357	while (len > 0) {
358		if (cookiep && ncookies == 0)
359			break;
360		bdp = (struct dirent *) inp;
361		reclen = bdp->d_reclen;
362		if (reclen & 3) {
363			error = EFAULT;
364			goto out;
365		}
366
367		if (bdp->d_fileno == 0) {
368			inp += reclen;
369			if (cookiep) {
370				off = *cookiep++;
371				ncookies--;
372			} else
373				off += reclen;
374
375			len -= reclen;
376			continue;
377		}
378
379		linuxreclen = (is64bit)
380		    ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
381		    : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
382
383		if (reclen > len || resid < linuxreclen) {
384			outp++;
385			break;
386		}
387
388		if (justone) {
389			/* readdir(2) case. */
390			linux_dirent.d_ino = (l_long)bdp->d_fileno;
391			linux_dirent.d_off = (l_off_t)linuxreclen;
392			linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
393			strcpy(linux_dirent.d_name, bdp->d_name);
394			error = copyout(&linux_dirent, outp, linuxreclen);
395		} else {
396			if (is64bit) {
397				linux_dirent64.d_ino = bdp->d_fileno;
398				linux_dirent64.d_off = (cookiep)
399				    ? (l_off_t)*cookiep
400				    : (l_off_t)(off + reclen);
401				linux_dirent64.d_reclen =
402				    (l_ushort)linuxreclen;
403				linux_dirent64.d_type = bdp->d_type;
404				strcpy(linux_dirent64.d_name, bdp->d_name);
405				error = copyout(&linux_dirent64, outp,
406				    linuxreclen);
407			} else {
408				linux_dirent.d_ino = bdp->d_fileno;
409				linux_dirent.d_off = (cookiep)
410				    ? (l_off_t)*cookiep
411				    : (l_off_t)(off + reclen);
412				linux_dirent.d_reclen = (l_ushort)linuxreclen;
413				strcpy(linux_dirent.d_name, bdp->d_name);
414				error = copyout(&linux_dirent, outp,
415				    linuxreclen);
416			}
417		}
418		if (error)
419			goto out;
420
421		inp += reclen;
422		if (cookiep) {
423			off = *cookiep++;
424			ncookies--;
425		} else
426			off += reclen;
427
428		outp += linuxreclen;
429		resid -= linuxreclen;
430		len -= reclen;
431		if (justone)
432			break;
433	}
434
435	if (outp == (caddr_t)args->dirent)
436		goto again;
437
438	fp->f_offset = off;
439	if (justone)
440		nbytes = resid + linuxreclen;
441
442eof:
443	td->td_retval[0] = nbytes - resid;
444
445out:
446	if (cookies)
447		free(cookies, M_TEMP);
448
449	VOP_UNLOCK(vp, 0, td);
450	fdrop(fp, td);
451	free(buf, M_TEMP);
452	return (error);
453}
454
455int
456linux_getdents(struct thread *td, struct linux_getdents_args *args)
457{
458
459#ifdef DEBUG
460	if (ldebug(getdents))
461		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
462#endif
463
464	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
465}
466
467int
468linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
469{
470
471#ifdef DEBUG
472	if (ldebug(getdents64))
473		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
474#endif
475
476	return (getdents_common(td, args, 1));
477}
478
479/*
480 * These exist mainly for hooks for doing /compat/linux translation.
481 */
482
483int
484linux_access(struct thread *td, struct linux_access_args *args)
485{
486	struct access_args bsd;
487	caddr_t sg;
488
489	sg = stackgap_init();
490	CHECKALTEXIST(td, &sg, args->path);
491
492#ifdef DEBUG
493	if (ldebug(access))
494		printf(ARGS(access, "%s, %d"), args->path, args->flags);
495#endif
496	bsd.path = args->path;
497	bsd.flags = args->flags;
498
499	return access(td, &bsd);
500}
501
502int
503linux_unlink(struct thread *td, struct linux_unlink_args *args)
504{
505	struct unlink_args bsd;
506	caddr_t sg;
507
508	sg = stackgap_init();
509	CHECKALTEXIST(td, &sg, args->path);
510
511#ifdef DEBUG
512	if (ldebug(unlink))
513		printf(ARGS(unlink, "%s"), args->path);
514#endif
515	bsd.path = args->path;
516
517	return unlink(td, &bsd);
518}
519
520int
521linux_chdir(struct thread *td, struct linux_chdir_args *args)
522{
523	struct chdir_args bsd;
524	caddr_t sg;
525
526	sg = stackgap_init();
527	CHECKALTEXIST(td, &sg, args->path);
528
529#ifdef DEBUG
530	if (ldebug(chdir))
531		printf(ARGS(chdir, "%s"), args->path);
532#endif
533	bsd.path = args->path;
534
535	return chdir(td, &bsd);
536}
537
538int
539linux_chmod(struct thread *td, struct linux_chmod_args *args)
540{
541	struct chmod_args bsd;
542	caddr_t sg;
543
544	sg = stackgap_init();
545	CHECKALTEXIST(td, &sg, args->path);
546
547#ifdef DEBUG
548	if (ldebug(chmod))
549		printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
550#endif
551	bsd.path = args->path;
552	bsd.mode = args->mode;
553
554	return chmod(td, &bsd);
555}
556
557int
558linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
559{
560	struct mkdir_args bsd;
561	caddr_t sg;
562
563	sg = stackgap_init();
564	CHECKALTCREAT(td, &sg, args->path);
565
566#ifdef DEBUG
567	if (ldebug(mkdir))
568		printf(ARGS(mkdir, "%s, %d"), args->path, args->mode);
569#endif
570	bsd.path = args->path;
571	bsd.mode = args->mode;
572
573	return mkdir(td, &bsd);
574}
575
576int
577linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
578{
579	struct rmdir_args bsd;
580	caddr_t sg;
581
582	sg = stackgap_init();
583	CHECKALTEXIST(td, &sg, args->path);
584
585#ifdef DEBUG
586	if (ldebug(rmdir))
587		printf(ARGS(rmdir, "%s"), args->path);
588#endif
589	bsd.path = args->path;
590
591	return rmdir(td, &bsd);
592}
593
594int
595linux_rename(struct thread *td, struct linux_rename_args *args)
596{
597	struct rename_args bsd;
598	caddr_t sg;
599
600	sg = stackgap_init();
601	CHECKALTEXIST(td, &sg, args->from);
602	CHECKALTCREAT(td, &sg, args->to);
603
604#ifdef DEBUG
605	if (ldebug(rename))
606		printf(ARGS(rename, "%s, %s"), args->from, args->to);
607#endif
608	bsd.from = args->from;
609	bsd.to = args->to;
610
611	return rename(td, &bsd);
612}
613
614int
615linux_symlink(struct thread *td, struct linux_symlink_args *args)
616{
617	struct symlink_args bsd;
618	caddr_t sg;
619
620	sg = stackgap_init();
621	CHECKALTEXIST(td, &sg, args->path);
622	CHECKALTCREAT(td, &sg, args->to);
623
624#ifdef DEBUG
625	if (ldebug(symlink))
626		printf(ARGS(symlink, "%s, %s"), args->path, args->to);
627#endif
628	bsd.path = args->path;
629	bsd.link = args->to;
630
631	return symlink(td, &bsd);
632}
633
634int
635linux_readlink(struct thread *td, struct linux_readlink_args *args)
636{
637	struct readlink_args bsd;
638	caddr_t sg;
639
640	sg = stackgap_init();
641	CHECKALTEXIST(td, &sg, args->name);
642
643#ifdef DEBUG
644	if (ldebug(readlink))
645		printf(ARGS(readlink, "%s, %p, %d"),
646		    args->name, (void *)args->buf, args->count);
647#endif
648	bsd.path = args->name;
649	bsd.buf = args->buf;
650	bsd.count = args->count;
651
652	return readlink(td, &bsd);
653}
654
655int
656linux_truncate(struct thread *td, struct linux_truncate_args *args)
657{
658	struct truncate_args bsd;
659	caddr_t sg;
660
661	sg = stackgap_init();
662	CHECKALTEXIST(td, &sg, args->path);
663
664#ifdef DEBUG
665	if (ldebug(truncate))
666		printf(ARGS(truncate, "%s, %ld"), args->path,
667		    (long)args->length);
668#endif
669	bsd.path = args->path;
670	bsd.length = args->length;
671
672	return truncate(td, &bsd);
673}
674
675int
676linux_link(struct thread *td, struct linux_link_args *args)
677{
678    struct link_args bsd;
679    caddr_t sg;
680
681    sg = stackgap_init();
682    CHECKALTEXIST(td, &sg, args->path);
683    CHECKALTCREAT(td, &sg, args->to);
684
685#ifdef DEBUG
686	if (ldebug(link))
687		printf(ARGS(link, "%s, %s"), args->path, args->to);
688#endif
689
690    bsd.path = args->path;
691    bsd.link = args->to;
692
693    return link(td, &bsd);
694}
695
696#ifndef __alpha__
697int
698linux_fdatasync(td, uap)
699	struct thread *td;
700	struct linux_fdatasync_args *uap;
701{
702	struct fsync_args bsd;
703
704	bsd.fd = uap->fd;
705	return fsync(td, &bsd);
706}
707#endif /*!__alpha__*/
708
709int
710linux_pread(td, uap)
711	struct thread *td;
712	struct linux_pread_args *uap;
713{
714	struct pread_args bsd;
715
716	bsd.fd = uap->fd;
717	bsd.buf = uap->buf;
718	bsd.nbyte = uap->nbyte;
719	bsd.offset = uap->offset;
720	return pread(td, &bsd);
721}
722
723int
724linux_pwrite(td, uap)
725	struct thread *td;
726	struct linux_pwrite_args *uap;
727{
728	struct pwrite_args bsd;
729
730	bsd.fd = uap->fd;
731	bsd.buf = uap->buf;
732	bsd.nbyte = uap->nbyte;
733	bsd.offset = uap->offset;
734	return pwrite(td, &bsd);
735}
736
737int
738linux_mount(struct thread *td, struct linux_mount_args *args)
739{
740	struct ufs_args ufs;
741        char fstypename[MFSNAMELEN];
742        char mntonname[MNAMELEN], mntfromname[MNAMELEN];
743	int error;
744	int fsflags;
745	const char *fstype;
746	void *fsdata;
747
748        error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
749	    NULL);
750	if (error)
751                return (error);
752        error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
753	if (error)
754                return (error);
755        error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
756	if (error)
757                return (error);
758
759#ifdef DEBUG
760	if (ldebug(mount))
761		printf(ARGS(mount, "%s, %s, %s"),
762		    fstypename, mntfromname, mntonname);
763#endif
764
765	if (strcmp(fstypename, "ext2") == 0) {
766		fstype = "ext2fs";
767		fsdata = &ufs;
768		ufs.fspec = mntfromname;
769#define DEFAULT_ROOTID		-2
770		ufs.export.ex_root = DEFAULT_ROOTID;
771		ufs.export.ex_flags =
772		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
773	} else if (strcmp(fstypename, "proc") == 0) {
774		fstype = "linprocfs";
775		fsdata = NULL;
776	} else {
777		return (ENODEV);
778	}
779
780	fsflags = 0;
781
782	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
783		/*
784		 * Linux SYNC flag is not included; the closest equivalent
785		 * FreeBSD has is !ASYNC, which is our default.
786		 */
787		if (args->rwflag & LINUX_MS_RDONLY)
788			fsflags |= MNT_RDONLY;
789		if (args->rwflag & LINUX_MS_NOSUID)
790			fsflags |= MNT_NOSUID;
791		if (args->rwflag & LINUX_MS_NODEV)
792			fsflags |= MNT_NODEV;
793		if (args->rwflag & LINUX_MS_NOEXEC)
794			fsflags |= MNT_NOEXEC;
795		if (args->rwflag & LINUX_MS_REMOUNT)
796			fsflags |= MNT_UPDATE;
797	}
798
799	return (vfs_mount(td, fstype, mntonname, fsflags, fsdata));
800}
801
802int
803linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
804{
805	struct linux_umount_args args2;
806
807	args2.path = args->path;
808	args2.flags = 0;
809	return (linux_umount(td, &args2));
810}
811
812int
813linux_umount(struct thread *td, struct linux_umount_args *args)
814{
815	struct unmount_args bsd;
816
817	bsd.path = args->path;
818	bsd.flags = args->flags;	/* XXX correct? */
819	return (unmount(td, &bsd));
820}
821
822/*
823 * fcntl family of syscalls
824 */
825
826struct l_flock {
827	l_short		l_type;
828	l_short		l_whence;
829	l_off_t		l_start;
830	l_off_t		l_len;
831	l_pid_t		l_pid;
832};
833
834static void
835linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
836{
837	switch (linux_flock->l_type) {
838	case LINUX_F_RDLCK:
839		bsd_flock->l_type = F_RDLCK;
840		break;
841	case LINUX_F_WRLCK:
842		bsd_flock->l_type = F_WRLCK;
843		break;
844	case LINUX_F_UNLCK:
845		bsd_flock->l_type = F_UNLCK;
846		break;
847	default:
848		bsd_flock->l_type = -1;
849		break;
850	}
851	bsd_flock->l_whence = linux_flock->l_whence;
852	bsd_flock->l_start = (off_t)linux_flock->l_start;
853	bsd_flock->l_len = (off_t)linux_flock->l_len;
854	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
855}
856
857static void
858bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
859{
860	switch (bsd_flock->l_type) {
861	case F_RDLCK:
862		linux_flock->l_type = LINUX_F_RDLCK;
863		break;
864	case F_WRLCK:
865		linux_flock->l_type = LINUX_F_WRLCK;
866		break;
867	case F_UNLCK:
868		linux_flock->l_type = LINUX_F_UNLCK;
869		break;
870	}
871	linux_flock->l_whence = bsd_flock->l_whence;
872	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
873	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
874	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
875}
876
877#if defined(__i386__)
878struct l_flock64 {
879	l_short		l_type;
880	l_short		l_whence;
881	l_loff_t	l_start;
882	l_loff_t	l_len;
883	l_pid_t		l_pid;
884};
885
886static void
887linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
888{
889	switch (linux_flock->l_type) {
890	case LINUX_F_RDLCK:
891		bsd_flock->l_type = F_RDLCK;
892		break;
893	case LINUX_F_WRLCK:
894		bsd_flock->l_type = F_WRLCK;
895		break;
896	case LINUX_F_UNLCK:
897		bsd_flock->l_type = F_UNLCK;
898		break;
899	default:
900		bsd_flock->l_type = -1;
901		break;
902	}
903	bsd_flock->l_whence = linux_flock->l_whence;
904	bsd_flock->l_start = (off_t)linux_flock->l_start;
905	bsd_flock->l_len = (off_t)linux_flock->l_len;
906	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
907}
908
909static void
910bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
911{
912	switch (bsd_flock->l_type) {
913	case F_RDLCK:
914		linux_flock->l_type = LINUX_F_RDLCK;
915		break;
916	case F_WRLCK:
917		linux_flock->l_type = LINUX_F_WRLCK;
918		break;
919	case F_UNLCK:
920		linux_flock->l_type = LINUX_F_UNLCK;
921		break;
922	}
923	linux_flock->l_whence = bsd_flock->l_whence;
924	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
925	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
926	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
927}
928#endif /* __i386__ */
929
930#if defined(__alpha__)
931#define	linux_fcntl64_args	linux_fcntl_args
932#endif
933
934static int
935fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
936{
937	struct fcntl_args fcntl_args;
938	struct file *fp;
939	int error, result;
940
941	fcntl_args.fd = args->fd;
942
943	switch (args->cmd) {
944	case LINUX_F_DUPFD:
945		fcntl_args.cmd = F_DUPFD;
946		fcntl_args.arg = args->arg;
947		return (fcntl(td, &fcntl_args));
948
949	case LINUX_F_GETFD:
950		fcntl_args.cmd = F_GETFD;
951		return (fcntl(td, &fcntl_args));
952
953	case LINUX_F_SETFD:
954		fcntl_args.cmd = F_SETFD;
955		fcntl_args.arg = args->arg;
956		return (fcntl(td, &fcntl_args));
957
958	case LINUX_F_GETFL:
959		fcntl_args.cmd = F_GETFL;
960		error = fcntl(td, &fcntl_args);
961		result = td->td_retval[0];
962		td->td_retval[0] = 0;
963		if (result & O_RDONLY)
964			td->td_retval[0] |= LINUX_O_RDONLY;
965		if (result & O_WRONLY)
966			td->td_retval[0] |= LINUX_O_WRONLY;
967		if (result & O_RDWR)
968			td->td_retval[0] |= LINUX_O_RDWR;
969		if (result & O_NDELAY)
970			td->td_retval[0] |= LINUX_O_NONBLOCK;
971		if (result & O_APPEND)
972			td->td_retval[0] |= LINUX_O_APPEND;
973		if (result & O_FSYNC)
974			td->td_retval[0] |= LINUX_O_SYNC;
975		if (result & O_ASYNC)
976			td->td_retval[0] |= LINUX_FASYNC;
977		return (error);
978
979	case LINUX_F_SETFL:
980		fcntl_args.arg = 0;
981		if (args->arg & LINUX_O_NDELAY)
982			fcntl_args.arg |= O_NONBLOCK;
983		if (args->arg & LINUX_O_APPEND)
984			fcntl_args.arg |= O_APPEND;
985		if (args->arg & LINUX_O_SYNC)
986			fcntl_args.arg |= O_FSYNC;
987		if (args->arg & LINUX_FASYNC)
988			fcntl_args.arg |= O_ASYNC;
989		fcntl_args.cmd = F_SETFL;
990		return (fcntl(td, &fcntl_args));
991
992	case LINUX_F_GETOWN:
993		fcntl_args.cmd = F_GETOWN;
994		return (fcntl(td, &fcntl_args));
995
996	case LINUX_F_SETOWN:
997		/*
998		 * XXX some Linux applications depend on F_SETOWN having no
999		 * significant effect for pipes (SIGIO is not delivered for
1000		 * pipes under Linux-2.2.35 at least).
1001		 */
1002		error = fget(td, args->fd, &fp);
1003		if (error)
1004			return (error);
1005		if (fp->f_type == DTYPE_PIPE) {
1006			fdrop(fp, td);
1007			return (EINVAL);
1008		}
1009		fdrop(fp, td);
1010
1011		fcntl_args.cmd = F_SETOWN;
1012		fcntl_args.arg = args->arg;
1013		return (fcntl(td, &fcntl_args));
1014	}
1015
1016	return (EINVAL);
1017}
1018
1019int
1020linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1021{
1022	struct linux_fcntl64_args args64;
1023	struct fcntl_args fcntl_args;
1024	struct l_flock linux_flock;
1025	struct flock *bsd_flock;
1026	int error;
1027	caddr_t sg;
1028
1029	sg = stackgap_init();
1030	bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
1031
1032#ifdef DEBUG
1033	if (ldebug(fcntl))
1034		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1035#endif
1036
1037	switch (args->cmd) {
1038	case LINUX_F_GETLK:
1039		error = copyin((caddr_t)args->arg, &linux_flock,
1040		    sizeof(linux_flock));
1041		if (error)
1042			return (error);
1043		linux_to_bsd_flock(&linux_flock, bsd_flock);
1044		fcntl_args.fd = args->fd;
1045		fcntl_args.cmd = F_GETLK;
1046		fcntl_args.arg = (long)bsd_flock;
1047		error = fcntl(td, &fcntl_args);
1048		if (error)
1049			return (error);
1050		bsd_to_linux_flock(bsd_flock, &linux_flock);
1051		return (copyout(&linux_flock, (caddr_t)args->arg,
1052		    sizeof(linux_flock)));
1053
1054	case LINUX_F_SETLK:
1055		error = copyin((caddr_t)args->arg, &linux_flock,
1056		    sizeof(linux_flock));
1057		if (error)
1058			return (error);
1059		linux_to_bsd_flock(&linux_flock, bsd_flock);
1060		fcntl_args.fd = args->fd;
1061		fcntl_args.cmd = F_SETLK;
1062		fcntl_args.arg = (long)bsd_flock;
1063		return (fcntl(td, &fcntl_args));
1064
1065	case LINUX_F_SETLKW:
1066		error = copyin((caddr_t)args->arg, &linux_flock,
1067		    sizeof(linux_flock));
1068		if (error)
1069			return (error);
1070		linux_to_bsd_flock(&linux_flock, bsd_flock);
1071		fcntl_args.fd = args->fd;
1072		fcntl_args.cmd = F_SETLKW;
1073		fcntl_args.arg = (long)bsd_flock;
1074		return (fcntl(td, &fcntl_args));
1075	}
1076
1077	args64.fd = args->fd;
1078	args64.cmd = args->cmd;
1079	args64.arg = args->arg;
1080	return (fcntl_common(td, &args64));
1081}
1082
1083#if defined(__i386__)
1084int
1085linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1086{
1087	struct fcntl_args fcntl_args;
1088	struct l_flock64 linux_flock;
1089	struct flock *bsd_flock;
1090	int error;
1091	caddr_t sg;
1092
1093	sg = stackgap_init();
1094	bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
1095
1096#ifdef DEBUG
1097	if (ldebug(fcntl64))
1098		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1099#endif
1100
1101	switch (args->cmd) {
1102	case LINUX_F_GETLK:
1103		error = copyin((caddr_t)args->arg, &linux_flock,
1104		    sizeof(linux_flock));
1105		if (error)
1106			return (error);
1107		linux_to_bsd_flock64(&linux_flock, bsd_flock);
1108		fcntl_args.fd = args->fd;
1109		fcntl_args.cmd = F_GETLK;
1110		fcntl_args.arg = (long)bsd_flock;
1111		error = fcntl(td, &fcntl_args);
1112		if (error)
1113			return (error);
1114		bsd_to_linux_flock64(bsd_flock, &linux_flock);
1115		return (copyout(&linux_flock, (caddr_t)args->arg,
1116		    sizeof(linux_flock)));
1117
1118	case LINUX_F_SETLK:
1119		error = copyin((caddr_t)args->arg, &linux_flock,
1120		    sizeof(linux_flock));
1121		if (error)
1122			return (error);
1123		linux_to_bsd_flock64(&linux_flock, bsd_flock);
1124		fcntl_args.fd = args->fd;
1125		fcntl_args.cmd = F_SETLK;
1126		fcntl_args.arg = (long)bsd_flock;
1127		return (fcntl(td, &fcntl_args));
1128
1129	case LINUX_F_SETLKW:
1130		error = copyin((caddr_t)args->arg, &linux_flock,
1131		    sizeof(linux_flock));
1132		if (error)
1133			return (error);
1134		linux_to_bsd_flock64(&linux_flock, bsd_flock);
1135		fcntl_args.fd = args->fd;
1136		fcntl_args.cmd = F_SETLKW;
1137		fcntl_args.arg = (long)bsd_flock;
1138		return (fcntl(td, &fcntl_args));
1139	}
1140
1141	return (fcntl_common(td, args));
1142}
1143#endif /* __i386__ */
1144
1145int
1146linux_chown(struct thread *td, struct linux_chown_args *args)
1147{
1148	struct chown_args bsd;
1149	caddr_t sg;
1150
1151	sg = stackgap_init();
1152	CHECKALTEXIST(td, &sg, args->path);
1153
1154#ifdef DEBUG
1155	if (ldebug(chown))
1156		printf(ARGS(chown, "%s, %d, %d"), args->path, args->uid,
1157		    args->gid);
1158#endif
1159
1160	bsd.path = args->path;
1161	bsd.uid = args->uid;
1162	bsd.gid = args->gid;
1163	return (chown(td, &bsd));
1164}
1165
1166int
1167linux_lchown(struct thread *td, struct linux_lchown_args *args)
1168{
1169	struct lchown_args bsd;
1170	caddr_t sg;
1171
1172	sg = stackgap_init();
1173	CHECKALTEXIST(td, &sg, args->path);
1174
1175#ifdef DEBUG
1176	if (ldebug(lchown))
1177		printf(ARGS(lchown, "%s, %d, %d"), args->path, args->uid,
1178		    args->gid);
1179#endif
1180
1181	bsd.path = args->path;
1182	bsd.uid = args->uid;
1183	bsd.gid = args->gid;
1184	return (lchown(td, &bsd));
1185}
1186