linux_file.c revision 9313
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 *
289313Ssos *  $Id: linux_file.c,v 1.2 1995/06/07 21:27:57 sos Exp $
299313Ssos */
309313Ssos
319313Ssos#include <i386/linux/linux.h>
329313Ssos#include <sys/param.h>
339313Ssos#include <sys/systm.h>
349313Ssos#include <sys/fcntl.h>
359313Ssos#include <sys/file.h>
369313Ssos#include <sys/filedesc.h>
379313Ssos#include <sys/proc.h>
389313Ssos#include <sys/ioctl.h>
399313Ssos#include <sys/stat.h>
409313Ssos#include <sys/vnode.h>
419313Ssos#include <sys/malloc.h>
429313Ssos#include <sys/exec.h>
439313Ssos#include <sys/dirent.h>
449313Ssos#include <vm/vm.h>
459313Ssos#include <ufs/ufs/dir.h>
469313Ssos
479313Ssos
489313Ssosstruct linux_creat_args {
499313Ssos    char    *path;
509313Ssos    int mode;
519313Ssos};
529313Ssos
539313Ssosint
549313Ssoslinux_creat(struct proc *p, struct linux_creat_args *args, int *retval)
559313Ssos{
569313Ssos    struct {
579313Ssos	char *path;
589313Ssos	int flags;
599313Ssos	int mode;
609313Ssos    } bsd_open_args;
619313Ssos
629313Ssos#ifdef DEBUG
639313Ssos    printf("Linux-emul(%d): creat(%s, %d)\n",
649313Ssos	   p->p_pid, args->path, args->mode);
659313Ssos#endif
669313Ssos    bsd_open_args.path = args->path;
679313Ssos    bsd_open_args.mode = args->mode;
689313Ssos    bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
699313Ssos    return open(p, &bsd_open_args, retval);
709313Ssos}
719313Ssos
729313Ssosstruct linux_open_args {
739313Ssos    char *path;
749313Ssos    int flags;
759313Ssos    int mode;
769313Ssos};
779313Ssos
789313Ssosint
799313Ssoslinux_open(struct proc *p, struct linux_open_args *args, int *retval)
809313Ssos{
819313Ssos    struct {
829313Ssos	char *path;
839313Ssos	int flags;
849313Ssos	int mode;
859313Ssos    } bsd_open_args;
869313Ssos    int error;
879313Ssos
889313Ssos#ifdef DEBUG
899313Ssos    printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n",
909313Ssos	   p->p_pid, args->path, args->flags, args->mode);
919313Ssos#endif
929313Ssos    bsd_open_args.flags = 0;
939313Ssos    if (args->flags & LINUX_O_RDONLY)
949313Ssos	bsd_open_args.flags |= O_RDONLY;
959313Ssos    if (args->flags & LINUX_O_WRONLY)
969313Ssos	bsd_open_args.flags |= O_WRONLY;
979313Ssos    if (args->flags & LINUX_O_RDWR)
989313Ssos	bsd_open_args.flags |= O_RDWR;
999313Ssos    if (args->flags & LINUX_O_NDELAY)
1009313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1019313Ssos    if (args->flags & LINUX_O_APPEND)
1029313Ssos	bsd_open_args.flags |= O_APPEND;
1039313Ssos    if (args->flags & LINUX_O_SYNC)
1049313Ssos	bsd_open_args.flags |= O_FSYNC;
1059313Ssos    if (args->flags & LINUX_O_NONBLOCK)
1069313Ssos	bsd_open_args.flags |= O_NONBLOCK;
1079313Ssos    if (args->flags & LINUX_FASYNC)
1089313Ssos	bsd_open_args.flags |= O_ASYNC;
1099313Ssos    if (args->flags & LINUX_O_CREAT)
1109313Ssos	bsd_open_args.flags |= O_CREAT;
1119313Ssos    if (args->flags & LINUX_O_TRUNC)
1129313Ssos	bsd_open_args.flags |= O_TRUNC;
1139313Ssos    if (args->flags & LINUX_O_EXCL)
1149313Ssos	bsd_open_args.flags |= O_EXCL;
1159313Ssos    if (args->flags & LINUX_O_NOCTTY)
1169313Ssos	bsd_open_args.flags |= O_NOCTTY;
1179313Ssos    bsd_open_args.path = args->path;
1189313Ssos    bsd_open_args.mode = args->mode;
1199313Ssos
1209313Ssos    error = open(p, &bsd_open_args, retval);
1219313Ssos    if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
1229313Ssos	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
1239313Ssos	struct filedesc *fdp = p->p_fd;
1249313Ssos	struct file *fp = fdp->fd_ofiles[*retval];
1259313Ssos
1269313Ssos	if (fp->f_type == DTYPE_VNODE)
1279313Ssos	    (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p);
1289313Ssos    }
1299313Ssos    return error;
1309313Ssos}
1319313Ssos
1329313Ssosstruct linux_flock {
1339313Ssos    short l_type;
1349313Ssos    short l_whence;
1359313Ssos    linux_off_t l_start;
1369313Ssos    linux_off_t l_len;
1379313Ssos    linux_pid_t l_pid;
1389313Ssos};
1399313Ssos
1409313Ssosstatic void
1419313Ssoslinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
1429313Ssos{
1439313Ssos    switch (linux_flock->l_type) {
1449313Ssos    case LINUX_F_RDLCK:
1459313Ssos	bsd_flock->l_type = F_RDLCK;
1469313Ssos	break;
1479313Ssos    case LINUX_F_WRLCK:
1489313Ssos	bsd_flock->l_type = F_WRLCK;
1499313Ssos	break;
1509313Ssos    case LINUX_F_UNLCK:
1519313Ssos	bsd_flock->l_type = F_UNLCK;
1529313Ssos	break;
1539313Ssos    }
1549313Ssos    bsd_flock->l_whence = linux_flock->l_whence;
1559313Ssos    bsd_flock->l_start = (off_t)linux_flock->l_start;
1569313Ssos    bsd_flock->l_len = (off_t)linux_flock->l_len;
1579313Ssos    bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1589313Ssos}
1599313Ssos
1609313Ssosstatic void
1619313Ssosbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
1629313Ssos{
1639313Ssos    switch (bsd_flock->l_type) {
1649313Ssos    case F_RDLCK:
1659313Ssos	linux_flock->l_type = LINUX_F_RDLCK;
1669313Ssos	break;
1679313Ssos    case F_WRLCK:
1689313Ssos	linux_flock->l_type = LINUX_F_WRLCK;
1699313Ssos	break;
1709313Ssos    case F_UNLCK:
1719313Ssos	linux_flock->l_type = LINUX_F_UNLCK;
1729313Ssos	break;
1739313Ssos    }
1749313Ssos    linux_flock->l_whence = bsd_flock->l_whence;
1759313Ssos    linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
1769313Ssos    linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
1779313Ssos    linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
1789313Ssos}
1799313Ssos
1809313Ssosstruct linux_fcntl_args {
1819313Ssos    int fd;
1829313Ssos    int cmd;
1839313Ssos    int arg;
1849313Ssos};
1859313Ssos
1869313Ssosint
1879313Ssoslinux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval)
1889313Ssos{
1899313Ssos    int error, result;
1909313Ssos    struct fcntl_args {
1919313Ssos	int fd;
1929313Ssos	int cmd;
1939313Ssos	int arg;
1949313Ssos    } fcntl_args;
1959313Ssos    struct linux_flock linux_flock;
1969313Ssos    struct flock *bsd_flock =
1979313Ssos	(struct flock *)ua_alloc_init(sizeof(struct flock));
1989313Ssos
1999313Ssos#ifdef DEBUG
2009313Ssos    printf("Linux-emul(%d): fcntl(%d, %08x, *)\n",
2019313Ssos	   p->p_pid, args->fd, args->cmd);
2029313Ssos#endif
2039313Ssos    fcntl_args.fd = args->fd;
2049313Ssos    fcntl_args.arg = 0;
2059313Ssos
2069313Ssos    switch (args->cmd) {
2079313Ssos    case LINUX_F_DUPFD:
2089313Ssos	fcntl_args.cmd = F_DUPFD;
2099313Ssos	return fcntl(p, &fcntl_args, retval);
2109313Ssos
2119313Ssos    case LINUX_F_GETFD:
2129313Ssos	fcntl_args.cmd = F_GETFD;
2139313Ssos	return fcntl(p, &fcntl_args, retval);
2149313Ssos
2159313Ssos    case LINUX_F_SETFD:
2169313Ssos	fcntl_args.cmd = F_SETFD;
2179313Ssos	return fcntl(p, &fcntl_args, retval);
2189313Ssos
2199313Ssos    case LINUX_F_GETFL:
2209313Ssos	fcntl_args.cmd = F_GETFL;
2219313Ssos	error = fcntl(p, &fcntl_args, &result);
2229313Ssos	*retval = 0;
2239313Ssos	if (result & O_RDONLY) *retval |= LINUX_O_RDONLY;
2249313Ssos	if (result & O_WRONLY) *retval |= LINUX_O_WRONLY;
2259313Ssos	if (result & O_RDWR) *retval |= LINUX_O_RDWR;
2269313Ssos	if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK;
2279313Ssos	if (result & O_APPEND) *retval |= LINUX_O_APPEND;
2289313Ssos	if (result & O_FSYNC) *retval |= LINUX_O_SYNC;
2299313Ssos	return error;
2309313Ssos
2319313Ssos    case LINUX_F_SETFL:
2329313Ssos	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
2339313Ssos	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
2349313Ssos	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
2359313Ssos	fcntl_args.cmd = F_SETFL;
2369313Ssos	return fcntl(p, &fcntl_args, retval);
2379313Ssos
2389313Ssos    case LINUX_F_GETLK:
2399313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2409313Ssos		   	    sizeof(struct linux_flock))))
2419313Ssos	    return error;
2429313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2439313Ssos	fcntl_args.cmd = F_GETLK;
2449313Ssos	fcntl_args.arg = (int)bsd_flock;
2459313Ssos	if (error = fcntl(p, &fcntl_args, retval))
2469313Ssos	    return error;
2479313Ssos	bsd_to_linux_flock(bsd_flock, &linux_flock);
2489313Ssos	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
2499313Ssos		       sizeof(struct linux_flock));
2509313Ssos
2519313Ssos    case LINUX_F_SETLK:
2529313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2539313Ssos		   	    sizeof(struct linux_flock))))
2549313Ssos	    return error;
2559313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2569313Ssos	fcntl_args.cmd = F_SETLK;
2579313Ssos	fcntl_args.arg = (int)bsd_flock;
2589313Ssos	return fcntl(p, &fcntl_args, retval);
2599313Ssos
2609313Ssos    case LINUX_F_SETLKW:
2619313Ssos	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
2629313Ssos		   	    sizeof(struct linux_flock))))
2639313Ssos	    return error;
2649313Ssos	linux_to_bsd_flock(&linux_flock, bsd_flock);
2659313Ssos	fcntl_args.cmd = F_SETLKW;
2669313Ssos	fcntl_args.arg = (int)bsd_flock;
2679313Ssos	return fcntl(p, &fcntl_args, retval);
2689313Ssos
2699313Ssos    case LINUX_F_SETOWN:
2709313Ssos	fcntl_args.cmd = F_SETOWN;
2719313Ssos	return fcntl(p, &fcntl_args, retval);
2729313Ssos
2739313Ssos    case LINUX_F_GETOWN:
2749313Ssos	fcntl_args.cmd = F_GETOWN;
2759313Ssos	return fcntl(p, &fcntl_args, retval);
2769313Ssos    }
2779313Ssos    return EINVAL;
2789313Ssos}
2799313Ssos
2809313Ssosstruct linux_lseek_args {
2819313Ssos    int fdes;
2829313Ssos    unsigned long off;
2839313Ssos    int whence;
2849313Ssos};
2859313Ssos
2869313Ssosint
2879313Ssoslinux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval)
2889313Ssos{
2899313Ssos
2909313Ssos    struct lseek_args {
2919313Ssos	int fdes;
2929313Ssos	int pad;
2939313Ssos	off_t off;
2949313Ssos	int whence;
2959313Ssos    } tmp_args;
2969313Ssos    off_t tmp_retval;
2979313Ssos    int error;
2989313Ssos
2999313Ssos#ifdef DEBUG
3009313Ssos    printf("Linux-emul(%d): lseek(%d, %d, %d)\n",
3019313Ssos	   p->p_pid, args->fdes, args->off, args->whence);
3029313Ssos#endif
3039313Ssos    tmp_args.fdes = args->fdes;
3049313Ssos    tmp_args.off = (off_t)args->off;
3059313Ssos    tmp_args.whence = args->whence;
3069313Ssos    error = lseek(p, &tmp_args, &tmp_retval);
3079313Ssos    *retval = (int)tmp_retval;
3089313Ssos    return error;
3099313Ssos}
3109313Ssos
3119313Ssosstruct linux_dirent {
3129313Ssos    long dino;
3139313Ssos    linux_off_t doff;
3149313Ssos    unsigned short dreclen;
3159313Ssos    char dname[LINUX_NAME_MAX + 1];
3169313Ssos};
3179313Ssos
3189313Ssos#define LINUX_RECLEN(de,namlen) \
3199313Ssos    ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
3209313Ssos
3219313Ssosstruct linux_readdir_args {
3229313Ssos    int fd;
3239313Ssos    struct linux_dirent *dent;
3249313Ssos    unsigned int count;
3259313Ssos};
3269313Ssos
3279313Ssosint
3289313Ssoslinux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval)
3299313Ssos{
3309313Ssos    register struct dirent *bdp;
3319313Ssos    struct vnode *vp;
3329313Ssos    caddr_t inp, buf;		/* BSD-format */
3339313Ssos    int len, reclen;		/* BSD-format */
3349313Ssos    caddr_t outp;		/* Linux-format */
3359313Ssos    int resid, linuxreclen=0;	/* Linux-format */
3369313Ssos    struct file *fp;
3379313Ssos    struct uio auio;
3389313Ssos    struct iovec aiov;
3399313Ssos    struct vattr va;
3409313Ssos    off_t off;
3419313Ssos    struct linux_dirent linux_dirent;
3429313Ssos    int buflen, error, eofflag, nbytes, justone;
3439313Ssos
3449313Ssos#ifdef DEBUG
3459313Ssos    printf("Linux-emul(%d): readdir(%d, *, %d)\n",
3469313Ssos	   p->p_pid, args->fd, args->count);
3479313Ssos#endif
3489313Ssos    if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
3499313Ssos	return (error);
3509313Ssos
3519313Ssos    if ((fp->f_flag & FREAD) == 0)
3529313Ssos	return (EBADF);
3539313Ssos
3549313Ssos    vp = (struct vnode *) fp->f_data;
3559313Ssos
3569313Ssos    if (vp->v_type != VDIR)
3579313Ssos	return (EINVAL);
3589313Ssos
3599313Ssos    if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
3609313Ssos	return error;
3619313Ssos
3629313Ssos    nbytes = args->count;
3639313Ssos    if (nbytes == 1) {
3649313Ssos	nbytes = sizeof (struct linux_dirent);
3659313Ssos	justone = 1;
3669313Ssos    }
3679313Ssos    else
3689313Ssos	justone = 0;
3699313Ssos
3709313Ssos    buflen = max(va.va_blocksize, nbytes);
3719313Ssos    buf = malloc(buflen, M_TEMP, M_WAITOK);
3729313Ssos    VOP_LOCK(vp);
3739313Ssos    off = fp->f_offset;
3749313Ssosagain:
3759313Ssos    aiov.iov_base = buf;
3769313Ssos    aiov.iov_len = buflen;
3779313Ssos    auio.uio_iov = &aiov;
3789313Ssos    auio.uio_iovcnt = 1;
3799313Ssos    auio.uio_rw = UIO_READ;
3809313Ssos    auio.uio_segflg = UIO_SYSSPACE;
3819313Ssos    auio.uio_procp = p;
3829313Ssos    auio.uio_resid = buflen;
3839313Ssos    auio.uio_offset = off;
3849313Ssos
3859313Ssos    error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *) 0, 0);
3869313Ssos    if (error)
3879313Ssos	goto out;
3889313Ssos
3899313Ssos    inp = buf;
3909313Ssos    outp = (caddr_t) args->dent;
3919313Ssos    resid = nbytes;
3929313Ssos    if ((len = buflen - auio.uio_resid) == 0)
3939313Ssos	goto eof;
3949313Ssos
3959313Ssos    while (len > 0) {
3969313Ssos	reclen = ((struct dirent *) inp)->d_reclen;
3979313Ssos	if (reclen & 3)
3989313Ssos	    panic("linux_readdir");
3999313Ssos	off += reclen;
4009313Ssos	bdp = (struct dirent *) inp;
4019313Ssos	if (bdp->d_fileno == 0) {
4029313Ssos	    inp += reclen;
4039313Ssos	    continue;
4049313Ssos	}
4059313Ssos	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
4069313Ssos	if (reclen > len || resid < linuxreclen) {
4079313Ssos	    outp++;
4089313Ssos	    break;
4099313Ssos	}
4109313Ssos	linux_dirent.dino = (long) bdp->d_fileno;
4119313Ssos	linux_dirent.doff = (linux_off_t) linuxreclen;
4129313Ssos	linux_dirent.dreclen = (u_short) bdp->d_namlen;
4139313Ssos	strcpy(linux_dirent.dname, bdp->d_name);
4149313Ssos	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen)))
4159313Ssos	    goto out;
4169313Ssos	inp += reclen;
4179313Ssos	outp += linuxreclen;
4189313Ssos	resid -= linuxreclen;
4199313Ssos	len -= reclen;
4209313Ssos	if (justone)
4219313Ssos	    break;
4229313Ssos    }
4239313Ssos
4249313Ssos    if (outp == (caddr_t) args->dent)
4259313Ssos	goto again;
4269313Ssos    fp->f_offset = off;
4279313Ssos
4289313Ssos    if (justone)
4299313Ssos	nbytes = resid + linuxreclen;
4309313Ssoseof:
4319313Ssos    *retval = nbytes - resid;
4329313Ssosout:
4339313Ssos    VOP_UNLOCK(vp);
4349313Ssos    free(buf, M_TEMP);
4359313Ssos    return error;
4369313Ssos}
437