linux_file.c revision 24672
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 *  $Id: linux_file.c,v 1.13 1997/04/05 14:50:56 dfr Exp $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/sysproto.h>
34#include <sys/fcntl.h>
35#include <sys/file.h>
36#include <sys/filedesc.h>
37#include <sys/proc.h>
38#include <sys/vnode.h>
39#include <sys/malloc.h>
40#include <sys/dirent.h>
41#include <sys/conf.h>
42#include <sys/tty.h>
43
44#include <i386/linux/linux.h>
45#include <i386/linux/linux_proto.h>
46#include <i386/linux/linux_util.h>
47
48int
49linux_creat(struct proc *p, struct linux_creat_args *args, int *retval)
50{
51    struct open_args /* {
52	char *path;
53	int flags;
54	int mode;
55    } */ bsd_open_args;
56    caddr_t sg;
57
58    sg = stackgap_init();
59    CHECKALTCREAT(p, &sg, args->path);
60
61#ifdef DEBUG
62    printf("Linux-emul(%d): creat(%s, %d)\n",
63	   p->p_pid, args->path, args->mode);
64#endif
65    bsd_open_args.path = args->path;
66    bsd_open_args.mode = args->mode;
67    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
68    return open(p, &bsd_open_args, retval);
69}
70
71int
72linux_open(struct proc *p, struct linux_open_args *args, int *retval)
73{
74    struct open_args /* {
75	char *path;
76	int flags;
77	int mode;
78    } */ bsd_open_args;
79    int error;
80    caddr_t sg;
81
82    sg = stackgap_init();
83
84    if (args->flags & LINUX_O_CREAT)
85	CHECKALTCREAT(p, &sg, args->path);
86    else
87	CHECKALTEXIST(p, &sg, args->path);
88
89#ifdef DEBUG
90    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
91	   p->p_pid, args->path, args->flags, args->mode);
92#endif
93    bsd_open_args.flags = 0;
94    if (args->flags & LINUX_O_RDONLY)
95	bsd_open_args.flags |= O_RDONLY;
96    if (args->flags & LINUX_O_WRONLY)
97	bsd_open_args.flags |= O_WRONLY;
98    if (args->flags & LINUX_O_RDWR)
99	bsd_open_args.flags |= O_RDWR;
100    if (args->flags & LINUX_O_NDELAY)
101	bsd_open_args.flags |= O_NONBLOCK;
102    if (args->flags & LINUX_O_APPEND)
103	bsd_open_args.flags |= O_APPEND;
104    if (args->flags & LINUX_O_SYNC)
105	bsd_open_args.flags |= O_FSYNC;
106    if (args->flags & LINUX_O_NONBLOCK)
107	bsd_open_args.flags |= O_NONBLOCK;
108    if (args->flags & LINUX_FASYNC)
109	bsd_open_args.flags |= O_ASYNC;
110    if (args->flags & LINUX_O_CREAT)
111	bsd_open_args.flags |= O_CREAT;
112    if (args->flags & LINUX_O_TRUNC)
113	bsd_open_args.flags |= O_TRUNC;
114    if (args->flags & LINUX_O_EXCL)
115	bsd_open_args.flags |= O_EXCL;
116    if (args->flags & LINUX_O_NOCTTY)
117	bsd_open_args.flags |= O_NOCTTY;
118    bsd_open_args.path = args->path;
119    bsd_open_args.mode = args->mode;
120
121    error = open(p, &bsd_open_args, retval);
122    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
123	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
124	struct filedesc *fdp = p->p_fd;
125	struct file *fp = fdp->fd_ofiles[*retval];
126
127	if (fp->f_type == DTYPE_VNODE)
128	    (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p);
129    }
130#ifdef DEBUG
131    printf("Linux-emul(%d): open returns error %d\n",
132	   p->p_pid, error);
133#endif
134    return error;
135}
136
137struct linux_flock {
138    short l_type;
139    short l_whence;
140    linux_off_t l_start;
141    linux_off_t l_len;
142    linux_pid_t l_pid;
143};
144
145static void
146linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
147{
148    switch (linux_flock->l_type) {
149    case LINUX_F_RDLCK:
150	bsd_flock->l_type = F_RDLCK;
151	break;
152    case LINUX_F_WRLCK:
153	bsd_flock->l_type = F_WRLCK;
154	break;
155    case LINUX_F_UNLCK:
156	bsd_flock->l_type = F_UNLCK;
157	break;
158    }
159    bsd_flock->l_whence = linux_flock->l_whence;
160    bsd_flock->l_start = (off_t)linux_flock->l_start;
161    bsd_flock->l_len = (off_t)linux_flock->l_len;
162    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
163}
164
165static void
166bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
167{
168    switch (bsd_flock->l_type) {
169    case F_RDLCK:
170	linux_flock->l_type = LINUX_F_RDLCK;
171	break;
172    case F_WRLCK:
173	linux_flock->l_type = LINUX_F_WRLCK;
174	break;
175    case F_UNLCK:
176	linux_flock->l_type = LINUX_F_UNLCK;
177	break;
178    }
179    linux_flock->l_whence = bsd_flock->l_whence;
180    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
181    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
182    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
183}
184
185int
186linux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval)
187{
188    int error, result;
189    struct fcntl_args /* {
190	int fd;
191	int cmd;
192	int arg;
193    } */ fcntl_args;
194    struct linux_flock linux_flock;
195    struct flock *bsd_flock;
196    struct filedesc *fdp;
197    struct file *fp;
198    struct vnode *vp;
199    struct vattr va;
200    long pgid;
201    struct pgrp *pgrp;
202    struct tty *tp, *(*d_tty) __P((dev_t));
203    caddr_t sg;
204
205    sg = stackgap_init();
206    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
207    d_tty = NULL;
208
209#ifdef DEBUG
210    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
211	   p->p_pid, args->fd, args->cmd);
212#endif
213    fcntl_args.fd = args->fd;
214    fcntl_args.arg = 0;
215
216    switch (args->cmd) {
217    case LINUX_F_DUPFD:
218	fcntl_args.cmd = F_DUPFD;
219	return fcntl(p, &fcntl_args, retval);
220
221    case LINUX_F_GETFD:
222	fcntl_args.cmd = F_GETFD;
223	return fcntl(p, &fcntl_args, retval);
224
225    case LINUX_F_SETFD:
226	fcntl_args.cmd = F_SETFD;
227	return fcntl(p, &fcntl_args, retval);
228
229    case LINUX_F_GETFL:
230	fcntl_args.cmd = F_GETFL;
231	error = fcntl(p, &fcntl_args, &result);
232	*retval = 0;
233	if (result & O_RDONLY) *retval |= LINUX_O_RDONLY;
234	if (result & O_WRONLY) *retval |= LINUX_O_WRONLY;
235	if (result & O_RDWR) *retval |= LINUX_O_RDWR;
236	if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK;
237	if (result & O_APPEND) *retval |= LINUX_O_APPEND;
238	if (result & O_FSYNC) *retval |= LINUX_O_SYNC;
239	return error;
240
241    case LINUX_F_SETFL:
242	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
243	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
244	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
245	fcntl_args.cmd = F_SETFL;
246	return fcntl(p, &fcntl_args, retval);
247
248    case LINUX_F_GETLK:
249	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
250		   	    sizeof(struct linux_flock))))
251	    return error;
252	linux_to_bsd_flock(&linux_flock, bsd_flock);
253	fcntl_args.cmd = F_GETLK;
254	fcntl_args.arg = (int)bsd_flock;
255	if (error = fcntl(p, &fcntl_args, retval))
256	    return error;
257	bsd_to_linux_flock(bsd_flock, &linux_flock);
258	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
259		       sizeof(struct linux_flock));
260
261    case LINUX_F_SETLK:
262	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
263		   	    sizeof(struct linux_flock))))
264	    return error;
265	linux_to_bsd_flock(&linux_flock, bsd_flock);
266	fcntl_args.cmd = F_SETLK;
267	fcntl_args.arg = (int)bsd_flock;
268	return fcntl(p, &fcntl_args, retval);
269
270    case LINUX_F_SETLKW:
271	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
272		   	    sizeof(struct linux_flock))))
273	    return error;
274	linux_to_bsd_flock(&linux_flock, bsd_flock);
275	fcntl_args.cmd = F_SETLKW;
276	fcntl_args.arg = (int)bsd_flock;
277	return fcntl(p, &fcntl_args, retval);
278
279    case LINUX_F_SETOWN:
280    case LINUX_F_GETOWN:
281	/*
282	 * We need to route around the normal fcntl() for these calls,
283	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
284	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
285	 * does not exist.
286	 */
287	fdp = p->p_fd;
288	if ((u_int)args->fd >= fdp->fd_nfiles ||
289		(fp = fdp->fd_ofiles[args->fd]) == NULL)
290	    return EBADF;
291	if (fp->f_type == DTYPE_SOCKET) {
292	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
293	    return fcntl(p, &fcntl_args, retval);
294	}
295	vp = (struct vnode *)fp->f_data;
296	if (vp->v_type != VCHR)
297	    return EINVAL;
298	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
299	    return error;
300
301	d_tty = cdevsw[major(va.va_rdev)]->d_devtotty;
302	if (!d_tty || (!(tp = (*d_tty)(va.va_rdev))))
303	    return EINVAL;
304	if (args->cmd == LINUX_F_GETOWN) {
305	    retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
306	    return 0;
307	}
308	if ((long)args->arg <= 0) {
309	    pgid = -(long)args->arg;
310	} else {
311	    struct proc *p1 = pfind((long)args->arg);
312	    if (p1 == 0)
313		return (ESRCH);
314	    pgid = (long)p1->p_pgrp->pg_id;
315	}
316	pgrp = pgfind(pgid);
317	if (pgrp == NULL || pgrp->pg_session != p->p_session)
318	    return EPERM;
319	tp->t_pgrp = pgrp;
320	return 0;
321    }
322    return EINVAL;
323}
324
325int
326linux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval)
327{
328
329    struct lseek_args /* {
330	int fd;
331	int pad;
332	off_t offset;
333	int whence;
334    } */ tmp_args;
335    int error;
336
337#ifdef DEBUG
338    printf("Linux-emul(%d): lseek(%d, %d, %d)\n",
339	   p->p_pid, args->fdes, args->off, args->whence);
340#endif
341    tmp_args.fd = args->fdes;
342    tmp_args.offset = (off_t)args->off;
343    tmp_args.whence = args->whence;
344    error = lseek(p, &tmp_args, retval);
345    return error;
346}
347
348int
349linux_llseek(struct proc *p, struct linux_llseek_args *args, int *retval)
350{
351	struct lseek_args bsd_args;
352	int error;
353	off_t off;
354
355#ifdef DEBUG
356        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
357	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
358#endif
359	off = (args->olow) | (((off_t) args->ohigh) << 32);
360
361	bsd_args.fd = args->fd;
362	bsd_args.offset = off;
363	bsd_args.whence = args->whence;
364
365	if ((error = lseek(p, &bsd_args, retval)))
366		return error;
367
368	if ((error = copyout(retval, (caddr_t)args->res, sizeof (off_t))))
369		return error;
370
371	retval[0] = 0;
372	return 0;
373}
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
386int
387linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval)
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, retval);
395}
396
397int
398linux_getdents(struct proc *p, struct linux_getdents_args *args, int *retval)
399{
400    register struct dirent *bdp;
401    struct vnode *vp;
402    caddr_t inp, buf;		/* BSD-format */
403    int len, reclen;		/* BSD-format */
404    caddr_t outp;		/* Linux-format */
405    int resid, linuxreclen=0;	/* Linux-format */
406    struct file *fp;
407    struct uio auio;
408    struct iovec aiov;
409    struct vattr va;
410    off_t off;
411    struct linux_dirent linux_dirent;
412    int buflen, error, eofflag, nbytes, justone;
413    u_long *cookies = NULL, *cookiep;
414    int ncookies;
415
416#ifdef DEBUG
417    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
418	   p->p_pid, args->fd, args->count);
419#endif
420    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
421	return (error);
422    }
423
424    if ((fp->f_flag & FREAD) == 0)
425	return (EBADF);
426
427    vp = (struct vnode *) fp->f_data;
428
429    if (vp->v_type != VDIR)
430	return (EINVAL);
431
432    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
433	return error;
434    }
435
436    nbytes = args->count;
437    if (nbytes == 1) {
438	nbytes = sizeof (struct linux_dirent);
439	justone = 1;
440    }
441    else
442	justone = 0;
443
444    off = fp->f_offset;
445#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
446    buflen = max(DIRBLKSIZ, nbytes);
447    buflen = min(buflen, MAXBSIZE);
448    buf = malloc(buflen, M_TEMP, M_WAITOK);
449    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
450again:
451    aiov.iov_base = buf;
452    aiov.iov_len = buflen;
453    auio.uio_iov = &aiov;
454    auio.uio_iovcnt = 1;
455    auio.uio_rw = UIO_READ;
456    auio.uio_segflg = UIO_SYSSPACE;
457    auio.uio_procp = p;
458    auio.uio_resid = buflen;
459    auio.uio_offset = off;
460
461    if (cookies) {
462	free(cookies, M_TEMP);
463	cookies = NULL;
464    }
465
466    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
467    if (error) {
468	goto out;
469    }
470
471    inp = buf;
472    outp = (caddr_t) args->dent;
473    resid = nbytes;
474    if ((len = buflen - auio.uio_resid) <= 0) {
475	goto eof;
476    }
477
478    cookiep = cookies;
479
480    if (cookies) {
481	/*
482	 * When using cookies, the vfs has the option of reading from
483	 * a different offset than that supplied (UFS truncates the
484	 * offset to a block boundary to make sure that it never reads
485	 * partway through a directory entry, even if the directory
486	 * has been compacted).
487	 */
488	while (len > 0 && ncookies > 0 && *cookiep <= off) {
489	    bdp = (struct dirent *) inp;
490	    len -= bdp->d_reclen;
491	    inp += bdp->d_reclen;
492	    cookiep++;
493	    ncookies--;
494	}
495    }
496
497    while (len > 0) {
498	if (cookiep && ncookies == 0)
499	    break;
500	bdp = (struct dirent *) inp;
501	reclen = bdp->d_reclen;
502	if (reclen & 3) {
503	    printf("linux_readdir: reclen=%d\n", reclen);
504	    error = EFAULT;
505	    goto out;
506	}
507
508	if (bdp->d_fileno == 0) {
509	    inp += reclen;
510	    if (cookiep) {
511		off = *cookiep++;
512		ncookies--;
513	    } else
514		off += reclen;
515	    len -= reclen;
516	    continue;
517	}
518	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
519	if (reclen > len || resid < linuxreclen) {
520	    outp++;
521	    break;
522	}
523	linux_dirent.dino = (long) bdp->d_fileno;
524	if (justone) {
525	    /*
526	     * old linux-style readdir usage.
527	     */
528	    linux_dirent.doff = (linux_off_t) linuxreclen;
529	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
530	} else {
531	    linux_dirent.doff = (linux_off_t) off;
532	    linux_dirent.dreclen = (u_short) linuxreclen;
533	}
534	strcpy(linux_dirent.dname, bdp->d_name);
535	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
536	    goto out;
537	}
538	inp += reclen;
539	if (cookiep) {
540	    off = *cookiep++;
541	    ncookies--;
542	} else
543	    off += reclen;
544	outp += linuxreclen;
545	resid -= linuxreclen;
546	len -= reclen;
547	if (justone)
548	    break;
549    }
550
551    if (outp == (caddr_t) args->dent)
552	goto again;
553    fp->f_offset = off;
554
555    if (justone)
556	nbytes = resid + linuxreclen;
557
558eof:
559    *retval = nbytes - resid;
560out:
561    if (cookies)
562	free(cookies, M_TEMP);
563    VOP_UNLOCK(vp, 0, p);
564    free(buf, M_TEMP);
565    return error;
566}
567
568/*
569 * These exist mainly for hooks for doing /compat/linux translation.
570 */
571
572int
573linux_access(struct proc *p, struct linux_access_args *args, int *retval)
574{
575	struct access_args bsd;
576	caddr_t sg;
577
578	sg = stackgap_init();
579	CHECKALTEXIST(p, &sg, args->path);
580
581#ifdef DEBUG
582        printf("Linux-emul(%d): access(%s, %d)\n",
583	    p->p_pid, args->path, args->flags);
584#endif
585	bsd.path = args->path;
586	bsd.flags = args->flags;
587
588	return access(p, &bsd, retval);
589}
590
591int
592linux_unlink(struct proc *p, struct linux_unlink_args *args, int *retval)
593{
594	struct unlink_args bsd;
595	caddr_t sg;
596
597	sg = stackgap_init();
598	CHECKALTEXIST(p, &sg, args->path);
599
600#ifdef DEBUG
601	printf("Linux-emul(%d): unlink(%s)\n",
602	   p->p_pid, args->path);
603#endif
604	bsd.path = args->path;
605
606	return unlink(p, &bsd, retval);
607}
608
609int
610linux_chdir(struct proc *p, struct linux_chdir_args *args, int *retval)
611{
612	struct chdir_args bsd;
613	caddr_t sg;
614
615	sg = stackgap_init();
616	CHECKALTEXIST(p, &sg, args->path);
617
618#ifdef DEBUG
619	printf("Linux-emul(%d): chdir(%s)\n",
620	   p->p_pid, args->path);
621#endif
622	bsd.path = args->path;
623
624	return chdir(p, &bsd, retval);
625}
626
627int
628linux_chmod(struct proc *p, struct linux_chmod_args *args, int *retval)
629{
630	struct chmod_args bsd;
631	caddr_t sg;
632
633	sg = stackgap_init();
634	CHECKALTEXIST(p, &sg, args->path);
635
636#ifdef DEBUG
637        printf("Linux-emul(%d): chmod(%s, %d)\n",
638	    p->p_pid, args->path, args->mode);
639#endif
640	bsd.path = args->path;
641	bsd.mode = args->mode;
642
643	return chmod(p, &bsd, retval);
644}
645
646int
647linux_chown(struct proc *p, struct linux_chown_args *args, int *retval)
648{
649	struct chown_args bsd;
650	caddr_t sg;
651
652	sg = stackgap_init();
653	CHECKALTEXIST(p, &sg, args->path);
654
655#ifdef DEBUG
656        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
657	    p->p_pid, args->path, args->uid, args->gid);
658#endif
659	bsd.path = args->path;
660	/* XXX size casts here */
661	bsd.uid = args->uid;
662	bsd.gid = args->gid;
663
664	return chown(p, &bsd, retval);
665}
666
667int
668linux_mkdir(struct proc *p, struct linux_mkdir_args *args, int *retval)
669{
670	struct mkdir_args bsd;
671	caddr_t sg;
672
673	sg = stackgap_init();
674	CHECKALTCREAT(p, &sg, args->path);
675
676#ifdef DEBUG
677        printf("Linux-emul(%d): mkdir(%s, %d)\n",
678	    p->p_pid, args->path, args->mode);
679#endif
680	bsd.path = args->path;
681	bsd.mode = args->mode;
682
683	return mkdir(p, &bsd, retval);
684}
685
686int
687linux_rmdir(struct proc *p, struct linux_rmdir_args *args, int *retval)
688{
689	struct rmdir_args bsd;
690	caddr_t sg;
691
692	sg = stackgap_init();
693	CHECKALTEXIST(p, &sg, args->path);
694
695#ifdef DEBUG
696        printf("Linux-emul(%d): rmdir(%s)\n",
697	    p->p_pid, args->path);
698#endif
699	bsd.path = args->path;
700
701	return rmdir(p, &bsd, retval);
702}
703
704int
705linux_rename(struct proc *p, struct linux_rename_args *args, int *retval)
706{
707	struct rename_args bsd;
708	caddr_t sg;
709
710	sg = stackgap_init();
711	CHECKALTEXIST(p, &sg, args->from);
712	CHECKALTCREAT(p, &sg, args->to);
713
714#ifdef DEBUG
715        printf("Linux-emul(%d): rename(%s, %s)\n",
716	    p->p_pid, args->from, args->to);
717#endif
718	bsd.from = args->from;
719	bsd.to = args->to;
720
721	return rename(p, &bsd, retval);
722}
723
724int
725linux_symlink(struct proc *p, struct linux_symlink_args *args, int *retval)
726{
727	struct symlink_args bsd;
728	caddr_t sg;
729
730	sg = stackgap_init();
731	CHECKALTEXIST(p, &sg, args->path);
732	CHECKALTCREAT(p, &sg, args->to);
733
734#ifdef DEBUG
735        printf("Linux-emul(%d): symlink(%s, %s)\n",
736	    p->p_pid, args->path, args->to);
737#endif
738	bsd.path = args->path;
739	bsd.link = args->to;
740
741	return symlink(p, &bsd, retval);
742}
743
744int
745linux_execve(struct proc *p, struct linux_execve_args *args, int *retval)
746{
747	struct execve_args bsd;
748	caddr_t sg;
749
750	sg = stackgap_init();
751	CHECKALTEXIST(p, &sg, args->path);
752
753#ifdef DEBUG
754        printf("Linux-emul(%d): execve(%s)\n",
755	    p->p_pid, args->path);
756#endif
757	bsd.fname = args->path;
758	bsd.argv = args->argp;
759	bsd.envv = args->envp;
760
761	return execve(p, &bsd, retval);
762}
763
764int
765linux_readlink(struct proc *p, struct linux_readlink_args *args, int *retval)
766{
767	struct readlink_args bsd;
768	caddr_t sg;
769
770	sg = stackgap_init();
771	CHECKALTEXIST(p, &sg, args->name);
772
773#ifdef DEBUG
774        printf("Linux-emul(%d): readlink(%s, 0x%x, %d)\n",
775	    p->p_pid, args->name, args->buf, args->count);
776#endif
777	bsd.path = args->name;
778	bsd.buf = args->buf;
779	bsd.count = args->count;
780
781	return readlink(p, &bsd, retval);
782}
783
784int
785linux_truncate(struct proc *p, struct linux_truncate_args *args, int *retval)
786{
787	struct otruncate_args bsd;
788	caddr_t sg;
789
790	sg = stackgap_init();
791	CHECKALTEXIST(p, &sg, args->path);
792
793#ifdef DEBUG
794        printf("Linux-emul(%d): truncate(%s)\n",
795	    p->p_pid, args->path);
796#endif
797	bsd.path = args->path;
798
799	return otruncate(p, &bsd, retval);
800}
801
802