linux_file.c revision 172930
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 172930 2007-10-24 19:04:04Z rwatson $"); 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> 46168014Sjulian#include <sys/namei.h> 4776166Smarkm#include <sys/proc.h> 48162201Snetchild#include <sys/stat.h> 49166085Skib#include <sys/sx.h> 50102814Siedowse#include <sys/syscallsubr.h> 5176166Smarkm#include <sys/sysproto.h> 5214331Speter#include <sys/tty.h> 53162585Snetchild#include <sys/unistd.h> 5476166Smarkm#include <sys/vnode.h> 5512458Sbde 56163606Srwatson#include <security/mac/mac_framework.h> 57163606Srwatson 5872538Sjlemon#include <ufs/ufs/extattr.h> 5972538Sjlemon#include <ufs/ufs/quota.h> 6072538Sjlemon#include <ufs/ufs/ufsmount.h> 6172538Sjlemon 62140214Sobrien#ifdef COMPAT_LINUX32 63140214Sobrien#include <machine/../linux32/linux.h> 64140214Sobrien#include <machine/../linux32/linux32_proto.h> 65140214Sobrien#else 6664905Smarcel#include <machine/../linux/linux.h> 6768583Smarcel#include <machine/../linux/linux_proto.h> 68133816Stjr#endif 6964905Smarcel#include <compat/linux/linux_util.h> 709313Ssos 719313Ssosint 7283366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 739313Ssos{ 74102814Siedowse char *path; 75102814Siedowse int error; 769313Ssos 77102814Siedowse LCONVPATHEXIST(td, args->path, &path); 7814331Speter 799313Ssos#ifdef DEBUG 8072543Sjlemon if (ldebug(creat)) 81102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 829313Ssos#endif 83102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 84102814Siedowse args->mode); 85102814Siedowse LFREEPATH(path); 86102814Siedowse return (error); 879313Ssos} 889313Ssos 89168014Sjulian 90168014Sjulianstatic int 91168014Sjulianlinux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat) 929313Ssos{ 9383382Sjhb struct proc *p = td->td_proc; 94166085Skib struct file *fp; 95166085Skib int fd; 96102814Siedowse int bsd_flags, error; 9714331Speter 98102814Siedowse bsd_flags = 0; 99168014Sjulian switch (l_flags & LINUX_O_ACCMODE) { 100168014Sjulian case LINUX_O_WRONLY: 101102814Siedowse bsd_flags |= O_WRONLY; 102168014Sjulian break; 103168014Sjulian case LINUX_O_RDWR: 104102814Siedowse bsd_flags |= O_RDWR; 105168014Sjulian break; 106168014Sjulian default: 107168014Sjulian bsd_flags |= O_RDONLY; 108168014Sjulian } 109168014Sjulian if (l_flags & LINUX_O_NDELAY) 110102814Siedowse bsd_flags |= O_NONBLOCK; 111168014Sjulian if (l_flags & LINUX_O_APPEND) 112102814Siedowse bsd_flags |= O_APPEND; 113168014Sjulian if (l_flags & LINUX_O_SYNC) 114102814Siedowse bsd_flags |= O_FSYNC; 115168014Sjulian if (l_flags & LINUX_O_NONBLOCK) 116102814Siedowse bsd_flags |= O_NONBLOCK; 117168014Sjulian if (l_flags & LINUX_FASYNC) 118102814Siedowse bsd_flags |= O_ASYNC; 119168014Sjulian if (l_flags & LINUX_O_CREAT) 120102814Siedowse bsd_flags |= O_CREAT; 121168014Sjulian if (l_flags & LINUX_O_TRUNC) 122102814Siedowse bsd_flags |= O_TRUNC; 123168014Sjulian if (l_flags & LINUX_O_EXCL) 124102814Siedowse bsd_flags |= O_EXCL; 125168014Sjulian if (l_flags & LINUX_O_NOCTTY) 126102814Siedowse bsd_flags |= O_NOCTTY; 127168014Sjulian if (l_flags & LINUX_O_DIRECT) 128166085Skib bsd_flags |= O_DIRECT; 129168014Sjulian if (l_flags & LINUX_O_NOFOLLOW) 130166085Skib bsd_flags |= O_NOFOLLOW; 131166085Skib /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1329313Ssos 133168014Sjulian error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode); 134166085Skib if (!error) { 135166085Skib fd = td->td_retval[0]; 136166085Skib /* 137166085Skib * XXX In between kern_open() and fget(), another process 138166085Skib * having the same filedesc could use that fd without 139166085Skib * checking below. 140166085Skib */ 141166085Skib error = fget(td, fd, &fp); 142166085Skib if (!error) { 143166085Skib sx_slock(&proctree_lock); 144166085Skib PROC_LOCK(p); 145166085Skib if (!(bsd_flags & O_NOCTTY) && 146166085Skib SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 147166085Skib PROC_UNLOCK(p); 148166085Skib sx_unlock(&proctree_lock); 149166085Skib if (fp->f_type == DTYPE_VNODE) 150166085Skib (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 151166085Skib td->td_ucred, td); 152166085Skib } else { 153166085Skib PROC_UNLOCK(p); 154166085Skib sx_sunlock(&proctree_lock); 155166085Skib } 156168014Sjulian if (l_flags & LINUX_O_DIRECTORY) { 157166085Skib if (fp->f_type != DTYPE_VNODE || 158166085Skib fp->f_vnode->v_type != VDIR) { 159166085Skib error = ENOTDIR; 160166085Skib } 161166085Skib } 162166085Skib fdrop(fp, td); 163166085Skib /* 164166085Skib * XXX as above, fdrop()/kern_close() pair is racy. 165166085Skib */ 166166085Skib if (error) 167166085Skib kern_close(td, fd); 168166085Skib } 169166085Skib } 1709313Ssos 17114331Speter#ifdef DEBUG 172166085Skib if (ldebug(open)) 173166085Skib printf(LMSG("open returns error %d"), error); 17414331Speter#endif 175168014Sjulian if (!openat) 176168014Sjulian LFREEPATH(path); 1779313Ssos return error; 1789313Ssos} 1799313Ssos 180168014Sjulian/* 181168014Sjulian * common code for linux *at set of syscalls 182168014Sjulian * 183168014Sjulian * works like this: 184168014Sjulian * if filename is absolute 185168014Sjulian * ignore dirfd 186168014Sjulian * else 187168014Sjulian * if dirfd == AT_FDCWD 188168014Sjulian * return CWD/filename 189168014Sjulian * else 190168014Sjulian * return DIRFD/filename 191168014Sjulian */ 192168014Sjulianstatic int 193168014Sjulianlinux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf) 194168014Sjulian{ 195168014Sjulian struct file *fp; 196168355Srwatson int error = 0, vfslocked; 197168014Sjulian struct vnode *dvp; 198168014Sjulian struct filedesc *fdp = td->td_proc->p_fd; 199168014Sjulian char *fullpath = "unknown"; 200168014Sjulian char *freepath = NULL; 201168014Sjulian 202168014Sjulian /* don't do anything if the pathname is absolute */ 203168014Sjulian if (*filename == '/') { 204168014Sjulian *newpath= filename; 205168014Sjulian return (0); 206168014Sjulian } 207168014Sjulian 208168014Sjulian /* check for AT_FDWCD */ 209168014Sjulian if (dirfd == LINUX_AT_FDCWD) { 210168355Srwatson FILEDESC_SLOCK(fdp); 211168014Sjulian dvp = fdp->fd_cdir; 212168355Srwatson vref(dvp); 213168355Srwatson FILEDESC_SUNLOCK(fdp); 214168014Sjulian } else { 215168014Sjulian error = fget(td, dirfd, &fp); 216168014Sjulian if (error) 217168014Sjulian return (error); 218168014Sjulian dvp = fp->f_vnode; 219168014Sjulian /* only a dir can be dfd */ 220168014Sjulian if (dvp->v_type != VDIR) { 221168014Sjulian fdrop(fp, td); 222168014Sjulian return (ENOTDIR); 223168014Sjulian } 224168355Srwatson vref(dvp); 225168014Sjulian fdrop(fp, td); 226168014Sjulian } 227168014Sjulian 228168355Srwatson /* 229168355Srwatson * XXXRW: This is bogus, as vn_fullpath() returns only an advisory 230168355Srwatson * file path, and may fail in several common situations, including 231168355Srwatson * for file systmes that don't use the name cache, and if the entry 232168355Srwatson * for the file falls out of the name cache. We should implement 233168355Srwatson * openat() in the FreeBSD native system call layer properly (using a 234168355Srwatson * requested starting directory), and have Linux and other ABIs wrap 235168355Srwatson * the native implementation. 236168355Srwatson */ 237168014Sjulian error = vn_fullpath(td, dvp, &fullpath, &freepath); 238168014Sjulian if (!error) { 239168014Sjulian *newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO); 240168014Sjulian *freebuf = freepath; 241168014Sjulian sprintf(*newpath, "%s/%s", fullpath, filename); 242170486Smjacob } else { 243170486Smjacob *newpath = NULL; 244168014Sjulian } 245168355Srwatson vfslocked = VFS_LOCK_GIANT(dvp->v_mount); 246168355Srwatson vrele(dvp); 247168355Srwatson VFS_UNLOCK_GIANT(vfslocked); 248168014Sjulian return (error); 249168014Sjulian} 250168014Sjulian 2519313Ssosint 252168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args) 253168014Sjulian{ 254168014Sjulian char *newpath, *oldpath, *freebuf = NULL, *path; 255168014Sjulian int error; 256168014Sjulian 257168014Sjulian oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 258168014Sjulian error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL); 259168014Sjulian 260168014Sjulian#ifdef DEBUG 261168014Sjulian if (ldebug(openat)) 262168014Sjulian printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 263168014Sjulian oldpath, args->flags, args->mode); 264168014Sjulian#endif 265168014Sjulian 266168014Sjulian error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf); 267168014Sjulian if (error) 268168014Sjulian return (error); 269168014Sjulian#ifdef DEBUG 270168014Sjulian printf(LMSG("newpath: %s"), newpath); 271168014Sjulian#endif 272168014Sjulian if (args->flags & LINUX_O_CREAT) 273168014Sjulian LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE); 274168014Sjulian else 275168014Sjulian LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE); 276168014Sjulian if (freebuf) 277168014Sjulian free(freebuf, M_TEMP); 278168014Sjulian if (*oldpath != '/') 279168014Sjulian free(newpath, M_TEMP); 280168014Sjulian 281168014Sjulian error = linux_common_open(td, path, args->flags, args->mode, 1); 282168014Sjulian free(oldpath, M_TEMP); 283168014Sjulian return (error); 284168014Sjulian} 285168014Sjulian 286168014Sjulianint 287168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 288168014Sjulian{ 289168014Sjulian char *path; 290168014Sjulian 291168014Sjulian if (args->flags & LINUX_O_CREAT) 292168014Sjulian LCONVPATHCREAT(td, args->path, &path); 293168014Sjulian else 294168014Sjulian LCONVPATHEXIST(td, args->path, &path); 295168014Sjulian 296168014Sjulian#ifdef DEBUG 297168014Sjulian if (ldebug(open)) 298168014Sjulian printf(ARGS(open, "%s, 0x%x, 0x%x"), 299168014Sjulian path, args->flags, args->mode); 300168014Sjulian#endif 301168014Sjulian 302168014Sjulian return linux_common_open(td, path, args->flags, args->mode, 0); 303168014Sjulian} 304168014Sjulian 305168014Sjulianint 30683366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 3079313Ssos{ 3089313Ssos 30912858Speter struct lseek_args /* { 31012858Speter int fd; 3119313Ssos int pad; 31212858Speter off_t offset; 3139313Ssos int whence; 31412858Speter } */ tmp_args; 3159313Ssos int error; 3169313Ssos 3179313Ssos#ifdef DEBUG 31872543Sjlemon if (ldebug(lseek)) 31972543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 32083221Smarcel args->fdes, (long)args->off, args->whence); 3219313Ssos#endif 32212858Speter tmp_args.fd = args->fdes; 32312858Speter tmp_args.offset = (off_t)args->off; 3249313Ssos tmp_args.whence = args->whence; 32583366Sjulian error = lseek(td, &tmp_args); 3269313Ssos return error; 3279313Ssos} 3289313Ssos 32914331Speterint 33083366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 33114331Speter{ 33214331Speter struct lseek_args bsd_args; 33314331Speter int error; 33414331Speter off_t off; 33514331Speter 33614331Speter#ifdef DEBUG 33772543Sjlemon if (ldebug(llseek)) 33872543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 33972543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 34014331Speter#endif 34114331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 34214331Speter 34314331Speter bsd_args.fd = args->fd; 34414331Speter bsd_args.offset = off; 34514331Speter bsd_args.whence = args->whence; 34614331Speter 34783366Sjulian if ((error = lseek(td, &bsd_args))) 34814331Speter return error; 34914331Speter 350111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 35114331Speter return error; 35214331Speter 35383366Sjulian td->td_retval[0] = 0; 35414331Speter return 0; 35514331Speter} 35614331Speter 3579313Ssosint 35883366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args) 3599313Ssos{ 36014331Speter struct linux_getdents_args lda; 36114331Speter 36214331Speter lda.fd = args->fd; 36314331Speter lda.dent = args->dent; 36414331Speter lda.count = 1; 36583366Sjulian return linux_getdents(td, &lda); 36614331Speter} 36714331Speter 36883221Smarcel/* 36983221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 37083221Smarcel * arguments. They only differ in the definition of struct dirent they 37183221Smarcel * operate on. We use this to common the code, with the exception of 37283221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented 37383221Smarcel * by means of linux_getdents(2). In this case we never operate on 37483221Smarcel * struct dirent64 and thus don't need to handle it... 37583221Smarcel */ 37683221Smarcel 37783221Smarcelstruct l_dirent { 37883221Smarcel l_long d_ino; 37983221Smarcel l_off_t d_off; 38083221Smarcel l_ushort d_reclen; 38183221Smarcel char d_name[LINUX_NAME_MAX + 1]; 38283221Smarcel}; 38383221Smarcel 38483221Smarcelstruct l_dirent64 { 38583221Smarcel uint64_t d_ino; 38683221Smarcel int64_t d_off; 38783221Smarcel l_ushort d_reclen; 38883221Smarcel u_char d_type; 38983221Smarcel char d_name[LINUX_NAME_MAX + 1]; 39083221Smarcel}; 39183221Smarcel 39283221Smarcel#define LINUX_RECLEN(de,namlen) \ 39383221Smarcel ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 39483221Smarcel 39583221Smarcel#define LINUX_DIRBLKSIZ 512 39683221Smarcel 39783221Smarcelstatic int 39883366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args, 39983221Smarcel int is64bit) 40014331Speter{ 401111798Sdes struct dirent *bdp; 40283221Smarcel struct vnode *vp; 40383221Smarcel caddr_t inp, buf; /* BSD-format */ 40483221Smarcel int len, reclen; /* BSD-format */ 40583221Smarcel caddr_t outp; /* Linux-format */ 40683221Smarcel int resid, linuxreclen=0; /* Linux-format */ 40783221Smarcel struct file *fp; 40883221Smarcel struct uio auio; 40983221Smarcel struct iovec aiov; 41083221Smarcel off_t off; 41183221Smarcel struct l_dirent linux_dirent; 41283221Smarcel struct l_dirent64 linux_dirent64; 41383221Smarcel int buflen, error, eofflag, nbytes, justone; 41483221Smarcel u_long *cookies = NULL, *cookiep; 415160276Sjhb int ncookies, vfslocked; 4169313Ssos 417160276Sjhb nbytes = args->count; 418160276Sjhb if (nbytes == 1) { 419160276Sjhb /* readdir(2) case. Always struct dirent. */ 420160276Sjhb if (is64bit) 421160276Sjhb return (EINVAL); 422160276Sjhb nbytes = sizeof(linux_dirent); 423160276Sjhb justone = 1; 424160276Sjhb } else 425160276Sjhb justone = 0; 426160276Sjhb 42783366Sjulian if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 42883221Smarcel return (error); 4299313Ssos 43089306Salfred if ((fp->f_flag & FREAD) == 0) { 43189306Salfred fdrop(fp, td); 43283221Smarcel return (EBADF); 43389306Salfred } 4349313Ssos 435116678Sphk vp = fp->f_vnode; 436160276Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 43789306Salfred if (vp->v_type != VDIR) { 438160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 43989306Salfred fdrop(fp, td); 44083221Smarcel return (EINVAL); 44189306Salfred } 4429313Ssos 44383221Smarcel off = fp->f_offset; 4449313Ssos 44583221Smarcel buflen = max(LINUX_DIRBLKSIZ, nbytes); 44683221Smarcel buflen = min(buflen, MAXBSIZE); 447111119Simp buf = malloc(buflen, M_TEMP, M_WAITOK); 44883366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 44983221Smarcel 4509313Ssosagain: 45183221Smarcel aiov.iov_base = buf; 45283221Smarcel aiov.iov_len = buflen; 45383221Smarcel auio.uio_iov = &aiov; 45483221Smarcel auio.uio_iovcnt = 1; 45583221Smarcel auio.uio_rw = UIO_READ; 45683221Smarcel auio.uio_segflg = UIO_SYSSPACE; 45783366Sjulian auio.uio_td = td; 45883221Smarcel auio.uio_resid = buflen; 45983221Smarcel auio.uio_offset = off; 4609313Ssos 46183221Smarcel if (cookies) { 46283221Smarcel free(cookies, M_TEMP); 46383221Smarcel cookies = NULL; 46483221Smarcel } 46524654Sdfr 466101189Srwatson#ifdef MAC 467101189Srwatson /* 468101189Srwatson * Do directory search MAC check using non-cached credentials. 469101189Srwatson */ 470172930Srwatson if ((error = mac_vnode_check_readdir(td->td_ucred, vp))) 471101189Srwatson goto out; 472101189Srwatson#endif /* MAC */ 47383221Smarcel if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 47483221Smarcel &cookies))) 47583221Smarcel goto out; 4769313Ssos 47783221Smarcel inp = buf; 47883221Smarcel outp = (caddr_t)args->dirent; 47983221Smarcel resid = nbytes; 48083221Smarcel if ((len = buflen - auio.uio_resid) <= 0) 48183221Smarcel goto eof; 4829313Ssos 48383221Smarcel cookiep = cookies; 48424654Sdfr 48583221Smarcel if (cookies) { 48683221Smarcel /* 48783221Smarcel * When using cookies, the vfs has the option of reading from 48883221Smarcel * a different offset than that supplied (UFS truncates the 48983221Smarcel * offset to a block boundary to make sure that it never reads 49083221Smarcel * partway through a directory entry, even if the directory 49183221Smarcel * has been compacted). 49283221Smarcel */ 49383221Smarcel while (len > 0 && ncookies > 0 && *cookiep <= off) { 49483221Smarcel bdp = (struct dirent *) inp; 49583221Smarcel len -= bdp->d_reclen; 49683221Smarcel inp += bdp->d_reclen; 49783221Smarcel cookiep++; 49883221Smarcel ncookies--; 49983221Smarcel } 50024654Sdfr } 50124654Sdfr 50283221Smarcel while (len > 0) { 50383221Smarcel if (cookiep && ncookies == 0) 50483221Smarcel break; 50583221Smarcel bdp = (struct dirent *) inp; 50683221Smarcel reclen = bdp->d_reclen; 50783221Smarcel if (reclen & 3) { 50883221Smarcel error = EFAULT; 50983221Smarcel goto out; 51083221Smarcel } 51183221Smarcel 51283221Smarcel if (bdp->d_fileno == 0) { 51383221Smarcel inp += reclen; 51483221Smarcel if (cookiep) { 51583221Smarcel off = *cookiep++; 51683221Smarcel ncookies--; 51783221Smarcel } else 51883221Smarcel off += reclen; 51983221Smarcel 52083221Smarcel len -= reclen; 52183221Smarcel continue; 52283221Smarcel } 52383221Smarcel 52483221Smarcel linuxreclen = (is64bit) 52583221Smarcel ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) 52683221Smarcel : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 52783221Smarcel 52883221Smarcel if (reclen > len || resid < linuxreclen) { 52983221Smarcel outp++; 53083221Smarcel break; 53183221Smarcel } 53283221Smarcel 53383221Smarcel if (justone) { 53483221Smarcel /* readdir(2) case. */ 53583221Smarcel linux_dirent.d_ino = (l_long)bdp->d_fileno; 53683221Smarcel linux_dirent.d_off = (l_off_t)linuxreclen; 53783221Smarcel linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 53883221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 53983221Smarcel error = copyout(&linux_dirent, outp, linuxreclen); 54083221Smarcel } else { 54183221Smarcel if (is64bit) { 54283221Smarcel linux_dirent64.d_ino = bdp->d_fileno; 54383221Smarcel linux_dirent64.d_off = (cookiep) 54483221Smarcel ? (l_off_t)*cookiep 54583221Smarcel : (l_off_t)(off + reclen); 54683221Smarcel linux_dirent64.d_reclen = 54783221Smarcel (l_ushort)linuxreclen; 54883221Smarcel linux_dirent64.d_type = bdp->d_type; 54983221Smarcel strcpy(linux_dirent64.d_name, bdp->d_name); 55083221Smarcel error = copyout(&linux_dirent64, outp, 55183221Smarcel linuxreclen); 55283221Smarcel } else { 55383221Smarcel linux_dirent.d_ino = bdp->d_fileno; 55483221Smarcel linux_dirent.d_off = (cookiep) 55583221Smarcel ? (l_off_t)*cookiep 55683221Smarcel : (l_off_t)(off + reclen); 55783221Smarcel linux_dirent.d_reclen = (l_ushort)linuxreclen; 55883221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 55983221Smarcel error = copyout(&linux_dirent, outp, 56083221Smarcel linuxreclen); 56183221Smarcel } 56283221Smarcel } 56383221Smarcel if (error) 56483221Smarcel goto out; 56583221Smarcel 56683221Smarcel inp += reclen; 56783221Smarcel if (cookiep) { 56883221Smarcel off = *cookiep++; 56983221Smarcel ncookies--; 57083221Smarcel } else 57183221Smarcel off += reclen; 57283221Smarcel 57383221Smarcel outp += linuxreclen; 57483221Smarcel resid -= linuxreclen; 57583221Smarcel len -= reclen; 57683221Smarcel if (justone) 57783221Smarcel break; 57810355Sswallace } 5799313Ssos 58083221Smarcel if (outp == (caddr_t)args->dirent) 58183221Smarcel goto again; 5829313Ssos 58383221Smarcel fp->f_offset = off; 58483221Smarcel if (justone) 58583221Smarcel nbytes = resid + linuxreclen; 58610355Sswallace 5879313Ssoseof: 58883366Sjulian td->td_retval[0] = nbytes - resid; 58983221Smarcel 5909313Ssosout: 59183221Smarcel if (cookies) 59283221Smarcel free(cookies, M_TEMP); 59383221Smarcel 59483366Sjulian VOP_UNLOCK(vp, 0, td); 595160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 59689306Salfred fdrop(fp, td); 59783221Smarcel free(buf, M_TEMP); 59883221Smarcel return (error); 5999313Ssos} 60014331Speter 60183221Smarcelint 60283366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args) 60383221Smarcel{ 60483221Smarcel 60583221Smarcel#ifdef DEBUG 60683221Smarcel if (ldebug(getdents)) 60783221Smarcel printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 60883221Smarcel#endif 60983221Smarcel 61083366Sjulian return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 61183221Smarcel} 61283221Smarcel 61383221Smarcelint 61483366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 61583221Smarcel{ 61683221Smarcel 61783221Smarcel#ifdef DEBUG 61883221Smarcel if (ldebug(getdents64)) 61983221Smarcel printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 62083221Smarcel#endif 62183221Smarcel 62283366Sjulian return (getdents_common(td, args, 1)); 62383221Smarcel} 62483221Smarcel 62514331Speter/* 62614331Speter * These exist mainly for hooks for doing /compat/linux translation. 62714331Speter */ 62814331Speter 62914331Speterint 63083366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 63114331Speter{ 632102814Siedowse char *path; 633102814Siedowse int error; 63414331Speter 635162585Snetchild /* linux convention */ 636162585Snetchild if (args->flags & ~(F_OK | X_OK | W_OK | R_OK)) 637162585Snetchild return (EINVAL); 638162585Snetchild 639102814Siedowse LCONVPATHEXIST(td, args->path, &path); 64014331Speter 64114331Speter#ifdef DEBUG 64272543Sjlemon if (ldebug(access)) 643102814Siedowse printf(ARGS(access, "%s, %d"), path, args->flags); 64414331Speter#endif 645102814Siedowse error = kern_access(td, path, UIO_SYSSPACE, args->flags); 646102814Siedowse LFREEPATH(path); 647162585Snetchild 648102814Siedowse return (error); 64914331Speter} 65014331Speter 65114331Speterint 65283366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 65314331Speter{ 654102814Siedowse char *path; 655102814Siedowse int error; 656162201Snetchild struct stat st; 65714331Speter 658102814Siedowse LCONVPATHEXIST(td, args->path, &path); 65914331Speter 66014331Speter#ifdef DEBUG 66172543Sjlemon if (ldebug(unlink)) 662102814Siedowse printf(ARGS(unlink, "%s"), path); 66314331Speter#endif 66414331Speter 665102814Siedowse error = kern_unlink(td, path, UIO_SYSSPACE); 666162201Snetchild if (error == EPERM) 667162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 668162201Snetchild if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 669162201Snetchild if (S_ISDIR(st.st_mode)) 670162201Snetchild error = EISDIR; 671102814Siedowse LFREEPATH(path); 672102814Siedowse return (error); 67314331Speter} 67414331Speter 67514331Speterint 67683366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 67714331Speter{ 678102814Siedowse char *path; 679102814Siedowse int error; 68014331Speter 681102814Siedowse LCONVPATHEXIST(td, args->path, &path); 68214331Speter 68314331Speter#ifdef DEBUG 68472543Sjlemon if (ldebug(chdir)) 685102814Siedowse printf(ARGS(chdir, "%s"), path); 68614331Speter#endif 687102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 688102814Siedowse LFREEPATH(path); 689102814Siedowse return (error); 69014331Speter} 69114331Speter 69214331Speterint 69383366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 69414331Speter{ 695102814Siedowse char *path; 696102814Siedowse int error; 69714331Speter 698102814Siedowse LCONVPATHEXIST(td, args->path, &path); 69914331Speter 70014331Speter#ifdef DEBUG 70172543Sjlemon if (ldebug(chmod)) 702102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 70314331Speter#endif 704102814Siedowse error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 705102814Siedowse LFREEPATH(path); 706102814Siedowse return (error); 70714331Speter} 70814331Speter 70914331Speterint 71083366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 71114331Speter{ 712102814Siedowse char *path; 713102814Siedowse int error; 71414331Speter 715102814Siedowse LCONVPATHCREAT(td, args->path, &path); 71614331Speter 71714331Speter#ifdef DEBUG 71872543Sjlemon if (ldebug(mkdir)) 719102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 72014331Speter#endif 721102814Siedowse error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 722102814Siedowse LFREEPATH(path); 723102814Siedowse return (error); 72414331Speter} 72514331Speter 72614331Speterint 72783366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 72814331Speter{ 729102814Siedowse char *path; 730102814Siedowse int error; 73114331Speter 732102814Siedowse LCONVPATHEXIST(td, args->path, &path); 73314331Speter 73414331Speter#ifdef DEBUG 73572543Sjlemon if (ldebug(rmdir)) 736102814Siedowse printf(ARGS(rmdir, "%s"), path); 73714331Speter#endif 738102814Siedowse error = kern_rmdir(td, path, UIO_SYSSPACE); 739102814Siedowse LFREEPATH(path); 740102814Siedowse return (error); 74114331Speter} 74214331Speter 74314331Speterint 74483366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 74514331Speter{ 746102814Siedowse char *from, *to; 747102814Siedowse int error; 74814331Speter 749102814Siedowse LCONVPATHEXIST(td, args->from, &from); 750102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 751102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 752102814Siedowse if (to == NULL) { 753102814Siedowse LFREEPATH(from); 754102814Siedowse return (error); 755102814Siedowse } 75614331Speter 75714331Speter#ifdef DEBUG 75872543Sjlemon if (ldebug(rename)) 759102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 76014331Speter#endif 761102814Siedowse error = kern_rename(td, from, to, UIO_SYSSPACE); 762102814Siedowse LFREEPATH(from); 763102814Siedowse LFREEPATH(to); 764102814Siedowse return (error); 76514331Speter} 76614331Speter 76714331Speterint 76883366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 76914331Speter{ 770102814Siedowse char *path, *to; 771102814Siedowse int error; 77214331Speter 773102814Siedowse LCONVPATHEXIST(td, args->path, &path); 774102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 775102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 776102814Siedowse if (to == NULL) { 777102814Siedowse LFREEPATH(path); 778102814Siedowse return (error); 779102814Siedowse } 78014331Speter 78114331Speter#ifdef DEBUG 78272543Sjlemon if (ldebug(symlink)) 783102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 78414331Speter#endif 785102814Siedowse error = kern_symlink(td, path, to, UIO_SYSSPACE); 786102814Siedowse LFREEPATH(path); 787102814Siedowse LFREEPATH(to); 788102814Siedowse return (error); 78914331Speter} 79014331Speter 79114331Speterint 79283366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 79314331Speter{ 794102814Siedowse char *name; 795102814Siedowse int error; 79614331Speter 797102814Siedowse LCONVPATHEXIST(td, args->name, &name); 79814331Speter 79914331Speter#ifdef DEBUG 80072543Sjlemon if (ldebug(readlink)) 801102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 802102814Siedowse args->count); 80314331Speter#endif 804102814Siedowse error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 805102814Siedowse args->count); 806102814Siedowse LFREEPATH(name); 807102814Siedowse return (error); 80814331Speter} 80914331Speter 81014331Speterint 81183366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 81214331Speter{ 813102814Siedowse char *path; 814102814Siedowse int error; 81514331Speter 816102814Siedowse LCONVPATHEXIST(td, args->path, &path); 81714331Speter 81814331Speter#ifdef DEBUG 81972543Sjlemon if (ldebug(truncate)) 820102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 82114331Speter#endif 82214331Speter 823102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 824102814Siedowse LFREEPATH(path); 825102814Siedowse return (error); 82614331Speter} 82714331Speter 82849662Smarcelint 829156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 830156842Snetchild{ 831156842Snetchild struct ftruncate_args /* { 832156842Snetchild int fd; 833156842Snetchild int pad; 834156842Snetchild off_t length; 835156842Snetchild } */ nuap; 836156842Snetchild 837156842Snetchild nuap.fd = args->fd; 838156842Snetchild nuap.length = args->length; 839156842Snetchild return (ftruncate(td, &nuap)); 840156842Snetchild} 841156842Snetchild 842156842Snetchildint 84383366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 84449662Smarcel{ 845102814Siedowse char *path, *to; 846102814Siedowse int error; 84749662Smarcel 848102814Siedowse LCONVPATHEXIST(td, args->path, &path); 849102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 850102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 851102814Siedowse if (to == NULL) { 852102814Siedowse LFREEPATH(path); 853102814Siedowse return (error); 854102814Siedowse } 85549662Smarcel 85649662Smarcel#ifdef DEBUG 85772543Sjlemon if (ldebug(link)) 858102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 85949662Smarcel#endif 860102814Siedowse error = kern_link(td, path, to, UIO_SYSSPACE); 861102814Siedowse LFREEPATH(path); 862102814Siedowse LFREEPATH(to); 863102814Siedowse return (error); 86449662Smarcel} 86549788Smarcel 86653713Smarcelint 86783366Sjulianlinux_fdatasync(td, uap) 86883366Sjulian struct thread *td; 86953713Smarcel struct linux_fdatasync_args *uap; 87053713Smarcel{ 87153713Smarcel struct fsync_args bsd; 87253713Smarcel 87353713Smarcel bsd.fd = uap->fd; 87483366Sjulian return fsync(td, &bsd); 87553713Smarcel} 87663285Smarcel 87763285Smarcelint 87883366Sjulianlinux_pread(td, uap) 87983366Sjulian struct thread *td; 88063285Smarcel struct linux_pread_args *uap; 88163285Smarcel{ 88263285Smarcel struct pread_args bsd; 883162585Snetchild struct vnode *vp; 884162585Snetchild int error; 88563285Smarcel 88663285Smarcel bsd.fd = uap->fd; 88763285Smarcel bsd.buf = uap->buf; 88863285Smarcel bsd.nbyte = uap->nbyte; 88963285Smarcel bsd.offset = uap->offset; 890162585Snetchild 891162585Snetchild error = pread(td, &bsd); 892162585Snetchild 893162585Snetchild if (error == 0) { 894162585Snetchild /* This seems to violate POSIX but linux does it */ 895162585Snetchild if ((error = fgetvp(td, uap->fd, &vp)) != 0) 896162585Snetchild return (error); 897162585Snetchild if (vp->v_type == VDIR) { 898162585Snetchild vrele(vp); 899162585Snetchild return (EISDIR); 900162585Snetchild } 901162585Snetchild vrele(vp); 902162585Snetchild } 903162585Snetchild 904162585Snetchild return (error); 90563285Smarcel} 90663285Smarcel 90763285Smarcelint 90883366Sjulianlinux_pwrite(td, uap) 90983366Sjulian struct thread *td; 91063285Smarcel struct linux_pwrite_args *uap; 91163285Smarcel{ 91263285Smarcel struct pwrite_args bsd; 91363285Smarcel 91463285Smarcel bsd.fd = uap->fd; 91563285Smarcel bsd.buf = uap->buf; 91663285Smarcel bsd.nbyte = uap->nbyte; 91763285Smarcel bsd.offset = uap->offset; 91883366Sjulian return pwrite(td, &bsd); 91963285Smarcel} 92072538Sjlemon 92172538Sjlemonint 92283366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 92372538Sjlemon{ 92472538Sjlemon struct ufs_args ufs; 925111798Sdes char fstypename[MFSNAMELEN]; 926111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 92773286Sadrian int error; 92873286Sadrian int fsflags; 92973286Sadrian void *fsdata; 93072538Sjlemon 931111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 93273286Sadrian NULL); 93372538Sjlemon if (error) 934111798Sdes return (error); 935127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 93672538Sjlemon if (error) 937111798Sdes return (error); 938127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 93972538Sjlemon if (error) 940111798Sdes return (error); 94172538Sjlemon 94272538Sjlemon#ifdef DEBUG 94372538Sjlemon if (ldebug(mount)) 94472538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 94572538Sjlemon fstypename, mntfromname, mntonname); 94672538Sjlemon#endif 94772538Sjlemon 94872538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 949127059Stjr strcpy(fstypename, "ext2fs"); 95073286Sadrian fsdata = &ufs; 95172538Sjlemon ufs.fspec = mntfromname; 95272538Sjlemon#define DEFAULT_ROOTID -2 95372538Sjlemon ufs.export.ex_root = DEFAULT_ROOTID; 95472538Sjlemon ufs.export.ex_flags = 95572538Sjlemon args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 95672538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 957127059Stjr strcpy(fstypename, "linprocfs"); 95873286Sadrian fsdata = NULL; 95972538Sjlemon } else { 96072538Sjlemon return (ENODEV); 96172538Sjlemon } 96272538Sjlemon 96373286Sadrian fsflags = 0; 96472538Sjlemon 96572538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 96672538Sjlemon /* 96772538Sjlemon * Linux SYNC flag is not included; the closest equivalent 96872538Sjlemon * FreeBSD has is !ASYNC, which is our default. 96972538Sjlemon */ 97072538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 971111798Sdes fsflags |= MNT_RDONLY; 97272538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 973111798Sdes fsflags |= MNT_NOSUID; 97472538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 975111798Sdes fsflags |= MNT_NOEXEC; 97672538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 977111798Sdes fsflags |= MNT_UPDATE; 97872538Sjlemon } 97972538Sjlemon 980127059Stjr if (strcmp(fstypename, "linprocfs") == 0) { 981132708Sphk error = kernel_vmount(fsflags, 982132708Sphk "fstype", fstypename, 983132708Sphk "fspath", mntonname, 984132708Sphk NULL); 985127059Stjr } else 986138353Sphk error = EOPNOTSUPP; 987127059Stjr return (error); 98872538Sjlemon} 98972538Sjlemon 99072538Sjlemonint 99183366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 99272538Sjlemon{ 99383221Smarcel struct linux_umount_args args2; 99472538Sjlemon 99572538Sjlemon args2.path = args->path; 99672538Sjlemon args2.flags = 0; 99783366Sjulian return (linux_umount(td, &args2)); 99872538Sjlemon} 99972538Sjlemon 100072538Sjlemonint 100183366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 100272538Sjlemon{ 100372538Sjlemon struct unmount_args bsd; 100472538Sjlemon 100572538Sjlemon bsd.path = args->path; 100672538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 100783366Sjulian return (unmount(td, &bsd)); 100872538Sjlemon} 100983221Smarcel 101083221Smarcel/* 101183221Smarcel * fcntl family of syscalls 101283221Smarcel */ 101383221Smarcel 101483221Smarcelstruct l_flock { 101583221Smarcel l_short l_type; 101683221Smarcel l_short l_whence; 101783221Smarcel l_off_t l_start; 101883221Smarcel l_off_t l_len; 101983221Smarcel l_pid_t l_pid; 1020133816Stjr} 1021140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1022133816Stjr__packed 1023133816Stjr#endif 1024133816Stjr; 102583221Smarcel 102683221Smarcelstatic void 102783221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 102883221Smarcel{ 102983221Smarcel switch (linux_flock->l_type) { 103083221Smarcel case LINUX_F_RDLCK: 103183221Smarcel bsd_flock->l_type = F_RDLCK; 103283221Smarcel break; 103383221Smarcel case LINUX_F_WRLCK: 103483221Smarcel bsd_flock->l_type = F_WRLCK; 103583221Smarcel break; 103683221Smarcel case LINUX_F_UNLCK: 103783221Smarcel bsd_flock->l_type = F_UNLCK; 103883221Smarcel break; 103983221Smarcel default: 104083221Smarcel bsd_flock->l_type = -1; 104183221Smarcel break; 104283221Smarcel } 104383221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 104483221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 104583221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 104683221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 104783221Smarcel} 104883221Smarcel 104983221Smarcelstatic void 105083221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 105183221Smarcel{ 105283221Smarcel switch (bsd_flock->l_type) { 105383221Smarcel case F_RDLCK: 105483221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 105583221Smarcel break; 105683221Smarcel case F_WRLCK: 105783221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 105883221Smarcel break; 105983221Smarcel case F_UNLCK: 106083221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 106183221Smarcel break; 106283221Smarcel } 106383221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 106483221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 106583221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 106683221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 106783221Smarcel} 106883221Smarcel 1069140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 107083221Smarcelstruct l_flock64 { 107183221Smarcel l_short l_type; 107283221Smarcel l_short l_whence; 107383221Smarcel l_loff_t l_start; 107483221Smarcel l_loff_t l_len; 107583221Smarcel l_pid_t l_pid; 1076133816Stjr} 1077140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1078133816Stjr__packed 1079133816Stjr#endif 1080133816Stjr; 108183221Smarcel 108283221Smarcelstatic void 108383221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 108483221Smarcel{ 108583221Smarcel switch (linux_flock->l_type) { 108683221Smarcel case LINUX_F_RDLCK: 108783221Smarcel bsd_flock->l_type = F_RDLCK; 108883221Smarcel break; 108983221Smarcel case LINUX_F_WRLCK: 109083221Smarcel bsd_flock->l_type = F_WRLCK; 109183221Smarcel break; 109283221Smarcel case LINUX_F_UNLCK: 109383221Smarcel bsd_flock->l_type = F_UNLCK; 109483221Smarcel break; 109583221Smarcel default: 109683221Smarcel bsd_flock->l_type = -1; 109783221Smarcel break; 109883221Smarcel } 109983221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 110083221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 110183221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 110283221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 110383221Smarcel} 110483221Smarcel 110583221Smarcelstatic void 110683221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 110783221Smarcel{ 110883221Smarcel switch (bsd_flock->l_type) { 110983221Smarcel case F_RDLCK: 111083221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 111183221Smarcel break; 111283221Smarcel case F_WRLCK: 111383221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 111483221Smarcel break; 111583221Smarcel case F_UNLCK: 111683221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 111783221Smarcel break; 111883221Smarcel } 111983221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 112083221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 112183221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 112283221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 112383221Smarcel} 1124133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 112583221Smarcel 112683221Smarcelstatic int 112783366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args) 112883221Smarcel{ 1129107680Siedowse struct l_flock linux_flock; 1130107680Siedowse struct flock bsd_flock; 113183221Smarcel struct file *fp; 1132102872Siedowse long arg; 113383221Smarcel int error, result; 113483221Smarcel 113583221Smarcel switch (args->cmd) { 113683221Smarcel case LINUX_F_DUPFD: 1137102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 113883221Smarcel 113983221Smarcel case LINUX_F_GETFD: 1140102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 114183221Smarcel 114283221Smarcel case LINUX_F_SETFD: 1143102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 114483221Smarcel 114583221Smarcel case LINUX_F_GETFL: 1146102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 114783366Sjulian result = td->td_retval[0]; 114883366Sjulian td->td_retval[0] = 0; 114983221Smarcel if (result & O_RDONLY) 115083366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 115183221Smarcel if (result & O_WRONLY) 115283366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 115383221Smarcel if (result & O_RDWR) 115483366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 115583221Smarcel if (result & O_NDELAY) 115683366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 115783221Smarcel if (result & O_APPEND) 115883366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 115983221Smarcel if (result & O_FSYNC) 116083366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 116183221Smarcel if (result & O_ASYNC) 116283366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1163144987Smdodd#ifdef LINUX_O_NOFOLLOW 1164144987Smdodd if (result & O_NOFOLLOW) 1165144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1166144987Smdodd#endif 1167144987Smdodd#ifdef LINUX_O_DIRECT 1168144987Smdodd if (result & O_DIRECT) 1169144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1170144987Smdodd#endif 117183221Smarcel return (error); 117283221Smarcel 117383221Smarcel case LINUX_F_SETFL: 1174102872Siedowse arg = 0; 117583221Smarcel if (args->arg & LINUX_O_NDELAY) 1176102872Siedowse arg |= O_NONBLOCK; 117783221Smarcel if (args->arg & LINUX_O_APPEND) 1178102872Siedowse arg |= O_APPEND; 117983221Smarcel if (args->arg & LINUX_O_SYNC) 1180102872Siedowse arg |= O_FSYNC; 118183221Smarcel if (args->arg & LINUX_FASYNC) 1182102872Siedowse arg |= O_ASYNC; 1183144987Smdodd#ifdef LINUX_O_NOFOLLOW 1184144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1185144987Smdodd arg |= O_NOFOLLOW; 1186144987Smdodd#endif 1187144987Smdodd#ifdef LINUX_O_DIRECT 1188144987Smdodd if (args->arg & LINUX_O_DIRECT) 1189144987Smdodd arg |= O_DIRECT; 1190144987Smdodd#endif 1191102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 119283221Smarcel 1193107680Siedowse case LINUX_F_GETLK: 1194111797Sdes error = copyin((void *)args->arg, &linux_flock, 1195107680Siedowse sizeof(linux_flock)); 1196107680Siedowse if (error) 1197107680Siedowse return (error); 1198107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1199107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1200107680Siedowse if (error) 1201107680Siedowse return (error); 1202107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1203111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1204107680Siedowse sizeof(linux_flock))); 1205107680Siedowse 1206107680Siedowse case LINUX_F_SETLK: 1207111797Sdes error = copyin((void *)args->arg, &linux_flock, 1208107680Siedowse sizeof(linux_flock)); 1209107680Siedowse if (error) 1210107680Siedowse return (error); 1211107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1212107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1213107680Siedowse (intptr_t)&bsd_flock)); 1214107680Siedowse 1215107680Siedowse case LINUX_F_SETLKW: 1216111797Sdes error = copyin((void *)args->arg, &linux_flock, 1217107680Siedowse sizeof(linux_flock)); 1218107680Siedowse if (error) 1219107680Siedowse return (error); 1220107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1221107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1222107680Siedowse (intptr_t)&bsd_flock)); 1223107680Siedowse 122483221Smarcel case LINUX_F_GETOWN: 1225102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 122683221Smarcel 122783221Smarcel case LINUX_F_SETOWN: 122883221Smarcel /* 122983221Smarcel * XXX some Linux applications depend on F_SETOWN having no 123083221Smarcel * significant effect for pipes (SIGIO is not delivered for 123183221Smarcel * pipes under Linux-2.2.35 at least). 123283221Smarcel */ 123389319Salfred error = fget(td, args->fd, &fp); 123489319Salfred if (error) 123589319Salfred return (error); 123689306Salfred if (fp->f_type == DTYPE_PIPE) { 123789306Salfred fdrop(fp, td); 123883221Smarcel return (EINVAL); 123989306Salfred } 124089306Salfred fdrop(fp, td); 124183221Smarcel 1242102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 124383221Smarcel } 124483221Smarcel 124583221Smarcel return (EINVAL); 124683221Smarcel} 124783221Smarcel 124883221Smarcelint 124983366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 125083221Smarcel{ 125183221Smarcel struct linux_fcntl64_args args64; 125283221Smarcel 125383221Smarcel#ifdef DEBUG 125483221Smarcel if (ldebug(fcntl)) 125583221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 125683221Smarcel#endif 125783221Smarcel 125883221Smarcel args64.fd = args->fd; 125983221Smarcel args64.cmd = args->cmd; 126083221Smarcel args64.arg = args->arg; 126183366Sjulian return (fcntl_common(td, &args64)); 126283221Smarcel} 126383221Smarcel 1264140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 126583221Smarcelint 126683366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 126783221Smarcel{ 126883221Smarcel struct l_flock64 linux_flock; 1269102872Siedowse struct flock bsd_flock; 127083221Smarcel int error; 127183221Smarcel 127283221Smarcel#ifdef DEBUG 127383221Smarcel if (ldebug(fcntl64)) 127483221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 127583221Smarcel#endif 127683221Smarcel 127783221Smarcel switch (args->cmd) { 127899687Srobert case LINUX_F_GETLK64: 1279111797Sdes error = copyin((void *)args->arg, &linux_flock, 128083221Smarcel sizeof(linux_flock)); 128183221Smarcel if (error) 128283221Smarcel return (error); 1283102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1284102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 128583221Smarcel if (error) 128683221Smarcel return (error); 1287102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1288111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1289111797Sdes sizeof(linux_flock))); 129083221Smarcel 129199687Srobert case LINUX_F_SETLK64: 1292111797Sdes error = copyin((void *)args->arg, &linux_flock, 129383221Smarcel sizeof(linux_flock)); 129483221Smarcel if (error) 129583221Smarcel return (error); 1296102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1297102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1298102872Siedowse (intptr_t)&bsd_flock)); 129983221Smarcel 130099687Srobert case LINUX_F_SETLKW64: 1301111797Sdes error = copyin((void *)args->arg, &linux_flock, 130283221Smarcel sizeof(linux_flock)); 130383221Smarcel if (error) 130483221Smarcel return (error); 1305102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1306102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1307102872Siedowse (intptr_t)&bsd_flock)); 130883221Smarcel } 130983221Smarcel 131083366Sjulian return (fcntl_common(td, args)); 131183221Smarcel} 1312133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 131385022Smarcel 131485022Smarcelint 131585022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 131685022Smarcel{ 1317102814Siedowse char *path; 1318102814Siedowse int error; 131985022Smarcel 1320102814Siedowse LCONVPATHEXIST(td, args->path, &path); 132185022Smarcel 132285022Smarcel#ifdef DEBUG 132385022Smarcel if (ldebug(chown)) 1324102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 132585022Smarcel#endif 1326102814Siedowse error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1327102814Siedowse LFREEPATH(path); 1328102814Siedowse return (error); 132985022Smarcel} 133085022Smarcel 133185022Smarcelint 133285022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 133385022Smarcel{ 1334102814Siedowse char *path; 1335102814Siedowse int error; 133685022Smarcel 1337102814Siedowse LCONVPATHEXIST(td, args->path, &path); 133885022Smarcel 133985022Smarcel#ifdef DEBUG 134085022Smarcel if (ldebug(lchown)) 1341102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 134285022Smarcel#endif 1343102814Siedowse error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1344102814Siedowse LFREEPATH(path); 1345102814Siedowse return (error); 134685022Smarcel} 1347