linux_file.c revision 72538
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 72538 2001-02-16 14:42:11Z jlemon $
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>
4372538Sjlemon#include <sys/mount.h>
449313Ssos#include <sys/dirent.h>
4514331Speter#include <sys/conf.h>
4614331Speter#include <sys/tty.h>
4712458Sbde
4872538Sjlemon#include <ufs/ufs/extattr.h>
4972538Sjlemon#include <ufs/ufs/quota.h>
5072538Sjlemon#include <ufs/ufs/ufsmount.h>
5172538Sjlemon
5264905Smarcel#include <machine/../linux/linux.h>
5368583Smarcel#include <machine/../linux/linux_proto.h>
5464905Smarcel#include <compat/linux/linux_util.h>
559313Ssos
5668201Sobrien#ifndef __alpha__
579313Ssosint
5830994Sphklinux_creat(struct proc *p, struct linux_creat_args *args)
599313Ssos{
6012858Speter    struct open_args /* {
619313Ssos	char *path;
629313Ssos	int flags;
639313Ssos	int mode;
6412858Speter    } */ bsd_open_args;
6514331Speter    caddr_t sg;
669313Ssos
6714331Speter    sg = stackgap_init();
6814331Speter    CHECKALTCREAT(p, &sg, args->path);
6914331Speter
709313Ssos#ifdef DEBUG
719313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
729313Ssos	   p->p_pid, args->path, args->mode);
739313Ssos#endif
749313Ssos    bsd_open_args.path = args->path;
759313Ssos    bsd_open_args.mode = args->mode;
769313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
7730994Sphk    return open(p, &bsd_open_args);
789313Ssos}
7968201Sobrien#endif /*!__alpha__*/
809313Ssos
819313Ssosint
8230994Sphklinux_open(struct proc *p, struct linux_open_args *args)
839313Ssos{
8412858Speter    struct open_args /* {
859313Ssos	char *path;
869313Ssos	int flags;
879313Ssos	int mode;
8812858Speter    } */ bsd_open_args;
899313Ssos    int error;
9014331Speter    caddr_t sg;
9114331Speter
9214331Speter    sg = stackgap_init();
939313Ssos
9414331Speter    if (args->flags & LINUX_O_CREAT)
9514331Speter	CHECKALTCREAT(p, &sg, args->path);
9614331Speter    else
9714331Speter	CHECKALTEXIST(p, &sg, args->path);
9814331Speter
999313Ssos#ifdef DEBUG
1009313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
1019313Ssos	   p->p_pid, args->path, args->flags, args->mode);
1029313Ssos#endif
1039313Ssos    bsd_open_args.flags = 0;
1049313Ssos    if (args->flags & LINUX_O_RDONLY)
1059313Ssos	bsd_open_args.flags |= O_RDONLY;
1069313Ssos    if (args->flags & LINUX_O_WRONLY)
1079313Ssos	bsd_open_args.flags |= O_WRONLY;
1089313Ssos    if (args->flags & LINUX_O_RDWR)
1099313Ssos	bsd_open_args.flags |= O_RDWR;
1109313Ssos    if (args->flags & LINUX_O_NDELAY)
1119313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1129313Ssos    if (args->flags & LINUX_O_APPEND)
1139313Ssos	bsd_open_args.flags |= O_APPEND;
1149313Ssos    if (args->flags & LINUX_O_SYNC)
1159313Ssos	bsd_open_args.flags |= O_FSYNC;
1169313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1179313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1189313Ssos    if (args->flags & LINUX_FASYNC)
1199313Ssos	bsd_open_args.flags |= O_ASYNC;
1209313Ssos    if (args->flags & LINUX_O_CREAT)
1219313Ssos	bsd_open_args.flags |= O_CREAT;
1229313Ssos    if (args->flags & LINUX_O_TRUNC)
1239313Ssos	bsd_open_args.flags |= O_TRUNC;
1249313Ssos    if (args->flags & LINUX_O_EXCL)
1259313Ssos	bsd_open_args.flags |= O_EXCL;
1269313Ssos    if (args->flags & LINUX_O_NOCTTY)
1279313Ssos	bsd_open_args.flags |= O_NOCTTY;
1289313Ssos    bsd_open_args.path = args->path;
1299313Ssos    bsd_open_args.mode = args->mode;
1309313Ssos
13130994Sphk    error = open(p, &bsd_open_args);
13270061Sjhb    PROC_LOCK(p);
1339313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1349313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1359313Ssos	struct filedesc *fdp = p->p_fd;
13630994Sphk	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
1379313Ssos
13870061Sjhb	PROC_UNLOCK(p);
1399313Ssos	if (fp->f_type == DTYPE_VNODE)
14051418Sgreen	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
14170061Sjhb    } else
14270061Sjhb	PROC_UNLOCK(p);
14314331Speter#ifdef DEBUG
14414331Speter    printf("Linux-emul(%d): open returns error %d\n",
14514331Speter	   p->p_pid, error);
14614331Speter#endif
1479313Ssos    return error;
1489313Ssos}
1499313Ssos
1509313Ssosstruct linux_flock {
1519313Ssos    short l_type;
1529313Ssos    short l_whence;
1539313Ssos    linux_off_t l_start;
1549313Ssos    linux_off_t l_len;
1559313Ssos    linux_pid_t l_pid;
1569313Ssos};
1579313Ssos
1589313Ssosstatic void
1599313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1609313Ssos{
1619313Ssos    switch (linux_flock->l_type) {
1629313Ssos    case LINUX_F_RDLCK:
1639313Ssos	bsd_flock->l_type = F_RDLCK;
1649313Ssos	break;
1659313Ssos    case LINUX_F_WRLCK:
1669313Ssos	bsd_flock->l_type = F_WRLCK;
1679313Ssos	break;
1689313Ssos    case LINUX_F_UNLCK:
1699313Ssos	bsd_flock->l_type = F_UNLCK;
1709313Ssos	break;
17149676Smarcel    default:
17249676Smarcel        bsd_flock->l_type = -1;
17349676Smarcel        break;
1749313Ssos    }
1759313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1769313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1779313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1789313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1799313Ssos}
1809313Ssos
1819313Ssosstatic void
1829313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1839313Ssos{
1849313Ssos    switch (bsd_flock->l_type) {
1859313Ssos    case F_RDLCK:
1869313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1879313Ssos	break;
1889313Ssos    case F_WRLCK:
1899313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1909313Ssos	break;
1919313Ssos    case F_UNLCK:
1929313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1939313Ssos	break;
1949313Ssos    }
1959313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1969313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1979313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1989313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1999313Ssos}
2009313Ssos
2019313Ssosint
20230994Sphklinux_fcntl(struct proc *p, struct linux_fcntl_args *args)
2039313Ssos{
2049313Ssos    int error, result;
20512858Speter    struct fcntl_args /* {
2069313Ssos	int fd;
2079313Ssos	int cmd;
20868662Smarcel	long arg;
20968662Smarcel    } */ fcntl_args;
2109313Ssos    struct linux_flock linux_flock;
21114331Speter    struct flock *bsd_flock;
21268662Smarcel    struct filedesc *fdp;
21368662Smarcel    struct file *fp;
21414331Speter    caddr_t sg;
2159313Ssos
21614331Speter    sg = stackgap_init();
21714331Speter    bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
21814331Speter
2199313Ssos#ifdef DEBUG
22068662Smarcel    printf("Linux-emul(%ld): fcntl(%d, %08x, *)\n", (long)p->p_pid,
22168662Smarcel	args->fd, args->cmd);
2229313Ssos#endif
2239313Ssos    fcntl_args.fd = args->fd;
2249313Ssos
2259313Ssos    switch (args->cmd) {
2269313Ssos    case LINUX_F_DUPFD:
2279313Ssos	fcntl_args.cmd = F_DUPFD;
22849845Smarcel	fcntl_args.arg = args->arg;
22930994Sphk	return fcntl(p, &fcntl_args);
2309313Ssos
2319313Ssos    case LINUX_F_GETFD:
2329313Ssos	fcntl_args.cmd = F_GETFD;
23330994Sphk	return fcntl(p, &fcntl_args);
2349313Ssos
2359313Ssos    case LINUX_F_SETFD:
2369313Ssos	fcntl_args.cmd = F_SETFD;
23749845Smarcel	fcntl_args.arg = args->arg;
23830994Sphk	return fcntl(p, &fcntl_args);
2399313Ssos
2409313Ssos    case LINUX_F_GETFL:
2419313Ssos	fcntl_args.cmd = F_GETFL;
24230994Sphk	error = fcntl(p, &fcntl_args);
24330994Sphk	result = p->p_retval[0];
24430994Sphk	p->p_retval[0] = 0;
24530994Sphk	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
24630994Sphk	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
24730994Sphk	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
24830994Sphk	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
24930994Sphk	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
25030994Sphk	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
25139978Sjfieber	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
2529313Ssos	return error;
2539313Ssos
2549313Ssos    case LINUX_F_SETFL:
25549845Smarcel	fcntl_args.arg = 0;
2569313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2579313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2589313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
25939978Sjfieber	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
2609313Ssos	fcntl_args.cmd = F_SETFL;
26130994Sphk	return fcntl(p, &fcntl_args);
26249676Smarcel
2639313Ssos    case LINUX_F_GETLK:
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_GETLK;
26968201Sobrien	fcntl_args.arg = (long)bsd_flock;
27046571Speter	error = fcntl(p, &fcntl_args);
27146571Speter	if (error)
2729313Ssos	    return error;
2739313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2749313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2759313Ssos		       sizeof(struct linux_flock));
2769313Ssos
2779313Ssos    case LINUX_F_SETLK:
2789313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2799313Ssos		   	    sizeof(struct linux_flock))))
2809313Ssos	    return error;
2819313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2829313Ssos	fcntl_args.cmd = F_SETLK;
28368201Sobrien	fcntl_args.arg = (long)bsd_flock;
28430994Sphk	return fcntl(p, &fcntl_args);
2859313Ssos
2869313Ssos    case LINUX_F_SETLKW:
2879313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2889313Ssos		   	    sizeof(struct linux_flock))))
2899313Ssos	    return error;
2909313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2919313Ssos	fcntl_args.cmd = F_SETLKW;
29268201Sobrien	fcntl_args.arg = (long)bsd_flock;
29330994Sphk	return fcntl(p, &fcntl_args);
2949313Ssos
29563233Smarcel    case LINUX_F_GETOWN:
29663233Smarcel	fcntl_args.cmd = F_GETOWN;
29763233Smarcel	return fcntl(p, &fcntl_args);
29863233Smarcel
2999313Ssos    case LINUX_F_SETOWN:
30068662Smarcel	/*
30168662Smarcel	 * XXX some Linux applications depend on F_SETOWN having no
30268662Smarcel	 * significant effect for pipes (SIGIO is not delivered for
30368662Smarcel	 * pipes under Linux-2.2.35 at least).
30468662Smarcel	 */
30568662Smarcel	fdp = p->p_fd;
30668662Smarcel	if ((u_int)args->fd >= fdp->fd_nfiles ||
30768662Smarcel	  (fp = fdp->fd_ofiles[args->fd]) == NULL)
30868662Smarcel	    return EBADF;
30968662Smarcel	if (fp->f_type == DTYPE_PIPE)
31068662Smarcel	    return EINVAL;
31168662Smarcel
31268662Smarcel 	fcntl_args.cmd = F_SETOWN;
31363233Smarcel	fcntl_args.arg = args->arg;
31463233Smarcel	return fcntl(p, &fcntl_args);
3159313Ssos    }
3169313Ssos    return EINVAL;
3179313Ssos}
3189313Ssos
3199313Ssosint
32030994Sphklinux_lseek(struct proc *p, struct linux_lseek_args *args)
3219313Ssos{
3229313Ssos
32312858Speter    struct lseek_args /* {
32412858Speter	int fd;
3259313Ssos	int pad;
32612858Speter	off_t offset;
3279313Ssos	int whence;
32812858Speter    } */ tmp_args;
3299313Ssos    int error;
3309313Ssos
3319313Ssos#ifdef DEBUG
33237950Sbde    printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n",
33337950Sbde	   (long)p->p_pid, args->fdes, args->off, args->whence);
3349313Ssos#endif
33512858Speter    tmp_args.fd = args->fdes;
33612858Speter    tmp_args.offset = (off_t)args->off;
3379313Ssos    tmp_args.whence = args->whence;
33830994Sphk    error = lseek(p, &tmp_args);
3399313Ssos    return error;
3409313Ssos}
3419313Ssos
34268201Sobrien#ifndef __alpha__
34314331Speterint
34430994Sphklinux_llseek(struct proc *p, struct linux_llseek_args *args)
34514331Speter{
34614331Speter	struct lseek_args bsd_args;
34714331Speter	int error;
34814331Speter	off_t off;
34914331Speter
35014331Speter#ifdef DEBUG
35114331Speter        printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n",
35214331Speter	   p->p_pid, args->fd, args->ohigh, args->olow, args->whence);
35314331Speter#endif
35414331Speter	off = (args->olow) | (((off_t) args->ohigh) << 32);
35514331Speter
35614331Speter	bsd_args.fd = args->fd;
35714331Speter	bsd_args.offset = off;
35814331Speter	bsd_args.whence = args->whence;
35914331Speter
36030994Sphk	if ((error = lseek(p, &bsd_args)))
36114331Speter		return error;
36214331Speter
36330994Sphk	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
36414331Speter		return error;
36514331Speter
36630994Sphk	p->p_retval[0] = 0;
36714331Speter	return 0;
36814331Speter}
36968201Sobrien#endif /*!__alpha__*/
37014331Speter
37114331Speter
3729313Ssosstruct linux_dirent {
3739313Ssos    long dino;
3749313Ssos    linux_off_t doff;
3759313Ssos    unsigned short dreclen;
3769313Ssos    char dname[LINUX_NAME_MAX + 1];
3779313Ssos};
3789313Ssos
3799313Ssos#define LINUX_RECLEN(de,namlen) \
3809313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3819313Ssos
38268201Sobrien#ifndef __alpha__
3839313Ssosint
38430994Sphklinux_readdir(struct proc *p, struct linux_readdir_args *args)
3859313Ssos{
38614331Speter	struct linux_getdents_args lda;
38714331Speter
38814331Speter	lda.fd = args->fd;
38914331Speter	lda.dent = args->dent;
39014331Speter	lda.count = 1;
39130994Sphk	return linux_getdents(p, &lda);
39214331Speter}
39368201Sobrien#endif /*!__alpha__*/
39414331Speter
39514331Speterint
39630994Sphklinux_getdents(struct proc *p, struct linux_getdents_args *args)
39714331Speter{
3989313Ssos    register struct dirent *bdp;
3999313Ssos    struct vnode *vp;
4009313Ssos    caddr_t inp, buf;		/* BSD-format */
4019313Ssos    int len, reclen;		/* BSD-format */
4029313Ssos    caddr_t outp;		/* Linux-format */
4039313Ssos    int resid, linuxreclen=0;	/* Linux-format */
4049313Ssos    struct file *fp;
4059313Ssos    struct uio auio;
4069313Ssos    struct iovec aiov;
4079313Ssos    struct vattr va;
4089313Ssos    off_t off;
4099313Ssos    struct linux_dirent linux_dirent;
41024654Sdfr    int buflen, error, eofflag, nbytes, justone;
41124654Sdfr    u_long *cookies = NULL, *cookiep;
41224654Sdfr    int ncookies;
4139313Ssos
4149313Ssos#ifdef DEBUG
41514331Speter    printf("Linux-emul(%d): getdents(%d, *, %d)\n",
4169313Ssos	   p->p_pid, args->fd, args->count);
4179313Ssos#endif
41810355Sswallace    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
4199313Ssos	return (error);
42014331Speter    }
4219313Ssos
4229313Ssos    if ((fp->f_flag & FREAD) == 0)
4239313Ssos	return (EBADF);
4249313Ssos
4259313Ssos    vp = (struct vnode *) fp->f_data;
4269313Ssos
4279313Ssos    if (vp->v_type != VDIR)
4289313Ssos	return (EINVAL);
4299313Ssos
43071699Sjhb    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
4319313Ssos	return error;
43211418Sswallace    }
4339313Ssos
4349313Ssos    nbytes = args->count;
4359313Ssos    if (nbytes == 1) {
4369313Ssos	nbytes = sizeof (struct linux_dirent);
4379313Ssos	justone = 1;
4389313Ssos    }
4399313Ssos    else
4409313Ssos	justone = 0;
4419313Ssos
44210355Sswallace    off = fp->f_offset;
44324672Sdfr#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
44424654Sdfr    buflen = max(DIRBLKSIZ, nbytes);
44511418Sswallace    buflen = min(buflen, MAXBSIZE);
4469313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
44722521Sdyson    vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4489313Ssosagain:
4499313Ssos    aiov.iov_base = buf;
4509313Ssos    aiov.iov_len = buflen;
4519313Ssos    auio.uio_iov = &aiov;
4529313Ssos    auio.uio_iovcnt = 1;
4539313Ssos    auio.uio_rw = UIO_READ;
4549313Ssos    auio.uio_segflg = UIO_SYSSPACE;
4559313Ssos    auio.uio_procp = p;
4569313Ssos    auio.uio_resid = buflen;
45724654Sdfr    auio.uio_offset = off;
4589313Ssos
45924654Sdfr    if (cookies) {
46024654Sdfr	free(cookies, M_TEMP);
46124654Sdfr	cookies = NULL;
46224654Sdfr    }
46324654Sdfr
46424654Sdfr    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
46510355Sswallace    if (error) {
4669313Ssos	goto out;
46714331Speter    }
4689313Ssos
4699313Ssos    inp = buf;
4709313Ssos    outp = (caddr_t) args->dent;
4719313Ssos    resid = nbytes;
47224654Sdfr    if ((len = buflen - auio.uio_resid) <= 0) {
4739313Ssos	goto eof;
47414331Speter    }
4759313Ssos
47624654Sdfr    cookiep = cookies;
47724654Sdfr
47824654Sdfr    if (cookies) {
47924654Sdfr	/*
48024654Sdfr	 * When using cookies, the vfs has the option of reading from
48124654Sdfr	 * a different offset than that supplied (UFS truncates the
48224654Sdfr	 * offset to a block boundary to make sure that it never reads
48324654Sdfr	 * partway through a directory entry, even if the directory
48424654Sdfr	 * has been compacted).
48524654Sdfr	 */
48624654Sdfr	while (len > 0 && ncookies > 0 && *cookiep <= off) {
48724654Sdfr	    bdp = (struct dirent *) inp;
48824654Sdfr	    len -= bdp->d_reclen;
48924654Sdfr	    inp += bdp->d_reclen;
49024654Sdfr	    cookiep++;
49124654Sdfr	    ncookies--;
49224654Sdfr	}
49324654Sdfr    }
49424654Sdfr
4959313Ssos    while (len > 0) {
49624654Sdfr	if (cookiep && ncookies == 0)
49724654Sdfr	    break;
49810355Sswallace	bdp = (struct dirent *) inp;
49910355Sswallace	reclen = bdp->d_reclen;
50010355Sswallace	if (reclen & 3) {
50110355Sswallace	    printf("linux_readdir: reclen=%d\n", reclen);
50210355Sswallace	    error = EFAULT;
50310355Sswallace	    goto out;
50410355Sswallace	}
50510355Sswallace
5069313Ssos	if (bdp->d_fileno == 0) {
5079313Ssos	    inp += reclen;
50824654Sdfr	    if (cookiep) {
50924654Sdfr		off = *cookiep++;
51024654Sdfr		ncookies--;
51124654Sdfr	    } else
51224654Sdfr		off += reclen;
51310355Sswallace	    len -= reclen;
5149313Ssos	    continue;
5159313Ssos	}
5169313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
5179313Ssos	if (reclen > len || resid < linuxreclen) {
5189313Ssos	    outp++;
5199313Ssos	    break;
5209313Ssos	}
5219313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
52214465Speter	if (justone) {
52314465Speter	    /*
52414465Speter	     * old linux-style readdir usage.
52514465Speter	     */
52614465Speter	    linux_dirent.doff = (linux_off_t) linuxreclen;
52714465Speter	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
52814465Speter	} else {
52968347Smarcel	    if (cookiep)
53068347Smarcel		linux_dirent.doff = (linux_off_t)*cookiep;
53168347Smarcel	    else
53268347Smarcel		linux_dirent.doff = (linux_off_t)(off + reclen);
53314465Speter	    linux_dirent.dreclen = (u_short) linuxreclen;
53414465Speter	}
5359313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
53610355Sswallace	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
5379313Ssos	    goto out;
53814331Speter	}
5399313Ssos	inp += reclen;
54024654Sdfr	if (cookiep) {
54124654Sdfr	    off = *cookiep++;
54224654Sdfr	    ncookies--;
54324654Sdfr	} else
54424654Sdfr	    off += reclen;
5459313Ssos	outp += linuxreclen;
5469313Ssos	resid -= linuxreclen;
5479313Ssos	len -= reclen;
5489313Ssos	if (justone)
5499313Ssos	    break;
5509313Ssos    }
5519313Ssos
5529313Ssos    if (outp == (caddr_t) args->dent)
5539313Ssos	goto again;
5549313Ssos    fp->f_offset = off;
5559313Ssos
5569313Ssos    if (justone)
5579313Ssos	nbytes = resid + linuxreclen;
55810355Sswallace
5599313Ssoseof:
56030994Sphk    p->p_retval[0] = nbytes - resid;
5619313Ssosout:
56224654Sdfr    if (cookies)
56324654Sdfr	free(cookies, M_TEMP);
56422543Smpp    VOP_UNLOCK(vp, 0, p);
5659313Ssos    free(buf, M_TEMP);
5669313Ssos    return error;
5679313Ssos}
56814331Speter
56914331Speter/*
57014331Speter * These exist mainly for hooks for doing /compat/linux translation.
57114331Speter */
57214331Speter
57314331Speterint
57430994Sphklinux_access(struct proc *p, struct linux_access_args *args)
57514331Speter{
57614331Speter	struct access_args bsd;
57714331Speter	caddr_t sg;
57814331Speter
57914331Speter	sg = stackgap_init();
58014331Speter	CHECKALTEXIST(p, &sg, args->path);
58114331Speter
58214331Speter#ifdef DEBUG
58314331Speter        printf("Linux-emul(%d): access(%s, %d)\n",
58414331Speter	    p->p_pid, args->path, args->flags);
58514331Speter#endif
58614331Speter	bsd.path = args->path;
58714331Speter	bsd.flags = args->flags;
58814331Speter
58930994Sphk	return access(p, &bsd);
59014331Speter}
59114331Speter
59214331Speterint
59330994Sphklinux_unlink(struct proc *p, struct linux_unlink_args *args)
59414331Speter{
59514331Speter	struct unlink_args bsd;
59614331Speter	caddr_t sg;
59714331Speter
59814331Speter	sg = stackgap_init();
59914331Speter	CHECKALTEXIST(p, &sg, args->path);
60014331Speter
60114331Speter#ifdef DEBUG
60214331Speter	printf("Linux-emul(%d): unlink(%s)\n",
60314331Speter	   p->p_pid, args->path);
60414331Speter#endif
60514331Speter	bsd.path = args->path;
60614331Speter
60730994Sphk	return unlink(p, &bsd);
60814331Speter}
60914331Speter
61014331Speterint
61130994Sphklinux_chdir(struct proc *p, struct linux_chdir_args *args)
61214331Speter{
61314331Speter	struct chdir_args bsd;
61414331Speter	caddr_t sg;
61514331Speter
61614331Speter	sg = stackgap_init();
61714331Speter	CHECKALTEXIST(p, &sg, args->path);
61814331Speter
61914331Speter#ifdef DEBUG
62014331Speter	printf("Linux-emul(%d): chdir(%s)\n",
62114331Speter	   p->p_pid, args->path);
62214331Speter#endif
62314331Speter	bsd.path = args->path;
62414331Speter
62530994Sphk	return chdir(p, &bsd);
62614331Speter}
62714331Speter
62814331Speterint
62930994Sphklinux_chmod(struct proc *p, struct linux_chmod_args *args)
63014331Speter{
63114331Speter	struct chmod_args bsd;
63214331Speter	caddr_t sg;
63314331Speter
63414331Speter	sg = stackgap_init();
63514331Speter	CHECKALTEXIST(p, &sg, args->path);
63614331Speter
63714331Speter#ifdef DEBUG
63814331Speter        printf("Linux-emul(%d): chmod(%s, %d)\n",
63914331Speter	    p->p_pid, args->path, args->mode);
64014331Speter#endif
64114331Speter	bsd.path = args->path;
64214331Speter	bsd.mode = args->mode;
64314331Speter
64430994Sphk	return chmod(p, &bsd);
64514331Speter}
64614331Speter
64714331Speterint
64830994Sphklinux_chown(struct proc *p, struct linux_chown_args *args)
64914331Speter{
65014331Speter	struct chown_args bsd;
65114331Speter	caddr_t sg;
65214331Speter
65314331Speter	sg = stackgap_init();
65414331Speter	CHECKALTEXIST(p, &sg, args->path);
65514331Speter
65614331Speter#ifdef DEBUG
65714331Speter        printf("Linux-emul(%d): chown(%s, %d, %d)\n",
65814331Speter	    p->p_pid, args->path, args->uid, args->gid);
65914331Speter#endif
66014331Speter	bsd.path = args->path;
66114331Speter	/* XXX size casts here */
66214331Speter	bsd.uid = args->uid;
66314331Speter	bsd.gid = args->gid;
66414331Speter
66530994Sphk	return chown(p, &bsd);
66614331Speter}
66714331Speter
66814331Speterint
66934941Speterlinux_lchown(struct proc *p, struct linux_lchown_args *args)
67034941Speter{
67134941Speter	struct lchown_args bsd;
67234941Speter	caddr_t sg;
67334941Speter
67434941Speter	sg = stackgap_init();
67534941Speter	CHECKALTEXIST(p, &sg, args->path);
67634941Speter
67734941Speter#ifdef DEBUG
67834941Speter        printf("Linux-emul(%d): lchown(%s, %d, %d)\n",
67934941Speter	    p->p_pid, args->path, args->uid, args->gid);
68034941Speter#endif
68134941Speter	bsd.path = args->path;
68234941Speter	/* XXX size casts here */
68334941Speter	bsd.uid = args->uid;
68434941Speter	bsd.gid = args->gid;
68534941Speter
68634941Speter	return lchown(p, &bsd);
68734941Speter}
68834941Speter
68934941Speterint
69030994Sphklinux_mkdir(struct proc *p, struct linux_mkdir_args *args)
69114331Speter{
69214331Speter	struct mkdir_args bsd;
69314331Speter	caddr_t sg;
69414331Speter
69514331Speter	sg = stackgap_init();
69614331Speter	CHECKALTCREAT(p, &sg, args->path);
69714331Speter
69814331Speter#ifdef DEBUG
69914331Speter        printf("Linux-emul(%d): mkdir(%s, %d)\n",
70014331Speter	    p->p_pid, args->path, args->mode);
70114331Speter#endif
70214331Speter	bsd.path = args->path;
70314331Speter	bsd.mode = args->mode;
70414331Speter
70530994Sphk	return mkdir(p, &bsd);
70614331Speter}
70714331Speter
70814331Speterint
70930994Sphklinux_rmdir(struct proc *p, struct linux_rmdir_args *args)
71014331Speter{
71114331Speter	struct rmdir_args bsd;
71214331Speter	caddr_t sg;
71314331Speter
71414331Speter	sg = stackgap_init();
71514331Speter	CHECKALTEXIST(p, &sg, args->path);
71614331Speter
71714331Speter#ifdef DEBUG
71814331Speter        printf("Linux-emul(%d): rmdir(%s)\n",
71914331Speter	    p->p_pid, args->path);
72014331Speter#endif
72114331Speter	bsd.path = args->path;
72214331Speter
72330994Sphk	return rmdir(p, &bsd);
72414331Speter}
72514331Speter
72614331Speterint
72730994Sphklinux_rename(struct proc *p, struct linux_rename_args *args)
72814331Speter{
72914331Speter	struct rename_args bsd;
73014331Speter	caddr_t sg;
73114331Speter
73214331Speter	sg = stackgap_init();
73314331Speter	CHECKALTEXIST(p, &sg, args->from);
73414331Speter	CHECKALTCREAT(p, &sg, args->to);
73514331Speter
73614331Speter#ifdef DEBUG
73714331Speter        printf("Linux-emul(%d): rename(%s, %s)\n",
73814331Speter	    p->p_pid, args->from, args->to);
73914331Speter#endif
74014331Speter	bsd.from = args->from;
74114331Speter	bsd.to = args->to;
74214331Speter
74330994Sphk	return rename(p, &bsd);
74414331Speter}
74514331Speter
74614331Speterint
74730994Sphklinux_symlink(struct proc *p, struct linux_symlink_args *args)
74814331Speter{
74914331Speter	struct symlink_args bsd;
75014331Speter	caddr_t sg;
75114331Speter
75214331Speter	sg = stackgap_init();
75314331Speter	CHECKALTEXIST(p, &sg, args->path);
75414331Speter	CHECKALTCREAT(p, &sg, args->to);
75514331Speter
75614331Speter#ifdef DEBUG
75714331Speter        printf("Linux-emul(%d): symlink(%s, %s)\n",
75814331Speter	    p->p_pid, args->path, args->to);
75914331Speter#endif
76014331Speter	bsd.path = args->path;
76114331Speter	bsd.link = args->to;
76214331Speter
76330994Sphk	return symlink(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
77637950Sbde        printf("Linux-emul(%ld): readlink(%s, %p, %d)\n",
77737950Sbde	    (long)p->p_pid, args->name, (void *)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{
78942499Seivind	struct truncate_args bsd;
79014331Speter	caddr_t sg;
79114331Speter
79214331Speter	sg = stackgap_init();
79314331Speter	CHECKALTEXIST(p, &sg, args->path);
79414331Speter
79514331Speter#ifdef DEBUG
79632266Sjmb        printf("Linux-emul(%d): truncate(%s, %ld)\n",
79732266Sjmb	    p->p_pid, args->path, args->length);
79814331Speter#endif
79914331Speter	bsd.path = args->path;
80032265Sjmb	bsd.length = args->length;
80114331Speter
80242499Seivind	return truncate(p, &bsd);
80314331Speter}
80414331Speter
80549662Smarcelint
80649662Smarcellinux_link(struct proc *p, struct linux_link_args *args)
80749662Smarcel{
80849662Smarcel    struct link_args bsd;
80949662Smarcel    caddr_t sg;
81049662Smarcel
81149662Smarcel    sg = stackgap_init();
81249662Smarcel    CHECKALTEXIST(p, &sg, args->path);
81349662Smarcel    CHECKALTCREAT(p, &sg, args->to);
81449662Smarcel
81549662Smarcel#ifdef DEBUG
81649662Smarcel    printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to);
81749662Smarcel#endif
81849662Smarcel
81949662Smarcel    bsd.path = args->path;
82049662Smarcel    bsd.link = args->to;
82149662Smarcel
82249662Smarcel    return link(p, &bsd);
82349662Smarcel}
82449788Smarcel
82549788Smarcelint
82649788Smarcellinux_getcwd(struct proc *p, struct linux_getcwd_args *args)
82749788Smarcel{
82851348Smarcel	struct __getcwd_args bsd;
82951348Smarcel	caddr_t sg;
83051348Smarcel	int error, len;
83149788Smarcel
83249788Smarcel#ifdef DEBUG
83351348Smarcel	printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid,
83451348Smarcel	       args->buf, args->bufsize);
83549788Smarcel#endif
83649788Smarcel
83751348Smarcel	sg = stackgap_init();
83851348Smarcel	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
83951348Smarcel	bsd.buflen = SPARE_USRSPACE;
84051348Smarcel	error = __getcwd(p, &bsd);
84151348Smarcel	if (!error) {
84251348Smarcel		len = strlen(bsd.buf) + 1;
84351348Smarcel		if (len <= args->bufsize) {
84451348Smarcel			p->p_retval[0] = len;
84551348Smarcel			error = copyout(bsd.buf, args->buf, len);
84651348Smarcel		}
84751348Smarcel		else
84851348Smarcel			error = ERANGE;
84951348Smarcel	}
85051348Smarcel	return (error);
85149788Smarcel}
85253713Smarcel
85368201Sobrien#ifndef __alpha__
85453713Smarcelint
85553713Smarcellinux_fdatasync(p, uap)
85653713Smarcel	struct proc *p;
85753713Smarcel	struct linux_fdatasync_args *uap;
85853713Smarcel{
85953713Smarcel	struct fsync_args bsd;
86053713Smarcel
86153713Smarcel	bsd.fd = uap->fd;
86253713Smarcel	return fsync(p, &bsd);
86353713Smarcel}
86468201Sobrien#endif /*!__alpha__*/
86563285Smarcel
86663285Smarcelint
86763285Smarcellinux_pread(p, uap)
86863285Smarcel	struct proc *p;
86963285Smarcel	struct linux_pread_args *uap;
87063285Smarcel{
87163285Smarcel	struct pread_args bsd;
87263285Smarcel
87363285Smarcel	bsd.fd = uap->fd;
87463285Smarcel	bsd.buf = uap->buf;
87563285Smarcel	bsd.nbyte = uap->nbyte;
87663285Smarcel	bsd.offset = uap->offset;
87763285Smarcel	return pread(p, &bsd);
87863285Smarcel}
87963285Smarcel
88063285Smarcelint
88163285Smarcellinux_pwrite(p, uap)
88263285Smarcel	struct proc *p;
88363285Smarcel	struct linux_pwrite_args *uap;
88463285Smarcel{
88563285Smarcel	struct pwrite_args bsd;
88663285Smarcel
88763285Smarcel	bsd.fd = uap->fd;
88863285Smarcel	bsd.buf = uap->buf;
88963285Smarcel	bsd.nbyte = uap->nbyte;
89063285Smarcel	bsd.offset = uap->offset;
89163285Smarcel	return pwrite(p, &bsd);
89263285Smarcel}
89372538Sjlemon
89472538Sjlemonint
89572538Sjlemonlinux_mount(struct proc *p, struct linux_mount_args *args)
89672538Sjlemon{
89772538Sjlemon	struct mount_args bsd_args;
89872538Sjlemon	struct ufs_args ufs;
89972538Sjlemon        char fstypename[MFSNAMELEN];
90072538Sjlemon        char mntonname[MNAMELEN], mntfromname[MNAMELEN];
90172538Sjlemon	int error = 0;
90272538Sjlemon
90372538Sjlemon        error = copyinstr(args->filesystemtype, fstypename,
90472538Sjlemon	    MFSNAMELEN - 1, NULL);
90572538Sjlemon	if (error)
90672538Sjlemon                return (error);
90772538Sjlemon        error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
90872538Sjlemon	if (error)
90972538Sjlemon                return (error);
91072538Sjlemon        error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
91172538Sjlemon	if (error)
91272538Sjlemon                return (error);
91372538Sjlemon
91472538Sjlemon#ifdef DEBUG
91572538Sjlemon	if (ldebug(mount))
91672538Sjlemon		printf(ARGS(mount, "%s, %s, %s"),
91772538Sjlemon		    fstypename, mntfromname, mntonname);
91872538Sjlemon#endif
91972538Sjlemon
92072538Sjlemon	if (strcmp(fstypename, "ext2") == 0) {
92172538Sjlemon		bsd_args.type = "ext2fs";
92272538Sjlemon		bsd_args.data = (void *)&ufs;
92372538Sjlemon		ufs.fspec = mntfromname;
92472538Sjlemon#define DEFAULT_ROOTID		-2
92572538Sjlemon		ufs.export.ex_root = DEFAULT_ROOTID;
92672538Sjlemon		ufs.export.ex_flags =
92772538Sjlemon		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
92872538Sjlemon	} else if (strcmp(fstypename, "proc") == 0) {
92972538Sjlemon		bsd_args.type = "linprocfs";
93072538Sjlemon		bsd_args.data = NULL;
93172538Sjlemon	} else {
93272538Sjlemon		return (ENODEV);
93372538Sjlemon	}
93472538Sjlemon
93572538Sjlemon	bsd_args.path = mntonname;
93672538Sjlemon	bsd_args.flags = 0;
93772538Sjlemon
93872538Sjlemon	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
93972538Sjlemon		/*
94072538Sjlemon		 * Linux SYNC flag is not included; the closest equivalent
94172538Sjlemon		 * FreeBSD has is !ASYNC, which is our default.
94272538Sjlemon		 */
94372538Sjlemon		if (args->rwflag & LINUX_MS_RDONLY)
94472538Sjlemon			bsd_args.flags |= MNT_RDONLY;
94572538Sjlemon		if (args->rwflag & LINUX_MS_NOSUID)
94672538Sjlemon			bsd_args.flags |= MNT_NOSUID;
94772538Sjlemon		if (args->rwflag & LINUX_MS_NODEV)
94872538Sjlemon			bsd_args.flags |= MNT_NODEV;
94972538Sjlemon		if (args->rwflag & LINUX_MS_NOEXEC)
95072538Sjlemon			bsd_args.flags |= MNT_NOEXEC;
95172538Sjlemon		if (args->rwflag & LINUX_MS_REMOUNT)
95272538Sjlemon			bsd_args.flags |= MNT_UPDATE;
95372538Sjlemon	}
95472538Sjlemon
95572538Sjlemon	return (mount1(p, &bsd_args, UIO_SYSSPACE));
95672538Sjlemon}
95772538Sjlemon
95872538Sjlemonint
95972538Sjlemonlinux_umount(struct proc *p, struct linux_umount_args *args)
96072538Sjlemon{
96172538Sjlemon	struct linux_umount2_args args2;
96272538Sjlemon
96372538Sjlemon	args2.path = args->path;
96472538Sjlemon	args2.flags = 0;
96572538Sjlemon	return (linux_umount2(p, &args2));
96672538Sjlemon}
96772538Sjlemon
96872538Sjlemonint
96972538Sjlemonlinux_umount2(struct proc *p, struct linux_umount2_args *args)
97072538Sjlemon{
97172538Sjlemon	struct unmount_args bsd;
97272538Sjlemon
97372538Sjlemon	bsd.path = args->path;
97472538Sjlemon	bsd.flags = args->flags;	/* XXX correct? */
97572538Sjlemon	return (unmount(p, &bsd));
97672538Sjlemon}
977