linux_file.c revision 50477
19313Ssos/*-
29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
99313Ssos *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
159313Ssos *    derived from this software withough specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos *
2850477Speter * $FreeBSD: head/sys/compat/linux/linux_file.c 50477 1999-08-28 01:08:13Z peter $
299313Ssos */
309313Ssos
3131784Seivind#include "opt_compat.h"
3231784Seivind
339313Ssos#include <sys/param.h>
349313Ssos#include <sys/systm.h>
3512458Sbde#include <sys/sysproto.h>
369313Ssos#include <sys/fcntl.h>
379313Ssos#include <sys/file.h>
389313Ssos#include <sys/filedesc.h>
3931561Sbde#include <sys/lock.h>
409313Ssos#include <sys/proc.h>
419313Ssos#include <sys/vnode.h>
429313Ssos#include <sys/malloc.h>
439313Ssos#include <sys/dirent.h>
4414331Speter#include <sys/conf.h>
4514331Speter#include <sys/tty.h>
4612458Sbde
4712458Sbde#include <i386/linux/linux.h>
4814331Speter#include <i386/linux/linux_proto.h>
4914331Speter#include <i386/linux/linux_util.h>
509313Ssos
519313Ssosint
5230994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
539313Ssos{
5412858Speter    struct open_args /* {
559313Ssos	char *path;
569313Ssos	int flags;
579313Ssos	int mode;
5812858Speter    } */ bsd_open_args;
5914331Speter    caddr_t sg;
609313Ssos
6114331Speter    sg = stackgap_init();
6214331Speter    CHECKALTCREAT(p, &sg, args->path);
6314331Speter
649313Ssos#ifdef DEBUG
659313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
669313Ssos	   p->p_pid, args->path, args->mode);
679313Ssos#endif
689313Ssos    bsd_open_args.path = args->path;
699313Ssos    bsd_open_args.mode = args->mode;
709313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7130994Sphk    return open(p, &bsd_open_args);
729313Ssos}
739313Ssos
749313Ssosint
7530994Sphklinux_open(struct proc *p, struct linux_open_args *args)
769313Ssos{
7712858Speter    struct open_args /* {
789313Ssos	char *path;
799313Ssos	int flags;
809313Ssos	int mode;
8112858Speter    } */ bsd_open_args;
829313Ssos    int error;
8314331Speter    caddr_t sg;
8414331Speter
8514331Speter    sg = stackgap_init();
869313Ssos
8714331Speter    if (args->flags & LINUX_O_CREAT)
8814331Speter	CHECKALTCREAT(p, &sg, args->path);
8914331Speter    else
9014331Speter	CHECKALTEXIST(p, &sg, args->path);
9114331Speter
929313Ssos#ifdef DEBUG
939313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
949313Ssos	   p->p_pid, args->path, args->flags, args->mode);
959313Ssos#endif
969313Ssos    bsd_open_args.flags = 0;
979313Ssos    if (args->flags & LINUX_O_RDONLY)
989313Ssos	bsd_open_args.flags |= O_RDONLY;
999313Ssos    if (args->flags & LINUX_O_WRONLY)
1009313Ssos	bsd_open_args.flags |= O_WRONLY;
1019313Ssos    if (args->flags & LINUX_O_RDWR)
1029313Ssos	bsd_open_args.flags |= O_RDWR;
1039313Ssos    if (args->flags & LINUX_O_NDELAY)
1049313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1059313Ssos    if (args->flags & LINUX_O_APPEND)
1069313Ssos	bsd_open_args.flags |= O_APPEND;
1079313Ssos    if (args->flags & LINUX_O_SYNC)
1089313Ssos	bsd_open_args.flags |= O_FSYNC;
1099313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1109313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1119313Ssos    if (args->flags & LINUX_FASYNC)
1129313Ssos	bsd_open_args.flags |= O_ASYNC;
1139313Ssos    if (args->flags & LINUX_O_CREAT)
1149313Ssos	bsd_open_args.flags |= O_CREAT;
1159313Ssos    if (args->flags & LINUX_O_TRUNC)
1169313Ssos	bsd_open_args.flags |= O_TRUNC;
1179313Ssos    if (args->flags & LINUX_O_EXCL)
1189313Ssos	bsd_open_args.flags |= O_EXCL;
1199313Ssos    if (args->flags & LINUX_O_NOCTTY)
1209313Ssos	bsd_open_args.flags |= O_NOCTTY;
1219313Ssos    bsd_open_args.path = args->path;
1229313Ssos    bsd_open_args.mode = args->mode;
1239313Ssos
12430994Sphk    error = open(p, &bsd_open_args);
1259313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1269313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1279313Ssos	struct filedesc *fdp = p->p_fd;
12830994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1299313Ssos
1309313Ssos	if (fp->f_type == DTYPE_VNODE)
1319313Ssos	    (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p);
1329313Ssos    }
13314331Speter#ifdef DEBUG
13414331Speter    printf("Linux-emul(%d): open returns error %d\n",
13514331Speter	   p->p_pid, error);
13614331Speter#endif
1379313Ssos    return error;
1389313Ssos}
1399313Ssos
1409313Ssosstruct linux_flock {
1419313Ssos    short l_type;
1429313Ssos    short l_whence;
1439313Ssos    linux_off_t l_start;
1449313Ssos    linux_off_t l_len;
1459313Ssos    linux_pid_t l_pid;
1469313Ssos};
1479313Ssos
1489313Ssosstatic void
1499313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1509313Ssos{
1519313Ssos    switch (linux_flock->l_type) {
1529313Ssos    case LINUX_F_RDLCK:
1539313Ssos	bsd_flock->l_type = F_RDLCK;
1549313Ssos	break;
1559313Ssos    case LINUX_F_WRLCK:
1569313Ssos	bsd_flock->l_type = F_WRLCK;
1579313Ssos	break;
1589313Ssos    case LINUX_F_UNLCK:
1599313Ssos	bsd_flock->l_type = F_UNLCK;
1609313Ssos	break;
16149676Smarcel    default:
16249676Smarcel        bsd_flock->l_type = -1;
16349676Smarcel        break;
1649313Ssos    }
1659313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1669313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1679313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1689313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1699313Ssos}
1709313Ssos
1719313Ssosstatic void
1729313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1739313Ssos{
1749313Ssos    switch (bsd_flock->l_type) {
1759313Ssos    case F_RDLCK:
1769313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1779313Ssos	break;
1789313Ssos    case F_WRLCK:
1799313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1809313Ssos	break;
1819313Ssos    case F_UNLCK:
1829313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1839313Ssos	break;
1849313Ssos    }
1859313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1869313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1879313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1889313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1899313Ssos}
1909313Ssos
1919313Ssosint
19230994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1939313Ssos{
1949313Ssos    int error, result;
19512858Speter    struct fcntl_args /* {
1969313Ssos	int fd;
1979313Ssos	int cmd;
1989313Ssos	int arg;
19912858Speter    } */ fcntl_args;
2009313Ssos    struct linux_flock linux_flock;
20114331Speter    struct flock *bsd_flock;
20214331Speter    struct filedesc *fdp;
20314331Speter    struct file *fp;
20414331Speter    struct vnode *vp;
20514331Speter    long pgid;
20614331Speter    struct pgrp *pgrp;
20714331Speter    struct tty *tp, *(*d_tty) __P((dev_t));
20814331Speter    caddr_t sg;
20947028Sphk    dev_t dev;
2109313Ssos
21114331Speter    sg = stackgap_init();
21214331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21314331Speter    d_tty = NULL;
21414331Speter
2159313Ssos#ifdef DEBUG
2169313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2179313Ssos	   p->p_pid, args->fd, args->cmd);
2189313Ssos#endif
2199313Ssos    fcntl_args.fd = args->fd;
2209313Ssos
2219313Ssos    switch (args->cmd) {
2229313Ssos    case LINUX_F_DUPFD:
2239313Ssos	fcntl_args.cmd = F_DUPFD;
22449845Smarcel	fcntl_args.arg = args->arg;
22530994Sphk	return fcntl(p, &fcntl_args);
2269313Ssos
2279313Ssos    case LINUX_F_GETFD:
2289313Ssos	fcntl_args.cmd = F_GETFD;
22930994Sphk	return fcntl(p, &fcntl_args);
2309313Ssos
2319313Ssos    case LINUX_F_SETFD:
2329313Ssos	fcntl_args.cmd = F_SETFD;
23349845Smarcel	fcntl_args.arg = args->arg;
23430994Sphk	return fcntl(p, &fcntl_args);
2359313Ssos
2369313Ssos    case LINUX_F_GETFL:
2379313Ssos	fcntl_args.cmd = F_GETFL;
23830994Sphk	error = fcntl(p, &fcntl_args);
23930994Sphk	result = p->p_retval[0];
24030994Sphk	p->p_retval[0] = 0;
24130994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24230994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24330994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24430994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24530994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24630994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
24739978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2489313Ssos	return error;
2499313Ssos
2509313Ssos    case LINUX_F_SETFL:
25149845Smarcel	fcntl_args.arg = 0;
2529313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2539313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2549313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
25539978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2569313Ssos	fcntl_args.cmd = F_SETFL;
25730994Sphk	return fcntl(p, &fcntl_args);
25849676Smarcel
2599313Ssos    case LINUX_F_GETLK:
2609313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2619313Ssos		   	    sizeof(struct linux_flock))))
2629313Ssos	    return error;
2639313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2649313Ssos	fcntl_args.cmd = F_GETLK;
2659313Ssos	fcntl_args.arg = (int)bsd_flock;
26646571Speter	error = fcntl(p, &fcntl_args);
26746571Speter	if (error)
2689313Ssos	    return error;
2699313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2709313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2719313Ssos		       sizeof(struct linux_flock));
2729313Ssos
2739313Ssos    case LINUX_F_SETLK:
2749313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2759313Ssos		   	    sizeof(struct linux_flock))))
2769313Ssos	    return error;
2779313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2789313Ssos	fcntl_args.cmd = F_SETLK;
2799313Ssos	fcntl_args.arg = (int)bsd_flock;
28030994Sphk	return fcntl(p, &fcntl_args);
2819313Ssos
2829313Ssos    case LINUX_F_SETLKW:
2839313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2849313Ssos		   	    sizeof(struct linux_flock))))
2859313Ssos	    return error;
2869313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2879313Ssos	fcntl_args.cmd = F_SETLKW;
2889313Ssos	fcntl_args.arg = (int)bsd_flock;
28930994Sphk	return fcntl(p, &fcntl_args);
2909313Ssos
2919313Ssos    case LINUX_F_SETOWN:
29214331Speter    case LINUX_F_GETOWN:
29314331Speter	/*
29414331Speter	 * We need to route around the normal fcntl() for these calls,
29514331Speter	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
29614331Speter	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
29714331Speter	 * does not exist.
29814331Speter	 */
29914331Speter	fdp = p->p_fd;
30014331Speter	if ((u_int)args->fd >= fdp->fd_nfiles ||
30114331Speter		(fp = fdp->fd_ofiles[args->fd]) == NULL)
30214331Speter	    return EBADF;
30314331Speter	if (fp->f_type == DTYPE_SOCKET) {
30414331Speter	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
30539978Sjfieber    	    fcntl_args.arg = args->arg;
30630994Sphk	    return fcntl(p, &fcntl_args);
30714331Speter	}
30814331Speter	vp = (struct vnode *)fp->f_data;
30948885Sphk	dev = vn_todev(vp);
31048885Sphk	if (vp->v_type != VCHR || dev == NODEV)
31114331Speter	    return EINVAL;
31247028Sphk	d_tty = devsw(dev)->d_devtotty;
31347028Sphk	if (!d_tty || (!(tp = (*d_tty)(dev))))
31414331Speter	    return EINVAL;
31514331Speter	if (args->cmd == LINUX_F_GETOWN) {
31630994Sphk	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
31714331Speter	    return 0;
31814331Speter	}
31914331Speter	if ((long)args->arg <= 0) {
32014331Speter	    pgid = -(long)args->arg;
32114331Speter	} else {
32214331Speter	    struct proc *p1 = pfind((long)args->arg);
32314331Speter	    if (p1 == 0)
32414331Speter		return (ESRCH);
32514331Speter	    pgid = (long)p1->p_pgrp->pg_id;
32614331Speter	}
32714331Speter	pgrp = pgfind(pgid);
32814331Speter	if (pgrp == NULL || pgrp->pg_session != p->p_session)
32914331Speter	    return EPERM;
33014331Speter	tp->t_pgrp = pgrp;
33114331Speter	return 0;
3329313Ssos    }
3339313Ssos    return EINVAL;
3349313Ssos}
3359313Ssos
3369313Ssosint
33730994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3389313Ssos{
3399313Ssos
34012858Speter    struct lseek_args /* {
34112858Speter	int fd;
3429313Ssos	int pad;
34312858Speter	off_t offset;
3449313Ssos	int whence;
34512858Speter    } */ tmp_args;
3469313Ssos    int error;
3479313Ssos
3489313Ssos#ifdef DEBUG
34937950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
35037950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3519313Ssos#endif
35212858Speter    tmp_args.fd = args->fdes;
35312858Speter    tmp_args.offset = (off_t)args->off;
3549313Ssos    tmp_args.whence = args->whence;
35530994Sphk    error = lseek(p, &tmp_args);
3569313Ssos    return error;
3579313Ssos}
3589313Ssos
35914331Speterint
36030994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
36114331Speter{
36214331Speter	struct lseek_args bsd_args;
36314331Speter	int error;
36414331Speter	off_t off;
36514331Speter
36614331Speter#ifdef DEBUG
36714331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
36814331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36914331Speter#endif
37014331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
37114331Speter
37214331Speter	bsd_args.fd = args->fd;
37314331Speter	bsd_args.offset = off;
37414331Speter	bsd_args.whence = args->whence;
37514331Speter
37630994Sphk	if ((error = lseek(p, &bsd_args)))
37714331Speter		return error;
37814331Speter
37930994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
38014331Speter		return error;
38114331Speter
38230994Sphk	p->p_retval[0] = 0;
38314331Speter	return 0;
38414331Speter}
38514331Speter
38614331Speter
3879313Ssosstruct linux_dirent {
3889313Ssos    long dino;
3899313Ssos    linux_off_t doff;
3909313Ssos    unsigned short dreclen;
3919313Ssos    char dname[LINUX_NAME_MAX + 1];
3929313Ssos};
3939313Ssos
3949313Ssos#define LINUX_RECLEN(de,namlen) \
3959313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3969313Ssos
3979313Ssosint
39830994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3999313Ssos{
40014331Speter	struct linux_getdents_args lda;
40114331Speter
40214331Speter	lda.fd = args->fd;
40314331Speter	lda.dent = args->dent;
40414331Speter	lda.count = 1;
40530994Sphk	return linux_getdents(p, &lda);
40614331Speter}
40714331Speter
40814331Speterint
40930994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
41014331Speter{
4119313Ssos    register struct dirent *bdp;
4129313Ssos    struct vnode *vp;
4139313Ssos    caddr_t inp, buf;		/* BSD-format */
4149313Ssos    int len, reclen;		/* BSD-format */
4159313Ssos    caddr_t outp;		/* Linux-format */
4169313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4179313Ssos    struct file *fp;
4189313Ssos    struct uio auio;
4199313Ssos    struct iovec aiov;
4209313Ssos    struct vattr va;
4219313Ssos    off_t off;
4229313Ssos    struct linux_dirent linux_dirent;
42324654Sdfr    int buflen, error, eofflag, nbytes, justone;
42424654Sdfr    u_long *cookies = NULL, *cookiep;
42524654Sdfr    int ncookies;
4269313Ssos
4279313Ssos#ifdef DEBUG
42814331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4299313Ssos	   p->p_pid, args->fd, args->count);
4309313Ssos#endif
43110355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4329313Ssos	return (error);
43314331Speter    }
4349313Ssos
4359313Ssos    if ((fp->f_flag & FREAD) == 0)
4369313Ssos	return (EBADF);
4379313Ssos
4389313Ssos    vp = (struct vnode *) fp->f_data;
4399313Ssos
4409313Ssos    if (vp->v_type != VDIR)
4419313Ssos	return (EINVAL);
4429313Ssos
44310355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4449313Ssos	return error;
44511418Sswallace    }
4469313Ssos
4479313Ssos    nbytes = args->count;
4489313Ssos    if (nbytes == 1) {
4499313Ssos	nbytes = sizeof (struct linux_dirent);
4509313Ssos	justone = 1;
4519313Ssos    }
4529313Ssos    else
4539313Ssos	justone = 0;
4549313Ssos
45510355Sswallace    off = fp->f_offset;
45624672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
45724654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
45811418Sswallace    buflen = min(buflen, MAXBSIZE);
4599313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
46022521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4619313Ssosagain:
4629313Ssos    aiov.iov_base = buf;
4639313Ssos    aiov.iov_len = buflen;
4649313Ssos    auio.uio_iov = &aiov;
4659313Ssos    auio.uio_iovcnt = 1;
4669313Ssos    auio.uio_rw = UIO_READ;
4679313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4689313Ssos    auio.uio_procp = p;
4699313Ssos    auio.uio_resid = buflen;
47024654Sdfr    auio.uio_offset = off;
4719313Ssos
47224654Sdfr    if (cookies) {
47324654Sdfr	free(cookies, M_TEMP);
47424654Sdfr	cookies = NULL;
47524654Sdfr    }
47624654Sdfr
47724654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
47810355Sswallace    if (error) {
4799313Ssos	goto out;
48014331Speter    }
4819313Ssos
4829313Ssos    inp = buf;
4839313Ssos    outp = (caddr_t) args->dent;
4849313Ssos    resid = nbytes;
48524654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4869313Ssos	goto eof;
48714331Speter    }
4889313Ssos
48924654Sdfr    cookiep = cookies;
49024654Sdfr
49124654Sdfr    if (cookies) {
49224654Sdfr	/*
49324654Sdfr	 * When using cookies, the vfs has the option of reading from
49424654Sdfr	 * a different offset than that supplied (UFS truncates the
49524654Sdfr	 * offset to a block boundary to make sure that it never reads
49624654Sdfr	 * partway through a directory entry, even if the directory
49724654Sdfr	 * has been compacted).
49824654Sdfr	 */
49924654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
50024654Sdfr	    bdp = (struct dirent *) inp;
50124654Sdfr	    len -= bdp->d_reclen;
50224654Sdfr	    inp += bdp->d_reclen;
50324654Sdfr	    cookiep++;
50424654Sdfr	    ncookies--;
50524654Sdfr	}
50624654Sdfr    }
50724654Sdfr
5089313Ssos    while (len > 0) {
50924654Sdfr	if (cookiep && ncookies == 0)
51024654Sdfr	    break;
51110355Sswallace	bdp = (struct dirent *) inp;
51210355Sswallace	reclen = bdp->d_reclen;
51310355Sswallace	if (reclen & 3) {
51410355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
51510355Sswallace	    error = EFAULT;
51610355Sswallace	    goto out;
51710355Sswallace	}
51810355Sswallace
5199313Ssos	if (bdp->d_fileno == 0) {
5209313Ssos	    inp += reclen;
52124654Sdfr	    if (cookiep) {
52224654Sdfr		off = *cookiep++;
52324654Sdfr		ncookies--;
52424654Sdfr	    } else
52524654Sdfr		off += reclen;
52610355Sswallace	    len -= reclen;
5279313Ssos	    continue;
5289313Ssos	}
5299313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5309313Ssos	if (reclen > len || resid < linuxreclen) {
5319313Ssos	    outp++;
5329313Ssos	    break;
5339313Ssos	}
5349313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
53514465Speter	if (justone) {
53614465Speter	    /*
53714465Speter	     * old linux-style readdir usage.
53814465Speter	     */
53914465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
54014465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
54114465Speter	} else {
54214465Speter	    linux_dirent.doff = (linux_off_t) off;
54314465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
54414465Speter	}
5459313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
54610355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5479313Ssos	    goto out;
54814331Speter	}
5499313Ssos	inp += reclen;
55024654Sdfr	if (cookiep) {
55124654Sdfr	    off = *cookiep++;
55224654Sdfr	    ncookies--;
55324654Sdfr	} else
55424654Sdfr	    off += reclen;
5559313Ssos	outp += linuxreclen;
5569313Ssos	resid -= linuxreclen;
5579313Ssos	len -= reclen;
5589313Ssos	if (justone)
5599313Ssos	    break;
5609313Ssos    }
5619313Ssos
5629313Ssos    if (outp == (caddr_t) args->dent)
5639313Ssos	goto again;
5649313Ssos    fp->f_offset = off;
5659313Ssos
5669313Ssos    if (justone)
5679313Ssos	nbytes = resid + linuxreclen;
56810355Sswallace
5699313Ssoseof:
57030994Sphk    p->p_retval[0] = nbytes - resid;
5719313Ssosout:
57224654Sdfr    if (cookies)
57324654Sdfr	free(cookies, M_TEMP);
57422543Smpp    VOP_UNLOCK(vp, 0, p);
5759313Ssos    free(buf, M_TEMP);
5769313Ssos    return error;
5779313Ssos}
57814331Speter
57914331Speter/*
58014331Speter * These exist mainly for hooks for doing /compat/linux translation.
58114331Speter */
58214331Speter
58314331Speterint
58430994Sphklinux_access(struct proc *p, struct linux_access_args *args)
58514331Speter{
58614331Speter	struct access_args bsd;
58714331Speter	caddr_t sg;
58814331Speter
58914331Speter	sg = stackgap_init();
59014331Speter	CHECKALTEXIST(p, &sg, args->path);
59114331Speter
59214331Speter#ifdef DEBUG
59314331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
59414331Speter	    p->p_pid, args->path, args->flags);
59514331Speter#endif
59614331Speter	bsd.path = args->path;
59714331Speter	bsd.flags = args->flags;
59814331Speter
59930994Sphk	return access(p, &bsd);
60014331Speter}
60114331Speter
60214331Speterint
60330994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
60414331Speter{
60514331Speter	struct unlink_args bsd;
60614331Speter	caddr_t sg;
60714331Speter
60814331Speter	sg = stackgap_init();
60914331Speter	CHECKALTEXIST(p, &sg, args->path);
61014331Speter
61114331Speter#ifdef DEBUG
61214331Speter	printf("Linux-emul(%d): unlink(%s)\n",
61314331Speter	   p->p_pid, args->path);
61414331Speter#endif
61514331Speter	bsd.path = args->path;
61614331Speter
61730994Sphk	return unlink(p, &bsd);
61814331Speter}
61914331Speter
62014331Speterint
62130994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
62214331Speter{
62314331Speter	struct chdir_args bsd;
62414331Speter	caddr_t sg;
62514331Speter
62614331Speter	sg = stackgap_init();
62714331Speter	CHECKALTEXIST(p, &sg, args->path);
62814331Speter
62914331Speter#ifdef DEBUG
63014331Speter	printf("Linux-emul(%d): chdir(%s)\n",
63114331Speter	   p->p_pid, args->path);
63214331Speter#endif
63314331Speter	bsd.path = args->path;
63414331Speter
63530994Sphk	return chdir(p, &bsd);
63614331Speter}
63714331Speter
63814331Speterint
63930994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
64014331Speter{
64114331Speter	struct chmod_args bsd;
64214331Speter	caddr_t sg;
64314331Speter
64414331Speter	sg = stackgap_init();
64514331Speter	CHECKALTEXIST(p, &sg, args->path);
64614331Speter
64714331Speter#ifdef DEBUG
64814331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
64914331Speter	    p->p_pid, args->path, args->mode);
65014331Speter#endif
65114331Speter	bsd.path = args->path;
65214331Speter	bsd.mode = args->mode;
65314331Speter
65430994Sphk	return chmod(p, &bsd);
65514331Speter}
65614331Speter
65714331Speterint
65830994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65914331Speter{
66014331Speter	struct chown_args bsd;
66114331Speter	caddr_t sg;
66214331Speter
66314331Speter	sg = stackgap_init();
66414331Speter	CHECKALTEXIST(p, &sg, args->path);
66514331Speter
66614331Speter#ifdef DEBUG
66714331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
66814331Speter	    p->p_pid, args->path, args->uid, args->gid);
66914331Speter#endif
67014331Speter	bsd.path = args->path;
67114331Speter	/* XXX size casts here */
67214331Speter	bsd.uid = args->uid;
67314331Speter	bsd.gid = args->gid;
67414331Speter
67530994Sphk	return chown(p, &bsd);
67614331Speter}
67714331Speter
67814331Speterint
67934941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
68034941Speter{
68134941Speter	struct lchown_args bsd;
68234941Speter	caddr_t sg;
68334941Speter
68434941Speter	sg = stackgap_init();
68534941Speter	CHECKALTEXIST(p, &sg, args->path);
68634941Speter
68734941Speter#ifdef DEBUG
68834941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
68934941Speter	    p->p_pid, args->path, args->uid, args->gid);
69034941Speter#endif
69134941Speter	bsd.path = args->path;
69234941Speter	/* XXX size casts here */
69334941Speter	bsd.uid = args->uid;
69434941Speter	bsd.gid = args->gid;
69534941Speter
69634941Speter	return lchown(p, &bsd);
69734941Speter}
69834941Speter
69934941Speterint
70030994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
70114331Speter{
70214331Speter	struct mkdir_args bsd;
70314331Speter	caddr_t sg;
70414331Speter
70514331Speter	sg = stackgap_init();
70614331Speter	CHECKALTCREAT(p, &sg, args->path);
70714331Speter
70814331Speter#ifdef DEBUG
70914331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
71014331Speter	    p->p_pid, args->path, args->mode);
71114331Speter#endif
71214331Speter	bsd.path = args->path;
71314331Speter	bsd.mode = args->mode;
71414331Speter
71530994Sphk	return mkdir(p, &bsd);
71614331Speter}
71714331Speter
71814331Speterint
71930994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
72014331Speter{
72114331Speter	struct rmdir_args bsd;
72214331Speter	caddr_t sg;
72314331Speter
72414331Speter	sg = stackgap_init();
72514331Speter	CHECKALTEXIST(p, &sg, args->path);
72614331Speter
72714331Speter#ifdef DEBUG
72814331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
72914331Speter	    p->p_pid, args->path);
73014331Speter#endif
73114331Speter	bsd.path = args->path;
73214331Speter
73330994Sphk	return rmdir(p, &bsd);
73414331Speter}
73514331Speter
73614331Speterint
73730994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
73814331Speter{
73914331Speter	struct rename_args bsd;
74014331Speter	caddr_t sg;
74114331Speter
74214331Speter	sg = stackgap_init();
74314331Speter	CHECKALTEXIST(p, &sg, args->from);
74414331Speter	CHECKALTCREAT(p, &sg, args->to);
74514331Speter
74614331Speter#ifdef DEBUG
74714331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
74814331Speter	    p->p_pid, args->from, args->to);
74914331Speter#endif
75014331Speter	bsd.from = args->from;
75114331Speter	bsd.to = args->to;
75214331Speter
75330994Sphk	return rename(p, &bsd);
75414331Speter}
75514331Speter
75614331Speterint
75730994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
75814331Speter{
75914331Speter	struct symlink_args bsd;
76014331Speter	caddr_t sg;
76114331Speter
76214331Speter	sg = stackgap_init();
76314331Speter	CHECKALTEXIST(p, &sg, args->path);
76414331Speter	CHECKALTCREAT(p, &sg, args->to);
76514331Speter
76614331Speter#ifdef DEBUG
76714331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
76814331Speter	    p->p_pid, args->path, args->to);
76914331Speter#endif
77014331Speter	bsd.path = args->path;
77114331Speter	bsd.link = args->to;
77214331Speter
77330994Sphk	return symlink(p, &bsd);
77414331Speter}
77514331Speter
77614331Speterint
77730994Sphklinux_execve(struct proc *p, struct linux_execve_args *args)
77814331Speter{
77914331Speter	struct execve_args bsd;
78014331Speter	caddr_t sg;
78114331Speter
78214331Speter	sg = stackgap_init();
78314331Speter	CHECKALTEXIST(p, &sg, args->path);
78414331Speter
78514331Speter#ifdef DEBUG
78614331Speter        printf("Linux-emul(%d): execve(%s)\n",
78714331Speter	    p->p_pid, args->path);
78814331Speter#endif
78914331Speter	bsd.fname = args->path;
79014331Speter	bsd.argv = args->argp;
79114331Speter	bsd.envv = args->envp;
79214331Speter
79330994Sphk	return execve(p, &bsd);
79414331Speter}
79514331Speter
79614331Speterint
79730994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
79814331Speter{
79914331Speter	struct readlink_args bsd;
80014331Speter	caddr_t sg;
80114331Speter
80214331Speter	sg = stackgap_init();
80314331Speter	CHECKALTEXIST(p, &sg, args->name);
80414331Speter
80514331Speter#ifdef DEBUG
80637950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
80737950Sbde	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
80814331Speter#endif
80914331Speter	bsd.path = args->name;
81014331Speter	bsd.buf = args->buf;
81114331Speter	bsd.count = args->count;
81214331Speter
81330994Sphk	return readlink(p, &bsd);
81414331Speter}
81514331Speter
81614331Speterint
81730994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
81814331Speter{
81942499Seivind	struct truncate_args bsd;
82014331Speter	caddr_t sg;
82114331Speter
82214331Speter	sg = stackgap_init();
82314331Speter	CHECKALTEXIST(p, &sg, args->path);
82414331Speter
82514331Speter#ifdef DEBUG
82632266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
82732266Sjmb	    p->p_pid, args->path, args->length);
82814331Speter#endif
82914331Speter	bsd.path = args->path;
83032265Sjmb	bsd.length = args->length;
83114331Speter
83242499Seivind	return truncate(p, &bsd);
83314331Speter}
83414331Speter
83549662Smarcelint
83649662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
83749662Smarcel{
83849662Smarcel    struct link_args bsd;
83949662Smarcel    caddr_t sg;
84049662Smarcel
84149662Smarcel    sg = stackgap_init();
84249662Smarcel    CHECKALTEXIST(p, &sg, args->path);
84349662Smarcel    CHECKALTCREAT(p, &sg, args->to);
84449662Smarcel
84549662Smarcel#ifdef DEBUG
84649662Smarcel    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
84749662Smarcel#endif
84849662Smarcel
84949662Smarcel    bsd.path = args->path;
85049662Smarcel    bsd.link = args->to;
85149662Smarcel
85249662Smarcel    return link(p, &bsd);
85349662Smarcel}
85449788Smarcel
85549788Smarcelint
85649788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
85749788Smarcel{
85849788Smarcel    struct __getcwd_args bsd;
85949788Smarcel
86049788Smarcel#ifdef DEBUG
86149788Smarcel    printf("Linux-emul(%d): getcwd(%p, %ld)\n",
86249788Smarcel	   p->p_pid, args->buf, args->bufsize);
86349788Smarcel#endif
86449788Smarcel
86549788Smarcel    bsd.buf = args->buf;
86649788Smarcel    bsd.buflen = args->bufsize;
86749788Smarcel    return __getcwd(p, &bsd);
86849788Smarcel}
869