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