linux_file.c revision 51348
140516Swpaul/*- 2119868Swpaul * Copyright (c) 1994-1995 S�ren Schmidt 340516Swpaul * All rights reserved. 440516Swpaul * 540516Swpaul * Redistribution and use in source and binary forms, with or without 640516Swpaul * modification, are permitted provided that the following conditions 740516Swpaul * are met: 840516Swpaul * 1. Redistributions of source code must retain the above copyright 940516Swpaul * notice, this list of conditions and the following disclaimer 1040516Swpaul * in this position and unchanged. 1140516Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1240516Swpaul * notice, this list of conditions and the following disclaimer in the 1340516Swpaul * documentation and/or other materials provided with the distribution. 1440516Swpaul * 3. The name of the author may not be used to endorse or promote products 1540516Swpaul * derived from this software withough specific prior written permission 1640516Swpaul * 1740516Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1840516Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1940516Swpaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2040516Swpaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2140516Swpaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2240516Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2340516Swpaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2440516Swpaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2540516Swpaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2640516Swpaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2740516Swpaul * 2840516Swpaul * $FreeBSD: head/sys/compat/linux/linux_file.c 51348 1999-09-17 08:35:08Z marcel $ 2940516Swpaul */ 3040516Swpaul 3140516Swpaul#include "opt_compat.h" 3240516Swpaul 33122678Sobrien#include <sys/param.h> 34122678Sobrien#include <sys/systm.h> 35122678Sobrien#include <sys/sysproto.h> 3640516Swpaul#include <sys/fcntl.h> 37119868Swpaul#include <sys/file.h> 3840516Swpaul#include <sys/filedesc.h> 39119868Swpaul#include <sys/lock.h> 40119868Swpaul#include <sys/proc.h> 4140516Swpaul#include <sys/vnode.h> 4240516Swpaul#include <sys/malloc.h> 43119868Swpaul#include <sys/dirent.h> 44119868Swpaul#include <sys/conf.h> 45119868Swpaul#include <sys/tty.h> 4640516Swpaul 4740516Swpaul#include <i386/linux/linux.h> 4840516Swpaul#include <i386/linux/linux_proto.h> 4940516Swpaul#include <i386/linux/linux_util.h> 5040516Swpaul 5140516Swpaulint 5240516Swpaullinux_creat(struct proc *p, struct linux_creat_args *args) 5340516Swpaul{ 5440516Swpaul struct open_args /* { 5540516Swpaul char *path; 5641569Swpaul int flags; 5740516Swpaul int mode; 5840516Swpaul } */ bsd_open_args; 5940516Swpaul caddr_t sg; 6040516Swpaul 6140516Swpaul sg = stackgap_init(); 6240516Swpaul CHECKALTCREAT(p, &sg, args->path); 6340516Swpaul 6440516Swpaul#ifdef DEBUG 6540516Swpaul printf("Linux-emul(%d): creat(%s, %d)\n", 6640516Swpaul p->p_pid, args->path, args->mode); 6740516Swpaul#endif 6840516Swpaul bsd_open_args.path = args->path; 6940516Swpaul bsd_open_args.mode = args->mode; 7040516Swpaul bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC; 7140516Swpaul return open(p, &bsd_open_args); 7240516Swpaul} 7340516Swpaul 7440516Swpaulint 7540516Swpaullinux_open(struct proc *p, struct linux_open_args *args) 7640516Swpaul{ 7740516Swpaul struct open_args /* { 7840516Swpaul char *path; 7940516Swpaul int flags; 8040516Swpaul int mode; 8140516Swpaul } */ bsd_open_args; 8240516Swpaul int error; 8340516Swpaul caddr_t sg; 8440516Swpaul 8540516Swpaul sg = stackgap_init(); 8640516Swpaul 87108729Sjake if (args->flags & LINUX_O_CREAT) 8840516Swpaul CHECKALTCREAT(p, &sg, args->path); 8940516Swpaul else 9040516Swpaul CHECKALTEXIST(p, &sg, args->path); 9140516Swpaul 9240516Swpaul#ifdef DEBUG 9340516Swpaul printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n", 9440516Swpaul p->p_pid, args->path, args->flags, args->mode); 9540516Swpaul#endif 9640516Swpaul bsd_open_args.flags = 0; 9740516Swpaul if (args->flags & LINUX_O_RDONLY) 9840516Swpaul bsd_open_args.flags |= O_RDONLY; 9940516Swpaul if (args->flags & LINUX_O_WRONLY) 10040516Swpaul bsd_open_args.flags |= O_WRONLY; 10140516Swpaul if (args->flags & LINUX_O_RDWR) 10240516Swpaul bsd_open_args.flags |= O_RDWR; 10341569Swpaul if (args->flags & LINUX_O_NDELAY) 10441569Swpaul bsd_open_args.flags |= O_NONBLOCK; 10541569Swpaul if (args->flags & LINUX_O_APPEND) 10650703Swpaul bsd_open_args.flags |= O_APPEND; 10750703Swpaul if (args->flags & LINUX_O_SYNC) 10850703Swpaul bsd_open_args.flags |= O_FSYNC; 10940516Swpaul if (args->flags & LINUX_O_NONBLOCK) 11050703Swpaul bsd_open_args.flags |= O_NONBLOCK; 11150703Swpaul if (args->flags & LINUX_FASYNC) 11250703Swpaul bsd_open_args.flags |= O_ASYNC; 113119871Swpaul if (args->flags & LINUX_O_CREAT) 114119871Swpaul bsd_open_args.flags |= O_CREAT; 11540516Swpaul if (args->flags & LINUX_O_TRUNC) 116113506Smdodd bsd_open_args.flags |= O_TRUNC; 117113506Smdodd if (args->flags & LINUX_O_EXCL) 11859758Speter bsd_open_args.flags |= O_EXCL; 11959758Speter if (args->flags & LINUX_O_NOCTTY) 12051089Speter bsd_open_args.flags |= O_NOCTTY; 12150703Swpaul bsd_open_args.path = args->path; 12250703Swpaul bsd_open_args.mode = args->mode; 12340516Swpaul 12440516Swpaul error = open(p, &bsd_open_args); 12540516Swpaul if (!error && !(bsd_open_args.flags & O_NOCTTY) && 12640516Swpaul SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 12740516Swpaul struct filedesc *fdp = p->p_fd; 12840516Swpaul struct file *fp = fdp->fd_ofiles[p->p_retval[0]]; 12940516Swpaul 13040516Swpaul if (fp->f_type == DTYPE_VNODE) 13140516Swpaul (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); 13240516Swpaul } 13340516Swpaul#ifdef DEBUG 13440516Swpaul printf("Linux-emul(%d): open returns error %d\n", 13540516Swpaul p->p_pid, error); 13640516Swpaul#endif 13740516Swpaul return error; 13840516Swpaul} 139117388Swpaul 14040516Swpaulstruct linux_flock { 141117388Swpaul short l_type; 14240516Swpaul short l_whence; 143117388Swpaul linux_off_t l_start; 14467771Swpaul linux_off_t l_len; 145118978Swpaul linux_pid_t l_pid; 146118978Swpaul}; 147117388Swpaul 14841243Swpaulstatic void 149117388Swpaullinux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) 15044238Swpaul{ 151117388Swpaul switch (linux_flock->l_type) { 15244238Swpaul case LINUX_F_RDLCK: 153117388Swpaul bsd_flock->l_type = F_RDLCK; 15472813Swpaul break; 155117388Swpaul case LINUX_F_WRLCK: 15696112Sjhb bsd_flock->l_type = F_WRLCK; 157117388Swpaul break; 15894400Swpaul case LINUX_F_UNLCK: 159117388Swpaul bsd_flock->l_type = F_UNLCK; 160103020Siwasaki break; 161117388Swpaul default: 162109095Ssanpei bsd_flock->l_type = -1; 163117388Swpaul break; 164111381Sdan } 165117388Swpaul bsd_flock->l_whence = linux_flock->l_whence; 166112379Ssanpei bsd_flock->l_start = (off_t)linux_flock->l_start; 167117388Swpaul bsd_flock->l_len = (off_t)linux_flock->l_len; 168117388Swpaul bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 169117388Swpaul} 170117388Swpaul 171117388Swpaulstatic void 172117388Swpaulbsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) 173123740Speter{ 17440516Swpaul switch (bsd_flock->l_type) { 17540516Swpaul case F_RDLCK: 17692739Salfred linux_flock->l_type = LINUX_F_RDLCK; 17792739Salfred break; 17892739Salfred case F_WRLCK: 17940516Swpaul linux_flock->l_type = LINUX_F_WRLCK; 180119868Swpaul break; 18140516Swpaul case F_UNLCK: 18292739Salfred linux_flock->l_type = LINUX_F_UNLCK; 18392739Salfred break; 18492739Salfred } 18592739Salfred linux_flock->l_whence = bsd_flock->l_whence; 18692739Salfred linux_flock->l_start = (linux_off_t)bsd_flock->l_start; 18792739Salfred linux_flock->l_len = (linux_off_t)bsd_flock->l_len; 18892739Salfred linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; 18992739Salfred} 19092739Salfred 19192739Salfredint 19292739Salfredlinux_fcntl(struct proc *p, struct linux_fcntl_args *args) 19392739Salfred{ 19492739Salfred int error, result; 19592739Salfred struct fcntl_args /* { 19640516Swpaul int fd; 19792739Salfred int cmd; 19892739Salfred int arg; 19992739Salfred } */ fcntl_args; 20092739Salfred struct linux_flock linux_flock; 20192739Salfred struct flock *bsd_flock; 20292739Salfred struct filedesc *fdp; 20392739Salfred struct file *fp; 20440516Swpaul struct vnode *vp; 20592739Salfred long pgid; 20692739Salfred struct pgrp *pgrp; 20792739Salfred struct tty *tp, *(*d_tty) __P((dev_t)); 20840516Swpaul caddr_t sg; 209123289Sobrien dev_t dev; 21092739Salfred 21192739Salfred sg = stackgap_init(); 21292739Salfred bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock)); 21340516Swpaul d_tty = NULL; 21492739Salfred 21592739Salfred#ifdef DEBUG 21681713Swpaul printf("Linux-emul(%d): fcntl(%d, %08x, *)\n", 21750703Swpaul p->p_pid, args->fd, args->cmd); 21850703Swpaul#endif 21950703Swpaul fcntl_args.fd = args->fd; 22050703Swpaul 22150703Swpaul switch (args->cmd) { 22250703Swpaul case LINUX_F_DUPFD: 22350703Swpaul fcntl_args.cmd = F_DUPFD; 22450703Swpaul fcntl_args.arg = args->arg; 22550703Swpaul return fcntl(p, &fcntl_args); 22650703Swpaul 22750703Swpaul case LINUX_F_GETFD: 22850703Swpaul fcntl_args.cmd = F_GETFD; 22950703Swpaul return fcntl(p, &fcntl_args); 23086822Siwasaki 23186822Siwasaki case LINUX_F_SETFD: 23250703Swpaul fcntl_args.cmd = F_SETFD; 23350703Swpaul fcntl_args.arg = args->arg; 23450703Swpaul return fcntl(p, &fcntl_args); 23550703Swpaul 23650703Swpaul case LINUX_F_GETFL: 23750703Swpaul fcntl_args.cmd = F_GETFL; 23850703Swpaul error = fcntl(p, &fcntl_args); 23950703Swpaul result = p->p_retval[0]; 24050703Swpaul p->p_retval[0] = 0; 24150703Swpaul if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY; 24250703Swpaul if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY; 24350703Swpaul if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR; 24450703Swpaul if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK; 24550703Swpaul if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND; 24650703Swpaul if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC; 24751455Swpaul if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC; 24850703Swpaul return error; 24950703Swpaul 25050703Swpaul case LINUX_F_SETFL: 25150703Swpaul fcntl_args.arg = 0; 25250703Swpaul if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; 25350703Swpaul if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; 254113506Smdodd if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; 255123019Simp if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC; 25651473Swpaul fcntl_args.cmd = F_SETFL; 25750703Swpaul return fcntl(p, &fcntl_args); 25840516Swpaul 25940516Swpaul case LINUX_F_GETLK: 26040516Swpaul if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 26140516Swpaul sizeof(struct linux_flock)))) 26240516Swpaul return error; 26340516Swpaul linux_to_bsd_flock(&linux_flock, bsd_flock); 26440516Swpaul fcntl_args.cmd = F_GETLK; 26540516Swpaul fcntl_args.arg = (int)bsd_flock; 26681713Swpaul error = fcntl(p, &fcntl_args); 26781713Swpaul if (error) 26881713Swpaul return error; 26981713Swpaul bsd_to_linux_flock(bsd_flock, &linux_flock); 27081713Swpaul return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, 27181713Swpaul sizeof(struct linux_flock)); 27281713Swpaul 27381713Swpaul case LINUX_F_SETLK: 27481713Swpaul if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 27581713Swpaul sizeof(struct linux_flock)))) 27681713Swpaul return error; 27781713Swpaul linux_to_bsd_flock(&linux_flock, bsd_flock); 27881713Swpaul fcntl_args.cmd = F_SETLK; 27981713Swpaul fcntl_args.arg = (int)bsd_flock; 28081713Swpaul return fcntl(p, &fcntl_args); 28181713Swpaul 28281713Swpaul case LINUX_F_SETLKW: 28381713Swpaul if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, 28481713Swpaul sizeof(struct linux_flock)))) 28581713Swpaul return error; 28681713Swpaul linux_to_bsd_flock(&linux_flock, bsd_flock); 28781713Swpaul fcntl_args.cmd = F_SETLKW; 28881713Swpaul fcntl_args.arg = (int)bsd_flock; 28981713Swpaul return fcntl(p, &fcntl_args); 29081713Swpaul 29181713Swpaul case LINUX_F_SETOWN: 29281713Swpaul case LINUX_F_GETOWN: 29381713Swpaul /* 29440516Swpaul * We need to route around the normal fcntl() for these calls, 29540516Swpaul * since it uses TIOC{G,S}PGRP, which is too restrictive for 29640516Swpaul * Linux F_{G,S}ETOWN semantics. For sockets, this problem 297102335Salfred * does not exist. 298102335Salfred */ 29940516Swpaul fdp = p->p_fd; 30041656Swpaul if ((u_int)args->fd >= fdp->fd_nfiles || 30140516Swpaul (fp = fdp->fd_ofiles[args->fd]) == NULL) 30240516Swpaul return EBADF; 30340516Swpaul if (fp->f_type == DTYPE_SOCKET) { 30467931Swpaul fcntl_args.cmd = args->cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN; 30540516Swpaul fcntl_args.arg = args->arg; 30640516Swpaul return fcntl(p, &fcntl_args); 30755170Sbillf } 30840516Swpaul vp = (struct vnode *)fp->f_data; 30940516Swpaul dev = vn_todev(vp); 31040516Swpaul if (vp->v_type != VCHR || dev == NODEV) 31140516Swpaul return EINVAL; 31240516Swpaul d_tty = devsw(dev)->d_devtotty; 31340516Swpaul if (!d_tty || (!(tp = (*d_tty)(dev)))) 31440516Swpaul return EINVAL; 31540516Swpaul if (args->cmd == LINUX_F_GETOWN) { 31640516Swpaul p->p_retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 31740516Swpaul return 0; 31840516Swpaul } 31940516Swpaul if ((long)args->arg <= 0) { 32040516Swpaul pgid = -(long)args->arg; 32140516Swpaul } else { 32240516Swpaul struct proc *p1 = pfind((long)args->arg); 32340516Swpaul if (p1 == 0) 32440516Swpaul return (ESRCH); 32540516Swpaul pgid = (long)p1->p_pgrp->pg_id; 32640516Swpaul } 32740516Swpaul pgrp = pgfind(pgid); 328102335Salfred if (pgrp == NULL || pgrp->pg_session != p->p_session) 329102335Salfred return EPERM; 33040516Swpaul tp->t_pgrp = pgrp; 33141656Swpaul return 0; 33240516Swpaul } 33340516Swpaul return EINVAL; 33440516Swpaul} 33540516Swpaul 33640516Swpaulint 33740516Swpaullinux_lseek(struct proc *p, struct linux_lseek_args *args) 33840516Swpaul{ 33940516Swpaul 34040516Swpaul struct lseek_args /* { 34140516Swpaul int fd; 34240516Swpaul int pad; 34340516Swpaul off_t offset; 34440516Swpaul int whence; 34540516Swpaul } */ tmp_args; 34640516Swpaul int error; 34740516Swpaul 34840516Swpaul#ifdef DEBUG 34940516Swpaul printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n", 35040516Swpaul (long)p->p_pid, args->fdes, args->off, args->whence); 35140516Swpaul#endif 35240516Swpaul tmp_args.fd = args->fdes; 35340516Swpaul tmp_args.offset = (off_t)args->off; 35440516Swpaul tmp_args.whence = args->whence; 35540516Swpaul error = lseek(p, &tmp_args); 35640516Swpaul return error; 35740516Swpaul} 35840516Swpaul 35940516Swpaulint 36040516Swpaullinux_llseek(struct proc *p, struct linux_llseek_args *args) 36140516Swpaul{ 36240516Swpaul struct lseek_args bsd_args; 36340516Swpaul int error; 36440516Swpaul off_t off; 36540516Swpaul 36640516Swpaul#ifdef DEBUG 36740516Swpaul printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n", 36840516Swpaul p->p_pid, args->fd, args->ohigh, args->olow, args->whence); 36940516Swpaul#endif 370102335Salfred off = (args->olow) | (((off_t) args->ohigh) << 32); 371102335Salfred 37240516Swpaul bsd_args.fd = args->fd; 37340516Swpaul bsd_args.offset = off; 37440516Swpaul bsd_args.whence = args->whence; 37540516Swpaul 37640516Swpaul if ((error = lseek(p, &bsd_args))) 37740516Swpaul return error; 37840516Swpaul 37940516Swpaul if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t)))) 38040516Swpaul return error; 38140516Swpaul 38240516Swpaul p->p_retval[0] = 0; 38340516Swpaul return 0; 38440516Swpaul} 38540516Swpaul 38640516Swpaul 38740516Swpaulstruct linux_dirent { 38840516Swpaul long dino; 38940516Swpaul linux_off_t doff; 39040516Swpaul unsigned short dreclen; 39140516Swpaul char dname[LINUX_NAME_MAX + 1]; 39240516Swpaul}; 39340516Swpaul 39440516Swpaul#define LINUX_RECLEN(de,namlen) \ 39540516Swpaul ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1)) 39640516Swpaul 39740516Swpaulint 39840516Swpaullinux_readdir(struct proc *p, struct linux_readdir_args *args) 39940516Swpaul{ 40040516Swpaul struct linux_getdents_args lda; 40140516Swpaul 402105221Sphk lda.fd = args->fd; 40340516Swpaul lda.dent = args->dent; 40440516Swpaul lda.count = 1; 40540516Swpaul return linux_getdents(p, &lda); 406105221Sphk} 40740516Swpaul 40840516Swpaulint 40940516Swpaullinux_getdents(struct proc *p, struct linux_getdents_args *args) 41040516Swpaul{ 411102335Salfred register struct dirent *bdp; 412102335Salfred struct vnode *vp; 41340516Swpaul caddr_t inp, buf; /* BSD-format */ 41440516Swpaul int len, reclen; /* BSD-format */ 41540516Swpaul caddr_t outp; /* Linux-format */ 41640516Swpaul int resid, linuxreclen=0; /* Linux-format */ 41740516Swpaul struct file *fp; 41840516Swpaul struct uio auio; 41940516Swpaul struct iovec aiov; 42040516Swpaul struct vattr va; 42140516Swpaul off_t off; 42240516Swpaul struct linux_dirent linux_dirent; 42340516Swpaul int buflen, error, eofflag, nbytes, justone; 42440516Swpaul u_long *cookies = NULL, *cookiep; 42540516Swpaul int ncookies; 42640516Swpaul 42740516Swpaul#ifdef DEBUG 42840516Swpaul printf("Linux-emul(%d): getdents(%d, *, %d)\n", 42940516Swpaul p->p_pid, args->fd, args->count); 43040516Swpaul#endif 43140516Swpaul if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) { 432102335Salfred return (error); 433102335Salfred } 43440516Swpaul 43540516Swpaul if ((fp->f_flag & FREAD) == 0) 43640516Swpaul return (EBADF); 43740516Swpaul 43840516Swpaul vp = (struct vnode *) fp->f_data; 43940516Swpaul 44040516Swpaul if (vp->v_type != VDIR) 44140516Swpaul return (EINVAL); 44240516Swpaul 443109109Sdes if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) { 44440516Swpaul return error; 445109109Sdes } 44640516Swpaul 447109109Sdes nbytes = args->count; 44840516Swpaul if (nbytes == 1) { 44940516Swpaul nbytes = sizeof (struct linux_dirent); 45040516Swpaul justone = 1; 45140516Swpaul } 45240516Swpaul else 45340516Swpaul justone = 0; 45440516Swpaul 45540516Swpaul off = fp->f_offset; 45640516Swpaul#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ 45740516Swpaul buflen = max(DIRBLKSIZ, nbytes); 458102335Salfred buflen = min(buflen, MAXBSIZE); 459102335Salfred buf = malloc(buflen, M_TEMP, M_WAITOK); 46040516Swpaul vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 46140516Swpaulagain: 462109109Sdes aiov.iov_base = buf; 46340516Swpaul aiov.iov_len = buflen; 46467087Swpaul auio.uio_iov = &aiov; 46540516Swpaul auio.uio_iovcnt = 1; 46667087Swpaul auio.uio_rw = UIO_READ; 46740516Swpaul auio.uio_segflg = UIO_SYSSPACE; 46840516Swpaul auio.uio_procp = p; 46940516Swpaul auio.uio_resid = buflen; 47040516Swpaul auio.uio_offset = off; 47140516Swpaul 47240516Swpaul if (cookies) { 47340516Swpaul free(cookies, M_TEMP); 47440516Swpaul cookies = NULL; 475109109Sdes } 47640516Swpaul 47740516Swpaul error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies); 47840516Swpaul if (error) { 479109109Sdes goto out; 48040516Swpaul } 48140516Swpaul 48240516Swpaul inp = buf; 48340516Swpaul outp = (caddr_t) args->dent; 48440516Swpaul resid = nbytes; 48540516Swpaul if ((len = buflen - auio.uio_resid) <= 0) { 48640516Swpaul goto eof; 48740516Swpaul } 48840516Swpaul 48940516Swpaul cookiep = cookies; 49040516Swpaul 49140516Swpaul if (cookies) { 49240516Swpaul /* 49340516Swpaul * When using cookies, the vfs has the option of reading from 49440516Swpaul * a different offset than that supplied (UFS truncates the 49540516Swpaul * offset to a block boundary to make sure that it never reads 49640516Swpaul * partway through a directory entry, even if the directory 49740516Swpaul * has been compacted). 49840516Swpaul */ 49940516Swpaul while (len > 0 && ncookies > 0 && *cookiep <= off) { 50040516Swpaul bdp = (struct dirent *) inp; 50140516Swpaul len -= bdp->d_reclen; 50240516Swpaul inp += bdp->d_reclen; 50340516Swpaul cookiep++; 50440516Swpaul ncookies--; 505109058Smbr } 50640516Swpaul } 50740516Swpaul 50840516Swpaul while (len > 0) { 50940516Swpaul if (cookiep && ncookies == 0) 51040516Swpaul break; 51140516Swpaul bdp = (struct dirent *) inp; 51240516Swpaul reclen = bdp->d_reclen; 51340516Swpaul if (reclen & 3) { 51440516Swpaul printf("linux_readdir: reclen=%d\n", reclen); 51540516Swpaul error = EFAULT; 51640516Swpaul goto out; 51740516Swpaul } 51840516Swpaul 51940516Swpaul if (bdp->d_fileno == 0) { 52040516Swpaul inp += reclen; 52140516Swpaul if (cookiep) { 52240516Swpaul off = *cookiep++; 52340516Swpaul ncookies--; 52440516Swpaul } else 52540516Swpaul off += reclen; 52640516Swpaul len -= reclen; 52740516Swpaul continue; 52840516Swpaul } 52940516Swpaul linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 53040516Swpaul if (reclen > len || resid < linuxreclen) { 53140516Swpaul outp++; 53240516Swpaul break; 53340516Swpaul } 53440516Swpaul linux_dirent.dino = (long) bdp->d_fileno; 53540516Swpaul if (justone) { 53640516Swpaul /* 53740516Swpaul * old linux-style readdir usage. 53840516Swpaul */ 53940516Swpaul linux_dirent.doff = (linux_off_t) linuxreclen; 54040516Swpaul linux_dirent.dreclen = (u_short) bdp->d_namlen; 54140516Swpaul } else { 54267087Swpaul linux_dirent.doff = (linux_off_t) off; 54340516Swpaul linux_dirent.dreclen = (u_short) linuxreclen; 54440516Swpaul } 54540516Swpaul strcpy(linux_dirent.dname, bdp->d_name); 54640516Swpaul if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) { 54740516Swpaul goto out; 54840516Swpaul } 54940516Swpaul inp += reclen; 55040516Swpaul if (cookiep) { 55140516Swpaul off = *cookiep++; 552102335Salfred ncookies--; 553102335Salfred } else 55440516Swpaul off += reclen; 55540516Swpaul outp += linuxreclen; 556109109Sdes resid -= linuxreclen; 55740516Swpaul len -= reclen; 55867087Swpaul if (justone) 55940516Swpaul break; 56040516Swpaul } 56140516Swpaul 56240516Swpaul if (outp == (caddr_t) args->dent) 56340516Swpaul goto again; 56440516Swpaul fp->f_offset = off; 56540516Swpaul 56640516Swpaul if (justone) 567109109Sdes nbytes = resid + linuxreclen; 56840516Swpaul 569109109Sdeseof: 57040516Swpaul p->p_retval[0] = nbytes - resid; 57140516Swpaulout: 57240516Swpaul if (cookies) 57340516Swpaul free(cookies, M_TEMP); 57440516Swpaul VOP_UNLOCK(vp, 0, p); 57540516Swpaul free(buf, M_TEMP); 57640516Swpaul return error; 57740516Swpaul} 57840516Swpaul 57940516Swpaul/* 58040516Swpaul * These exist mainly for hooks for doing /compat/linux translation. 58140516Swpaul */ 58240516Swpaul 58340516Swpaulint 58440516Swpaullinux_access(struct proc *p, struct linux_access_args *args) 58540516Swpaul{ 58640516Swpaul struct access_args bsd; 58740516Swpaul caddr_t sg; 58840516Swpaul 58940516Swpaul sg = stackgap_init(); 59040516Swpaul CHECKALTEXIST(p, &sg, args->path); 59140516Swpaul 59240516Swpaul#ifdef DEBUG 59367087Swpaul printf("Linux-emul(%d): access(%s, %d)\n", 59440516Swpaul p->p_pid, args->path, args->flags); 59540516Swpaul#endif 59640516Swpaul bsd.path = args->path; 59740516Swpaul bsd.flags = args->flags; 598102335Salfred 599102335Salfred return access(p, &bsd); 60050703Swpaul} 60150703Swpaul 60250703Swpaulint 60340516Swpaullinux_unlink(struct proc *p, struct linux_unlink_args *args) 60440516Swpaul{ 60540516Swpaul struct unlink_args bsd; 60640516Swpaul caddr_t sg; 60740516Swpaul 60850703Swpaul sg = stackgap_init(); 60967087Swpaul CHECKALTEXIST(p, &sg, args->path); 61050703Swpaul 611119868Swpaul#ifdef DEBUG 61250703Swpaul printf("Linux-emul(%d): unlink(%s)\n", 61367087Swpaul p->p_pid, args->path); 61467087Swpaul#endif 61550703Swpaul bsd.path = args->path; 61667087Swpaul 61740516Swpaul return unlink(p, &bsd); 61850703Swpaul} 61940516Swpaul 62040516Swpaulint 62150703Swpaullinux_chdir(struct proc *p, struct linux_chdir_args *args) 62240516Swpaul{ 62340516Swpaul struct chdir_args bsd; 62450703Swpaul caddr_t sg; 62540516Swpaul 62640516Swpaul sg = stackgap_init(); 62750703Swpaul CHECKALTEXIST(p, &sg, args->path); 62850703Swpaul 62950703Swpaul#ifdef DEBUG 63050703Swpaul printf("Linux-emul(%d): chdir(%s)\n", 63140516Swpaul p->p_pid, args->path); 63240516Swpaul#endif 63350703Swpaul bsd.path = args->path; 63450703Swpaul 63567087Swpaul return chdir(p, &bsd); 63650703Swpaul} 63794149Swpaul 63894149Swpaulint 63994149Swpaullinux_chmod(struct proc *p, struct linux_chmod_args *args) 64094149Swpaul{ 64194149Swpaul struct chmod_args bsd; 64294149Swpaul caddr_t sg; 64394149Swpaul 64494149Swpaul sg = stackgap_init(); 64594149Swpaul CHECKALTEXIST(p, &sg, args->path); 64694149Swpaul 64740516Swpaul#ifdef DEBUG 64840516Swpaul printf("Linux-emul(%d): chmod(%s, %d)\n", 64967087Swpaul p->p_pid, args->path, args->mode); 65040516Swpaul#endif 65140516Swpaul bsd.path = args->path; 65240516Swpaul bsd.mode = args->mode; 65367087Swpaul 65440516Swpaul return chmod(p, &bsd); 65540516Swpaul} 65640516Swpaul 65740516Swpaulint 65840516Swpaullinux_chown(struct proc *p, struct linux_chown_args *args) 65950703Swpaul{ 66040516Swpaul struct chown_args bsd; 66140516Swpaul caddr_t sg; 66267087Swpaul 66340516Swpaul sg = stackgap_init(); 66440516Swpaul CHECKALTEXIST(p, &sg, args->path); 66540516Swpaul 66640516Swpaul#ifdef DEBUG 667102335Salfred printf("Linux-emul(%d): chown(%s, %d, %d)\n", 668102335Salfred p->p_pid, args->path, args->uid, args->gid); 66950703Swpaul#endif 67050703Swpaul bsd.path = args->path; 67150703Swpaul /* XXX size casts here */ 67240516Swpaul bsd.uid = args->uid; 67340516Swpaul bsd.gid = args->gid; 67440516Swpaul 67540516Swpaul return chown(p, &bsd); 67650703Swpaul} 67767087Swpaul 67850703Swpaulint 679119868Swpaullinux_lchown(struct proc *p, struct linux_lchown_args *args) 68050703Swpaul{ 68167087Swpaul struct lchown_args bsd; 68267087Swpaul caddr_t sg; 68350703Swpaul 68467087Swpaul sg = stackgap_init(); 68540516Swpaul CHECKALTEXIST(p, &sg, args->path); 68650703Swpaul 68740516Swpaul#ifdef DEBUG 68840516Swpaul printf("Linux-emul(%d): lchown(%s, %d, %d)\n", 68950703Swpaul p->p_pid, args->path, args->uid, args->gid); 69040516Swpaul#endif 69140516Swpaul bsd.path = args->path; 69250703Swpaul /* XXX size casts here */ 69340516Swpaul bsd.uid = args->uid; 69440516Swpaul bsd.gid = args->gid; 69550703Swpaul 69650703Swpaul return lchown(p, &bsd); 69750703Swpaul} 69850703Swpaul 69940516Swpaulint 70040516Swpaullinux_mkdir(struct proc *p, struct linux_mkdir_args *args) 70150703Swpaul{ 70250703Swpaul struct mkdir_args bsd; 70367087Swpaul caddr_t sg; 70450703Swpaul 70550703Swpaul sg = stackgap_init(); 70640516Swpaul CHECKALTCREAT(p, &sg, args->path); 70740516Swpaul 70867087Swpaul#ifdef DEBUG 70950703Swpaul printf("Linux-emul(%d): mkdir(%s, %d)\n", 71040516Swpaul p->p_pid, args->path, args->mode); 71140516Swpaul#endif 71267087Swpaul bsd.path = args->path; 71350703Swpaul bsd.mode = args->mode; 71440516Swpaul 71540516Swpaul return mkdir(p, &bsd); 71640516Swpaul} 71740516Swpaul 71850703Swpaulint 71940516Swpaullinux_rmdir(struct proc *p, struct linux_rmdir_args *args) 72040516Swpaul{ 72140516Swpaul struct rmdir_args bsd; 72240516Swpaul caddr_t sg; 72340516Swpaul 72467087Swpaul sg = stackgap_init(); 72550703Swpaul CHECKALTEXIST(p, &sg, args->path); 72650703Swpaul 72750703Swpaul#ifdef DEBUG 728102335Salfred printf("Linux-emul(%d): rmdir(%s)\n", 729102335Salfred p->p_pid, args->path); 73050703Swpaul#endif 73150703Swpaul bsd.path = args->path; 73240516Swpaul 73340516Swpaul return rmdir(p, &bsd); 73440516Swpaul} 73540516Swpaul 73643062Swpaulint 73740516Swpaullinux_rename(struct proc *p, struct linux_rename_args *args) 738122625Sobrien{ 739122625Sobrien struct rename_args bsd; 740123289Sobrien caddr_t sg; 74140516Swpaul 742123289Sobrien sg = stackgap_init(); 743123289Sobrien CHECKALTEXIST(p, &sg, args->from); 744123289Sobrien CHECKALTCREAT(p, &sg, args->to); 74540516Swpaul 74640516Swpaul#ifdef DEBUG 74740516Swpaul printf("Linux-emul(%d): rename(%s, %s)\n", 74840516Swpaul p->p_pid, args->from, args->to); 749122625Sobrien#endif 750122625Sobrien bsd.from = args->from; 751122625Sobrien bsd.to = args->to; 75240516Swpaul 75340516Swpaul return rename(p, &bsd); 75440516Swpaul} 75540516Swpaul 75640516Swpaulint 75740516Swpaullinux_symlink(struct proc *p, struct linux_symlink_args *args) 75840516Swpaul{ 75943062Swpaul struct symlink_args bsd; 76040516Swpaul caddr_t sg; 76140516Swpaul 76240516Swpaul sg = stackgap_init(); 76340516Swpaul CHECKALTEXIST(p, &sg, args->path); 76440516Swpaul CHECKALTCREAT(p, &sg, args->to); 765102335Salfred 766102335Salfred#ifdef DEBUG 76740516Swpaul printf("Linux-emul(%d): symlink(%s, %s)\n", 76840516Swpaul p->p_pid, args->path, args->to); 76940516Swpaul#endif 77040516Swpaul bsd.path = args->path; 77140516Swpaul bsd.link = args->to; 77240516Swpaul 77340516Swpaul return symlink(p, &bsd); 77440516Swpaul} 77540516Swpaul 77640516Swpaulint 77740516Swpaullinux_execve(struct proc *p, struct linux_execve_args *args) 77840516Swpaul{ 77940516Swpaul struct execve_args bsd; 78043062Swpaul caddr_t sg; 78140516Swpaul 78240516Swpaul sg = stackgap_init(); 78340516Swpaul CHECKALTEXIST(p, &sg, args->path); 78440516Swpaul 78540516Swpaul#ifdef DEBUG 78640516Swpaul printf("Linux-emul(%d): execve(%s)\n", 78740516Swpaul p->p_pid, args->path); 78840516Swpaul#endif 78940516Swpaul bsd.fname = args->path; 79040516Swpaul bsd.argv = args->argp; 79140516Swpaul bsd.envv = args->envp; 79240516Swpaul 79372084Sphk return execve(p, &bsd); 79440516Swpaul} 79540516Swpaul 796122625Sobrienint 79740516Swpaullinux_readlink(struct proc *p, struct linux_readlink_args *args) 79840516Swpaul{ 79940516Swpaul struct readlink_args bsd; 80040516Swpaul caddr_t sg; 80140516Swpaul 80240516Swpaul sg = stackgap_init(); 80340516Swpaul CHECKALTEXIST(p, &sg, args->name); 80440516Swpaul 80540516Swpaul#ifdef DEBUG 80640516Swpaul printf("Linux-emul(%ld): readlink(%s, %p, %d)\n", 80740516Swpaul (long)p->p_pid, args->name, (void *)args->buf, args->count); 80840516Swpaul#endif 80940516Swpaul bsd.path = args->name; 81040516Swpaul bsd.buf = args->buf; 81140516Swpaul bsd.count = args->count; 81240516Swpaul 81340516Swpaul return readlink(p, &bsd); 81440516Swpaul} 81540516Swpaul 816102335Salfredint 817102335Salfredlinux_truncate(struct proc *p, struct linux_truncate_args *args) 81840516Swpaul{ 81940516Swpaul struct truncate_args bsd; 82040516Swpaul caddr_t sg; 82140516Swpaul 82240516Swpaul sg = stackgap_init(); 82340516Swpaul CHECKALTEXIST(p, &sg, args->path); 82440516Swpaul 82540516Swpaul#ifdef DEBUG 82640516Swpaul printf("Linux-emul(%d): truncate(%s, %ld)\n", 82740516Swpaul p->p_pid, args->path, args->length); 82840516Swpaul#endif 82940516Swpaul bsd.path = args->path; 83040516Swpaul bsd.length = args->length; 83140516Swpaul 832109109Sdes return truncate(p, &bsd); 83340516Swpaul} 83440516Swpaul 83540516Swpaulint 83640516Swpaullinux_link(struct proc *p, struct linux_link_args *args) 83740516Swpaul{ 83840516Swpaul struct link_args bsd; 839102335Salfred caddr_t sg; 840102335Salfred 84150703Swpaul sg = stackgap_init(); 84240516Swpaul CHECKALTEXIST(p, &sg, args->path); 84340516Swpaul CHECKALTCREAT(p, &sg, args->to); 844119868Swpaul 845117388Swpaul#ifdef DEBUG 846117388Swpaul printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to); 84740516Swpaul#endif 84840516Swpaul 849117388Swpaul bsd.path = args->path; 85040516Swpaul bsd.link = args->to; 85140516Swpaul 85250703Swpaul return link(p, &bsd); 85350703Swpaul} 854117388Swpaul 855117388Swpaulint 856117388Swpaullinux_getcwd(struct proc *p, struct linux_getcwd_args *args) 857117388Swpaul{ 858117388Swpaul struct __getcwd_args bsd; 859117388Swpaul caddr_t sg; 860127135Snjl int error, len; 861127135Snjl 862117388Swpaul#ifdef DEBUG 863117388Swpaul printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid, 864117388Swpaul args->buf, args->bufsize); 865117388Swpaul#endif 866117388Swpaul 867117388Swpaul sg = stackgap_init(); 868117388Swpaul bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE); 869117388Swpaul bsd.buflen = SPARE_USRSPACE; 870117388Swpaul error = __getcwd(p, &bsd); 871117388Swpaul if (!error) { 872119868Swpaul len = strlen(bsd.buf) + 1; 873119868Swpaul if (len <= args->bufsize) { 874119868Swpaul p->p_retval[0] = len; 875117388Swpaul error = copyout(bsd.buf, args->buf, len); 876117388Swpaul } 877119868Swpaul else 878119868Swpaul error = ERANGE; 879119868Swpaul } 880124076Swpaul return (error); 881124076Swpaul} 882119954Swpaul