linux_file.c revision 76166
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 76166 2001-05-01 08:13:21Z markm $
299313Ssos */
309313Ssos
3131784Seivind#include "opt_compat.h"
3231784Seivind
339313Ssos#include <sys/param.h>
349313Ssos#include <sys/systm.h>
3576166Smarkm#include <sys/conf.h>
3676166Smarkm#include <sys/dirent.h>
379313Ssos#include <sys/fcntl.h>
389313Ssos#include <sys/file.h>
399313Ssos#include <sys/filedesc.h>
4031561Sbde#include <sys/lock.h>
419313Ssos#include <sys/malloc.h>
4272538Sjlemon#include <sys/mount.h>
4376166Smarkm#include <sys/mutex.h>
4476166Smarkm#include <sys/proc.h>
4576166Smarkm#include <sys/sysproto.h>
4614331Speter#include <sys/tty.h>
4776166Smarkm#include <sys/vnode.h>
4812458Sbde
4972538Sjlemon#include <ufs/ufs/extattr.h>
5072538Sjlemon#include <ufs/ufs/quota.h>
5172538Sjlemon#include <ufs/ufs/ufsmount.h>
5272538Sjlemon
5364905Smarcel#include <machine/../linux/linux.h>
5468583Smarcel#include <machine/../linux/linux_proto.h>
5564905Smarcel#include <compat/linux/linux_util.h>
569313Ssos
5768201Sobrien#ifndef __alpha__
589313Ssosint
5930994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
609313Ssos{
6112858Speter    struct open_args /* {
629313Ssos	char *path;
639313Ssos	int flags;
649313Ssos	int mode;
6512858Speter    } */ bsd_open_args;
6614331Speter    caddr_t sg;
679313Ssos
6814331Speter    sg = stackgap_init();
6914331Speter    CHECKALTCREAT(p, &sg, args->path);
7014331Speter
719313Ssos#ifdef DEBUG
7272543Sjlemon	if (ldebug(creat))
7372543Sjlemon		printf(ARGS(creat, "%s, %d"), args->path, args->mode);
749313Ssos#endif
759313Ssos    bsd_open_args.path = args->path;
769313Ssos    bsd_open_args.mode = args->mode;
779313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7830994Sphk    return open(p, &bsd_open_args);
799313Ssos}
8068201Sobrien#endif /*!__alpha__*/
819313Ssos
829313Ssosint
8330994Sphklinux_open(struct proc *p, struct linux_open_args *args)
849313Ssos{
8512858Speter    struct open_args /* {
869313Ssos	char *path;
879313Ssos	int flags;
889313Ssos	int mode;
8912858Speter    } */ bsd_open_args;
909313Ssos    int error;
9114331Speter    caddr_t sg;
9214331Speter
9314331Speter    sg = stackgap_init();
949313Ssos
9514331Speter    if (args->flags & LINUX_O_CREAT)
9614331Speter	CHECKALTCREAT(p, &sg, args->path);
9714331Speter    else
9814331Speter	CHECKALTEXIST(p, &sg, args->path);
9914331Speter
1009313Ssos#ifdef DEBUG
10172543Sjlemon	if (ldebug(open))
10272543Sjlemon		printf(ARGS(open, "%s, 0x%x, 0x%x"),
10372543Sjlemon		    args->path, args->flags, args->mode);
1049313Ssos#endif
1059313Ssos    bsd_open_args.flags = 0;
1069313Ssos    if (args->flags & LINUX_O_RDONLY)
1079313Ssos	bsd_open_args.flags |= O_RDONLY;
1089313Ssos    if (args->flags & LINUX_O_WRONLY)
1099313Ssos	bsd_open_args.flags |= O_WRONLY;
1109313Ssos    if (args->flags & LINUX_O_RDWR)
1119313Ssos	bsd_open_args.flags |= O_RDWR;
1129313Ssos    if (args->flags & LINUX_O_NDELAY)
1139313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1149313Ssos    if (args->flags & LINUX_O_APPEND)
1159313Ssos	bsd_open_args.flags |= O_APPEND;
1169313Ssos    if (args->flags & LINUX_O_SYNC)
1179313Ssos	bsd_open_args.flags |= O_FSYNC;
1189313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1199313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1209313Ssos    if (args->flags & LINUX_FASYNC)
1219313Ssos	bsd_open_args.flags |= O_ASYNC;
1229313Ssos    if (args->flags & LINUX_O_CREAT)
1239313Ssos	bsd_open_args.flags |= O_CREAT;
1249313Ssos    if (args->flags & LINUX_O_TRUNC)
1259313Ssos	bsd_open_args.flags |= O_TRUNC;
1269313Ssos    if (args->flags & LINUX_O_EXCL)
1279313Ssos	bsd_open_args.flags |= O_EXCL;
1289313Ssos    if (args->flags & LINUX_O_NOCTTY)
1299313Ssos	bsd_open_args.flags |= O_NOCTTY;
1309313Ssos    bsd_open_args.path = args->path;
1319313Ssos    bsd_open_args.mode = args->mode;
1329313Ssos
13330994Sphk    error = open(p, &bsd_open_args);
13470061Sjhb    PROC_LOCK(p);
1359313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1369313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1379313Ssos	struct filedesc *fdp = p->p_fd;
13830994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1399313Ssos
14070061Sjhb	PROC_UNLOCK(p);
1419313Ssos	if (fp->f_type == DTYPE_VNODE)
14251418Sgreen	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
14370061Sjhb    } else
14470061Sjhb	PROC_UNLOCK(p);
14514331Speter#ifdef DEBUG
14672543Sjlemon	if (ldebug(open))
14772543Sjlemon		printf(LMSG("open returns error %d"), error);
14814331Speter#endif
1499313Ssos    return error;
1509313Ssos}
1519313Ssos
1529313Ssosstruct linux_flock {
1539313Ssos    short l_type;
1549313Ssos    short l_whence;
1559313Ssos    linux_off_t l_start;
1569313Ssos    linux_off_t l_len;
1579313Ssos    linux_pid_t l_pid;
1589313Ssos};
1599313Ssos
1609313Ssosstatic void
1619313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1629313Ssos{
1639313Ssos    switch (linux_flock->l_type) {
1649313Ssos    case LINUX_F_RDLCK:
1659313Ssos	bsd_flock->l_type = F_RDLCK;
1669313Ssos	break;
1679313Ssos    case LINUX_F_WRLCK:
1689313Ssos	bsd_flock->l_type = F_WRLCK;
1699313Ssos	break;
1709313Ssos    case LINUX_F_UNLCK:
1719313Ssos	bsd_flock->l_type = F_UNLCK;
1729313Ssos	break;
17349676Smarcel    default:
17449676Smarcel        bsd_flock->l_type = -1;
17549676Smarcel        break;
1769313Ssos    }
1779313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1789313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1799313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1809313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1819313Ssos}
1829313Ssos
1839313Ssosstatic void
1849313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1859313Ssos{
1869313Ssos    switch (bsd_flock->l_type) {
1879313Ssos    case F_RDLCK:
1889313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1899313Ssos	break;
1909313Ssos    case F_WRLCK:
1919313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1929313Ssos	break;
1939313Ssos    case F_UNLCK:
1949313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1959313Ssos	break;
1969313Ssos    }
1979313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1989313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1999313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
2009313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
2019313Ssos}
2029313Ssos
2039313Ssosint
20430994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
2059313Ssos{
2069313Ssos    int error, result;
20712858Speter    struct fcntl_args /* {
2089313Ssos	int fd;
2099313Ssos	int cmd;
21068662Smarcel	long arg;
21168662Smarcel    } */ fcntl_args;
2129313Ssos    struct linux_flock linux_flock;
21314331Speter    struct flock *bsd_flock;
21468662Smarcel    struct filedesc *fdp;
21568662Smarcel    struct file *fp;
21614331Speter    caddr_t sg;
2179313Ssos
21814331Speter    sg = stackgap_init();
21914331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
22014331Speter
2219313Ssos#ifdef DEBUG
22272543Sjlemon	if (ldebug(fcntl))
22372543Sjlemon		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
2249313Ssos#endif
2259313Ssos    fcntl_args.fd = args->fd;
2269313Ssos
2279313Ssos    switch (args->cmd) {
2289313Ssos    case LINUX_F_DUPFD:
2299313Ssos	fcntl_args.cmd = F_DUPFD;
23049845Smarcel	fcntl_args.arg = args->arg;
23130994Sphk	return fcntl(p, &fcntl_args);
2329313Ssos
2339313Ssos    case LINUX_F_GETFD:
2349313Ssos	fcntl_args.cmd = F_GETFD;
23530994Sphk	return fcntl(p, &fcntl_args);
2369313Ssos
2379313Ssos    case LINUX_F_SETFD:
2389313Ssos	fcntl_args.cmd = F_SETFD;
23949845Smarcel	fcntl_args.arg = args->arg;
24030994Sphk	return fcntl(p, &fcntl_args);
2419313Ssos
2429313Ssos    case LINUX_F_GETFL:
2439313Ssos	fcntl_args.cmd = F_GETFL;
24430994Sphk	error = fcntl(p, &fcntl_args);
24530994Sphk	result = p->p_retval[0];
24630994Sphk	p->p_retval[0] = 0;
24730994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24830994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24930994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
25030994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
25130994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
25230994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
25339978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2549313Ssos	return error;
2559313Ssos
2569313Ssos    case LINUX_F_SETFL:
25749845Smarcel	fcntl_args.arg = 0;
2589313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2599313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2609313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
26139978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2629313Ssos	fcntl_args.cmd = F_SETFL;
26330994Sphk	return fcntl(p, &fcntl_args);
26449676Smarcel
2659313Ssos    case LINUX_F_GETLK:
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_GETLK;
27168201Sobrien	fcntl_args.arg = (long)bsd_flock;
27246571Speter	error = fcntl(p, &fcntl_args);
27346571Speter	if (error)
2749313Ssos	    return error;
2759313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2769313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2779313Ssos		       sizeof(struct linux_flock));
2789313Ssos
2799313Ssos    case LINUX_F_SETLK:
2809313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2819313Ssos		   	    sizeof(struct linux_flock))))
2829313Ssos	    return error;
2839313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2849313Ssos	fcntl_args.cmd = F_SETLK;
28568201Sobrien	fcntl_args.arg = (long)bsd_flock;
28630994Sphk	return fcntl(p, &fcntl_args);
2879313Ssos
2889313Ssos    case LINUX_F_SETLKW:
2899313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2909313Ssos		   	    sizeof(struct linux_flock))))
2919313Ssos	    return error;
2929313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2939313Ssos	fcntl_args.cmd = F_SETLKW;
29468201Sobrien	fcntl_args.arg = (long)bsd_flock;
29530994Sphk	return fcntl(p, &fcntl_args);
2969313Ssos
29763233Smarcel    case LINUX_F_GETOWN:
29863233Smarcel	fcntl_args.cmd = F_GETOWN;
29963233Smarcel	return fcntl(p, &fcntl_args);
30063233Smarcel
3019313Ssos    case LINUX_F_SETOWN:
30268662Smarcel	/*
30368662Smarcel	 * XXX some Linux applications depend on F_SETOWN having no
30468662Smarcel	 * significant effect for pipes (SIGIO is not delivered for
30568662Smarcel	 * pipes under Linux-2.2.35 at least).
30668662Smarcel	 */
30768662Smarcel	fdp = p->p_fd;
30868662Smarcel	if ((u_int)args->fd >= fdp->fd_nfiles ||
30968662Smarcel	  (fp = fdp->fd_ofiles[args->fd]) == NULL)
31068662Smarcel	    return EBADF;
31168662Smarcel	if (fp->f_type == DTYPE_PIPE)
31268662Smarcel	    return EINVAL;
31368662Smarcel
31468662Smarcel 	fcntl_args.cmd = F_SETOWN;
31563233Smarcel	fcntl_args.arg = args->arg;
31663233Smarcel	return fcntl(p, &fcntl_args);
3179313Ssos    }
3189313Ssos    return EINVAL;
3199313Ssos}
3209313Ssos
3219313Ssosint
32230994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3239313Ssos{
3249313Ssos
32512858Speter    struct lseek_args /* {
32612858Speter	int fd;
3279313Ssos	int pad;
32812858Speter	off_t offset;
3299313Ssos	int whence;
33012858Speter    } */ tmp_args;
3319313Ssos    int error;
3329313Ssos
3339313Ssos#ifdef DEBUG
33472543Sjlemon	if (ldebug(lseek))
33572543Sjlemon		printf(ARGS(lseek, "%d, %ld, %d"),
33672543Sjlemon		    args->fdes, args->off, args->whence);
3379313Ssos#endif
33812858Speter    tmp_args.fd = args->fdes;
33912858Speter    tmp_args.offset = (off_t)args->off;
3409313Ssos    tmp_args.whence = args->whence;
34130994Sphk    error = lseek(p, &tmp_args);
3429313Ssos    return error;
3439313Ssos}
3449313Ssos
34568201Sobrien#ifndef __alpha__
34614331Speterint
34730994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
34814331Speter{
34914331Speter	struct lseek_args bsd_args;
35014331Speter	int error;
35114331Speter	off_t off;
35214331Speter
35314331Speter#ifdef DEBUG
35472543Sjlemon	if (ldebug(llseek))
35572543Sjlemon		printf(ARGS(llseek, "%d, %d:%d, %d"),
35672543Sjlemon		    args->fd, args->ohigh, args->olow, args->whence);
35714331Speter#endif
35814331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
35914331Speter
36014331Speter	bsd_args.fd = args->fd;
36114331Speter	bsd_args.offset = off;
36214331Speter	bsd_args.whence = args->whence;
36314331Speter
36430994Sphk	if ((error = lseek(p, &bsd_args)))
36514331Speter		return error;
36614331Speter
36730994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
36814331Speter		return error;
36914331Speter
37030994Sphk	p->p_retval[0] = 0;
37114331Speter	return 0;
37214331Speter}
37368201Sobrien#endif /*!__alpha__*/
37414331Speter
37514331Speter
3769313Ssosstruct linux_dirent {
3779313Ssos    long dino;
3789313Ssos    linux_off_t doff;
3799313Ssos    unsigned short dreclen;
3809313Ssos    char dname[LINUX_NAME_MAX + 1];
3819313Ssos};
3829313Ssos
3839313Ssos#define LINUX_RECLEN(de,namlen) \
3849313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3859313Ssos
38668201Sobrien#ifndef __alpha__
3879313Ssosint
38830994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3899313Ssos{
39014331Speter	struct linux_getdents_args lda;
39114331Speter
39214331Speter	lda.fd = args->fd;
39314331Speter	lda.dent = args->dent;
39414331Speter	lda.count = 1;
39530994Sphk	return linux_getdents(p, &lda);
39614331Speter}
39768201Sobrien#endif /*!__alpha__*/
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
41972543Sjlemon	if (ldebug(getdents))
42072543Sjlemon		printf(ARGS(getdents, "%d, *, %d"), 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
43471699Sjhb    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 {
53368347Smarcel	    if (cookiep)
53468347Smarcel		linux_dirent.doff = (linux_off_t)*cookiep;
53568347Smarcel	    else
53668347Smarcel		linux_dirent.doff = (linux_off_t)(off + reclen);
53714465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53814465Speter	}
5399313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
54010355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5419313Ssos	    goto out;
54214331Speter	}
5439313Ssos	inp += reclen;
54424654Sdfr	if (cookiep) {
54524654Sdfr	    off = *cookiep++;
54624654Sdfr	    ncookies--;
54724654Sdfr	} else
54824654Sdfr	    off += reclen;
5499313Ssos	outp += linuxreclen;
5509313Ssos	resid -= linuxreclen;
5519313Ssos	len -= reclen;
5529313Ssos	if (justone)
5539313Ssos	    break;
5549313Ssos    }
5559313Ssos
5569313Ssos    if (outp == (caddr_t) args->dent)
5579313Ssos	goto again;
5589313Ssos    fp->f_offset = off;
5599313Ssos
5609313Ssos    if (justone)
5619313Ssos	nbytes = resid + linuxreclen;
56210355Sswallace
5639313Ssoseof:
56430994Sphk    p->p_retval[0] = nbytes - resid;
5659313Ssosout:
56624654Sdfr    if (cookies)
56724654Sdfr	free(cookies, M_TEMP);
56822543Smpp    VOP_UNLOCK(vp, 0, p);
5699313Ssos    free(buf, M_TEMP);
5709313Ssos    return error;
5719313Ssos}
57214331Speter
57314331Speter/*
57414331Speter * These exist mainly for hooks for doing /compat/linux translation.
57514331Speter */
57614331Speter
57714331Speterint
57830994Sphklinux_access(struct proc *p, struct linux_access_args *args)
57914331Speter{
58014331Speter	struct access_args bsd;
58114331Speter	caddr_t sg;
58214331Speter
58314331Speter	sg = stackgap_init();
58414331Speter	CHECKALTEXIST(p, &sg, args->path);
58514331Speter
58614331Speter#ifdef DEBUG
58772543Sjlemon	if (ldebug(access))
58872543Sjlemon		printf(ARGS(access, "%s, %d"), args->path, args->flags);
58914331Speter#endif
59014331Speter	bsd.path = args->path;
59114331Speter	bsd.flags = args->flags;
59214331Speter
59330994Sphk	return access(p, &bsd);
59414331Speter}
59514331Speter
59614331Speterint
59730994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59814331Speter{
59914331Speter	struct unlink_args bsd;
60014331Speter	caddr_t sg;
60114331Speter
60214331Speter	sg = stackgap_init();
60314331Speter	CHECKALTEXIST(p, &sg, args->path);
60414331Speter
60514331Speter#ifdef DEBUG
60672543Sjlemon	if (ldebug(unlink))
60772543Sjlemon		printf(ARGS(unlink, "%s"), args->path);
60814331Speter#endif
60914331Speter	bsd.path = args->path;
61014331Speter
61130994Sphk	return unlink(p, &bsd);
61214331Speter}
61314331Speter
61414331Speterint
61530994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61614331Speter{
61714331Speter	struct chdir_args bsd;
61814331Speter	caddr_t sg;
61914331Speter
62014331Speter	sg = stackgap_init();
62114331Speter	CHECKALTEXIST(p, &sg, args->path);
62214331Speter
62314331Speter#ifdef DEBUG
62472543Sjlemon	if (ldebug(chdir))
62572543Sjlemon		printf(ARGS(chdir, "%s"), args->path);
62614331Speter#endif
62714331Speter	bsd.path = args->path;
62814331Speter
62930994Sphk	return chdir(p, &bsd);
63014331Speter}
63114331Speter
63214331Speterint
63330994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63414331Speter{
63514331Speter	struct chmod_args bsd;
63614331Speter	caddr_t sg;
63714331Speter
63814331Speter	sg = stackgap_init();
63914331Speter	CHECKALTEXIST(p, &sg, args->path);
64014331Speter
64114331Speter#ifdef DEBUG
64272543Sjlemon	if (ldebug(chmod))
64372543Sjlemon		printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
64414331Speter#endif
64514331Speter	bsd.path = args->path;
64614331Speter	bsd.mode = args->mode;
64714331Speter
64830994Sphk	return chmod(p, &bsd);
64914331Speter}
65014331Speter
65114331Speterint
65230994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
65314331Speter{
65414331Speter	struct chown_args bsd;
65514331Speter	caddr_t sg;
65614331Speter
65714331Speter	sg = stackgap_init();
65814331Speter	CHECKALTEXIST(p, &sg, args->path);
65914331Speter
66014331Speter#ifdef DEBUG
66172543Sjlemon	if (ldebug(chown))
66272543Sjlemon		printf(ARGS(chown, "%s, %d, %d"),
66372543Sjlemon		    args->path, args->uid, args->gid);
66414331Speter#endif
66514331Speter	bsd.path = args->path;
66614331Speter	/* XXX size casts here */
66714331Speter	bsd.uid = args->uid;
66814331Speter	bsd.gid = args->gid;
66914331Speter
67030994Sphk	return chown(p, &bsd);
67114331Speter}
67214331Speter
67314331Speterint
67434941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
67534941Speter{
67634941Speter	struct lchown_args bsd;
67734941Speter	caddr_t sg;
67834941Speter
67934941Speter	sg = stackgap_init();
68034941Speter	CHECKALTEXIST(p, &sg, args->path);
68134941Speter
68234941Speter#ifdef DEBUG
68372543Sjlemon	if (ldebug(lchown))
68472543Sjlemon		printf(ARGS(lchown, "%s, %d, %d"),
68572543Sjlemon		    args->path, args->uid, args->gid);
68634941Speter#endif
68734941Speter	bsd.path = args->path;
68834941Speter	/* XXX size casts here */
68934941Speter	bsd.uid = args->uid;
69034941Speter	bsd.gid = args->gid;
69134941Speter
69234941Speter	return lchown(p, &bsd);
69334941Speter}
69434941Speter
69534941Speterint
69630994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
69714331Speter{
69814331Speter	struct mkdir_args bsd;
69914331Speter	caddr_t sg;
70014331Speter
70114331Speter	sg = stackgap_init();
70214331Speter	CHECKALTCREAT(p, &sg, args->path);
70314331Speter
70414331Speter#ifdef DEBUG
70572543Sjlemon	if (ldebug(mkdir))
70672543Sjlemon		printf(ARGS(mkdir, "%s, %d"), args->path, args->mode);
70714331Speter#endif
70814331Speter	bsd.path = args->path;
70914331Speter	bsd.mode = args->mode;
71014331Speter
71130994Sphk	return mkdir(p, &bsd);
71214331Speter}
71314331Speter
71414331Speterint
71530994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
71614331Speter{
71714331Speter	struct rmdir_args bsd;
71814331Speter	caddr_t sg;
71914331Speter
72014331Speter	sg = stackgap_init();
72114331Speter	CHECKALTEXIST(p, &sg, args->path);
72214331Speter
72314331Speter#ifdef DEBUG
72472543Sjlemon	if (ldebug(rmdir))
72572543Sjlemon		printf(ARGS(rmdir, "%s"), args->path);
72614331Speter#endif
72714331Speter	bsd.path = args->path;
72814331Speter
72930994Sphk	return rmdir(p, &bsd);
73014331Speter}
73114331Speter
73214331Speterint
73330994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
73414331Speter{
73514331Speter	struct rename_args bsd;
73614331Speter	caddr_t sg;
73714331Speter
73814331Speter	sg = stackgap_init();
73914331Speter	CHECKALTEXIST(p, &sg, args->from);
74014331Speter	CHECKALTCREAT(p, &sg, args->to);
74114331Speter
74214331Speter#ifdef DEBUG
74372543Sjlemon	if (ldebug(rename))
74472543Sjlemon		printf(ARGS(rename, "%s, %s"), args->from, args->to);
74514331Speter#endif
74614331Speter	bsd.from = args->from;
74714331Speter	bsd.to = args->to;
74814331Speter
74930994Sphk	return rename(p, &bsd);
75014331Speter}
75114331Speter
75214331Speterint
75330994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
75414331Speter{
75514331Speter	struct symlink_args bsd;
75614331Speter	caddr_t sg;
75714331Speter
75814331Speter	sg = stackgap_init();
75914331Speter	CHECKALTEXIST(p, &sg, args->path);
76014331Speter	CHECKALTCREAT(p, &sg, args->to);
76114331Speter
76214331Speter#ifdef DEBUG
76372543Sjlemon	if (ldebug(symlink))
76472543Sjlemon		printf(ARGS(symlink, "%s, %s"), args->path, args->to);
76514331Speter#endif
76614331Speter	bsd.path = args->path;
76714331Speter	bsd.link = args->to;
76814331Speter
76930994Sphk	return symlink(p, &bsd);
77014331Speter}
77114331Speter
77214331Speterint
77330994Sphklinux_readlink(struct proc *p, struct linux_readlink_args *args)
77414331Speter{
77514331Speter	struct readlink_args bsd;
77614331Speter	caddr_t sg;
77714331Speter
77814331Speter	sg = stackgap_init();
77914331Speter	CHECKALTEXIST(p, &sg, args->name);
78014331Speter
78114331Speter#ifdef DEBUG
78272543Sjlemon	if (ldebug(readlink))
78372543Sjlemon		printf(ARGS(readlink, "%s, %p, %d"),
78472543Sjlemon		    args->name, (void *)args->buf, args->count);
78514331Speter#endif
78614331Speter	bsd.path = args->name;
78714331Speter	bsd.buf = args->buf;
78814331Speter	bsd.count = args->count;
78914331Speter
79030994Sphk	return readlink(p, &bsd);
79114331Speter}
79214331Speter
79314331Speterint
79430994Sphklinux_truncate(struct proc *p, struct linux_truncate_args *args)
79514331Speter{
79642499Seivind	struct truncate_args bsd;
79714331Speter	caddr_t sg;
79814331Speter
79914331Speter	sg = stackgap_init();
80014331Speter	CHECKALTEXIST(p, &sg, args->path);
80114331Speter
80214331Speter#ifdef DEBUG
80372543Sjlemon	if (ldebug(truncate))
80472543Sjlemon		printf(ARGS(truncate, "%s, %ld"), args->path, args->length);
80514331Speter#endif
80614331Speter	bsd.path = args->path;
80732265Sjmb	bsd.length = args->length;
80814331Speter
80942499Seivind	return truncate(p, &bsd);
81014331Speter}
81114331Speter
81249662Smarcelint
81349662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
81449662Smarcel{
81549662Smarcel    struct link_args bsd;
81649662Smarcel    caddr_t sg;
81749662Smarcel
81849662Smarcel    sg = stackgap_init();
81949662Smarcel    CHECKALTEXIST(p, &sg, args->path);
82049662Smarcel    CHECKALTCREAT(p, &sg, args->to);
82149662Smarcel
82249662Smarcel#ifdef DEBUG
82372543Sjlemon	if (ldebug(link))
82472543Sjlemon		printf(ARGS(link, "%s, %s"), args->path, args->to);
82549662Smarcel#endif
82649662Smarcel
82749662Smarcel    bsd.path = args->path;
82849662Smarcel    bsd.link = args->to;
82949662Smarcel
83049662Smarcel    return link(p, &bsd);
83149662Smarcel}
83249788Smarcel
83349788Smarcelint
83449788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
83549788Smarcel{
83651348Smarcel	struct __getcwd_args bsd;
83751348Smarcel	caddr_t sg;
83851348Smarcel	int error, len;
83949788Smarcel
84049788Smarcel#ifdef DEBUG
84172543Sjlemon	if (ldebug(getcwd))
84272543Sjlemon		printf(ARGS(getcwd, "%p, %ld"), args->buf, args->bufsize);
84349788Smarcel#endif
84449788Smarcel
84551348Smarcel	sg = stackgap_init();
84651348Smarcel	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
84751348Smarcel	bsd.buflen = SPARE_USRSPACE;
84851348Smarcel	error = __getcwd(p, &bsd);
84951348Smarcel	if (!error) {
85051348Smarcel		len = strlen(bsd.buf) + 1;
85151348Smarcel		if (len <= args->bufsize) {
85251348Smarcel			p->p_retval[0] = len;
85351348Smarcel			error = copyout(bsd.buf, args->buf, len);
85451348Smarcel		}
85551348Smarcel		else
85651348Smarcel			error = ERANGE;
85751348Smarcel	}
85851348Smarcel	return (error);
85949788Smarcel}
86053713Smarcel
86168201Sobrien#ifndef __alpha__
86253713Smarcelint
86353713Smarcellinux_fdatasync(p, uap)
86453713Smarcel	struct proc *p;
86553713Smarcel	struct linux_fdatasync_args *uap;
86653713Smarcel{
86753713Smarcel	struct fsync_args bsd;
86853713Smarcel
86953713Smarcel	bsd.fd = uap->fd;
87053713Smarcel	return fsync(p, &bsd);
87153713Smarcel}
87268201Sobrien#endif /*!__alpha__*/
87363285Smarcel
87463285Smarcelint
87563285Smarcellinux_pread(p, uap)
87663285Smarcel	struct proc *p;
87763285Smarcel	struct linux_pread_args *uap;
87863285Smarcel{
87963285Smarcel	struct pread_args bsd;
88063285Smarcel
88163285Smarcel	bsd.fd = uap->fd;
88263285Smarcel	bsd.buf = uap->buf;
88363285Smarcel	bsd.nbyte = uap->nbyte;
88463285Smarcel	bsd.offset = uap->offset;
88563285Smarcel	return pread(p, &bsd);
88663285Smarcel}
88763285Smarcel
88863285Smarcelint
88963285Smarcellinux_pwrite(p, uap)
89063285Smarcel	struct proc *p;
89163285Smarcel	struct linux_pwrite_args *uap;
89263285Smarcel{
89363285Smarcel	struct pwrite_args bsd;
89463285Smarcel
89563285Smarcel	bsd.fd = uap->fd;
89663285Smarcel	bsd.buf = uap->buf;
89763285Smarcel	bsd.nbyte = uap->nbyte;
89863285Smarcel	bsd.offset = uap->offset;
89963285Smarcel	return pwrite(p, &bsd);
90063285Smarcel}
90172538Sjlemon
90272538Sjlemonint
90372538Sjlemonlinux_mount(struct proc *p, struct linux_mount_args *args)
90472538Sjlemon{
90572538Sjlemon	struct ufs_args ufs;
90672538Sjlemon        char fstypename[MFSNAMELEN];
90772538Sjlemon        char mntonname[MNAMELEN], mntfromname[MNAMELEN];
90873286Sadrian	int error;
90973286Sadrian	int fsflags;
91073286Sadrian	const char *fstype;
91173286Sadrian	void *fsdata;
91272538Sjlemon
91373286Sadrian        error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
91473286Sadrian	    NULL);
91572538Sjlemon	if (error)
91672538Sjlemon                return (error);
91772538Sjlemon        error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
91872538Sjlemon	if (error)
91972538Sjlemon                return (error);
92072538Sjlemon        error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
92172538Sjlemon	if (error)
92272538Sjlemon                return (error);
92372538Sjlemon
92472538Sjlemon#ifdef DEBUG
92572538Sjlemon	if (ldebug(mount))
92672538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
92772538Sjlemon		    fstypename, mntfromname, mntonname);
92872538Sjlemon#endif
92972538Sjlemon
93072538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
93173286Sadrian		fstype = "ext2fs";
93273286Sadrian		fsdata = &ufs;
93372538Sjlemon		ufs.fspec = mntfromname;
93472538Sjlemon#define DEFAULT_ROOTID		-2
93572538Sjlemon		ufs.export.ex_root = DEFAULT_ROOTID;
93672538Sjlemon		ufs.export.ex_flags =
93772538Sjlemon		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
93872538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
93973286Sadrian		fstype = "linprocfs";
94073286Sadrian		fsdata = NULL;
94172538Sjlemon	} else {
94272538Sjlemon		return (ENODEV);
94372538Sjlemon	}
94472538Sjlemon
94573286Sadrian	fsflags = 0;
94672538Sjlemon
94772538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
94872538Sjlemon		/*
94972538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
95072538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
95172538Sjlemon		 */
95272538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
95373286Sadrian			fsflags |= MNT_RDONLY;
95472538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
95573286Sadrian			fsflags |= MNT_NOSUID;
95672538Sjlemon		if (args->rwflag & LINUX_MS_NODEV)
95773286Sadrian			fsflags |= MNT_NODEV;
95872538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
95973286Sadrian			fsflags |= MNT_NOEXEC;
96072538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
96173286Sadrian			fsflags |= MNT_UPDATE;
96272538Sjlemon	}
96372538Sjlemon
96473286Sadrian	return (vfs_mount(p, fstype, mntonname, fsflags, fsdata));
96572538Sjlemon}
96672538Sjlemon
96772538Sjlemonint
96872538Sjlemonlinux_umount(struct proc *p, struct linux_umount_args *args)
96972538Sjlemon{
97072538Sjlemon	struct linux_umount2_args args2;
97172538Sjlemon
97272538Sjlemon	args2.path = args->path;
97372538Sjlemon	args2.flags = 0;
97472538Sjlemon	return (linux_umount2(p, &args2));
97572538Sjlemon}
97672538Sjlemon
97772538Sjlemonint
97872538Sjlemonlinux_umount2(struct proc *p, struct linux_umount2_args *args)
97972538Sjlemon{
98072538Sjlemon	struct unmount_args bsd;
98172538Sjlemon
98272538Sjlemon	bsd.path = args->path;
98372538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
98472538Sjlemon	return (unmount(p, &bsd));
98572538Sjlemon}
986