linux_file.c revision 82518
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 82518 2001-08-29 19:05:27Z gallatin $
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
152struct linux_flock {
153    short l_type;
154    short l_whence;
155    linux_off_t l_start;
156    linux_off_t l_len;
157    linux_pid_t l_pid;
158};
159
160static void
161linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
162{
163    switch (linux_flock->l_type) {
164    case LINUX_F_RDLCK:
165	bsd_flock->l_type = F_RDLCK;
166	break;
167    case LINUX_F_WRLCK:
168	bsd_flock->l_type = F_WRLCK;
169	break;
170    case LINUX_F_UNLCK:
171	bsd_flock->l_type = F_UNLCK;
172	break;
173    default:
174        bsd_flock->l_type = -1;
175        break;
176    }
177    bsd_flock->l_whence = linux_flock->l_whence;
178    bsd_flock->l_start = (off_t)linux_flock->l_start;
179    bsd_flock->l_len = (off_t)linux_flock->l_len;
180    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
181}
182
183static void
184bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
185{
186    switch (bsd_flock->l_type) {
187    case F_RDLCK:
188	linux_flock->l_type = LINUX_F_RDLCK;
189	break;
190    case F_WRLCK:
191	linux_flock->l_type = LINUX_F_WRLCK;
192	break;
193    case F_UNLCK:
194	linux_flock->l_type = LINUX_F_UNLCK;
195	break;
196    }
197    linux_flock->l_whence = bsd_flock->l_whence;
198    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
199    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
200    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
201}
202
203int
204linux_fcntl(struct proc *p, struct linux_fcntl_args *args)
205{
206    int error, result;
207    struct fcntl_args /* {
208	int fd;
209	int cmd;
210	long arg;
211    } */ fcntl_args;
212    struct linux_flock linux_flock;
213    struct flock *bsd_flock;
214    struct filedesc *fdp;
215    struct file *fp;
216    caddr_t sg;
217
218    sg = stackgap_init();
219    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
220
221#ifdef DEBUG
222	if (ldebug(fcntl))
223		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
224#endif
225    fcntl_args.fd = args->fd;
226
227    switch (args->cmd) {
228    case LINUX_F_DUPFD:
229	fcntl_args.cmd = F_DUPFD;
230	fcntl_args.arg = args->arg;
231	return fcntl(p, &fcntl_args);
232
233    case LINUX_F_GETFD:
234	fcntl_args.cmd = F_GETFD;
235	return fcntl(p, &fcntl_args);
236
237    case LINUX_F_SETFD:
238	fcntl_args.cmd = F_SETFD;
239	fcntl_args.arg = args->arg;
240	return fcntl(p, &fcntl_args);
241
242    case LINUX_F_GETFL:
243	fcntl_args.cmd = F_GETFL;
244	error = fcntl(p, &fcntl_args);
245	result = p->p_retval[0];
246	p->p_retval[0] = 0;
247	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
248	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
249	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
250	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
251	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
252	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
253	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
254	return error;
255
256    case LINUX_F_SETFL:
257	fcntl_args.arg = 0;
258	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
259	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
260	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
261	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
262	fcntl_args.cmd = F_SETFL;
263	return fcntl(p, &fcntl_args);
264
265    case LINUX_F_GETLK:
266	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
267		   	    sizeof(struct linux_flock))))
268	    return error;
269	linux_to_bsd_flock(&linux_flock, bsd_flock);
270	fcntl_args.cmd = F_GETLK;
271	fcntl_args.arg = (long)bsd_flock;
272	error = fcntl(p, &fcntl_args);
273	if (error)
274	    return error;
275	bsd_to_linux_flock(bsd_flock, &linux_flock);
276	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
277		       sizeof(struct linux_flock));
278
279    case LINUX_F_SETLK:
280	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
281		   	    sizeof(struct linux_flock))))
282	    return error;
283	linux_to_bsd_flock(&linux_flock, bsd_flock);
284	fcntl_args.cmd = F_SETLK;
285	fcntl_args.arg = (long)bsd_flock;
286	return fcntl(p, &fcntl_args);
287
288    case LINUX_F_SETLKW:
289	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
290		   	    sizeof(struct linux_flock))))
291	    return error;
292	linux_to_bsd_flock(&linux_flock, bsd_flock);
293	fcntl_args.cmd = F_SETLKW;
294	fcntl_args.arg = (long)bsd_flock;
295	return fcntl(p, &fcntl_args);
296
297    case LINUX_F_GETOWN:
298	fcntl_args.cmd = F_GETOWN;
299	return fcntl(p, &fcntl_args);
300
301    case LINUX_F_SETOWN:
302	/*
303	 * XXX some Linux applications depend on F_SETOWN having no
304	 * significant effect for pipes (SIGIO is not delivered for
305	 * pipes under Linux-2.2.35 at least).
306	 */
307	fdp = p->p_fd;
308	if ((u_int)args->fd >= fdp->fd_nfiles ||
309	  (fp = fdp->fd_ofiles[args->fd]) == NULL)
310	    return EBADF;
311	if (fp->f_type == DTYPE_PIPE)
312	    return EINVAL;
313
314 	fcntl_args.cmd = F_SETOWN;
315	fcntl_args.arg = args->arg;
316	return fcntl(p, &fcntl_args);
317    }
318    return EINVAL;
319}
320
321int
322linux_lseek(struct proc *p, struct linux_lseek_args *args)
323{
324
325    struct lseek_args /* {
326	int fd;
327	int pad;
328	off_t offset;
329	int whence;
330    } */ tmp_args;
331    int error;
332
333#ifdef DEBUG
334	if (ldebug(lseek))
335		printf(ARGS(lseek, "%d, %ld, %d"),
336		    args->fdes, args->off, args->whence);
337#endif
338    tmp_args.fd = args->fdes;
339    tmp_args.offset = (off_t)args->off;
340    tmp_args.whence = args->whence;
341    error = lseek(p, &tmp_args);
342    return error;
343}
344
345#ifndef __alpha__
346int
347linux_llseek(struct proc *p, struct linux_llseek_args *args)
348{
349	struct lseek_args bsd_args;
350	int error;
351	off_t off;
352
353#ifdef DEBUG
354	if (ldebug(llseek))
355		printf(ARGS(llseek, "%d, %d:%d, %d"),
356		    args->fd, args->ohigh, args->olow, args->whence);
357#endif
358	off = (args->olow) | (((off_t) args->ohigh) << 32);
359
360	bsd_args.fd = args->fd;
361	bsd_args.offset = off;
362	bsd_args.whence = args->whence;
363
364	if ((error = lseek(p, &bsd_args)))
365		return error;
366
367	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
368		return error;
369
370	p->p_retval[0] = 0;
371	return 0;
372}
373#endif /*!__alpha__*/
374
375
376struct linux_dirent {
377    long dino;
378    linux_off_t doff;
379    unsigned short dreclen;
380    char dname[LINUX_NAME_MAX + 1];
381};
382
383#define LINUX_RECLEN(de,namlen) \
384    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
385
386#ifndef __alpha__
387int
388linux_readdir(struct proc *p, struct linux_readdir_args *args)
389{
390	struct linux_getdents_args lda;
391
392	lda.fd = args->fd;
393	lda.dent = args->dent;
394	lda.count = 1;
395	return linux_getdents(p, &lda);
396}
397#endif /*!__alpha__*/
398
399int
400linux_getdents(struct proc *p, struct linux_getdents_args *args)
401{
402    register struct dirent *bdp;
403    struct vnode *vp;
404    caddr_t inp, buf;		/* BSD-format */
405    int len, reclen;		/* BSD-format */
406    caddr_t outp;		/* Linux-format */
407    int resid, linuxreclen=0;	/* Linux-format */
408    struct file *fp;
409    struct uio auio;
410    struct iovec aiov;
411    struct vattr va;
412    off_t off;
413    struct linux_dirent linux_dirent;
414    int buflen, error, eofflag, nbytes, justone;
415    u_long *cookies = NULL, *cookiep;
416    int ncookies;
417
418#ifdef DEBUG
419	if (ldebug(getdents))
420		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
421#endif
422    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
423	return (error);
424    }
425
426    if ((fp->f_flag & FREAD) == 0)
427	return (EBADF);
428
429    vp = (struct vnode *) fp->f_data;
430
431    if (vp->v_type != VDIR)
432	return (EINVAL);
433
434    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
435	return error;
436    }
437
438    nbytes = args->count;
439    if (nbytes == 1) {
440	nbytes = sizeof (struct linux_dirent);
441	justone = 1;
442    }
443    else
444	justone = 0;
445
446    off = fp->f_offset;
447#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
448    buflen = max(DIRBLKSIZ, nbytes);
449    buflen = min(buflen, MAXBSIZE);
450    buf = malloc(buflen, M_TEMP, M_WAITOK);
451    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
452again:
453    aiov.iov_base = buf;
454    aiov.iov_len = buflen;
455    auio.uio_iov = &aiov;
456    auio.uio_iovcnt = 1;
457    auio.uio_rw = UIO_READ;
458    auio.uio_segflg = UIO_SYSSPACE;
459    auio.uio_procp = p;
460    auio.uio_resid = buflen;
461    auio.uio_offset = off;
462
463    if (cookies) {
464	free(cookies, M_TEMP);
465	cookies = NULL;
466    }
467
468    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
469    if (error) {
470	goto out;
471    }
472
473    inp = buf;
474    outp = (caddr_t) args->dent;
475    resid = nbytes;
476    if ((len = buflen - auio.uio_resid) <= 0) {
477	goto eof;
478    }
479
480    cookiep = cookies;
481
482    if (cookies) {
483	/*
484	 * When using cookies, the vfs has the option of reading from
485	 * a different offset than that supplied (UFS truncates the
486	 * offset to a block boundary to make sure that it never reads
487	 * partway through a directory entry, even if the directory
488	 * has been compacted).
489	 */
490	while (len > 0 && ncookies > 0 && *cookiep <= off) {
491	    bdp = (struct dirent *) inp;
492	    len -= bdp->d_reclen;
493	    inp += bdp->d_reclen;
494	    cookiep++;
495	    ncookies--;
496	}
497    }
498
499    while (len > 0) {
500	if (cookiep && ncookies == 0)
501	    break;
502	bdp = (struct dirent *) inp;
503	reclen = bdp->d_reclen;
504	if (reclen & 3) {
505	    printf("linux_readdir: reclen=%d\n", reclen);
506	    error = EFAULT;
507	    goto out;
508	}
509
510	if (bdp->d_fileno == 0) {
511	    inp += reclen;
512	    if (cookiep) {
513		off = *cookiep++;
514		ncookies--;
515	    } else
516		off += reclen;
517	    len -= reclen;
518	    continue;
519	}
520	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
521	if (reclen > len || resid < linuxreclen) {
522	    outp++;
523	    break;
524	}
525	linux_dirent.dino = (long) bdp->d_fileno;
526	if (justone) {
527	    /*
528	     * old linux-style readdir usage.
529	     */
530	    linux_dirent.doff = (linux_off_t) linuxreclen;
531	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
532	} else {
533	    if (cookiep)
534		linux_dirent.doff = (linux_off_t)*cookiep;
535	    else
536		linux_dirent.doff = (linux_off_t)(off + reclen);
537	    linux_dirent.dreclen = (u_short) linuxreclen;
538	}
539	strcpy(linux_dirent.dname, bdp->d_name);
540	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
541	    goto out;
542	}
543	inp += reclen;
544	if (cookiep) {
545	    off = *cookiep++;
546	    ncookies--;
547	} else
548	    off += reclen;
549	outp += linuxreclen;
550	resid -= linuxreclen;
551	len -= reclen;
552	if (justone)
553	    break;
554    }
555
556    if (outp == (caddr_t) args->dent)
557	goto again;
558    fp->f_offset = off;
559
560    if (justone)
561	nbytes = resid + linuxreclen;
562
563eof:
564    p->p_retval[0] = nbytes - resid;
565out:
566    if (cookies)
567	free(cookies, M_TEMP);
568    VOP_UNLOCK(vp, 0, p);
569    free(buf, M_TEMP);
570    return error;
571}
572
573/*
574 * These exist mainly for hooks for doing /compat/linux translation.
575 */
576
577int
578linux_access(struct proc *p, struct linux_access_args *args)
579{
580	struct access_args bsd;
581	caddr_t sg;
582
583	sg = stackgap_init();
584	CHECKALTEXIST(p, &sg, args->path);
585
586#ifdef DEBUG
587	if (ldebug(access))
588		printf(ARGS(access, "%s, %d"), args->path, args->flags);
589#endif
590	bsd.path = args->path;
591	bsd.flags = args->flags;
592
593	return access(p, &bsd);
594}
595
596int
597linux_unlink(struct proc *p, struct linux_unlink_args *args)
598{
599	struct unlink_args bsd;
600	caddr_t sg;
601
602	sg = stackgap_init();
603	CHECKALTEXIST(p, &sg, args->path);
604
605#ifdef DEBUG
606	if (ldebug(unlink))
607		printf(ARGS(unlink, "%s"), args->path);
608#endif
609	bsd.path = args->path;
610
611	return unlink(p, &bsd);
612}
613
614int
615linux_chdir(struct proc *p, struct linux_chdir_args *args)
616{
617	struct chdir_args bsd;
618	caddr_t sg;
619
620	sg = stackgap_init();
621	CHECKALTEXIST(p, &sg, args->path);
622
623#ifdef DEBUG
624	if (ldebug(chdir))
625		printf(ARGS(chdir, "%s"), args->path);
626#endif
627	bsd.path = args->path;
628
629	return chdir(p, &bsd);
630}
631
632int
633linux_chmod(struct proc *p, struct linux_chmod_args *args)
634{
635	struct chmod_args bsd;
636	caddr_t sg;
637
638	sg = stackgap_init();
639	CHECKALTEXIST(p, &sg, args->path);
640
641#ifdef DEBUG
642	if (ldebug(chmod))
643		printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
644#endif
645	bsd.path = args->path;
646	bsd.mode = args->mode;
647
648	return chmod(p, &bsd);
649}
650
651int
652linux_chown(struct proc *p, struct linux_chown_args *args)
653{
654	struct chown_args bsd;
655	caddr_t sg;
656
657	sg = stackgap_init();
658	CHECKALTEXIST(p, &sg, args->path);
659
660#ifdef DEBUG
661	if (ldebug(chown))
662		printf(ARGS(chown, "%s, %d, %d"),
663		    args->path, args->uid, args->gid);
664#endif
665	bsd.path = args->path;
666	/* XXX size casts here */
667	bsd.uid = args->uid;
668	bsd.gid = args->gid;
669
670	return chown(p, &bsd);
671}
672
673int
674linux_lchown(struct proc *p, struct linux_lchown_args *args)
675{
676	struct lchown_args bsd;
677	caddr_t sg;
678
679	sg = stackgap_init();
680	CHECKALTEXIST(p, &sg, args->path);
681
682#ifdef DEBUG
683	if (ldebug(lchown))
684		printf(ARGS(lchown, "%s, %d, %d"),
685		    args->path, args->uid, args->gid);
686#endif
687	bsd.path = args->path;
688	/* XXX size casts here */
689	bsd.uid = args->uid;
690	bsd.gid = args->gid;
691
692	return lchown(p, &bsd);
693}
694
695int
696linux_mkdir(struct proc *p, struct linux_mkdir_args *args)
697{
698	struct mkdir_args bsd;
699	caddr_t sg;
700
701	sg = stackgap_init();
702	CHECKALTCREAT(p, &sg, args->path);
703
704#ifdef DEBUG
705	if (ldebug(mkdir))
706		printf(ARGS(mkdir, "%s, %d"), args->path, args->mode);
707#endif
708	bsd.path = args->path;
709	bsd.mode = args->mode;
710
711	return mkdir(p, &bsd);
712}
713
714int
715linux_rmdir(struct proc *p, struct linux_rmdir_args *args)
716{
717	struct rmdir_args bsd;
718	caddr_t sg;
719
720	sg = stackgap_init();
721	CHECKALTEXIST(p, &sg, args->path);
722
723#ifdef DEBUG
724	if (ldebug(rmdir))
725		printf(ARGS(rmdir, "%s"), args->path);
726#endif
727	bsd.path = args->path;
728
729	return rmdir(p, &bsd);
730}
731
732int
733linux_rename(struct proc *p, struct linux_rename_args *args)
734{
735	struct rename_args bsd;
736	caddr_t sg;
737
738	sg = stackgap_init();
739	CHECKALTEXIST(p, &sg, args->from);
740	CHECKALTCREAT(p, &sg, args->to);
741
742#ifdef DEBUG
743	if (ldebug(rename))
744		printf(ARGS(rename, "%s, %s"), args->from, args->to);
745#endif
746	bsd.from = args->from;
747	bsd.to = args->to;
748
749	return rename(p, &bsd);
750}
751
752int
753linux_symlink(struct proc *p, struct linux_symlink_args *args)
754{
755	struct symlink_args bsd;
756	caddr_t sg;
757
758	sg = stackgap_init();
759	CHECKALTEXIST(p, &sg, args->path);
760	CHECKALTCREAT(p, &sg, args->to);
761
762#ifdef DEBUG
763	if (ldebug(symlink))
764		printf(ARGS(symlink, "%s, %s"), args->path, args->to);
765#endif
766	bsd.path = args->path;
767	bsd.link = args->to;
768
769	return symlink(p, &bsd);
770}
771
772int
773linux_readlink(struct proc *p, struct linux_readlink_args *args)
774{
775	struct readlink_args bsd;
776	caddr_t sg;
777
778	sg = stackgap_init();
779	CHECKALTEXIST(p, &sg, args->name);
780
781#ifdef DEBUG
782	if (ldebug(readlink))
783		printf(ARGS(readlink, "%s, %p, %d"),
784		    args->name, (void *)args->buf, args->count);
785#endif
786	bsd.path = args->name;
787	bsd.buf = args->buf;
788	bsd.count = args->count;
789
790	return readlink(p, &bsd);
791}
792
793int
794linux_truncate(struct proc *p, struct linux_truncate_args *args)
795{
796	struct truncate_args bsd;
797	caddr_t sg;
798
799	sg = stackgap_init();
800	CHECKALTEXIST(p, &sg, args->path);
801
802#ifdef DEBUG
803	if (ldebug(truncate))
804		printf(ARGS(truncate, "%s, %ld"), args->path, args->length);
805#endif
806	bsd.path = args->path;
807	bsd.length = args->length;
808
809	return truncate(p, &bsd);
810}
811
812int
813linux_link(struct proc *p, struct linux_link_args *args)
814{
815    struct link_args bsd;
816    caddr_t sg;
817
818    sg = stackgap_init();
819    CHECKALTEXIST(p, &sg, args->path);
820    CHECKALTCREAT(p, &sg, args->to);
821
822#ifdef DEBUG
823	if (ldebug(link))
824		printf(ARGS(link, "%s, %s"), args->path, args->to);
825#endif
826
827    bsd.path = args->path;
828    bsd.link = args->to;
829
830    return link(p, &bsd);
831}
832
833#ifndef __alpha__
834int
835linux_fdatasync(p, uap)
836	struct proc *p;
837	struct linux_fdatasync_args *uap;
838{
839	struct fsync_args bsd;
840
841	bsd.fd = uap->fd;
842	return fsync(p, &bsd);
843}
844#endif /*!__alpha__*/
845
846int
847linux_pread(p, uap)
848	struct proc *p;
849	struct linux_pread_args *uap;
850{
851	struct pread_args bsd;
852
853	bsd.fd = uap->fd;
854	bsd.buf = uap->buf;
855	bsd.nbyte = uap->nbyte;
856	bsd.offset = uap->offset;
857	return pread(p, &bsd);
858}
859
860int
861linux_pwrite(p, uap)
862	struct proc *p;
863	struct linux_pwrite_args *uap;
864{
865	struct pwrite_args bsd;
866
867	bsd.fd = uap->fd;
868	bsd.buf = uap->buf;
869	bsd.nbyte = uap->nbyte;
870	bsd.offset = uap->offset;
871	return pwrite(p, &bsd);
872}
873
874int
875linux_mount(struct proc *p, struct linux_mount_args *args)
876{
877	struct ufs_args ufs;
878        char fstypename[MFSNAMELEN];
879        char mntonname[MNAMELEN], mntfromname[MNAMELEN];
880	int error;
881	int fsflags;
882	const char *fstype;
883	void *fsdata;
884
885        error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
886	    NULL);
887	if (error)
888                return (error);
889        error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
890	if (error)
891                return (error);
892        error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
893	if (error)
894                return (error);
895
896#ifdef DEBUG
897	if (ldebug(mount))
898		printf(ARGS(mount, "%s, %s, %s"),
899		    fstypename, mntfromname, mntonname);
900#endif
901
902	if (strcmp(fstypename, "ext2") == 0) {
903		fstype = "ext2fs";
904		fsdata = &ufs;
905		ufs.fspec = mntfromname;
906#define DEFAULT_ROOTID		-2
907		ufs.export.ex_root = DEFAULT_ROOTID;
908		ufs.export.ex_flags =
909		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
910	} else if (strcmp(fstypename, "proc") == 0) {
911		fstype = "linprocfs";
912		fsdata = NULL;
913	} else {
914		return (ENODEV);
915	}
916
917	fsflags = 0;
918
919	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
920		/*
921		 * Linux SYNC flag is not included; the closest equivalent
922		 * FreeBSD has is !ASYNC, which is our default.
923		 */
924		if (args->rwflag & LINUX_MS_RDONLY)
925			fsflags |= MNT_RDONLY;
926		if (args->rwflag & LINUX_MS_NOSUID)
927			fsflags |= MNT_NOSUID;
928		if (args->rwflag & LINUX_MS_NODEV)
929			fsflags |= MNT_NODEV;
930		if (args->rwflag & LINUX_MS_NOEXEC)
931			fsflags |= MNT_NOEXEC;
932		if (args->rwflag & LINUX_MS_REMOUNT)
933			fsflags |= MNT_UPDATE;
934	}
935
936	return (vfs_mount(p, fstype, mntonname, fsflags, fsdata));
937}
938
939int
940linux_umount(struct proc *p, struct linux_umount_args *args)
941{
942	struct linux_umount2_args args2;
943
944	args2.path = args->path;
945	args2.flags = 0;
946	return (linux_umount2(p, &args2));
947}
948
949int
950linux_umount2(struct proc *p, struct linux_umount2_args *args)
951{
952	struct unmount_args bsd;
953
954	bsd.path = args->path;
955	bsd.flags = args->flags;	/* XXX correct? */
956	return (unmount(p, &bsd));
957}
958