linux_file.c revision 166085
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 9111798Sdes * 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 1597748Sschweikh * derived from this software without 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 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linux/linux_file.c 166085 2007-01-18 09:32:08Z kib $"); 31116173Sobrien 32156874Sru#include "opt_compat.h" 33101189Srwatson#include "opt_mac.h" 3431784Seivind 359313Ssos#include <sys/param.h> 369313Ssos#include <sys/systm.h> 3776166Smarkm#include <sys/conf.h> 3876166Smarkm#include <sys/dirent.h> 399313Ssos#include <sys/fcntl.h> 409313Ssos#include <sys/file.h> 419313Ssos#include <sys/filedesc.h> 4231561Sbde#include <sys/lock.h> 439313Ssos#include <sys/malloc.h> 4472538Sjlemon#include <sys/mount.h> 4576166Smarkm#include <sys/mutex.h> 4676166Smarkm#include <sys/proc.h> 47162201Snetchild#include <sys/stat.h> 48166085Skib#include <sys/sx.h> 49102814Siedowse#include <sys/syscallsubr.h> 5076166Smarkm#include <sys/sysproto.h> 5114331Speter#include <sys/tty.h> 52162585Snetchild#include <sys/unistd.h> 5376166Smarkm#include <sys/vnode.h> 5412458Sbde 55163606Srwatson#include <security/mac/mac_framework.h> 56163606Srwatson 5772538Sjlemon#include <ufs/ufs/extattr.h> 5872538Sjlemon#include <ufs/ufs/quota.h> 5972538Sjlemon#include <ufs/ufs/ufsmount.h> 6072538Sjlemon 61140214Sobrien#ifdef COMPAT_LINUX32 62140214Sobrien#include <machine/../linux32/linux.h> 63140214Sobrien#include <machine/../linux32/linux32_proto.h> 64140214Sobrien#else 6564905Smarcel#include <machine/../linux/linux.h> 6668583Smarcel#include <machine/../linux/linux_proto.h> 67133816Stjr#endif 6864905Smarcel#include <compat/linux/linux_util.h> 699313Ssos 709313Ssosint 7183366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 729313Ssos{ 73102814Siedowse char *path; 74102814Siedowse int error; 759313Ssos 76102814Siedowse LCONVPATHEXIST(td, args->path, &path); 7714331Speter 789313Ssos#ifdef DEBUG 7972543Sjlemon if (ldebug(creat)) 80102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 819313Ssos#endif 82102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 83102814Siedowse args->mode); 84102814Siedowse LFREEPATH(path); 85102814Siedowse return (error); 869313Ssos} 879313Ssos 889313Ssosint 8983366Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 909313Ssos{ 9183382Sjhb struct proc *p = td->td_proc; 92166085Skib struct file *fp; 93166085Skib int fd; 94102814Siedowse char *path; 95102814Siedowse int bsd_flags, error; 9614331Speter 9714331Speter if (args->flags & LINUX_O_CREAT) 98102814Siedowse LCONVPATHCREAT(td, args->path, &path); 9914331Speter else 100102814Siedowse LCONVPATHEXIST(td, args->path, &path); 10114331Speter 1029313Ssos#ifdef DEBUG 10372543Sjlemon if (ldebug(open)) 10472543Sjlemon printf(ARGS(open, "%s, 0x%x, 0x%x"), 105102814Siedowse path, args->flags, args->mode); 1069313Ssos#endif 107102814Siedowse bsd_flags = 0; 1089313Ssos if (args->flags & LINUX_O_RDONLY) 109102814Siedowse bsd_flags |= O_RDONLY; 110111798Sdes if (args->flags & LINUX_O_WRONLY) 111102814Siedowse bsd_flags |= O_WRONLY; 1129313Ssos if (args->flags & LINUX_O_RDWR) 113102814Siedowse bsd_flags |= O_RDWR; 1149313Ssos if (args->flags & LINUX_O_NDELAY) 115102814Siedowse bsd_flags |= O_NONBLOCK; 1169313Ssos if (args->flags & LINUX_O_APPEND) 117102814Siedowse bsd_flags |= O_APPEND; 1189313Ssos if (args->flags & LINUX_O_SYNC) 119102814Siedowse bsd_flags |= O_FSYNC; 1209313Ssos if (args->flags & LINUX_O_NONBLOCK) 121102814Siedowse bsd_flags |= O_NONBLOCK; 1229313Ssos if (args->flags & LINUX_FASYNC) 123102814Siedowse bsd_flags |= O_ASYNC; 1249313Ssos if (args->flags & LINUX_O_CREAT) 125102814Siedowse bsd_flags |= O_CREAT; 1269313Ssos if (args->flags & LINUX_O_TRUNC) 127102814Siedowse bsd_flags |= O_TRUNC; 1289313Ssos if (args->flags & LINUX_O_EXCL) 129102814Siedowse bsd_flags |= O_EXCL; 1309313Ssos if (args->flags & LINUX_O_NOCTTY) 131102814Siedowse bsd_flags |= O_NOCTTY; 132166085Skib if (args->flags & LINUX_O_DIRECT) 133166085Skib bsd_flags |= O_DIRECT; 134166085Skib if (args->flags & LINUX_O_NOFOLLOW) 135166085Skib bsd_flags |= O_NOFOLLOW; 136166085Skib /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1379313Ssos 138102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode); 139166085Skib if (!error) { 140166085Skib fd = td->td_retval[0]; 141166085Skib /* 142166085Skib * XXX In between kern_open() and fget(), another process 143166085Skib * having the same filedesc could use that fd without 144166085Skib * checking below. 145166085Skib */ 146166085Skib error = fget(td, fd, &fp); 147166085Skib if (!error) { 148166085Skib sx_slock(&proctree_lock); 149166085Skib PROC_LOCK(p); 150166085Skib if (!(bsd_flags & O_NOCTTY) && 151166085Skib SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 152166085Skib PROC_UNLOCK(p); 153166085Skib sx_unlock(&proctree_lock); 154166085Skib if (fp->f_type == DTYPE_VNODE) 155166085Skib (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 156166085Skib td->td_ucred, td); 157166085Skib } else { 158166085Skib PROC_UNLOCK(p); 159166085Skib sx_sunlock(&proctree_lock); 160166085Skib } 161166085Skib if (args->flags & LINUX_O_DIRECTORY) { 162166085Skib if (fp->f_type != DTYPE_VNODE || 163166085Skib fp->f_vnode->v_type != VDIR) { 164166085Skib error = ENOTDIR; 165166085Skib } 166166085Skib } 167166085Skib fdrop(fp, td); 168166085Skib /* 169166085Skib * XXX as above, fdrop()/kern_close() pair is racy. 170166085Skib */ 171166085Skib if (error) 172166085Skib kern_close(td, fd); 173166085Skib } 174166085Skib } 1759313Ssos 17614331Speter#ifdef DEBUG 177166085Skib if (ldebug(open)) 178166085Skib printf(LMSG("open returns error %d"), error); 17914331Speter#endif 180102814Siedowse LFREEPATH(path); 1819313Ssos return error; 1829313Ssos} 1839313Ssos 1849313Ssosint 18583366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 1869313Ssos{ 1879313Ssos 18812858Speter struct lseek_args /* { 18912858Speter int fd; 1909313Ssos int pad; 19112858Speter off_t offset; 1929313Ssos int whence; 19312858Speter } */ tmp_args; 1949313Ssos int error; 1959313Ssos 1969313Ssos#ifdef DEBUG 19772543Sjlemon if (ldebug(lseek)) 19872543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 19983221Smarcel args->fdes, (long)args->off, args->whence); 2009313Ssos#endif 20112858Speter tmp_args.fd = args->fdes; 20212858Speter tmp_args.offset = (off_t)args->off; 2039313Ssos tmp_args.whence = args->whence; 20483366Sjulian error = lseek(td, &tmp_args); 2059313Ssos return error; 2069313Ssos} 2079313Ssos 20814331Speterint 20983366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 21014331Speter{ 21114331Speter struct lseek_args bsd_args; 21214331Speter int error; 21314331Speter off_t off; 21414331Speter 21514331Speter#ifdef DEBUG 21672543Sjlemon if (ldebug(llseek)) 21772543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 21872543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 21914331Speter#endif 22014331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 22114331Speter 22214331Speter bsd_args.fd = args->fd; 22314331Speter bsd_args.offset = off; 22414331Speter bsd_args.whence = args->whence; 22514331Speter 22683366Sjulian if ((error = lseek(td, &bsd_args))) 22714331Speter return error; 22814331Speter 229111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 23014331Speter return error; 23114331Speter 23283366Sjulian td->td_retval[0] = 0; 23314331Speter return 0; 23414331Speter} 23514331Speter 2369313Ssosint 23783366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args) 2389313Ssos{ 23914331Speter struct linux_getdents_args lda; 24014331Speter 24114331Speter lda.fd = args->fd; 24214331Speter lda.dent = args->dent; 24314331Speter lda.count = 1; 24483366Sjulian return linux_getdents(td, &lda); 24514331Speter} 24614331Speter 24783221Smarcel/* 24883221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 24983221Smarcel * arguments. They only differ in the definition of struct dirent they 25083221Smarcel * operate on. We use this to common the code, with the exception of 25183221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented 25283221Smarcel * by means of linux_getdents(2). In this case we never operate on 25383221Smarcel * struct dirent64 and thus don't need to handle it... 25483221Smarcel */ 25583221Smarcel 25683221Smarcelstruct l_dirent { 25783221Smarcel l_long d_ino; 25883221Smarcel l_off_t d_off; 25983221Smarcel l_ushort d_reclen; 26083221Smarcel char d_name[LINUX_NAME_MAX + 1]; 26183221Smarcel}; 26283221Smarcel 26383221Smarcelstruct l_dirent64 { 26483221Smarcel uint64_t d_ino; 26583221Smarcel int64_t d_off; 26683221Smarcel l_ushort d_reclen; 26783221Smarcel u_char d_type; 26883221Smarcel char d_name[LINUX_NAME_MAX + 1]; 26983221Smarcel}; 27083221Smarcel 27183221Smarcel#define LINUX_RECLEN(de,namlen) \ 27283221Smarcel ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 27383221Smarcel 27483221Smarcel#define LINUX_DIRBLKSIZ 512 27583221Smarcel 27683221Smarcelstatic int 27783366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args, 27883221Smarcel int is64bit) 27914331Speter{ 280111798Sdes struct dirent *bdp; 28183221Smarcel struct vnode *vp; 28283221Smarcel caddr_t inp, buf; /* BSD-format */ 28383221Smarcel int len, reclen; /* BSD-format */ 28483221Smarcel caddr_t outp; /* Linux-format */ 28583221Smarcel int resid, linuxreclen=0; /* Linux-format */ 28683221Smarcel struct file *fp; 28783221Smarcel struct uio auio; 28883221Smarcel struct iovec aiov; 28983221Smarcel off_t off; 29083221Smarcel struct l_dirent linux_dirent; 29183221Smarcel struct l_dirent64 linux_dirent64; 29283221Smarcel int buflen, error, eofflag, nbytes, justone; 29383221Smarcel u_long *cookies = NULL, *cookiep; 294160276Sjhb int ncookies, vfslocked; 2959313Ssos 296160276Sjhb nbytes = args->count; 297160276Sjhb if (nbytes == 1) { 298160276Sjhb /* readdir(2) case. Always struct dirent. */ 299160276Sjhb if (is64bit) 300160276Sjhb return (EINVAL); 301160276Sjhb nbytes = sizeof(linux_dirent); 302160276Sjhb justone = 1; 303160276Sjhb } else 304160276Sjhb justone = 0; 305160276Sjhb 30683366Sjulian if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 30783221Smarcel return (error); 3089313Ssos 30989306Salfred if ((fp->f_flag & FREAD) == 0) { 31089306Salfred fdrop(fp, td); 31183221Smarcel return (EBADF); 31289306Salfred } 3139313Ssos 314116678Sphk vp = fp->f_vnode; 315160276Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 31689306Salfred if (vp->v_type != VDIR) { 317160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 31889306Salfred fdrop(fp, td); 31983221Smarcel return (EINVAL); 32089306Salfred } 3219313Ssos 32283221Smarcel off = fp->f_offset; 3239313Ssos 32483221Smarcel buflen = max(LINUX_DIRBLKSIZ, nbytes); 32583221Smarcel buflen = min(buflen, MAXBSIZE); 326111119Simp buf = malloc(buflen, M_TEMP, M_WAITOK); 32783366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 32883221Smarcel 3299313Ssosagain: 33083221Smarcel aiov.iov_base = buf; 33183221Smarcel aiov.iov_len = buflen; 33283221Smarcel auio.uio_iov = &aiov; 33383221Smarcel auio.uio_iovcnt = 1; 33483221Smarcel auio.uio_rw = UIO_READ; 33583221Smarcel auio.uio_segflg = UIO_SYSSPACE; 33683366Sjulian auio.uio_td = td; 33783221Smarcel auio.uio_resid = buflen; 33883221Smarcel auio.uio_offset = off; 3399313Ssos 34083221Smarcel if (cookies) { 34183221Smarcel free(cookies, M_TEMP); 34283221Smarcel cookies = NULL; 34383221Smarcel } 34424654Sdfr 345101189Srwatson#ifdef MAC 346101189Srwatson /* 347101189Srwatson * Do directory search MAC check using non-cached credentials. 348101189Srwatson */ 349112451Sjhb if ((error = mac_check_vnode_readdir(td->td_ucred, vp))) 350101189Srwatson goto out; 351101189Srwatson#endif /* MAC */ 35283221Smarcel if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 35383221Smarcel &cookies))) 35483221Smarcel goto out; 3559313Ssos 35683221Smarcel inp = buf; 35783221Smarcel outp = (caddr_t)args->dirent; 35883221Smarcel resid = nbytes; 35983221Smarcel if ((len = buflen - auio.uio_resid) <= 0) 36083221Smarcel goto eof; 3619313Ssos 36283221Smarcel cookiep = cookies; 36324654Sdfr 36483221Smarcel if (cookies) { 36583221Smarcel /* 36683221Smarcel * When using cookies, the vfs has the option of reading from 36783221Smarcel * a different offset than that supplied (UFS truncates the 36883221Smarcel * offset to a block boundary to make sure that it never reads 36983221Smarcel * partway through a directory entry, even if the directory 37083221Smarcel * has been compacted). 37183221Smarcel */ 37283221Smarcel while (len > 0 && ncookies > 0 && *cookiep <= off) { 37383221Smarcel bdp = (struct dirent *) inp; 37483221Smarcel len -= bdp->d_reclen; 37583221Smarcel inp += bdp->d_reclen; 37683221Smarcel cookiep++; 37783221Smarcel ncookies--; 37883221Smarcel } 37924654Sdfr } 38024654Sdfr 38183221Smarcel while (len > 0) { 38283221Smarcel if (cookiep && ncookies == 0) 38383221Smarcel break; 38483221Smarcel bdp = (struct dirent *) inp; 38583221Smarcel reclen = bdp->d_reclen; 38683221Smarcel if (reclen & 3) { 38783221Smarcel error = EFAULT; 38883221Smarcel goto out; 38983221Smarcel } 39083221Smarcel 39183221Smarcel if (bdp->d_fileno == 0) { 39283221Smarcel inp += reclen; 39383221Smarcel if (cookiep) { 39483221Smarcel off = *cookiep++; 39583221Smarcel ncookies--; 39683221Smarcel } else 39783221Smarcel off += reclen; 39883221Smarcel 39983221Smarcel len -= reclen; 40083221Smarcel continue; 40183221Smarcel } 40283221Smarcel 40383221Smarcel linuxreclen = (is64bit) 40483221Smarcel ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) 40583221Smarcel : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 40683221Smarcel 40783221Smarcel if (reclen > len || resid < linuxreclen) { 40883221Smarcel outp++; 40983221Smarcel break; 41083221Smarcel } 41183221Smarcel 41283221Smarcel if (justone) { 41383221Smarcel /* readdir(2) case. */ 41483221Smarcel linux_dirent.d_ino = (l_long)bdp->d_fileno; 41583221Smarcel linux_dirent.d_off = (l_off_t)linuxreclen; 41683221Smarcel linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 41783221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 41883221Smarcel error = copyout(&linux_dirent, outp, linuxreclen); 41983221Smarcel } else { 42083221Smarcel if (is64bit) { 42183221Smarcel linux_dirent64.d_ino = bdp->d_fileno; 42283221Smarcel linux_dirent64.d_off = (cookiep) 42383221Smarcel ? (l_off_t)*cookiep 42483221Smarcel : (l_off_t)(off + reclen); 42583221Smarcel linux_dirent64.d_reclen = 42683221Smarcel (l_ushort)linuxreclen; 42783221Smarcel linux_dirent64.d_type = bdp->d_type; 42883221Smarcel strcpy(linux_dirent64.d_name, bdp->d_name); 42983221Smarcel error = copyout(&linux_dirent64, outp, 43083221Smarcel linuxreclen); 43183221Smarcel } else { 43283221Smarcel linux_dirent.d_ino = bdp->d_fileno; 43383221Smarcel linux_dirent.d_off = (cookiep) 43483221Smarcel ? (l_off_t)*cookiep 43583221Smarcel : (l_off_t)(off + reclen); 43683221Smarcel linux_dirent.d_reclen = (l_ushort)linuxreclen; 43783221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 43883221Smarcel error = copyout(&linux_dirent, outp, 43983221Smarcel linuxreclen); 44083221Smarcel } 44183221Smarcel } 44283221Smarcel if (error) 44383221Smarcel goto out; 44483221Smarcel 44583221Smarcel inp += reclen; 44683221Smarcel if (cookiep) { 44783221Smarcel off = *cookiep++; 44883221Smarcel ncookies--; 44983221Smarcel } else 45083221Smarcel off += reclen; 45183221Smarcel 45283221Smarcel outp += linuxreclen; 45383221Smarcel resid -= linuxreclen; 45483221Smarcel len -= reclen; 45583221Smarcel if (justone) 45683221Smarcel break; 45710355Sswallace } 4589313Ssos 45983221Smarcel if (outp == (caddr_t)args->dirent) 46083221Smarcel goto again; 4619313Ssos 46283221Smarcel fp->f_offset = off; 46383221Smarcel if (justone) 46483221Smarcel nbytes = resid + linuxreclen; 46510355Sswallace 4669313Ssoseof: 46783366Sjulian td->td_retval[0] = nbytes - resid; 46883221Smarcel 4699313Ssosout: 47083221Smarcel if (cookies) 47183221Smarcel free(cookies, M_TEMP); 47283221Smarcel 47383366Sjulian VOP_UNLOCK(vp, 0, td); 474160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 47589306Salfred fdrop(fp, td); 47683221Smarcel free(buf, M_TEMP); 47783221Smarcel return (error); 4789313Ssos} 47914331Speter 48083221Smarcelint 48183366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args) 48283221Smarcel{ 48383221Smarcel 48483221Smarcel#ifdef DEBUG 48583221Smarcel if (ldebug(getdents)) 48683221Smarcel printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 48783221Smarcel#endif 48883221Smarcel 48983366Sjulian return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 49083221Smarcel} 49183221Smarcel 49283221Smarcelint 49383366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 49483221Smarcel{ 49583221Smarcel 49683221Smarcel#ifdef DEBUG 49783221Smarcel if (ldebug(getdents64)) 49883221Smarcel printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 49983221Smarcel#endif 50083221Smarcel 50183366Sjulian return (getdents_common(td, args, 1)); 50283221Smarcel} 50383221Smarcel 50414331Speter/* 50514331Speter * These exist mainly for hooks for doing /compat/linux translation. 50614331Speter */ 50714331Speter 50814331Speterint 50983366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 51014331Speter{ 511102814Siedowse char *path; 512102814Siedowse int error; 51314331Speter 514162585Snetchild /* linux convention */ 515162585Snetchild if (args->flags & ~(F_OK | X_OK | W_OK | R_OK)) 516162585Snetchild return (EINVAL); 517162585Snetchild 518102814Siedowse LCONVPATHEXIST(td, args->path, &path); 51914331Speter 52014331Speter#ifdef DEBUG 52172543Sjlemon if (ldebug(access)) 522102814Siedowse printf(ARGS(access, "%s, %d"), path, args->flags); 52314331Speter#endif 524102814Siedowse error = kern_access(td, path, UIO_SYSSPACE, args->flags); 525102814Siedowse LFREEPATH(path); 526162585Snetchild 527102814Siedowse return (error); 52814331Speter} 52914331Speter 53014331Speterint 53183366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 53214331Speter{ 533102814Siedowse char *path; 534102814Siedowse int error; 535162201Snetchild struct stat st; 53614331Speter 537102814Siedowse LCONVPATHEXIST(td, args->path, &path); 53814331Speter 53914331Speter#ifdef DEBUG 54072543Sjlemon if (ldebug(unlink)) 541102814Siedowse printf(ARGS(unlink, "%s"), path); 54214331Speter#endif 54314331Speter 544102814Siedowse error = kern_unlink(td, path, UIO_SYSSPACE); 545162201Snetchild if (error == EPERM) 546162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 547162201Snetchild if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 548162201Snetchild if (S_ISDIR(st.st_mode)) 549162201Snetchild error = EISDIR; 550102814Siedowse LFREEPATH(path); 551102814Siedowse return (error); 55214331Speter} 55314331Speter 55414331Speterint 55583366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 55614331Speter{ 557102814Siedowse char *path; 558102814Siedowse int error; 55914331Speter 560102814Siedowse LCONVPATHEXIST(td, args->path, &path); 56114331Speter 56214331Speter#ifdef DEBUG 56372543Sjlemon if (ldebug(chdir)) 564102814Siedowse printf(ARGS(chdir, "%s"), path); 56514331Speter#endif 566102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 567102814Siedowse LFREEPATH(path); 568102814Siedowse return (error); 56914331Speter} 57014331Speter 57114331Speterint 57283366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 57314331Speter{ 574102814Siedowse char *path; 575102814Siedowse int error; 57614331Speter 577102814Siedowse LCONVPATHEXIST(td, args->path, &path); 57814331Speter 57914331Speter#ifdef DEBUG 58072543Sjlemon if (ldebug(chmod)) 581102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 58214331Speter#endif 583102814Siedowse error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 584102814Siedowse LFREEPATH(path); 585102814Siedowse return (error); 58614331Speter} 58714331Speter 58814331Speterint 58983366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 59014331Speter{ 591102814Siedowse char *path; 592102814Siedowse int error; 59314331Speter 594102814Siedowse LCONVPATHCREAT(td, args->path, &path); 59514331Speter 59614331Speter#ifdef DEBUG 59772543Sjlemon if (ldebug(mkdir)) 598102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 59914331Speter#endif 600102814Siedowse error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 601102814Siedowse LFREEPATH(path); 602102814Siedowse return (error); 60314331Speter} 60414331Speter 60514331Speterint 60683366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 60714331Speter{ 608102814Siedowse char *path; 609102814Siedowse int error; 61014331Speter 611102814Siedowse LCONVPATHEXIST(td, args->path, &path); 61214331Speter 61314331Speter#ifdef DEBUG 61472543Sjlemon if (ldebug(rmdir)) 615102814Siedowse printf(ARGS(rmdir, "%s"), path); 61614331Speter#endif 617102814Siedowse error = kern_rmdir(td, path, UIO_SYSSPACE); 618102814Siedowse LFREEPATH(path); 619102814Siedowse return (error); 62014331Speter} 62114331Speter 62214331Speterint 62383366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 62414331Speter{ 625102814Siedowse char *from, *to; 626102814Siedowse int error; 62714331Speter 628102814Siedowse LCONVPATHEXIST(td, args->from, &from); 629102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 630102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 631102814Siedowse if (to == NULL) { 632102814Siedowse LFREEPATH(from); 633102814Siedowse return (error); 634102814Siedowse } 63514331Speter 63614331Speter#ifdef DEBUG 63772543Sjlemon if (ldebug(rename)) 638102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 63914331Speter#endif 640102814Siedowse error = kern_rename(td, from, to, UIO_SYSSPACE); 641102814Siedowse LFREEPATH(from); 642102814Siedowse LFREEPATH(to); 643102814Siedowse return (error); 64414331Speter} 64514331Speter 64614331Speterint 64783366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 64814331Speter{ 649102814Siedowse char *path, *to; 650102814Siedowse int error; 65114331Speter 652102814Siedowse LCONVPATHEXIST(td, args->path, &path); 653102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 654102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 655102814Siedowse if (to == NULL) { 656102814Siedowse LFREEPATH(path); 657102814Siedowse return (error); 658102814Siedowse } 65914331Speter 66014331Speter#ifdef DEBUG 66172543Sjlemon if (ldebug(symlink)) 662102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 66314331Speter#endif 664102814Siedowse error = kern_symlink(td, path, to, UIO_SYSSPACE); 665102814Siedowse LFREEPATH(path); 666102814Siedowse LFREEPATH(to); 667102814Siedowse return (error); 66814331Speter} 66914331Speter 67014331Speterint 67183366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 67214331Speter{ 673102814Siedowse char *name; 674102814Siedowse int error; 67514331Speter 676102814Siedowse LCONVPATHEXIST(td, args->name, &name); 67714331Speter 67814331Speter#ifdef DEBUG 67972543Sjlemon if (ldebug(readlink)) 680102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 681102814Siedowse args->count); 68214331Speter#endif 683102814Siedowse error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 684102814Siedowse args->count); 685102814Siedowse LFREEPATH(name); 686102814Siedowse return (error); 68714331Speter} 68814331Speter 68914331Speterint 69083366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 69114331Speter{ 692102814Siedowse char *path; 693102814Siedowse int error; 69414331Speter 695102814Siedowse LCONVPATHEXIST(td, args->path, &path); 69614331Speter 69714331Speter#ifdef DEBUG 69872543Sjlemon if (ldebug(truncate)) 699102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 70014331Speter#endif 70114331Speter 702102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 703102814Siedowse LFREEPATH(path); 704102814Siedowse return (error); 70514331Speter} 70614331Speter 70749662Smarcelint 708156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 709156842Snetchild{ 710156842Snetchild struct ftruncate_args /* { 711156842Snetchild int fd; 712156842Snetchild int pad; 713156842Snetchild off_t length; 714156842Snetchild } */ nuap; 715156842Snetchild 716156842Snetchild nuap.fd = args->fd; 717156842Snetchild nuap.pad = 0; 718156842Snetchild nuap.length = args->length; 719156842Snetchild return (ftruncate(td, &nuap)); 720156842Snetchild} 721156842Snetchild 722156842Snetchildint 72383366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 72449662Smarcel{ 725102814Siedowse char *path, *to; 726102814Siedowse int error; 72749662Smarcel 728102814Siedowse LCONVPATHEXIST(td, args->path, &path); 729102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 730102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 731102814Siedowse if (to == NULL) { 732102814Siedowse LFREEPATH(path); 733102814Siedowse return (error); 734102814Siedowse } 73549662Smarcel 73649662Smarcel#ifdef DEBUG 73772543Sjlemon if (ldebug(link)) 738102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 73949662Smarcel#endif 740102814Siedowse error = kern_link(td, path, to, UIO_SYSSPACE); 741102814Siedowse LFREEPATH(path); 742102814Siedowse LFREEPATH(to); 743102814Siedowse return (error); 74449662Smarcel} 74549788Smarcel 74653713Smarcelint 74783366Sjulianlinux_fdatasync(td, uap) 74883366Sjulian struct thread *td; 74953713Smarcel struct linux_fdatasync_args *uap; 75053713Smarcel{ 75153713Smarcel struct fsync_args bsd; 75253713Smarcel 75353713Smarcel bsd.fd = uap->fd; 75483366Sjulian return fsync(td, &bsd); 75553713Smarcel} 75663285Smarcel 75763285Smarcelint 75883366Sjulianlinux_pread(td, uap) 75983366Sjulian struct thread *td; 76063285Smarcel struct linux_pread_args *uap; 76163285Smarcel{ 76263285Smarcel struct pread_args bsd; 763162585Snetchild struct vnode *vp; 764162585Snetchild int error; 76563285Smarcel 76663285Smarcel bsd.fd = uap->fd; 76763285Smarcel bsd.buf = uap->buf; 76863285Smarcel bsd.nbyte = uap->nbyte; 76963285Smarcel bsd.offset = uap->offset; 770162585Snetchild 771162585Snetchild error = pread(td, &bsd); 772162585Snetchild 773162585Snetchild if (error == 0) { 774162585Snetchild /* This seems to violate POSIX but linux does it */ 775162585Snetchild if ((error = fgetvp(td, uap->fd, &vp)) != 0) 776162585Snetchild return (error); 777162585Snetchild if (vp->v_type == VDIR) { 778162585Snetchild vrele(vp); 779162585Snetchild return (EISDIR); 780162585Snetchild } 781162585Snetchild vrele(vp); 782162585Snetchild } 783162585Snetchild 784162585Snetchild return (error); 78563285Smarcel} 78663285Smarcel 78763285Smarcelint 78883366Sjulianlinux_pwrite(td, uap) 78983366Sjulian struct thread *td; 79063285Smarcel struct linux_pwrite_args *uap; 79163285Smarcel{ 79263285Smarcel struct pwrite_args bsd; 79363285Smarcel 79463285Smarcel bsd.fd = uap->fd; 79563285Smarcel bsd.buf = uap->buf; 79663285Smarcel bsd.nbyte = uap->nbyte; 79763285Smarcel bsd.offset = uap->offset; 79883366Sjulian return pwrite(td, &bsd); 79963285Smarcel} 80072538Sjlemon 80172538Sjlemonint 80283366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 80372538Sjlemon{ 80472538Sjlemon struct ufs_args ufs; 805111798Sdes char fstypename[MFSNAMELEN]; 806111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 80773286Sadrian int error; 80873286Sadrian int fsflags; 80973286Sadrian void *fsdata; 81072538Sjlemon 811111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 81273286Sadrian NULL); 81372538Sjlemon if (error) 814111798Sdes return (error); 815127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 81672538Sjlemon if (error) 817111798Sdes return (error); 818127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 81972538Sjlemon if (error) 820111798Sdes return (error); 82172538Sjlemon 82272538Sjlemon#ifdef DEBUG 82372538Sjlemon if (ldebug(mount)) 82472538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 82572538Sjlemon fstypename, mntfromname, mntonname); 82672538Sjlemon#endif 82772538Sjlemon 82872538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 829127059Stjr strcpy(fstypename, "ext2fs"); 83073286Sadrian fsdata = &ufs; 83172538Sjlemon ufs.fspec = mntfromname; 83272538Sjlemon#define DEFAULT_ROOTID -2 83372538Sjlemon ufs.export.ex_root = DEFAULT_ROOTID; 83472538Sjlemon ufs.export.ex_flags = 83572538Sjlemon args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 83672538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 837127059Stjr strcpy(fstypename, "linprocfs"); 83873286Sadrian fsdata = NULL; 83972538Sjlemon } else { 84072538Sjlemon return (ENODEV); 84172538Sjlemon } 84272538Sjlemon 84373286Sadrian fsflags = 0; 84472538Sjlemon 84572538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 84672538Sjlemon /* 84772538Sjlemon * Linux SYNC flag is not included; the closest equivalent 84872538Sjlemon * FreeBSD has is !ASYNC, which is our default. 84972538Sjlemon */ 85072538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 851111798Sdes fsflags |= MNT_RDONLY; 85272538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 853111798Sdes fsflags |= MNT_NOSUID; 85472538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 855111798Sdes fsflags |= MNT_NOEXEC; 85672538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 857111798Sdes fsflags |= MNT_UPDATE; 85872538Sjlemon } 85972538Sjlemon 860127059Stjr if (strcmp(fstypename, "linprocfs") == 0) { 861132708Sphk error = kernel_vmount(fsflags, 862132708Sphk "fstype", fstypename, 863132708Sphk "fspath", mntonname, 864132708Sphk NULL); 865127059Stjr } else 866138353Sphk error = EOPNOTSUPP; 867127059Stjr return (error); 86872538Sjlemon} 86972538Sjlemon 87072538Sjlemonint 87183366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 87272538Sjlemon{ 87383221Smarcel struct linux_umount_args args2; 87472538Sjlemon 87572538Sjlemon args2.path = args->path; 87672538Sjlemon args2.flags = 0; 87783366Sjulian return (linux_umount(td, &args2)); 87872538Sjlemon} 87972538Sjlemon 88072538Sjlemonint 88183366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 88272538Sjlemon{ 88372538Sjlemon struct unmount_args bsd; 88472538Sjlemon 88572538Sjlemon bsd.path = args->path; 88672538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 88783366Sjulian return (unmount(td, &bsd)); 88872538Sjlemon} 88983221Smarcel 89083221Smarcel/* 89183221Smarcel * fcntl family of syscalls 89283221Smarcel */ 89383221Smarcel 89483221Smarcelstruct l_flock { 89583221Smarcel l_short l_type; 89683221Smarcel l_short l_whence; 89783221Smarcel l_off_t l_start; 89883221Smarcel l_off_t l_len; 89983221Smarcel l_pid_t l_pid; 900133816Stjr} 901140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 902133816Stjr__packed 903133816Stjr#endif 904133816Stjr; 90583221Smarcel 90683221Smarcelstatic void 90783221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 90883221Smarcel{ 90983221Smarcel switch (linux_flock->l_type) { 91083221Smarcel case LINUX_F_RDLCK: 91183221Smarcel bsd_flock->l_type = F_RDLCK; 91283221Smarcel break; 91383221Smarcel case LINUX_F_WRLCK: 91483221Smarcel bsd_flock->l_type = F_WRLCK; 91583221Smarcel break; 91683221Smarcel case LINUX_F_UNLCK: 91783221Smarcel bsd_flock->l_type = F_UNLCK; 91883221Smarcel break; 91983221Smarcel default: 92083221Smarcel bsd_flock->l_type = -1; 92183221Smarcel break; 92283221Smarcel } 92383221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 92483221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 92583221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 92683221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 92783221Smarcel} 92883221Smarcel 92983221Smarcelstatic void 93083221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 93183221Smarcel{ 93283221Smarcel switch (bsd_flock->l_type) { 93383221Smarcel case F_RDLCK: 93483221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 93583221Smarcel break; 93683221Smarcel case F_WRLCK: 93783221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 93883221Smarcel break; 93983221Smarcel case F_UNLCK: 94083221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 94183221Smarcel break; 94283221Smarcel } 94383221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 94483221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 94583221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 94683221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 94783221Smarcel} 94883221Smarcel 949140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 95083221Smarcelstruct l_flock64 { 95183221Smarcel l_short l_type; 95283221Smarcel l_short l_whence; 95383221Smarcel l_loff_t l_start; 95483221Smarcel l_loff_t l_len; 95583221Smarcel l_pid_t l_pid; 956133816Stjr} 957140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 958133816Stjr__packed 959133816Stjr#endif 960133816Stjr; 96183221Smarcel 96283221Smarcelstatic void 96383221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 96483221Smarcel{ 96583221Smarcel switch (linux_flock->l_type) { 96683221Smarcel case LINUX_F_RDLCK: 96783221Smarcel bsd_flock->l_type = F_RDLCK; 96883221Smarcel break; 96983221Smarcel case LINUX_F_WRLCK: 97083221Smarcel bsd_flock->l_type = F_WRLCK; 97183221Smarcel break; 97283221Smarcel case LINUX_F_UNLCK: 97383221Smarcel bsd_flock->l_type = F_UNLCK; 97483221Smarcel break; 97583221Smarcel default: 97683221Smarcel bsd_flock->l_type = -1; 97783221Smarcel break; 97883221Smarcel } 97983221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 98083221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 98183221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 98283221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 98383221Smarcel} 98483221Smarcel 98583221Smarcelstatic void 98683221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 98783221Smarcel{ 98883221Smarcel switch (bsd_flock->l_type) { 98983221Smarcel case F_RDLCK: 99083221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 99183221Smarcel break; 99283221Smarcel case F_WRLCK: 99383221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 99483221Smarcel break; 99583221Smarcel case F_UNLCK: 99683221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 99783221Smarcel break; 99883221Smarcel } 99983221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 100083221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 100183221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 100283221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 100383221Smarcel} 1004133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 100583221Smarcel 100683221Smarcelstatic int 100783366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args) 100883221Smarcel{ 1009107680Siedowse struct l_flock linux_flock; 1010107680Siedowse struct flock bsd_flock; 101183221Smarcel struct file *fp; 1012102872Siedowse long arg; 101383221Smarcel int error, result; 101483221Smarcel 101583221Smarcel switch (args->cmd) { 101683221Smarcel case LINUX_F_DUPFD: 1017102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 101883221Smarcel 101983221Smarcel case LINUX_F_GETFD: 1020102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 102183221Smarcel 102283221Smarcel case LINUX_F_SETFD: 1023102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 102483221Smarcel 102583221Smarcel case LINUX_F_GETFL: 1026102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 102783366Sjulian result = td->td_retval[0]; 102883366Sjulian td->td_retval[0] = 0; 102983221Smarcel if (result & O_RDONLY) 103083366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 103183221Smarcel if (result & O_WRONLY) 103283366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 103383221Smarcel if (result & O_RDWR) 103483366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 103583221Smarcel if (result & O_NDELAY) 103683366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 103783221Smarcel if (result & O_APPEND) 103883366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 103983221Smarcel if (result & O_FSYNC) 104083366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 104183221Smarcel if (result & O_ASYNC) 104283366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1043144987Smdodd#ifdef LINUX_O_NOFOLLOW 1044144987Smdodd if (result & O_NOFOLLOW) 1045144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1046144987Smdodd#endif 1047144987Smdodd#ifdef LINUX_O_DIRECT 1048144987Smdodd if (result & O_DIRECT) 1049144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1050144987Smdodd#endif 105183221Smarcel return (error); 105283221Smarcel 105383221Smarcel case LINUX_F_SETFL: 1054102872Siedowse arg = 0; 105583221Smarcel if (args->arg & LINUX_O_NDELAY) 1056102872Siedowse arg |= O_NONBLOCK; 105783221Smarcel if (args->arg & LINUX_O_APPEND) 1058102872Siedowse arg |= O_APPEND; 105983221Smarcel if (args->arg & LINUX_O_SYNC) 1060102872Siedowse arg |= O_FSYNC; 106183221Smarcel if (args->arg & LINUX_FASYNC) 1062102872Siedowse arg |= O_ASYNC; 1063144987Smdodd#ifdef LINUX_O_NOFOLLOW 1064144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1065144987Smdodd arg |= O_NOFOLLOW; 1066144987Smdodd#endif 1067144987Smdodd#ifdef LINUX_O_DIRECT 1068144987Smdodd if (args->arg & LINUX_O_DIRECT) 1069144987Smdodd arg |= O_DIRECT; 1070144987Smdodd#endif 1071102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 107283221Smarcel 1073107680Siedowse case LINUX_F_GETLK: 1074111797Sdes error = copyin((void *)args->arg, &linux_flock, 1075107680Siedowse sizeof(linux_flock)); 1076107680Siedowse if (error) 1077107680Siedowse return (error); 1078107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1079107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1080107680Siedowse if (error) 1081107680Siedowse return (error); 1082107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1083111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1084107680Siedowse sizeof(linux_flock))); 1085107680Siedowse 1086107680Siedowse case LINUX_F_SETLK: 1087111797Sdes error = copyin((void *)args->arg, &linux_flock, 1088107680Siedowse sizeof(linux_flock)); 1089107680Siedowse if (error) 1090107680Siedowse return (error); 1091107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1092107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1093107680Siedowse (intptr_t)&bsd_flock)); 1094107680Siedowse 1095107680Siedowse case LINUX_F_SETLKW: 1096111797Sdes error = copyin((void *)args->arg, &linux_flock, 1097107680Siedowse sizeof(linux_flock)); 1098107680Siedowse if (error) 1099107680Siedowse return (error); 1100107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1101107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1102107680Siedowse (intptr_t)&bsd_flock)); 1103107680Siedowse 110483221Smarcel case LINUX_F_GETOWN: 1105102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 110683221Smarcel 110783221Smarcel case LINUX_F_SETOWN: 110883221Smarcel /* 110983221Smarcel * XXX some Linux applications depend on F_SETOWN having no 111083221Smarcel * significant effect for pipes (SIGIO is not delivered for 111183221Smarcel * pipes under Linux-2.2.35 at least). 111283221Smarcel */ 111389319Salfred error = fget(td, args->fd, &fp); 111489319Salfred if (error) 111589319Salfred return (error); 111689306Salfred if (fp->f_type == DTYPE_PIPE) { 111789306Salfred fdrop(fp, td); 111883221Smarcel return (EINVAL); 111989306Salfred } 112089306Salfred fdrop(fp, td); 112183221Smarcel 1122102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 112383221Smarcel } 112483221Smarcel 112583221Smarcel return (EINVAL); 112683221Smarcel} 112783221Smarcel 112883221Smarcelint 112983366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 113083221Smarcel{ 113183221Smarcel struct linux_fcntl64_args args64; 113283221Smarcel 113383221Smarcel#ifdef DEBUG 113483221Smarcel if (ldebug(fcntl)) 113583221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 113683221Smarcel#endif 113783221Smarcel 113883221Smarcel args64.fd = args->fd; 113983221Smarcel args64.cmd = args->cmd; 114083221Smarcel args64.arg = args->arg; 114183366Sjulian return (fcntl_common(td, &args64)); 114283221Smarcel} 114383221Smarcel 1144140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 114583221Smarcelint 114683366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 114783221Smarcel{ 114883221Smarcel struct l_flock64 linux_flock; 1149102872Siedowse struct flock bsd_flock; 115083221Smarcel int error; 115183221Smarcel 115283221Smarcel#ifdef DEBUG 115383221Smarcel if (ldebug(fcntl64)) 115483221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 115583221Smarcel#endif 115683221Smarcel 115783221Smarcel switch (args->cmd) { 115899687Srobert case LINUX_F_GETLK64: 1159111797Sdes error = copyin((void *)args->arg, &linux_flock, 116083221Smarcel sizeof(linux_flock)); 116183221Smarcel if (error) 116283221Smarcel return (error); 1163102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1164102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 116583221Smarcel if (error) 116683221Smarcel return (error); 1167102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1168111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1169111797Sdes sizeof(linux_flock))); 117083221Smarcel 117199687Srobert case LINUX_F_SETLK64: 1172111797Sdes error = copyin((void *)args->arg, &linux_flock, 117383221Smarcel sizeof(linux_flock)); 117483221Smarcel if (error) 117583221Smarcel return (error); 1176102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1177102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1178102872Siedowse (intptr_t)&bsd_flock)); 117983221Smarcel 118099687Srobert case LINUX_F_SETLKW64: 1181111797Sdes error = copyin((void *)args->arg, &linux_flock, 118283221Smarcel sizeof(linux_flock)); 118383221Smarcel if (error) 118483221Smarcel return (error); 1185102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1186102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1187102872Siedowse (intptr_t)&bsd_flock)); 118883221Smarcel } 118983221Smarcel 119083366Sjulian return (fcntl_common(td, args)); 119183221Smarcel} 1192133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 119385022Smarcel 119485022Smarcelint 119585022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 119685022Smarcel{ 1197102814Siedowse char *path; 1198102814Siedowse int error; 119985022Smarcel 1200102814Siedowse LCONVPATHEXIST(td, args->path, &path); 120185022Smarcel 120285022Smarcel#ifdef DEBUG 120385022Smarcel if (ldebug(chown)) 1204102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 120585022Smarcel#endif 1206102814Siedowse error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1207102814Siedowse LFREEPATH(path); 1208102814Siedowse return (error); 120985022Smarcel} 121085022Smarcel 121185022Smarcelint 121285022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 121385022Smarcel{ 1214102814Siedowse char *path; 1215102814Siedowse int error; 121685022Smarcel 1217102814Siedowse LCONVPATHEXIST(td, args->path, &path); 121885022Smarcel 121985022Smarcel#ifdef DEBUG 122085022Smarcel if (ldebug(lchown)) 1221102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 122285022Smarcel#endif 1223102814Siedowse error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1224102814Siedowse LFREEPATH(path); 1225102814Siedowse return (error); 122685022Smarcel} 1227