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