linux_file.c revision 31561
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 *
2831561Sbde *  $Id: linux_file.c,v 1.15 1997/11/06 19:28:54 phk Exp $
299313Ssos */
309313Ssos
319313Ssos#include <sys/param.h>
329313Ssos#include <sys/systm.h>
3312458Sbde#include <sys/sysproto.h>
349313Ssos#include <sys/fcntl.h>
359313Ssos#include <sys/file.h>
369313Ssos#include <sys/filedesc.h>
3731561Sbde#include <sys/lock.h>
389313Ssos#include <sys/proc.h>
399313Ssos#include <sys/vnode.h>
409313Ssos#include <sys/malloc.h>
419313Ssos#include <sys/dirent.h>
4214331Speter#include <sys/conf.h>
4314331Speter#include <sys/tty.h>
4412458Sbde
4512458Sbde#include <i386/linux/linux.h>
4614331Speter#include <i386/linux/linux_proto.h>
4714331Speter#include <i386/linux/linux_util.h>
489313Ssos
499313Ssosint
5030994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
519313Ssos{
5212858Speter    struct open_args /* {
539313Ssos	char *path;
549313Ssos	int flags;
559313Ssos	int mode;
5612858Speter    } */ bsd_open_args;
5714331Speter    caddr_t sg;
589313Ssos
5914331Speter    sg = stackgap_init();
6014331Speter    CHECKALTCREAT(p, &sg, args->path);
6114331Speter
629313Ssos#ifdef DEBUG
639313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
649313Ssos	   p->p_pid, args->path, args->mode);
659313Ssos#endif
669313Ssos    bsd_open_args.path = args->path;
679313Ssos    bsd_open_args.mode = args->mode;
689313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
6930994Sphk    return open(p, &bsd_open_args);
709313Ssos}
719313Ssos
729313Ssosint
7330994Sphklinux_open(struct proc *p, struct linux_open_args *args)
749313Ssos{
7512858Speter    struct open_args /* {
769313Ssos	char *path;
779313Ssos	int flags;
789313Ssos	int mode;
7912858Speter    } */ bsd_open_args;
809313Ssos    int error;
8114331Speter    caddr_t sg;
8214331Speter
8314331Speter    sg = stackgap_init();
849313Ssos
8514331Speter    if (args->flags & LINUX_O_CREAT)
8614331Speter	CHECKALTCREAT(p, &sg, args->path);
8714331Speter    else
8814331Speter	CHECKALTEXIST(p, &sg, args->path);
8914331Speter
909313Ssos#ifdef DEBUG
919313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
929313Ssos	   p->p_pid, args->path, args->flags, args->mode);
939313Ssos#endif
949313Ssos    bsd_open_args.flags = 0;
959313Ssos    if (args->flags & LINUX_O_RDONLY)
969313Ssos	bsd_open_args.flags |= O_RDONLY;
979313Ssos    if (args->flags & LINUX_O_WRONLY)
989313Ssos	bsd_open_args.flags |= O_WRONLY;
999313Ssos    if (args->flags & LINUX_O_RDWR)
1009313Ssos	bsd_open_args.flags |= O_RDWR;
1019313Ssos    if (args->flags & LINUX_O_NDELAY)
1029313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1039313Ssos    if (args->flags & LINUX_O_APPEND)
1049313Ssos	bsd_open_args.flags |= O_APPEND;
1059313Ssos    if (args->flags & LINUX_O_SYNC)
1069313Ssos	bsd_open_args.flags |= O_FSYNC;
1079313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1089313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1099313Ssos    if (args->flags & LINUX_FASYNC)
1109313Ssos	bsd_open_args.flags |= O_ASYNC;
1119313Ssos    if (args->flags & LINUX_O_CREAT)
1129313Ssos	bsd_open_args.flags |= O_CREAT;
1139313Ssos    if (args->flags & LINUX_O_TRUNC)
1149313Ssos	bsd_open_args.flags |= O_TRUNC;
1159313Ssos    if (args->flags & LINUX_O_EXCL)
1169313Ssos	bsd_open_args.flags |= O_EXCL;
1179313Ssos    if (args->flags & LINUX_O_NOCTTY)
1189313Ssos	bsd_open_args.flags |= O_NOCTTY;
1199313Ssos    bsd_open_args.path = args->path;
1209313Ssos    bsd_open_args.mode = args->mode;
1219313Ssos
12230994Sphk    error = open(p, &bsd_open_args);
1239313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1249313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1259313Ssos	struct filedesc *fdp = p->p_fd;
12630994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1279313Ssos
1289313Ssos	if (fp->f_type == DTYPE_VNODE)
1299313Ssos	    (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p);
1309313Ssos    }
13114331Speter#ifdef DEBUG
13214331Speter    printf("Linux-emul(%d): open returns error %d\n",
13314331Speter	   p->p_pid, error);
13414331Speter#endif
1359313Ssos    return error;
1369313Ssos}
1379313Ssos
1389313Ssosstruct linux_flock {
1399313Ssos    short l_type;
1409313Ssos    short l_whence;
1419313Ssos    linux_off_t l_start;
1429313Ssos    linux_off_t l_len;
1439313Ssos    linux_pid_t l_pid;
1449313Ssos};
1459313Ssos
1469313Ssosstatic void
1479313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1489313Ssos{
1499313Ssos    switch (linux_flock->l_type) {
1509313Ssos    case LINUX_F_RDLCK:
1519313Ssos	bsd_flock->l_type = F_RDLCK;
1529313Ssos	break;
1539313Ssos    case LINUX_F_WRLCK:
1549313Ssos	bsd_flock->l_type = F_WRLCK;
1559313Ssos	break;
1569313Ssos    case LINUX_F_UNLCK:
1579313Ssos	bsd_flock->l_type = F_UNLCK;
1589313Ssos	break;
1599313Ssos    }
1609313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1619313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1629313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1639313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1649313Ssos}
1659313Ssos
1669313Ssosstatic void
1679313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1689313Ssos{
1699313Ssos    switch (bsd_flock->l_type) {
1709313Ssos    case F_RDLCK:
1719313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1729313Ssos	break;
1739313Ssos    case F_WRLCK:
1749313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1759313Ssos	break;
1769313Ssos    case F_UNLCK:
1779313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1789313Ssos	break;
1799313Ssos    }
1809313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1819313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1829313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1839313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1849313Ssos}
1859313Ssos
1869313Ssosint
18730994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
1889313Ssos{
1899313Ssos    int error, result;
19012858Speter    struct fcntl_args /* {
1919313Ssos	int fd;
1929313Ssos	int cmd;
1939313Ssos	int arg;
19412858Speter    } */ fcntl_args;
1959313Ssos    struct linux_flock linux_flock;
19614331Speter    struct flock *bsd_flock;
19714331Speter    struct filedesc *fdp;
19814331Speter    struct file *fp;
19914331Speter    struct vnode *vp;
20014331Speter    struct vattr va;
20114331Speter    long pgid;
20214331Speter    struct pgrp *pgrp;
20314331Speter    struct tty *tp, *(*d_tty) __P((dev_t));
20414331Speter    caddr_t sg;
2059313Ssos
20614331Speter    sg = stackgap_init();
20714331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
20814331Speter    d_tty = NULL;
20914331Speter
2109313Ssos#ifdef DEBUG
2119313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2129313Ssos	   p->p_pid, args->fd, args->cmd);
2139313Ssos#endif
2149313Ssos    fcntl_args.fd = args->fd;
2159313Ssos    fcntl_args.arg = 0;
2169313Ssos
2179313Ssos    switch (args->cmd) {
2189313Ssos    case LINUX_F_DUPFD:
2199313Ssos	fcntl_args.cmd = F_DUPFD;
22030994Sphk	return fcntl(p, &fcntl_args);
2219313Ssos
2229313Ssos    case LINUX_F_GETFD:
2239313Ssos	fcntl_args.cmd = F_GETFD;
22430994Sphk	return fcntl(p, &fcntl_args);
2259313Ssos
2269313Ssos    case LINUX_F_SETFD:
2279313Ssos	fcntl_args.cmd = F_SETFD;
22830994Sphk	return fcntl(p, &fcntl_args);
2299313Ssos
2309313Ssos    case LINUX_F_GETFL:
2319313Ssos	fcntl_args.cmd = F_GETFL;
23230994Sphk	error = fcntl(p, &fcntl_args);
23330994Sphk	result = p->p_retval[0];
23430994Sphk	p->p_retval[0] = 0;
23530994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
23630994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
23730994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
23830994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
23930994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24030994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
2419313Ssos	return error;
2429313Ssos
2439313Ssos    case LINUX_F_SETFL:
2449313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2459313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2469313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
2479313Ssos	fcntl_args.cmd = F_SETFL;
24830994Sphk	return fcntl(p, &fcntl_args);
2499313Ssos
2509313Ssos    case LINUX_F_GETLK:
2519313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2529313Ssos		   	    sizeof(struct linux_flock))))
2539313Ssos	    return error;
2549313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2559313Ssos	fcntl_args.cmd = F_GETLK;
2569313Ssos	fcntl_args.arg = (int)bsd_flock;
25730994Sphk	if (error = fcntl(p, &fcntl_args))
2589313Ssos	    return error;
2599313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2609313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2619313Ssos		       sizeof(struct linux_flock));
2629313Ssos
2639313Ssos    case LINUX_F_SETLK:
2649313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2659313Ssos		   	    sizeof(struct linux_flock))))
2669313Ssos	    return error;
2679313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2689313Ssos	fcntl_args.cmd = F_SETLK;
2699313Ssos	fcntl_args.arg = (int)bsd_flock;
27030994Sphk	return fcntl(p, &fcntl_args);
2719313Ssos
2729313Ssos    case LINUX_F_SETLKW:
2739313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2749313Ssos		   	    sizeof(struct linux_flock))))
2759313Ssos	    return error;
2769313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2779313Ssos	fcntl_args.cmd = F_SETLKW;
2789313Ssos	fcntl_args.arg = (int)bsd_flock;
27930994Sphk	return fcntl(p, &fcntl_args);
2809313Ssos
2819313Ssos    case LINUX_F_SETOWN:
28214331Speter    case LINUX_F_GETOWN:
28314331Speter	/*
28414331Speter	 * We need to route around the normal fcntl() for these calls,
28514331Speter	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
28614331Speter	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
28714331Speter	 * does not exist.
28814331Speter	 */
28914331Speter	fdp = p->p_fd;
29014331Speter	if ((u_int)args->fd >= fdp->fd_nfiles ||
29114331Speter		(fp = fdp->fd_ofiles[args->fd]) == NULL)
29214331Speter	    return EBADF;
29314331Speter	if (fp->f_type == DTYPE_SOCKET) {
29414331Speter	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
29530994Sphk	    return fcntl(p, &fcntl_args);
29614331Speter	}
29714331Speter	vp = (struct vnode *)fp->f_data;
29814331Speter	if (vp->v_type != VCHR)
29914331Speter	    return EINVAL;
30014331Speter	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
30114331Speter	    return error;
3029313Ssos
30314331Speter	d_tty = cdevsw[major(va.va_rdev)]->d_devtotty;
30414331Speter	if (!d_tty || (!(tp = (*d_tty)(va.va_rdev))))
30514331Speter	    return EINVAL;
30614331Speter	if (args->cmd == LINUX_F_GETOWN) {
30730994Sphk	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
30814331Speter	    return 0;
30914331Speter	}
31014331Speter	if ((long)args->arg <= 0) {
31114331Speter	    pgid = -(long)args->arg;
31214331Speter	} else {
31314331Speter	    struct proc *p1 = pfind((long)args->arg);
31414331Speter	    if (p1 == 0)
31514331Speter		return (ESRCH);
31614331Speter	    pgid = (long)p1->p_pgrp->pg_id;
31714331Speter	}
31814331Speter	pgrp = pgfind(pgid);
31914331Speter	if (pgrp == NULL || pgrp->pg_session != p->p_session)
32014331Speter	    return EPERM;
32114331Speter	tp->t_pgrp = pgrp;
32214331Speter	return 0;
3239313Ssos    }
3249313Ssos    return EINVAL;
3259313Ssos}
3269313Ssos
3279313Ssosint
32830994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3299313Ssos{
3309313Ssos
33112858Speter    struct lseek_args /* {
33212858Speter	int fd;
3339313Ssos	int pad;
33412858Speter	off_t offset;
3359313Ssos	int whence;
33612858Speter    } */ tmp_args;
3379313Ssos    int error;
3389313Ssos
3399313Ssos#ifdef DEBUG
3409313Ssos    printf("Linux-emul(%d): lseek(%d, %d, %d)\n",
3419313Ssos	   p->p_pid, args->fdes, args->off, args->whence);
3429313Ssos#endif
34312858Speter    tmp_args.fd = args->fdes;
34412858Speter    tmp_args.offset = (off_t)args->off;
3459313Ssos    tmp_args.whence = args->whence;
34630994Sphk    error = lseek(p, &tmp_args);
3479313Ssos    return error;
3489313Ssos}
3499313Ssos
35014331Speterint
35130994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
35214331Speter{
35314331Speter	struct lseek_args bsd_args;
35414331Speter	int error;
35514331Speter	off_t off;
35614331Speter
35714331Speter#ifdef DEBUG
35814331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
35914331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36014331Speter#endif
36114331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
36214331Speter
36314331Speter	bsd_args.fd = args->fd;
36414331Speter	bsd_args.offset = off;
36514331Speter	bsd_args.whence = args->whence;
36614331Speter
36730994Sphk	if ((error = lseek(p, &bsd_args)))
36814331Speter		return error;
36914331Speter
37030994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
37114331Speter		return error;
37214331Speter
37330994Sphk	p->p_retval[0] = 0;
37414331Speter	return 0;
37514331Speter}
37614331Speter
37714331Speter
3789313Ssosstruct linux_dirent {
3799313Ssos    long dino;
3809313Ssos    linux_off_t doff;
3819313Ssos    unsigned short dreclen;
3829313Ssos    char dname[LINUX_NAME_MAX + 1];
3839313Ssos};
3849313Ssos
3859313Ssos#define LINUX_RECLEN(de,namlen) \
3869313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3879313Ssos
3889313Ssosint
38930994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3909313Ssos{
39114331Speter	struct linux_getdents_args lda;
39214331Speter
39314331Speter	lda.fd = args->fd;
39414331Speter	lda.dent = args->dent;
39514331Speter	lda.count = 1;
39630994Sphk	return linux_getdents(p, &lda);
39714331Speter}
39814331Speter
39914331Speterint
40030994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
40114331Speter{
4029313Ssos    register struct dirent *bdp;
4039313Ssos    struct vnode *vp;
4049313Ssos    caddr_t inp, buf;		/* BSD-format */
4059313Ssos    int len, reclen;		/* BSD-format */
4069313Ssos    caddr_t outp;		/* Linux-format */
4079313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4089313Ssos    struct file *fp;
4099313Ssos    struct uio auio;
4109313Ssos    struct iovec aiov;
4119313Ssos    struct vattr va;
4129313Ssos    off_t off;
4139313Ssos    struct linux_dirent linux_dirent;
41424654Sdfr    int buflen, error, eofflag, nbytes, justone;
41524654Sdfr    u_long *cookies = NULL, *cookiep;
41624654Sdfr    int ncookies;
4179313Ssos
4189313Ssos#ifdef DEBUG
41914331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4209313Ssos	   p->p_pid, args->fd, args->count);
4219313Ssos#endif
42210355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4239313Ssos	return (error);
42414331Speter    }
4259313Ssos
4269313Ssos    if ((fp->f_flag & FREAD) == 0)
4279313Ssos	return (EBADF);
4289313Ssos
4299313Ssos    vp = (struct vnode *) fp->f_data;
4309313Ssos
4319313Ssos    if (vp->v_type != VDIR)
4329313Ssos	return (EINVAL);
4339313Ssos
43410355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4359313Ssos	return error;
43611418Sswallace    }
4379313Ssos
4389313Ssos    nbytes = args->count;
4399313Ssos    if (nbytes == 1) {
4409313Ssos	nbytes = sizeof (struct linux_dirent);
4419313Ssos	justone = 1;
4429313Ssos    }
4439313Ssos    else
4449313Ssos	justone = 0;
4459313Ssos
44610355Sswallace    off = fp->f_offset;
44724672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
44824654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
44911418Sswallace    buflen = min(buflen, MAXBSIZE);
4509313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
45122521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4529313Ssosagain:
4539313Ssos    aiov.iov_base = buf;
4549313Ssos    aiov.iov_len = buflen;
4559313Ssos    auio.uio_iov = &aiov;
4569313Ssos    auio.uio_iovcnt = 1;
4579313Ssos    auio.uio_rw = UIO_READ;
4589313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4599313Ssos    auio.uio_procp = p;
4609313Ssos    auio.uio_resid = buflen;
46124654Sdfr    auio.uio_offset = off;
4629313Ssos
46324654Sdfr    if (cookies) {
46424654Sdfr	free(cookies, M_TEMP);
46524654Sdfr	cookies = NULL;
46624654Sdfr    }
46724654Sdfr
46824654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
46910355Sswallace    if (error) {
4709313Ssos	goto out;
47114331Speter    }
4729313Ssos
4739313Ssos    inp = buf;
4749313Ssos    outp = (caddr_t) args->dent;
4759313Ssos    resid = nbytes;
47624654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4779313Ssos	goto eof;
47814331Speter    }
4799313Ssos
48024654Sdfr    cookiep = cookies;
48124654Sdfr
48224654Sdfr    if (cookies) {
48324654Sdfr	/*
48424654Sdfr	 * When using cookies, the vfs has the option of reading from
48524654Sdfr	 * a different offset than that supplied (UFS truncates the
48624654Sdfr	 * offset to a block boundary to make sure that it never reads
48724654Sdfr	 * partway through a directory entry, even if the directory
48824654Sdfr	 * has been compacted).
48924654Sdfr	 */
49024654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
49124654Sdfr	    bdp = (struct dirent *) inp;
49224654Sdfr	    len -= bdp->d_reclen;
49324654Sdfr	    inp += bdp->d_reclen;
49424654Sdfr	    cookiep++;
49524654Sdfr	    ncookies--;
49624654Sdfr	}
49724654Sdfr    }
49824654Sdfr
4999313Ssos    while (len > 0) {
50024654Sdfr	if (cookiep && ncookies == 0)
50124654Sdfr	    break;
50210355Sswallace	bdp = (struct dirent *) inp;
50310355Sswallace	reclen = bdp->d_reclen;
50410355Sswallace	if (reclen & 3) {
50510355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
50610355Sswallace	    error = EFAULT;
50710355Sswallace	    goto out;
50810355Sswallace	}
50910355Sswallace
5109313Ssos	if (bdp->d_fileno == 0) {
5119313Ssos	    inp += reclen;
51224654Sdfr	    if (cookiep) {
51324654Sdfr		off = *cookiep++;
51424654Sdfr		ncookies--;
51524654Sdfr	    } else
51624654Sdfr		off += reclen;
51710355Sswallace	    len -= reclen;
5189313Ssos	    continue;
5199313Ssos	}
5209313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5219313Ssos	if (reclen > len || resid < linuxreclen) {
5229313Ssos	    outp++;
5239313Ssos	    break;
5249313Ssos	}
5259313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
52614465Speter	if (justone) {
52714465Speter	    /*
52814465Speter	     * old linux-style readdir usage.
52914465Speter	     */
53014465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
53114465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
53214465Speter	} else {
53314465Speter	    linux_dirent.doff = (linux_off_t) off;
53414465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53514465Speter	}
5369313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
53710355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5389313Ssos	    goto out;
53914331Speter	}
5409313Ssos	inp += reclen;
54124654Sdfr	if (cookiep) {
54224654Sdfr	    off = *cookiep++;
54324654Sdfr	    ncookies--;
54424654Sdfr	} else
54524654Sdfr	    off += reclen;
5469313Ssos	outp += linuxreclen;
5479313Ssos	resid -= linuxreclen;
5489313Ssos	len -= reclen;
5499313Ssos	if (justone)
5509313Ssos	    break;
5519313Ssos    }
5529313Ssos
5539313Ssos    if (outp == (caddr_t) args->dent)
5549313Ssos	goto again;
5559313Ssos    fp->f_offset = off;
5569313Ssos
5579313Ssos    if (justone)
5589313Ssos	nbytes = resid + linuxreclen;
55910355Sswallace
5609313Ssoseof:
56130994Sphk    p->p_retval[0] = nbytes - resid;
5629313Ssosout:
56324654Sdfr    if (cookies)
56424654Sdfr	free(cookies, M_TEMP);
56522543Smpp    VOP_UNLOCK(vp, 0, p);
5669313Ssos    free(buf, M_TEMP);
5679313Ssos    return error;
5689313Ssos}
56914331Speter
57014331Speter/*
57114331Speter * These exist mainly for hooks for doing /compat/linux translation.
57214331Speter */
57314331Speter
57414331Speterint
57530994Sphklinux_access(struct proc *p, struct linux_access_args *args)
57614331Speter{
57714331Speter	struct access_args bsd;
57814331Speter	caddr_t sg;
57914331Speter
58014331Speter	sg = stackgap_init();
58114331Speter	CHECKALTEXIST(p, &sg, args->path);
58214331Speter
58314331Speter#ifdef DEBUG
58414331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
58514331Speter	    p->p_pid, args->path, args->flags);
58614331Speter#endif
58714331Speter	bsd.path = args->path;
58814331Speter	bsd.flags = args->flags;
58914331Speter
59030994Sphk	return access(p, &bsd);
59114331Speter}
59214331Speter
59314331Speterint
59430994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59514331Speter{
59614331Speter	struct unlink_args bsd;
59714331Speter	caddr_t sg;
59814331Speter
59914331Speter	sg = stackgap_init();
60014331Speter	CHECKALTEXIST(p, &sg, args->path);
60114331Speter
60214331Speter#ifdef DEBUG
60314331Speter	printf("Linux-emul(%d): unlink(%s)\n",
60414331Speter	   p->p_pid, args->path);
60514331Speter#endif
60614331Speter	bsd.path = args->path;
60714331Speter
60830994Sphk	return unlink(p, &bsd);
60914331Speter}
61014331Speter
61114331Speterint
61230994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61314331Speter{
61414331Speter	struct chdir_args bsd;
61514331Speter	caddr_t sg;
61614331Speter
61714331Speter	sg = stackgap_init();
61814331Speter	CHECKALTEXIST(p, &sg, args->path);
61914331Speter
62014331Speter#ifdef DEBUG
62114331Speter	printf("Linux-emul(%d): chdir(%s)\n",
62214331Speter	   p->p_pid, args->path);
62314331Speter#endif
62414331Speter	bsd.path = args->path;
62514331Speter
62630994Sphk	return chdir(p, &bsd);
62714331Speter}
62814331Speter
62914331Speterint
63030994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63114331Speter{
63214331Speter	struct chmod_args bsd;
63314331Speter	caddr_t sg;
63414331Speter
63514331Speter	sg = stackgap_init();
63614331Speter	CHECKALTEXIST(p, &sg, args->path);
63714331Speter
63814331Speter#ifdef DEBUG
63914331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
64014331Speter	    p->p_pid, args->path, args->mode);
64114331Speter#endif
64214331Speter	bsd.path = args->path;
64314331Speter	bsd.mode = args->mode;
64414331Speter
64530994Sphk	return chmod(p, &bsd);
64614331Speter}
64714331Speter
64814331Speterint
64930994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65014331Speter{
65114331Speter	struct chown_args bsd;
65214331Speter	caddr_t sg;
65314331Speter
65414331Speter	sg = stackgap_init();
65514331Speter	CHECKALTEXIST(p, &sg, args->path);
65614331Speter
65714331Speter#ifdef DEBUG
65814331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
65914331Speter	    p->p_pid, args->path, args->uid, args->gid);
66014331Speter#endif
66114331Speter	bsd.path = args->path;
66214331Speter	/* XXX size casts here */
66314331Speter	bsd.uid = args->uid;
66414331Speter	bsd.gid = args->gid;
66514331Speter
66630994Sphk	return chown(p, &bsd);
66714331Speter}
66814331Speter
66914331Speterint
67030994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
67114331Speter{
67214331Speter	struct mkdir_args bsd;
67314331Speter	caddr_t sg;
67414331Speter
67514331Speter	sg = stackgap_init();
67614331Speter	CHECKALTCREAT(p, &sg, args->path);
67714331Speter
67814331Speter#ifdef DEBUG
67914331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
68014331Speter	    p->p_pid, args->path, args->mode);
68114331Speter#endif
68214331Speter	bsd.path = args->path;
68314331Speter	bsd.mode = args->mode;
68414331Speter
68530994Sphk	return mkdir(p, &bsd);
68614331Speter}
68714331Speter
68814331Speterint
68930994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
69014331Speter{
69114331Speter	struct rmdir_args bsd;
69214331Speter	caddr_t sg;
69314331Speter
69414331Speter	sg = stackgap_init();
69514331Speter	CHECKALTEXIST(p, &sg, args->path);
69614331Speter
69714331Speter#ifdef DEBUG
69814331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
69914331Speter	    p->p_pid, args->path);
70014331Speter#endif
70114331Speter	bsd.path = args->path;
70214331Speter
70330994Sphk	return rmdir(p, &bsd);
70414331Speter}
70514331Speter
70614331Speterint
70730994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
70814331Speter{
70914331Speter	struct rename_args bsd;
71014331Speter	caddr_t sg;
71114331Speter
71214331Speter	sg = stackgap_init();
71314331Speter	CHECKALTEXIST(p, &sg, args->from);
71414331Speter	CHECKALTCREAT(p, &sg, args->to);
71514331Speter
71614331Speter#ifdef DEBUG
71714331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
71814331Speter	    p->p_pid, args->from, args->to);
71914331Speter#endif
72014331Speter	bsd.from = args->from;
72114331Speter	bsd.to = args->to;
72214331Speter
72330994Sphk	return rename(p, &bsd);
72414331Speter}
72514331Speter
72614331Speterint
72730994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
72814331Speter{
72914331Speter	struct symlink_args bsd;
73014331Speter	caddr_t sg;
73114331Speter
73214331Speter	sg = stackgap_init();
73314331Speter	CHECKALTEXIST(p, &sg, args->path);
73414331Speter	CHECKALTCREAT(p, &sg, args->to);
73514331Speter
73614331Speter#ifdef DEBUG
73714331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
73814331Speter	    p->p_pid, args->path, args->to);
73914331Speter#endif
74014331Speter	bsd.path = args->path;
74114331Speter	bsd.link = args->to;
74214331Speter
74330994Sphk	return symlink(p, &bsd);
74414331Speter}
74514331Speter
74614331Speterint
74730994Sphklinux_execve(struct proc *p, struct linux_execve_args *args)
74814331Speter{
74914331Speter	struct execve_args bsd;
75014331Speter	caddr_t sg;
75114331Speter
75214331Speter	sg = stackgap_init();
75314331Speter	CHECKALTEXIST(p, &sg, args->path);
75414331Speter
75514331Speter#ifdef DEBUG
75614331Speter        printf("Linux-emul(%d): execve(%s)\n",
75714331Speter	    p->p_pid, args->path);
75814331Speter#endif
75914331Speter	bsd.fname = args->path;
76014331Speter	bsd.argv = args->argp;
76114331Speter	bsd.envv = args->envp;
76214331Speter
76330994Sphk	return execve(p, &bsd);
76414331Speter}
76514331Speter
76614331Speterint
76730994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
76814331Speter{
76914331Speter	struct readlink_args bsd;
77014331Speter	caddr_t sg;
77114331Speter
77214331Speter	sg = stackgap_init();
77314331Speter	CHECKALTEXIST(p, &sg, args->name);
77414331Speter
77514331Speter#ifdef DEBUG
77614331Speter        printf("Linux-emul(%d): readlink(%s, 0x%x, %d)\n",
77714331Speter	    p->p_pid, args->name, args->buf, args->count);
77814331Speter#endif
77914331Speter	bsd.path = args->name;
78014331Speter	bsd.buf = args->buf;
78114331Speter	bsd.count = args->count;
78214331Speter
78330994Sphk	return readlink(p, &bsd);
78414331Speter}
78514331Speter
78614331Speterint
78730994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
78814331Speter{
78914331Speter	struct otruncate_args bsd;
79014331Speter	caddr_t sg;
79114331Speter
79214331Speter	sg = stackgap_init();
79314331Speter	CHECKALTEXIST(p, &sg, args->path);
79414331Speter
79514331Speter#ifdef DEBUG
79614331Speter        printf("Linux-emul(%d): truncate(%s)\n",
79714331Speter	    p->p_pid, args->path);
79814331Speter#endif
79914331Speter	bsd.path = args->path;
80014331Speter
80130994Sphk	return otruncate(p, &bsd);
80214331Speter}
80314331Speter
804