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