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