linux_file.c revision 31784
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 *
2831784Seivind *  $Id: linux_file.c,v 1.16 1997/12/05 19:55:37 bde 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;
2079313Ssos
20814331Speter    sg = stackgap_init();
20914331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21014331Speter    d_tty = NULL;
21114331Speter
2129313Ssos#ifdef DEBUG
2139313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2149313Ssos	   p->p_pid, args->fd, args->cmd);
2159313Ssos#endif
2169313Ssos    fcntl_args.fd = args->fd;
2179313Ssos    fcntl_args.arg = 0;
2189313Ssos
2199313Ssos    switch (args->cmd) {
2209313Ssos    case LINUX_F_DUPFD:
2219313Ssos	fcntl_args.cmd = F_DUPFD;
22230994Sphk	return fcntl(p, &fcntl_args);
2239313Ssos
2249313Ssos    case LINUX_F_GETFD:
2259313Ssos	fcntl_args.cmd = F_GETFD;
22630994Sphk	return fcntl(p, &fcntl_args);
2279313Ssos
2289313Ssos    case LINUX_F_SETFD:
2299313Ssos	fcntl_args.cmd = F_SETFD;
23030994Sphk	return fcntl(p, &fcntl_args);
2319313Ssos
2329313Ssos    case LINUX_F_GETFL:
2339313Ssos	fcntl_args.cmd = F_GETFL;
23430994Sphk	error = fcntl(p, &fcntl_args);
23530994Sphk	result = p->p_retval[0];
23630994Sphk	p->p_retval[0] = 0;
23730994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
23830994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
23930994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24030994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24130994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
24230994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
2439313Ssos	return error;
2449313Ssos
2459313Ssos    case LINUX_F_SETFL:
2469313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2479313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2489313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
2499313Ssos	fcntl_args.cmd = F_SETFL;
25030994Sphk	return fcntl(p, &fcntl_args);
2519313Ssos
2529313Ssos    case LINUX_F_GETLK:
2539313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2549313Ssos		   	    sizeof(struct linux_flock))))
2559313Ssos	    return error;
2569313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2579313Ssos	fcntl_args.cmd = F_GETLK;
2589313Ssos	fcntl_args.arg = (int)bsd_flock;
25930994Sphk	if (error = fcntl(p, &fcntl_args))
2609313Ssos	    return error;
2619313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2629313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2639313Ssos		       sizeof(struct linux_flock));
2649313Ssos
2659313Ssos    case LINUX_F_SETLK:
2669313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2679313Ssos		   	    sizeof(struct linux_flock))))
2689313Ssos	    return error;
2699313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2709313Ssos	fcntl_args.cmd = F_SETLK;
2719313Ssos	fcntl_args.arg = (int)bsd_flock;
27230994Sphk	return fcntl(p, &fcntl_args);
2739313Ssos
2749313Ssos    case LINUX_F_SETLKW:
2759313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2769313Ssos		   	    sizeof(struct linux_flock))))
2779313Ssos	    return error;
2789313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2799313Ssos	fcntl_args.cmd = F_SETLKW;
2809313Ssos	fcntl_args.arg = (int)bsd_flock;
28130994Sphk	return fcntl(p, &fcntl_args);
2829313Ssos
2839313Ssos    case LINUX_F_SETOWN:
28414331Speter    case LINUX_F_GETOWN:
28514331Speter	/*
28614331Speter	 * We need to route around the normal fcntl() for these calls,
28714331Speter	 * since it uses TIOC{G,S}PGRP, which is too restrictive for
28814331Speter	 * Linux F_{G,S}ETOWN semantics. For sockets, this problem
28914331Speter	 * does not exist.
29014331Speter	 */
29114331Speter	fdp = p->p_fd;
29214331Speter	if ((u_int)args->fd >= fdp->fd_nfiles ||
29314331Speter		(fp = fdp->fd_ofiles[args->fd]) == NULL)
29414331Speter	    return EBADF;
29514331Speter	if (fp->f_type == DTYPE_SOCKET) {
29614331Speter	    fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
29730994Sphk	    return fcntl(p, &fcntl_args);
29814331Speter	}
29914331Speter	vp = (struct vnode *)fp->f_data;
30014331Speter	if (vp->v_type != VCHR)
30114331Speter	    return EINVAL;
30214331Speter	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
30314331Speter	    return error;
3049313Ssos
30514331Speter	d_tty = cdevsw[major(va.va_rdev)]->d_devtotty;
30614331Speter	if (!d_tty || (!(tp = (*d_tty)(va.va_rdev))))
30714331Speter	    return EINVAL;
30814331Speter	if (args->cmd == LINUX_F_GETOWN) {
30930994Sphk	    p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
31014331Speter	    return 0;
31114331Speter	}
31214331Speter	if ((long)args->arg <= 0) {
31314331Speter	    pgid = -(long)args->arg;
31414331Speter	} else {
31514331Speter	    struct proc *p1 = pfind((long)args->arg);
31614331Speter	    if (p1 == 0)
31714331Speter		return (ESRCH);
31814331Speter	    pgid = (long)p1->p_pgrp->pg_id;
31914331Speter	}
32014331Speter	pgrp = pgfind(pgid);
32114331Speter	if (pgrp == NULL || pgrp->pg_session != p->p_session)
32214331Speter	    return EPERM;
32314331Speter	tp->t_pgrp = pgrp;
32414331Speter	return 0;
3259313Ssos    }
3269313Ssos    return EINVAL;
3279313Ssos}
3289313Ssos
3299313Ssosint
33030994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3319313Ssos{
3329313Ssos
33312858Speter    struct lseek_args /* {
33412858Speter	int fd;
3359313Ssos	int pad;
33612858Speter	off_t offset;
3379313Ssos	int whence;
33812858Speter    } */ tmp_args;
3399313Ssos    int error;
3409313Ssos
3419313Ssos#ifdef DEBUG
3429313Ssos    printf("Linux-emul(%d): lseek(%d, %d, %d)\n",
3439313Ssos	   p->p_pid, args->fdes, args->off, args->whence);
3449313Ssos#endif
34512858Speter    tmp_args.fd = args->fdes;
34612858Speter    tmp_args.offset = (off_t)args->off;
3479313Ssos    tmp_args.whence = args->whence;
34830994Sphk    error = lseek(p, &tmp_args);
3499313Ssos    return error;
3509313Ssos}
3519313Ssos
35214331Speterint
35330994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
35414331Speter{
35514331Speter	struct lseek_args bsd_args;
35614331Speter	int error;
35714331Speter	off_t off;
35814331Speter
35914331Speter#ifdef DEBUG
36014331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
36114331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
36214331Speter#endif
36314331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
36414331Speter
36514331Speter	bsd_args.fd = args->fd;
36614331Speter	bsd_args.offset = off;
36714331Speter	bsd_args.whence = args->whence;
36814331Speter
36930994Sphk	if ((error = lseek(p, &bsd_args)))
37014331Speter		return error;
37114331Speter
37230994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
37314331Speter		return error;
37414331Speter
37530994Sphk	p->p_retval[0] = 0;
37614331Speter	return 0;
37714331Speter}
37814331Speter
37914331Speter
3809313Ssosstruct linux_dirent {
3819313Ssos    long dino;
3829313Ssos    linux_off_t doff;
3839313Ssos    unsigned short dreclen;
3849313Ssos    char dname[LINUX_NAME_MAX + 1];
3859313Ssos};
3869313Ssos
3879313Ssos#define LINUX_RECLEN(de,namlen) \
3889313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3899313Ssos
3909313Ssosint
39130994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3929313Ssos{
39314331Speter	struct linux_getdents_args lda;
39414331Speter
39514331Speter	lda.fd = args->fd;
39614331Speter	lda.dent = args->dent;
39714331Speter	lda.count = 1;
39830994Sphk	return linux_getdents(p, &lda);
39914331Speter}
40014331Speter
40114331Speterint
40230994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
40314331Speter{
4049313Ssos    register struct dirent *bdp;
4059313Ssos    struct vnode *vp;
4069313Ssos    caddr_t inp, buf;		/* BSD-format */
4079313Ssos    int len, reclen;		/* BSD-format */
4089313Ssos    caddr_t outp;		/* Linux-format */
4099313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4109313Ssos    struct file *fp;
4119313Ssos    struct uio auio;
4129313Ssos    struct iovec aiov;
4139313Ssos    struct vattr va;
4149313Ssos    off_t off;
4159313Ssos    struct linux_dirent linux_dirent;
41624654Sdfr    int buflen, error, eofflag, nbytes, justone;
41724654Sdfr    u_long *cookies = NULL, *cookiep;
41824654Sdfr    int ncookies;
4199313Ssos
4209313Ssos#ifdef DEBUG
42114331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4229313Ssos	   p->p_pid, args->fd, args->count);
4239313Ssos#endif
42410355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4259313Ssos	return (error);
42614331Speter    }
4279313Ssos
4289313Ssos    if ((fp->f_flag & FREAD) == 0)
4299313Ssos	return (EBADF);
4309313Ssos
4319313Ssos    vp = (struct vnode *) fp->f_data;
4329313Ssos
4339313Ssos    if (vp->v_type != VDIR)
4349313Ssos	return (EINVAL);
4359313Ssos
43610355Sswallace    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4379313Ssos	return error;
43811418Sswallace    }
4399313Ssos
4409313Ssos    nbytes = args->count;
4419313Ssos    if (nbytes == 1) {
4429313Ssos	nbytes = sizeof (struct linux_dirent);
4439313Ssos	justone = 1;
4449313Ssos    }
4459313Ssos    else
4469313Ssos	justone = 0;
4479313Ssos
44810355Sswallace    off = fp->f_offset;
44924672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
45024654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
45111418Sswallace    buflen = min(buflen, MAXBSIZE);
4529313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
45322521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4549313Ssosagain:
4559313Ssos    aiov.iov_base = buf;
4569313Ssos    aiov.iov_len = buflen;
4579313Ssos    auio.uio_iov = &aiov;
4589313Ssos    auio.uio_iovcnt = 1;
4599313Ssos    auio.uio_rw = UIO_READ;
4609313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4619313Ssos    auio.uio_procp = p;
4629313Ssos    auio.uio_resid = buflen;
46324654Sdfr    auio.uio_offset = off;
4649313Ssos
46524654Sdfr    if (cookies) {
46624654Sdfr	free(cookies, M_TEMP);
46724654Sdfr	cookies = NULL;
46824654Sdfr    }
46924654Sdfr
47024654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
47110355Sswallace    if (error) {
4729313Ssos	goto out;
47314331Speter    }
4749313Ssos
4759313Ssos    inp = buf;
4769313Ssos    outp = (caddr_t) args->dent;
4779313Ssos    resid = nbytes;
47824654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4799313Ssos	goto eof;
48014331Speter    }
4819313Ssos
48224654Sdfr    cookiep = cookies;
48324654Sdfr
48424654Sdfr    if (cookies) {
48524654Sdfr	/*
48624654Sdfr	 * When using cookies, the vfs has the option of reading from
48724654Sdfr	 * a different offset than that supplied (UFS truncates the
48824654Sdfr	 * offset to a block boundary to make sure that it never reads
48924654Sdfr	 * partway through a directory entry, even if the directory
49024654Sdfr	 * has been compacted).
49124654Sdfr	 */
49224654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
49324654Sdfr	    bdp = (struct dirent *) inp;
49424654Sdfr	    len -= bdp->d_reclen;
49524654Sdfr	    inp += bdp->d_reclen;
49624654Sdfr	    cookiep++;
49724654Sdfr	    ncookies--;
49824654Sdfr	}
49924654Sdfr    }
50024654Sdfr
5019313Ssos    while (len > 0) {
50224654Sdfr	if (cookiep && ncookies == 0)
50324654Sdfr	    break;
50410355Sswallace	bdp = (struct dirent *) inp;
50510355Sswallace	reclen = bdp->d_reclen;
50610355Sswallace	if (reclen & 3) {
50710355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
50810355Sswallace	    error = EFAULT;
50910355Sswallace	    goto out;
51010355Sswallace	}
51110355Sswallace
5129313Ssos	if (bdp->d_fileno == 0) {
5139313Ssos	    inp += reclen;
51424654Sdfr	    if (cookiep) {
51524654Sdfr		off = *cookiep++;
51624654Sdfr		ncookies--;
51724654Sdfr	    } else
51824654Sdfr		off += reclen;
51910355Sswallace	    len -= reclen;
5209313Ssos	    continue;
5219313Ssos	}
5229313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5239313Ssos	if (reclen > len || resid < linuxreclen) {
5249313Ssos	    outp++;
5259313Ssos	    break;
5269313Ssos	}
5279313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
52814465Speter	if (justone) {
52914465Speter	    /*
53014465Speter	     * old linux-style readdir usage.
53114465Speter	     */
53214465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
53314465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
53414465Speter	} else {
53514465Speter	    linux_dirent.doff = (linux_off_t) off;
53614465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53714465Speter	}
5389313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
53910355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5409313Ssos	    goto out;
54114331Speter	}
5429313Ssos	inp += reclen;
54324654Sdfr	if (cookiep) {
54424654Sdfr	    off = *cookiep++;
54524654Sdfr	    ncookies--;
54624654Sdfr	} else
54724654Sdfr	    off += reclen;
5489313Ssos	outp += linuxreclen;
5499313Ssos	resid -= linuxreclen;
5509313Ssos	len -= reclen;
5519313Ssos	if (justone)
5529313Ssos	    break;
5539313Ssos    }
5549313Ssos
5559313Ssos    if (outp == (caddr_t) args->dent)
5569313Ssos	goto again;
5579313Ssos    fp->f_offset = off;
5589313Ssos
5599313Ssos    if (justone)
5609313Ssos	nbytes = resid + linuxreclen;
56110355Sswallace
5629313Ssoseof:
56330994Sphk    p->p_retval[0] = nbytes - resid;
5649313Ssosout:
56524654Sdfr    if (cookies)
56624654Sdfr	free(cookies, M_TEMP);
56722543Smpp    VOP_UNLOCK(vp, 0, p);
5689313Ssos    free(buf, M_TEMP);
5699313Ssos    return error;
5709313Ssos}
57114331Speter
57214331Speter/*
57314331Speter * These exist mainly for hooks for doing /compat/linux translation.
57414331Speter */
57514331Speter
57614331Speterint
57730994Sphklinux_access(struct proc *p, struct linux_access_args *args)
57814331Speter{
57914331Speter	struct access_args bsd;
58014331Speter	caddr_t sg;
58114331Speter
58214331Speter	sg = stackgap_init();
58314331Speter	CHECKALTEXIST(p, &sg, args->path);
58414331Speter
58514331Speter#ifdef DEBUG
58614331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
58714331Speter	    p->p_pid, args->path, args->flags);
58814331Speter#endif
58914331Speter	bsd.path = args->path;
59014331Speter	bsd.flags = args->flags;
59114331Speter
59230994Sphk	return access(p, &bsd);
59314331Speter}
59414331Speter
59514331Speterint
59630994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59714331Speter{
59814331Speter	struct unlink_args bsd;
59914331Speter	caddr_t sg;
60014331Speter
60114331Speter	sg = stackgap_init();
60214331Speter	CHECKALTEXIST(p, &sg, args->path);
60314331Speter
60414331Speter#ifdef DEBUG
60514331Speter	printf("Linux-emul(%d): unlink(%s)\n",
60614331Speter	   p->p_pid, args->path);
60714331Speter#endif
60814331Speter	bsd.path = args->path;
60914331Speter
61030994Sphk	return unlink(p, &bsd);
61114331Speter}
61214331Speter
61314331Speterint
61430994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61514331Speter{
61614331Speter	struct chdir_args bsd;
61714331Speter	caddr_t sg;
61814331Speter
61914331Speter	sg = stackgap_init();
62014331Speter	CHECKALTEXIST(p, &sg, args->path);
62114331Speter
62214331Speter#ifdef DEBUG
62314331Speter	printf("Linux-emul(%d): chdir(%s)\n",
62414331Speter	   p->p_pid, args->path);
62514331Speter#endif
62614331Speter	bsd.path = args->path;
62714331Speter
62830994Sphk	return chdir(p, &bsd);
62914331Speter}
63014331Speter
63114331Speterint
63230994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63314331Speter{
63414331Speter	struct chmod_args bsd;
63514331Speter	caddr_t sg;
63614331Speter
63714331Speter	sg = stackgap_init();
63814331Speter	CHECKALTEXIST(p, &sg, args->path);
63914331Speter
64014331Speter#ifdef DEBUG
64114331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
64214331Speter	    p->p_pid, args->path, args->mode);
64314331Speter#endif
64414331Speter	bsd.path = args->path;
64514331Speter	bsd.mode = args->mode;
64614331Speter
64730994Sphk	return chmod(p, &bsd);
64814331Speter}
64914331Speter
65014331Speterint
65130994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65214331Speter{
65314331Speter	struct chown_args bsd;
65414331Speter	caddr_t sg;
65514331Speter
65614331Speter	sg = stackgap_init();
65714331Speter	CHECKALTEXIST(p, &sg, args->path);
65814331Speter
65914331Speter#ifdef DEBUG
66014331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
66114331Speter	    p->p_pid, args->path, args->uid, args->gid);
66214331Speter#endif
66314331Speter	bsd.path = args->path;
66414331Speter	/* XXX size casts here */
66514331Speter	bsd.uid = args->uid;
66614331Speter	bsd.gid = args->gid;
66714331Speter
66830994Sphk	return chown(p, &bsd);
66914331Speter}
67014331Speter
67114331Speterint
67230994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
67314331Speter{
67414331Speter	struct mkdir_args bsd;
67514331Speter	caddr_t sg;
67614331Speter
67714331Speter	sg = stackgap_init();
67814331Speter	CHECKALTCREAT(p, &sg, args->path);
67914331Speter
68014331Speter#ifdef DEBUG
68114331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
68214331Speter	    p->p_pid, args->path, args->mode);
68314331Speter#endif
68414331Speter	bsd.path = args->path;
68514331Speter	bsd.mode = args->mode;
68614331Speter
68730994Sphk	return mkdir(p, &bsd);
68814331Speter}
68914331Speter
69014331Speterint
69130994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
69214331Speter{
69314331Speter	struct rmdir_args bsd;
69414331Speter	caddr_t sg;
69514331Speter
69614331Speter	sg = stackgap_init();
69714331Speter	CHECKALTEXIST(p, &sg, args->path);
69814331Speter
69914331Speter#ifdef DEBUG
70014331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
70114331Speter	    p->p_pid, args->path);
70214331Speter#endif
70314331Speter	bsd.path = args->path;
70414331Speter
70530994Sphk	return rmdir(p, &bsd);
70614331Speter}
70714331Speter
70814331Speterint
70930994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
71014331Speter{
71114331Speter	struct rename_args bsd;
71214331Speter	caddr_t sg;
71314331Speter
71414331Speter	sg = stackgap_init();
71514331Speter	CHECKALTEXIST(p, &sg, args->from);
71614331Speter	CHECKALTCREAT(p, &sg, args->to);
71714331Speter
71814331Speter#ifdef DEBUG
71914331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
72014331Speter	    p->p_pid, args->from, args->to);
72114331Speter#endif
72214331Speter	bsd.from = args->from;
72314331Speter	bsd.to = args->to;
72414331Speter
72530994Sphk	return rename(p, &bsd);
72614331Speter}
72714331Speter
72814331Speterint
72930994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
73014331Speter{
73114331Speter	struct symlink_args bsd;
73214331Speter	caddr_t sg;
73314331Speter
73414331Speter	sg = stackgap_init();
73514331Speter	CHECKALTEXIST(p, &sg, args->path);
73614331Speter	CHECKALTCREAT(p, &sg, args->to);
73714331Speter
73814331Speter#ifdef DEBUG
73914331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
74014331Speter	    p->p_pid, args->path, args->to);
74114331Speter#endif
74214331Speter	bsd.path = args->path;
74314331Speter	bsd.link = args->to;
74414331Speter
74530994Sphk	return symlink(p, &bsd);
74614331Speter}
74714331Speter
74814331Speterint
74930994Sphklinux_execve(struct proc *p, struct linux_execve_args *args)
75014331Speter{
75114331Speter	struct execve_args bsd;
75214331Speter	caddr_t sg;
75314331Speter
75414331Speter	sg = stackgap_init();
75514331Speter	CHECKALTEXIST(p, &sg, args->path);
75614331Speter
75714331Speter#ifdef DEBUG
75814331Speter        printf("Linux-emul(%d): execve(%s)\n",
75914331Speter	    p->p_pid, args->path);
76014331Speter#endif
76114331Speter	bsd.fname = args->path;
76214331Speter	bsd.argv = args->argp;
76314331Speter	bsd.envv = args->envp;
76414331Speter
76530994Sphk	return execve(p, &bsd);
76614331Speter}
76714331Speter
76814331Speterint
76930994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
77014331Speter{
77114331Speter	struct readlink_args bsd;
77214331Speter	caddr_t sg;
77314331Speter
77414331Speter	sg = stackgap_init();
77514331Speter	CHECKALTEXIST(p, &sg, args->name);
77614331Speter
77714331Speter#ifdef DEBUG
77814331Speter        printf("Linux-emul(%d): readlink(%s, 0x%x, %d)\n",
77914331Speter	    p->p_pid, args->name, args->buf, args->count);
78014331Speter#endif
78114331Speter	bsd.path = args->name;
78214331Speter	bsd.buf = args->buf;
78314331Speter	bsd.count = args->count;
78414331Speter
78530994Sphk	return readlink(p, &bsd);
78614331Speter}
78714331Speter
78814331Speterint
78930994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
79014331Speter{
79114331Speter	struct otruncate_args bsd;
79214331Speter	caddr_t sg;
79314331Speter
79414331Speter	sg = stackgap_init();
79514331Speter	CHECKALTEXIST(p, &sg, args->path);
79614331Speter
79714331Speter#ifdef DEBUG
79814331Speter        printf("Linux-emul(%d): truncate(%s)\n",
79914331Speter	    p->p_pid, args->path);
80014331Speter#endif
80114331Speter	bsd.path = args->path;
80214331Speter
80330994Sphk	return otruncate(p, &bsd);
80414331Speter}
80514331Speter
806