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