linux_file.c revision 47028
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 *
2847028Sphk *  $Id: linux_file.c,v 1.25 1999/05/08 06:39:26 phk Exp $
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;
1619313Ssos    }
1629313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1639313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1649313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1659313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1669313Ssos}
1679313Ssos
1689313Ssosstatic void
1699313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1709313Ssos{
1719313Ssos    switch (bsd_flock->l_type) {
1729313Ssos    case F_RDLCK:
1739313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1749313Ssos	break;
1759313Ssos    case F_WRLCK:
1769313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1779313Ssos	break;
1789313Ssos    case F_UNLCK:
1799313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1809313Ssos	break;
1819313Ssos    }
1829313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1839313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1849313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1859313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1869313Ssos}
1879313Ssos
1889313Ssosint
18930994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1909313Ssos{
1919313Ssos    int error, result;
19212858Speter    struct fcntl_args /* {
1939313Ssos	int fd;
1949313Ssos	int cmd;
1959313Ssos	int arg;
19612858Speter    } */ fcntl_args;
1979313Ssos    struct linux_flock linux_flock;
19814331Speter    struct flock *bsd_flock;
19914331Speter    struct filedesc *fdp;
20014331Speter    struct file *fp;
20114331Speter    struct vnode *vp;
20214331Speter    struct vattr va;
20314331Speter    long pgid;
20414331Speter    struct pgrp *pgrp;
20514331Speter    struct tty *tp, *(*d_tty) __P((dev_t));
20614331Speter    caddr_t sg;
20747028Sphk    dev_t dev;
2089313Ssos
20914331Speter    sg = stackgap_init();
21014331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21114331Speter    d_tty = NULL;
21214331Speter
2139313Ssos#ifdef DEBUG
2149313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2159313Ssos	   p->p_pid, args->fd, args->cmd);
2169313Ssos#endif
2179313Ssos    fcntl_args.fd = args->fd;
2189313Ssos    fcntl_args.arg = 0;
2199313Ssos
2209313Ssos    switch (args->cmd) {
2219313Ssos    case LINUX_F_DUPFD:
2229313Ssos	fcntl_args.cmd = F_DUPFD;
22330994Sphk	return fcntl(p, &fcntl_args);
2249313Ssos
2259313Ssos    case LINUX_F_GETFD:
2269313Ssos	fcntl_args.cmd = F_GETFD;
22730994Sphk	return fcntl(p, &fcntl_args);
2289313Ssos
2299313Ssos    case LINUX_F_SETFD:
2309313Ssos	fcntl_args.cmd = F_SETFD;
23130994Sphk	return fcntl(p, &fcntl_args);
2329313Ssos
2339313Ssos    case LINUX_F_GETFL:
2349313Ssos	fcntl_args.cmd = F_GETFL;
23530994Sphk	error = fcntl(p, &fcntl_args);
23630994Sphk	result = p->p_retval[0];
23730994Sphk	p->p_retval[0] = 0;
23830994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
23930994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24030994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24130994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24230994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24330994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
24439978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2459313Ssos	return error;
2469313Ssos
2479313Ssos    case LINUX_F_SETFL:
2489313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2499313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2509313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
25139978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2529313Ssos	fcntl_args.cmd = F_SETFL;
25330994Sphk	return fcntl(p, &fcntl_args);
2549313Ssos
2559313Ssos    case LINUX_F_GETLK:
2569313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2579313Ssos		   	    sizeof(struct linux_flock))))
2589313Ssos	    return error;
2599313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2609313Ssos	fcntl_args.cmd = F_GETLK;
2619313Ssos	fcntl_args.arg = (int)bsd_flock;
26246571Speter	error = fcntl(p, &fcntl_args);
26346571Speter	if (error)
2649313Ssos	    return error;
2659313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2669313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2679313Ssos		       sizeof(struct linux_flock));
2689313Ssos
2699313Ssos    case LINUX_F_SETLK:
2709313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2719313Ssos		   	    sizeof(struct linux_flock))))
2729313Ssos	    return error;
2739313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2749313Ssos	fcntl_args.cmd = F_SETLK;
2759313Ssos	fcntl_args.arg = (int)bsd_flock;
27630994Sphk	return fcntl(p, &fcntl_args);
2779313Ssos
2789313Ssos    case LINUX_F_SETLKW:
2799313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2809313Ssos		   	    sizeof(struct linux_flock))))
2819313Ssos	    return error;
2829313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2839313Ssos	fcntl_args.cmd = F_SETLKW;
2849313Ssos	fcntl_args.arg = (int)bsd_flock;
28530994Sphk	return fcntl(p, &fcntl_args);
2869313Ssos
2879313Ssos    case LINUX_F_SETOWN:
28814331Speter    case LINUX_F_GETOWN:
28914331Speter	/*
29014331Speter	 * We need to route around the normal fcntl() for these calls,
29114331Speter	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
29214331Speter	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
29314331Speter	 * does not exist.
29414331Speter	 */
29514331Speter	fdp = p->p_fd;
29614331Speter	if ((u_int)args->fd >= fdp->fd_nfiles ||
29714331Speter		(fp = fdp->fd_ofiles[args->fd]) == NULL)
29814331Speter	    return EBADF;
29914331Speter	if (fp->f_type == DTYPE_SOCKET) {
30014331Speter	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
30139978Sjfieber    	    fcntl_args.arg = args->arg;
30230994Sphk	    return fcntl(p, &fcntl_args);
30314331Speter	}
30414331Speter	vp = (struct vnode *)fp->f_data;
30514331Speter	if (vp->v_type != VCHR)
30614331Speter	    return EINVAL;
30714331Speter	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
30814331Speter	    return error;
3099313Ssos
31047028Sphk	dev = udev2dev(va.va_rdev, 0);		/* XXX vp->v_rdev ? */
31147028Sphk	d_tty = devsw(dev)->d_devtotty;
31247028Sphk	if (!d_tty || (!(tp = (*d_tty)(dev))))
31314331Speter	    return EINVAL;
31414331Speter	if (args->cmd == LINUX_F_GETOWN) {
31530994Sphk	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
31614331Speter	    return 0;
31714331Speter	}
31814331Speter	if ((long)args->arg <= 0) {
31914331Speter	    pgid = -(long)args->arg;
32014331Speter	} else {
32114331Speter	    struct proc *p1 = pfind((long)args->arg);
32214331Speter	    if (p1 == 0)
32314331Speter		return (ESRCH);
32414331Speter	    pgid = (long)p1->p_pgrp->pg_id;
32514331Speter	}
32614331Speter	pgrp = pgfind(pgid);
32714331Speter	if (pgrp == NULL || pgrp->pg_session != p->p_session)
32814331Speter	    return EPERM;
32914331Speter	tp->t_pgrp = pgrp;
33014331Speter	return 0;
3319313Ssos    }
3329313Ssos    return EINVAL;
3339313Ssos}
3349313Ssos
3359313Ssosint
33630994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3379313Ssos{
3389313Ssos
33912858Speter    struct lseek_args /* {
34012858Speter	int fd;
3419313Ssos	int pad;
34212858Speter	off_t offset;
3439313Ssos	int whence;
34412858Speter    } */ tmp_args;
3459313Ssos    int error;
3469313Ssos
3479313Ssos#ifdef DEBUG
34837950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
34937950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3509313Ssos#endif
35112858Speter    tmp_args.fd = args->fdes;
35212858Speter    tmp_args.offset = (off_t)args->off;
3539313Ssos    tmp_args.whence = args->whence;
35430994Sphk    error = lseek(p, &tmp_args);
3559313Ssos    return error;
3569313Ssos}
3579313Ssos
35814331Speterint
35930994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
36014331Speter{
36114331Speter	struct lseek_args bsd_args;
36214331Speter	int error;
36314331Speter	off_t off;
36414331Speter
36514331Speter#ifdef DEBUG
36614331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
36714331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36814331Speter#endif
36914331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
37014331Speter
37114331Speter	bsd_args.fd = args->fd;
37214331Speter	bsd_args.offset = off;
37314331Speter	bsd_args.whence = args->whence;
37414331Speter
37530994Sphk	if ((error = lseek(p, &bsd_args)))
37614331Speter		return error;
37714331Speter
37830994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
37914331Speter		return error;
38014331Speter
38130994Sphk	p->p_retval[0] = 0;
38214331Speter	return 0;
38314331Speter}
38414331Speter
38514331Speter
3869313Ssosstruct linux_dirent {
3879313Ssos    long dino;
3889313Ssos    linux_off_t doff;
3899313Ssos    unsigned short dreclen;
3909313Ssos    char dname[LINUX_NAME_MAX + 1];
3919313Ssos};
3929313Ssos
3939313Ssos#define LINUX_RECLEN(de,namlen) \
3949313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3959313Ssos
3969313Ssosint
39730994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3989313Ssos{
39914331Speter	struct linux_getdents_args lda;
40014331Speter
40114331Speter	lda.fd = args->fd;
40214331Speter	lda.dent = args->dent;
40314331Speter	lda.count = 1;
40430994Sphk	return linux_getdents(p, &lda);
40514331Speter}
40614331Speter
40714331Speterint
40830994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
40914331Speter{
4109313Ssos    register struct dirent *bdp;
4119313Ssos    struct vnode *vp;
4129313Ssos    caddr_t inp, buf;		/* BSD-format */
4139313Ssos    int len, reclen;		/* BSD-format */
4149313Ssos    caddr_t outp;		/* Linux-format */
4159313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4169313Ssos    struct file *fp;
4179313Ssos    struct uio auio;
4189313Ssos    struct iovec aiov;
4199313Ssos    struct vattr va;
4209313Ssos    off_t off;
4219313Ssos    struct linux_dirent linux_dirent;
42224654Sdfr    int buflen, error, eofflag, nbytes, justone;
42324654Sdfr    u_long *cookies = NULL, *cookiep;
42424654Sdfr    int ncookies;
4259313Ssos
4269313Ssos#ifdef DEBUG
42714331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4289313Ssos	   p->p_pid, args->fd, args->count);
4299313Ssos#endif
43010355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4319313Ssos	return (error);
43214331Speter    }
4339313Ssos
4349313Ssos    if ((fp->f_flag & FREAD) == 0)
4359313Ssos	return (EBADF);
4369313Ssos
4379313Ssos    vp = (struct vnode *) fp->f_data;
4389313Ssos
4399313Ssos    if (vp->v_type != VDIR)
4409313Ssos	return (EINVAL);
4419313Ssos
44210355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4439313Ssos	return error;
44411418Sswallace    }
4459313Ssos
4469313Ssos    nbytes = args->count;
4479313Ssos    if (nbytes == 1) {
4489313Ssos	nbytes = sizeof (struct linux_dirent);
4499313Ssos	justone = 1;
4509313Ssos    }
4519313Ssos    else
4529313Ssos	justone = 0;
4539313Ssos
45410355Sswallace    off = fp->f_offset;
45524672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
45624654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
45711418Sswallace    buflen = min(buflen, MAXBSIZE);
4589313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
45922521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4609313Ssosagain:
4619313Ssos    aiov.iov_base = buf;
4629313Ssos    aiov.iov_len = buflen;
4639313Ssos    auio.uio_iov = &aiov;
4649313Ssos    auio.uio_iovcnt = 1;
4659313Ssos    auio.uio_rw = UIO_READ;
4669313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4679313Ssos    auio.uio_procp = p;
4689313Ssos    auio.uio_resid = buflen;
46924654Sdfr    auio.uio_offset = off;
4709313Ssos
47124654Sdfr    if (cookies) {
47224654Sdfr	free(cookies, M_TEMP);
47324654Sdfr	cookies = NULL;
47424654Sdfr    }
47524654Sdfr
47624654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
47710355Sswallace    if (error) {
4789313Ssos	goto out;
47914331Speter    }
4809313Ssos
4819313Ssos    inp = buf;
4829313Ssos    outp = (caddr_t) args->dent;
4839313Ssos    resid = nbytes;
48424654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4859313Ssos	goto eof;
48614331Speter    }
4879313Ssos
48824654Sdfr    cookiep = cookies;
48924654Sdfr
49024654Sdfr    if (cookies) {
49124654Sdfr	/*
49224654Sdfr	 * When using cookies, the vfs has the option of reading from
49324654Sdfr	 * a different offset than that supplied (UFS truncates the
49424654Sdfr	 * offset to a block boundary to make sure that it never reads
49524654Sdfr	 * partway through a directory entry, even if the directory
49624654Sdfr	 * has been compacted).
49724654Sdfr	 */
49824654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
49924654Sdfr	    bdp = (struct dirent *) inp;
50024654Sdfr	    len -= bdp->d_reclen;
50124654Sdfr	    inp += bdp->d_reclen;
50224654Sdfr	    cookiep++;
50324654Sdfr	    ncookies--;
50424654Sdfr	}
50524654Sdfr    }
50624654Sdfr
5079313Ssos    while (len > 0) {
50824654Sdfr	if (cookiep && ncookies == 0)
50924654Sdfr	    break;
51010355Sswallace	bdp = (struct dirent *) inp;
51110355Sswallace	reclen = bdp->d_reclen;
51210355Sswallace	if (reclen & 3) {
51310355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
51410355Sswallace	    error = EFAULT;
51510355Sswallace	    goto out;
51610355Sswallace	}
51710355Sswallace
5189313Ssos	if (bdp->d_fileno == 0) {
5199313Ssos	    inp += reclen;
52024654Sdfr	    if (cookiep) {
52124654Sdfr		off = *cookiep++;
52224654Sdfr		ncookies--;
52324654Sdfr	    } else
52424654Sdfr		off += reclen;
52510355Sswallace	    len -= reclen;
5269313Ssos	    continue;
5279313Ssos	}
5289313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5299313Ssos	if (reclen > len || resid < linuxreclen) {
5309313Ssos	    outp++;
5319313Ssos	    break;
5329313Ssos	}
5339313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
53414465Speter	if (justone) {
53514465Speter	    /*
53614465Speter	     * old linux-style readdir usage.
53714465Speter	     */
53814465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
53914465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
54014465Speter	} else {
54114465Speter	    linux_dirent.doff = (linux_off_t) off;
54214465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
54314465Speter	}
5449313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
54510355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5469313Ssos	    goto out;
54714331Speter	}
5489313Ssos	inp += reclen;
54924654Sdfr	if (cookiep) {
55024654Sdfr	    off = *cookiep++;
55124654Sdfr	    ncookies--;
55224654Sdfr	} else
55324654Sdfr	    off += reclen;
5549313Ssos	outp += linuxreclen;
5559313Ssos	resid -= linuxreclen;
5569313Ssos	len -= reclen;
5579313Ssos	if (justone)
5589313Ssos	    break;
5599313Ssos    }
5609313Ssos
5619313Ssos    if (outp == (caddr_t) args->dent)
5629313Ssos	goto again;
5639313Ssos    fp->f_offset = off;
5649313Ssos
5659313Ssos    if (justone)
5669313Ssos	nbytes = resid + linuxreclen;
56710355Sswallace
5689313Ssoseof:
56930994Sphk    p->p_retval[0] = nbytes - resid;
5709313Ssosout:
57124654Sdfr    if (cookies)
57224654Sdfr	free(cookies, M_TEMP);
57322543Smpp    VOP_UNLOCK(vp, 0, p);
5749313Ssos    free(buf, M_TEMP);
5759313Ssos    return error;
5769313Ssos}
57714331Speter
57814331Speter/*
57914331Speter * These exist mainly for hooks for doing /compat/linux translation.
58014331Speter */
58114331Speter
58214331Speterint
58330994Sphklinux_access(struct proc *p, struct linux_access_args *args)
58414331Speter{
58514331Speter	struct access_args bsd;
58614331Speter	caddr_t sg;
58714331Speter
58814331Speter	sg = stackgap_init();
58914331Speter	CHECKALTEXIST(p, &sg, args->path);
59014331Speter
59114331Speter#ifdef DEBUG
59214331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
59314331Speter	    p->p_pid, args->path, args->flags);
59414331Speter#endif
59514331Speter	bsd.path = args->path;
59614331Speter	bsd.flags = args->flags;
59714331Speter
59830994Sphk	return access(p, &bsd);
59914331Speter}
60014331Speter
60114331Speterint
60230994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
60314331Speter{
60414331Speter	struct unlink_args bsd;
60514331Speter	caddr_t sg;
60614331Speter
60714331Speter	sg = stackgap_init();
60814331Speter	CHECKALTEXIST(p, &sg, args->path);
60914331Speter
61014331Speter#ifdef DEBUG
61114331Speter	printf("Linux-emul(%d): unlink(%s)\n",
61214331Speter	   p->p_pid, args->path);
61314331Speter#endif
61414331Speter	bsd.path = args->path;
61514331Speter
61630994Sphk	return unlink(p, &bsd);
61714331Speter}
61814331Speter
61914331Speterint
62030994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
62114331Speter{
62214331Speter	struct chdir_args bsd;
62314331Speter	caddr_t sg;
62414331Speter
62514331Speter	sg = stackgap_init();
62614331Speter	CHECKALTEXIST(p, &sg, args->path);
62714331Speter
62814331Speter#ifdef DEBUG
62914331Speter	printf("Linux-emul(%d): chdir(%s)\n",
63014331Speter	   p->p_pid, args->path);
63114331Speter#endif
63214331Speter	bsd.path = args->path;
63314331Speter
63430994Sphk	return chdir(p, &bsd);
63514331Speter}
63614331Speter
63714331Speterint
63830994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63914331Speter{
64014331Speter	struct chmod_args bsd;
64114331Speter	caddr_t sg;
64214331Speter
64314331Speter	sg = stackgap_init();
64414331Speter	CHECKALTEXIST(p, &sg, args->path);
64514331Speter
64614331Speter#ifdef DEBUG
64714331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
64814331Speter	    p->p_pid, args->path, args->mode);
64914331Speter#endif
65014331Speter	bsd.path = args->path;
65114331Speter	bsd.mode = args->mode;
65214331Speter
65330994Sphk	return chmod(p, &bsd);
65414331Speter}
65514331Speter
65614331Speterint
65730994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65814331Speter{
65914331Speter	struct chown_args bsd;
66014331Speter	caddr_t sg;
66114331Speter
66214331Speter	sg = stackgap_init();
66314331Speter	CHECKALTEXIST(p, &sg, args->path);
66414331Speter
66514331Speter#ifdef DEBUG
66614331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
66714331Speter	    p->p_pid, args->path, args->uid, args->gid);
66814331Speter#endif
66914331Speter	bsd.path = args->path;
67014331Speter	/* XXX size casts here */
67114331Speter	bsd.uid = args->uid;
67214331Speter	bsd.gid = args->gid;
67314331Speter
67430994Sphk	return chown(p, &bsd);
67514331Speter}
67614331Speter
67714331Speterint
67834941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
67934941Speter{
68034941Speter	struct lchown_args bsd;
68134941Speter	caddr_t sg;
68234941Speter
68334941Speter	sg = stackgap_init();
68434941Speter	CHECKALTEXIST(p, &sg, args->path);
68534941Speter
68634941Speter#ifdef DEBUG
68734941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
68834941Speter	    p->p_pid, args->path, args->uid, args->gid);
68934941Speter#endif
69034941Speter	bsd.path = args->path;
69134941Speter	/* XXX size casts here */
69234941Speter	bsd.uid = args->uid;
69334941Speter	bsd.gid = args->gid;
69434941Speter
69534941Speter	return lchown(p, &bsd);
69634941Speter}
69734941Speter
69834941Speterint
69930994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
70014331Speter{
70114331Speter	struct mkdir_args bsd;
70214331Speter	caddr_t sg;
70314331Speter
70414331Speter	sg = stackgap_init();
70514331Speter	CHECKALTCREAT(p, &sg, args->path);
70614331Speter
70714331Speter#ifdef DEBUG
70814331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
70914331Speter	    p->p_pid, args->path, args->mode);
71014331Speter#endif
71114331Speter	bsd.path = args->path;
71214331Speter	bsd.mode = args->mode;
71314331Speter
71430994Sphk	return mkdir(p, &bsd);
71514331Speter}
71614331Speter
71714331Speterint
71830994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
71914331Speter{
72014331Speter	struct rmdir_args bsd;
72114331Speter	caddr_t sg;
72214331Speter
72314331Speter	sg = stackgap_init();
72414331Speter	CHECKALTEXIST(p, &sg, args->path);
72514331Speter
72614331Speter#ifdef DEBUG
72714331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
72814331Speter	    p->p_pid, args->path);
72914331Speter#endif
73014331Speter	bsd.path = args->path;
73114331Speter
73230994Sphk	return rmdir(p, &bsd);
73314331Speter}
73414331Speter
73514331Speterint
73630994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
73714331Speter{
73814331Speter	struct rename_args bsd;
73914331Speter	caddr_t sg;
74014331Speter
74114331Speter	sg = stackgap_init();
74214331Speter	CHECKALTEXIST(p, &sg, args->from);
74314331Speter	CHECKALTCREAT(p, &sg, args->to);
74414331Speter
74514331Speter#ifdef DEBUG
74614331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
74714331Speter	    p->p_pid, args->from, args->to);
74814331Speter#endif
74914331Speter	bsd.from = args->from;
75014331Speter	bsd.to = args->to;
75114331Speter
75230994Sphk	return rename(p, &bsd);
75314331Speter}
75414331Speter
75514331Speterint
75630994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
75714331Speter{
75814331Speter	struct symlink_args bsd;
75914331Speter	caddr_t sg;
76014331Speter
76114331Speter	sg = stackgap_init();
76214331Speter	CHECKALTEXIST(p, &sg, args->path);
76314331Speter	CHECKALTCREAT(p, &sg, args->to);
76414331Speter
76514331Speter#ifdef DEBUG
76614331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
76714331Speter	    p->p_pid, args->path, args->to);
76814331Speter#endif
76914331Speter	bsd.path = args->path;
77014331Speter	bsd.link = args->to;
77114331Speter
77230994Sphk	return symlink(p, &bsd);
77314331Speter}
77414331Speter
77514331Speterint
77630994Sphklinux_execve(struct proc *p, struct linux_execve_args *args)
77714331Speter{
77814331Speter	struct execve_args bsd;
77914331Speter	caddr_t sg;
78014331Speter
78114331Speter	sg = stackgap_init();
78214331Speter	CHECKALTEXIST(p, &sg, args->path);
78314331Speter
78414331Speter#ifdef DEBUG
78514331Speter        printf("Linux-emul(%d): execve(%s)\n",
78614331Speter	    p->p_pid, args->path);
78714331Speter#endif
78814331Speter	bsd.fname = args->path;
78914331Speter	bsd.argv = args->argp;
79014331Speter	bsd.envv = args->envp;
79114331Speter
79230994Sphk	return execve(p, &bsd);
79314331Speter}
79414331Speter
79514331Speterint
79630994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
79714331Speter{
79814331Speter	struct readlink_args bsd;
79914331Speter	caddr_t sg;
80014331Speter
80114331Speter	sg = stackgap_init();
80214331Speter	CHECKALTEXIST(p, &sg, args->name);
80314331Speter
80414331Speter#ifdef DEBUG
80537950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
80637950Sbde	    (long)p->p_pid, args->name, (void *)args->buf, args->count);
80714331Speter#endif
80814331Speter	bsd.path = args->name;
80914331Speter	bsd.buf = args->buf;
81014331Speter	bsd.count = args->count;
81114331Speter
81230994Sphk	return readlink(p, &bsd);
81314331Speter}
81414331Speter
81514331Speterint
81630994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
81714331Speter{
81842499Seivind	struct truncate_args bsd;
81914331Speter	caddr_t sg;
82014331Speter
82114331Speter	sg = stackgap_init();
82214331Speter	CHECKALTEXIST(p, &sg, args->path);
82314331Speter
82414331Speter#ifdef DEBUG
82532266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
82632266Sjmb	    p->p_pid, args->path, args->length);
82714331Speter#endif
82814331Speter	bsd.path = args->path;
82932265Sjmb	bsd.length = args->length;
83014331Speter
83142499Seivind	return truncate(p, &bsd);
83214331Speter}
83314331Speter
834