19313Ssos/*- 2230132Suqs * 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$"); 31116173Sobrien 32156874Sru#include "opt_compat.h" 3331784Seivind 349313Ssos#include <sys/param.h> 359313Ssos#include <sys/systm.h> 36224778Srwatson#include <sys/capability.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 69246085Sjhb#include <compat/linux/linux_misc.h> 7064905Smarcel#include <compat/linux/linux_util.h> 71177997Skib#include <compat/linux/linux_file.h> 729313Ssos 739313Ssosint 7483366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 759313Ssos{ 76102814Siedowse char *path; 77102814Siedowse int error; 789313Ssos 79102814Siedowse LCONVPATHEXIST(td, args->path, &path); 8014331Speter 819313Ssos#ifdef DEBUG 8272543Sjlemon if (ldebug(creat)) 83102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 849313Ssos#endif 85102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 86102814Siedowse args->mode); 87102814Siedowse LFREEPATH(path); 88102814Siedowse return (error); 899313Ssos} 909313Ssos 91168014Sjulian 92168014Sjulianstatic int 93177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 949313Ssos{ 95255219Spjd cap_rights_t rights; 9683382Sjhb struct proc *p = td->td_proc; 97166085Skib struct file *fp; 98166085Skib int fd; 99102814Siedowse int bsd_flags, error; 10014331Speter 101102814Siedowse bsd_flags = 0; 102168014Sjulian switch (l_flags & LINUX_O_ACCMODE) { 103168014Sjulian case LINUX_O_WRONLY: 104102814Siedowse bsd_flags |= O_WRONLY; 105168014Sjulian break; 106168014Sjulian case LINUX_O_RDWR: 107102814Siedowse bsd_flags |= O_RDWR; 108168014Sjulian break; 109168014Sjulian default: 110168014Sjulian bsd_flags |= O_RDONLY; 111168014Sjulian } 112168014Sjulian if (l_flags & LINUX_O_NDELAY) 113102814Siedowse bsd_flags |= O_NONBLOCK; 114168014Sjulian if (l_flags & LINUX_O_APPEND) 115102814Siedowse bsd_flags |= O_APPEND; 116168014Sjulian if (l_flags & LINUX_O_SYNC) 117102814Siedowse bsd_flags |= O_FSYNC; 118168014Sjulian if (l_flags & LINUX_O_NONBLOCK) 119102814Siedowse bsd_flags |= O_NONBLOCK; 120168014Sjulian if (l_flags & LINUX_FASYNC) 121102814Siedowse bsd_flags |= O_ASYNC; 122168014Sjulian if (l_flags & LINUX_O_CREAT) 123102814Siedowse bsd_flags |= O_CREAT; 124168014Sjulian if (l_flags & LINUX_O_TRUNC) 125102814Siedowse bsd_flags |= O_TRUNC; 126168014Sjulian if (l_flags & LINUX_O_EXCL) 127102814Siedowse bsd_flags |= O_EXCL; 128168014Sjulian if (l_flags & LINUX_O_NOCTTY) 129102814Siedowse bsd_flags |= O_NOCTTY; 130168014Sjulian if (l_flags & LINUX_O_DIRECT) 131166085Skib bsd_flags |= O_DIRECT; 132168014Sjulian if (l_flags & LINUX_O_NOFOLLOW) 133166085Skib bsd_flags |= O_NOFOLLOW; 134205423Sed if (l_flags & LINUX_O_DIRECTORY) 135205423Sed bsd_flags |= O_DIRECTORY; 136166085Skib /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1379313Ssos 138178036Srdivacky error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 139178036Srdivacky 140166085Skib if (!error) { 141166085Skib fd = td->td_retval[0]; 142166085Skib /* 143166085Skib * XXX In between kern_open() and fget(), another process 144166085Skib * having the same filedesc could use that fd without 145166085Skib * checking below. 146166085Skib */ 147255219Spjd error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp); 148166085Skib if (!error) { 149166085Skib sx_slock(&proctree_lock); 150166085Skib PROC_LOCK(p); 151166085Skib if (!(bsd_flags & O_NOCTTY) && 152166085Skib SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 153166085Skib PROC_UNLOCK(p); 154166085Skib sx_unlock(&proctree_lock); 155247602Spjd /* XXXPJD: Verify if TIOCSCTTY is allowed. */ 156166085Skib if (fp->f_type == DTYPE_VNODE) 157166085Skib (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 158166085Skib td->td_ucred, td); 159166085Skib } else { 160166085Skib PROC_UNLOCK(p); 161166085Skib sx_sunlock(&proctree_lock); 162166085Skib } 163166085Skib fdrop(fp, td); 164166085Skib /* 165166085Skib * XXX as above, fdrop()/kern_close() pair is racy. 166166085Skib */ 167166085Skib if (error) 168166085Skib kern_close(td, fd); 169166085Skib } 170166085Skib } 1719313Ssos 17214331Speter#ifdef DEBUG 173166085Skib if (ldebug(open)) 174166085Skib printf(LMSG("open returns error %d"), error); 17514331Speter#endif 176177997Skib LFREEPATH(path); 177177997Skib return (error); 1789313Ssos} 1799313Ssos 1809313Ssosint 181168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args) 182168014Sjulian{ 183177997Skib char *path; 184177997Skib int dfd; 185168014Sjulian 186177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 187177997Skib if (args->flags & LINUX_O_CREAT) 188177997Skib LCONVPATH_AT(td, args->filename, &path, 1, dfd); 189177997Skib else 190177997Skib LCONVPATH_AT(td, args->filename, &path, 0, dfd); 191168014Sjulian#ifdef DEBUG 192168014Sjulian if (ldebug(openat)) 193168014Sjulian printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 194177997Skib path, args->flags, args->mode); 195168014Sjulian#endif 196177997Skib return (linux_common_open(td, dfd, path, args->flags, args->mode)); 197168014Sjulian} 198168014Sjulian 199168014Sjulianint 200168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 201168014Sjulian{ 202168014Sjulian char *path; 203168014Sjulian 204168014Sjulian if (args->flags & LINUX_O_CREAT) 205168014Sjulian LCONVPATHCREAT(td, args->path, &path); 206168014Sjulian else 207168014Sjulian LCONVPATHEXIST(td, args->path, &path); 208168014Sjulian 209168014Sjulian#ifdef DEBUG 210168014Sjulian if (ldebug(open)) 211168014Sjulian printf(ARGS(open, "%s, 0x%x, 0x%x"), 212168014Sjulian path, args->flags, args->mode); 213168014Sjulian#endif 214168014Sjulian 215178036Srdivacky return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 216168014Sjulian} 217168014Sjulian 218168014Sjulianint 21983366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 2209313Ssos{ 2219313Ssos 22212858Speter struct lseek_args /* { 22312858Speter int fd; 2249313Ssos int pad; 22512858Speter off_t offset; 2269313Ssos int whence; 22712858Speter } */ tmp_args; 2289313Ssos int error; 2299313Ssos 2309313Ssos#ifdef DEBUG 23172543Sjlemon if (ldebug(lseek)) 23272543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 23383221Smarcel args->fdes, (long)args->off, args->whence); 2349313Ssos#endif 23512858Speter tmp_args.fd = args->fdes; 23612858Speter tmp_args.offset = (off_t)args->off; 2379313Ssos tmp_args.whence = args->whence; 238225617Skmacy error = sys_lseek(td, &tmp_args); 2399313Ssos return error; 2409313Ssos} 2419313Ssos 24214331Speterint 24383366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 24414331Speter{ 24514331Speter struct lseek_args bsd_args; 24614331Speter int error; 24714331Speter off_t off; 24814331Speter 24914331Speter#ifdef DEBUG 25072543Sjlemon if (ldebug(llseek)) 25172543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 25272543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 25314331Speter#endif 25414331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 25514331Speter 25614331Speter bsd_args.fd = args->fd; 25714331Speter bsd_args.offset = off; 25814331Speter bsd_args.whence = args->whence; 25914331Speter 260225617Skmacy if ((error = sys_lseek(td, &bsd_args))) 26114331Speter return error; 26214331Speter 263111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 26414331Speter return error; 26514331Speter 26683366Sjulian td->td_retval[0] = 0; 26714331Speter return 0; 26814331Speter} 26914331Speter 2709313Ssosint 27183366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args) 2729313Ssos{ 27314331Speter struct linux_getdents_args lda; 27414331Speter 27514331Speter lda.fd = args->fd; 27614331Speter lda.dent = args->dent; 27714331Speter lda.count = 1; 27883366Sjulian return linux_getdents(td, &lda); 27914331Speter} 28014331Speter 28183221Smarcel/* 28283221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 28383221Smarcel * arguments. They only differ in the definition of struct dirent they 28483221Smarcel * operate on. We use this to common the code, with the exception of 28583221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented 28683221Smarcel * by means of linux_getdents(2). In this case we never operate on 28783221Smarcel * struct dirent64 and thus don't need to handle it... 28883221Smarcel */ 28983221Smarcel 29083221Smarcelstruct l_dirent { 291179651Srdivacky l_ulong d_ino; 29283221Smarcel l_off_t d_off; 29383221Smarcel l_ushort d_reclen; 29483221Smarcel char d_name[LINUX_NAME_MAX + 1]; 29583221Smarcel}; 29683221Smarcel 29783221Smarcelstruct l_dirent64 { 29883221Smarcel uint64_t d_ino; 29983221Smarcel int64_t d_off; 30083221Smarcel l_ushort d_reclen; 30183221Smarcel u_char d_type; 30283221Smarcel char d_name[LINUX_NAME_MAX + 1]; 30383221Smarcel}; 30483221Smarcel 305182892Srdivacky/* 306182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type, 307182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. 308182892Srdivacky */ 309182892Srdivacky#define LINUX_RECLEN(namlen) \ 310182892Srdivacky roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2), \ 311182892Srdivacky sizeof(l_ulong)) 31283221Smarcel 313182892Srdivacky#define LINUX_RECLEN64(namlen) \ 314182892Srdivacky roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1), \ 315182892Srdivacky sizeof(uint64_t)) 316182892Srdivacky 317182892Srdivacky#define LINUX_MAXRECLEN max(LINUX_RECLEN(LINUX_NAME_MAX), \ 318182892Srdivacky LINUX_RECLEN64(LINUX_NAME_MAX)) 31983221Smarcel#define LINUX_DIRBLKSIZ 512 32083221Smarcel 32183221Smarcelstatic int 32283366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args, 32383221Smarcel int is64bit) 32414331Speter{ 325111798Sdes struct dirent *bdp; 32683221Smarcel struct vnode *vp; 32783221Smarcel caddr_t inp, buf; /* BSD-format */ 32883221Smarcel int len, reclen; /* BSD-format */ 32983221Smarcel caddr_t outp; /* Linux-format */ 33083221Smarcel int resid, linuxreclen=0; /* Linux-format */ 331182892Srdivacky caddr_t lbuf; /* Linux-format */ 332255219Spjd cap_rights_t rights; 33383221Smarcel struct file *fp; 33483221Smarcel struct uio auio; 33583221Smarcel struct iovec aiov; 33683221Smarcel off_t off; 337182892Srdivacky struct l_dirent *linux_dirent; 338182892Srdivacky struct l_dirent64 *linux_dirent64; 33983221Smarcel int buflen, error, eofflag, nbytes, justone; 34083221Smarcel u_long *cookies = NULL, *cookiep; 341241896Skib int ncookies; 3429313Ssos 343160276Sjhb nbytes = args->count; 344160276Sjhb if (nbytes == 1) { 345160276Sjhb /* readdir(2) case. Always struct dirent. */ 346160276Sjhb if (is64bit) 347160276Sjhb return (EINVAL); 348188572Snetchild nbytes = sizeof(*linux_dirent); 349160276Sjhb justone = 1; 350160276Sjhb } else 351160276Sjhb justone = 0; 352160276Sjhb 353255219Spjd error = getvnode(td->td_proc->p_fd, args->fd, 354255219Spjd cap_rights_init(&rights, CAP_READ), &fp); 355255219Spjd if (error != 0) 35683221Smarcel return (error); 3579313Ssos 35889306Salfred if ((fp->f_flag & FREAD) == 0) { 35989306Salfred fdrop(fp, td); 36083221Smarcel return (EBADF); 36189306Salfred } 3629313Ssos 363238029Skib off = foffset_lock(fp, 0); 364116678Sphk vp = fp->f_vnode; 36589306Salfred if (vp->v_type != VDIR) { 366238029Skib foffset_unlock(fp, off, 0); 36789306Salfred fdrop(fp, td); 36883221Smarcel return (EINVAL); 36989306Salfred } 3709313Ssos 3719313Ssos 37283221Smarcel buflen = max(LINUX_DIRBLKSIZ, nbytes); 37383221Smarcel buflen = min(buflen, MAXBSIZE); 374111119Simp buf = malloc(buflen, M_TEMP, M_WAITOK); 375182892Srdivacky lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO); 376188588Sjhb vn_lock(vp, LK_SHARED | LK_RETRY); 37783221Smarcel 37883221Smarcel aiov.iov_base = buf; 37983221Smarcel aiov.iov_len = buflen; 38083221Smarcel auio.uio_iov = &aiov; 38183221Smarcel auio.uio_iovcnt = 1; 38283221Smarcel auio.uio_rw = UIO_READ; 38383221Smarcel auio.uio_segflg = UIO_SYSSPACE; 38483366Sjulian auio.uio_td = td; 38583221Smarcel auio.uio_resid = buflen; 38683221Smarcel auio.uio_offset = off; 3879313Ssos 388101189Srwatson#ifdef MAC 389101189Srwatson /* 390101189Srwatson * Do directory search MAC check using non-cached credentials. 391101189Srwatson */ 392172930Srwatson if ((error = mac_vnode_check_readdir(td->td_ucred, vp))) 393101189Srwatson goto out; 394101189Srwatson#endif /* MAC */ 39583221Smarcel if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 39683221Smarcel &cookies))) 39783221Smarcel goto out; 3989313Ssos 39983221Smarcel inp = buf; 40083221Smarcel outp = (caddr_t)args->dirent; 40183221Smarcel resid = nbytes; 40283221Smarcel if ((len = buflen - auio.uio_resid) <= 0) 40383221Smarcel goto eof; 4049313Ssos 40583221Smarcel cookiep = cookies; 40624654Sdfr 40783221Smarcel if (cookies) { 40883221Smarcel /* 40983221Smarcel * When using cookies, the vfs has the option of reading from 41083221Smarcel * a different offset than that supplied (UFS truncates the 41183221Smarcel * offset to a block boundary to make sure that it never reads 41283221Smarcel * partway through a directory entry, even if the directory 41383221Smarcel * has been compacted). 41483221Smarcel */ 41583221Smarcel while (len > 0 && ncookies > 0 && *cookiep <= off) { 41683221Smarcel bdp = (struct dirent *) inp; 41783221Smarcel len -= bdp->d_reclen; 41883221Smarcel inp += bdp->d_reclen; 41983221Smarcel cookiep++; 42083221Smarcel ncookies--; 42183221Smarcel } 42224654Sdfr } 42324654Sdfr 42483221Smarcel while (len > 0) { 42583221Smarcel if (cookiep && ncookies == 0) 42683221Smarcel break; 42783221Smarcel bdp = (struct dirent *) inp; 42883221Smarcel reclen = bdp->d_reclen; 42983221Smarcel if (reclen & 3) { 43083221Smarcel error = EFAULT; 43183221Smarcel goto out; 43283221Smarcel } 43383221Smarcel 43483221Smarcel if (bdp->d_fileno == 0) { 43583221Smarcel inp += reclen; 43683221Smarcel if (cookiep) { 43783221Smarcel off = *cookiep++; 43883221Smarcel ncookies--; 43983221Smarcel } else 44083221Smarcel off += reclen; 44183221Smarcel 44283221Smarcel len -= reclen; 44383221Smarcel continue; 44483221Smarcel } 44583221Smarcel 44683221Smarcel linuxreclen = (is64bit) 447182892Srdivacky ? LINUX_RECLEN64(bdp->d_namlen) 448182892Srdivacky : LINUX_RECLEN(bdp->d_namlen); 44983221Smarcel 45083221Smarcel if (reclen > len || resid < linuxreclen) { 45183221Smarcel outp++; 45283221Smarcel break; 45383221Smarcel } 45483221Smarcel 45583221Smarcel if (justone) { 45683221Smarcel /* readdir(2) case. */ 457182892Srdivacky linux_dirent = (struct l_dirent*)lbuf; 458182892Srdivacky linux_dirent->d_ino = bdp->d_fileno; 459182892Srdivacky linux_dirent->d_off = (l_off_t)linuxreclen; 460182892Srdivacky linux_dirent->d_reclen = (l_ushort)bdp->d_namlen; 461182892Srdivacky strlcpy(linux_dirent->d_name, bdp->d_name, 462182892Srdivacky linuxreclen - offsetof(struct l_dirent, d_name)); 463182892Srdivacky error = copyout(linux_dirent, outp, linuxreclen); 46483221Smarcel } 465182892Srdivacky if (is64bit) { 466182892Srdivacky linux_dirent64 = (struct l_dirent64*)lbuf; 467182892Srdivacky linux_dirent64->d_ino = bdp->d_fileno; 468182892Srdivacky linux_dirent64->d_off = (cookiep) 469182892Srdivacky ? (l_off_t)*cookiep 470182892Srdivacky : (l_off_t)(off + reclen); 471182892Srdivacky linux_dirent64->d_reclen = (l_ushort)linuxreclen; 472182892Srdivacky linux_dirent64->d_type = bdp->d_type; 473182892Srdivacky strlcpy(linux_dirent64->d_name, bdp->d_name, 474182892Srdivacky linuxreclen - offsetof(struct l_dirent64, d_name)); 475182892Srdivacky error = copyout(linux_dirent64, outp, linuxreclen); 476182892Srdivacky } else if (!justone) { 477182892Srdivacky linux_dirent = (struct l_dirent*)lbuf; 478182892Srdivacky linux_dirent->d_ino = bdp->d_fileno; 479182892Srdivacky linux_dirent->d_off = (cookiep) 480182892Srdivacky ? (l_off_t)*cookiep 481182892Srdivacky : (l_off_t)(off + reclen); 482182892Srdivacky linux_dirent->d_reclen = (l_ushort)linuxreclen; 483182892Srdivacky /* 484182892Srdivacky * Copy d_type to last byte of l_dirent buffer 485182892Srdivacky */ 486182892Srdivacky lbuf[linuxreclen-1] = bdp->d_type; 487182892Srdivacky strlcpy(linux_dirent->d_name, bdp->d_name, 488182892Srdivacky linuxreclen - offsetof(struct l_dirent, d_name)-1); 489182892Srdivacky error = copyout(linux_dirent, outp, linuxreclen); 490182892Srdivacky } 491182892Srdivacky 49283221Smarcel if (error) 49383221Smarcel goto out; 49483221Smarcel 49583221Smarcel inp += reclen; 49683221Smarcel if (cookiep) { 49783221Smarcel off = *cookiep++; 49883221Smarcel ncookies--; 49983221Smarcel } else 50083221Smarcel off += reclen; 50183221Smarcel 50283221Smarcel outp += linuxreclen; 50383221Smarcel resid -= linuxreclen; 50483221Smarcel len -= reclen; 50583221Smarcel if (justone) 50683221Smarcel break; 50710355Sswallace } 5089313Ssos 509217578Skib if (outp == (caddr_t)args->dirent) { 510217578Skib nbytes = resid; 511217578Skib goto eof; 512217578Skib } 5139313Ssos 51483221Smarcel if (justone) 51583221Smarcel nbytes = resid + linuxreclen; 51610355Sswallace 5179313Ssoseof: 51883366Sjulian td->td_retval[0] = nbytes - resid; 51983221Smarcel 5209313Ssosout: 521247764Seadler free(cookies, M_TEMP); 52283221Smarcel 523175294Sattilio VOP_UNLOCK(vp, 0); 524238029Skib foffset_unlock(fp, off, 0); 52589306Salfred fdrop(fp, td); 52683221Smarcel free(buf, M_TEMP); 527182892Srdivacky free(lbuf, M_TEMP); 52883221Smarcel return (error); 5299313Ssos} 53014331Speter 53183221Smarcelint 53283366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args) 53383221Smarcel{ 53483221Smarcel 53583221Smarcel#ifdef DEBUG 53683221Smarcel if (ldebug(getdents)) 53783221Smarcel printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 53883221Smarcel#endif 53983221Smarcel 54083366Sjulian return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 54183221Smarcel} 54283221Smarcel 54383221Smarcelint 54483366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 54583221Smarcel{ 54683221Smarcel 54783221Smarcel#ifdef DEBUG 54883221Smarcel if (ldebug(getdents64)) 54983221Smarcel printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 55083221Smarcel#endif 55183221Smarcel 55283366Sjulian return (getdents_common(td, args, 1)); 55383221Smarcel} 55483221Smarcel 55514331Speter/* 55614331Speter * These exist mainly for hooks for doing /compat/linux translation. 55714331Speter */ 55814331Speter 55914331Speterint 56083366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 56114331Speter{ 562102814Siedowse char *path; 563102814Siedowse int error; 56414331Speter 565162585Snetchild /* linux convention */ 566227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 567162585Snetchild return (EINVAL); 568162585Snetchild 569102814Siedowse LCONVPATHEXIST(td, args->path, &path); 57014331Speter 57114331Speter#ifdef DEBUG 57272543Sjlemon if (ldebug(access)) 573227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 57414331Speter#endif 575227691Sed error = kern_access(td, path, UIO_SYSSPACE, args->amode); 576102814Siedowse LFREEPATH(path); 577162585Snetchild 578102814Siedowse return (error); 57914331Speter} 58014331Speter 58114331Speterint 582177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args) 583177997Skib{ 584177997Skib char *path; 585227693Sed int error, dfd, flag; 586177997Skib 587227693Sed if (args->flag & ~LINUX_AT_EACCESS) 588227693Sed return (EINVAL); 589177997Skib /* linux convention */ 590227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 591177997Skib return (EINVAL); 592177997Skib 593177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 594177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 595177997Skib 596177997Skib#ifdef DEBUG 597177997Skib if (ldebug(access)) 598227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 599177997Skib#endif 600177997Skib 601227693Sed flag = (args->flag & LINUX_AT_EACCESS) == 0 ? 0 : AT_EACCESS; 602227693Sed error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flag, args->amode); 603177997Skib LFREEPATH(path); 604177997Skib 605177997Skib return (error); 606177997Skib} 607177997Skib 608177997Skibint 60983366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 61014331Speter{ 611102814Siedowse char *path; 612102814Siedowse int error; 613162201Snetchild struct stat st; 61414331Speter 615102814Siedowse LCONVPATHEXIST(td, args->path, &path); 61614331Speter 61714331Speter#ifdef DEBUG 61872543Sjlemon if (ldebug(unlink)) 619102814Siedowse printf(ARGS(unlink, "%s"), path); 62014331Speter#endif 62114331Speter 622102814Siedowse error = kern_unlink(td, path, UIO_SYSSPACE); 623162201Snetchild if (error == EPERM) 624162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 625162201Snetchild if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 626162201Snetchild if (S_ISDIR(st.st_mode)) 627162201Snetchild error = EISDIR; 628102814Siedowse LFREEPATH(path); 629102814Siedowse return (error); 63014331Speter} 63114331Speter 63214331Speterint 633177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 634177997Skib{ 635177997Skib char *path; 636177997Skib int error, dfd; 637177997Skib struct stat st; 638177997Skib 639177997Skib if (args->flag & ~LINUX_AT_REMOVEDIR) 640177997Skib return (EINVAL); 641177997Skib 642177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 643177997Skib LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 644177997Skib 645177997Skib#ifdef DEBUG 646177997Skib if (ldebug(unlinkat)) 647177997Skib printf(ARGS(unlinkat, "%s"), path); 648177997Skib#endif 649177997Skib 650177997Skib if (args->flag & LINUX_AT_REMOVEDIR) 651177997Skib error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); 652177997Skib else 653202113Smckusick error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0); 654177997Skib if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 655177997Skib /* Introduce POSIX noncompliant behaviour of Linux */ 656177997Skib if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 657177997Skib UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode)) 658177997Skib error = EISDIR; 659177997Skib } 660177997Skib LFREEPATH(path); 661177997Skib return (error); 662177997Skib} 663177997Skibint 66483366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 66514331Speter{ 666102814Siedowse char *path; 667102814Siedowse int error; 66814331Speter 669102814Siedowse LCONVPATHEXIST(td, args->path, &path); 67014331Speter 67114331Speter#ifdef DEBUG 67272543Sjlemon if (ldebug(chdir)) 673102814Siedowse printf(ARGS(chdir, "%s"), path); 67414331Speter#endif 675102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 676102814Siedowse LFREEPATH(path); 677102814Siedowse return (error); 67814331Speter} 67914331Speter 68014331Speterint 68183366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 68214331Speter{ 683102814Siedowse char *path; 684102814Siedowse int error; 68514331Speter 686102814Siedowse LCONVPATHEXIST(td, args->path, &path); 68714331Speter 68814331Speter#ifdef DEBUG 68972543Sjlemon if (ldebug(chmod)) 690102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 69114331Speter#endif 692102814Siedowse error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 693102814Siedowse LFREEPATH(path); 694102814Siedowse return (error); 69514331Speter} 69614331Speter 69714331Speterint 698177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 699177997Skib{ 700177997Skib char *path; 701177997Skib int error, dfd; 702177997Skib 703177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 704177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 705177997Skib 706177997Skib#ifdef DEBUG 707177997Skib if (ldebug(fchmodat)) 708177997Skib printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 709177997Skib#endif 710177997Skib 711177997Skib error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 712177997Skib LFREEPATH(path); 713177997Skib return (error); 714177997Skib} 715177997Skib 716177997Skibint 71783366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 71814331Speter{ 719102814Siedowse char *path; 720102814Siedowse int error; 72114331Speter 722102814Siedowse LCONVPATHCREAT(td, args->path, &path); 72314331Speter 72414331Speter#ifdef DEBUG 72572543Sjlemon if (ldebug(mkdir)) 726102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 72714331Speter#endif 728102814Siedowse error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 729102814Siedowse LFREEPATH(path); 730102814Siedowse return (error); 73114331Speter} 73214331Speter 73314331Speterint 734177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 735177997Skib{ 736177997Skib char *path; 737177997Skib int error, dfd; 738177997Skib 739177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 740177997Skib LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 741177997Skib 742177997Skib#ifdef DEBUG 743177997Skib if (ldebug(mkdirat)) 744177997Skib printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 745177997Skib#endif 746177997Skib error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 747177997Skib LFREEPATH(path); 748177997Skib return (error); 749177997Skib} 750177997Skib 751177997Skibint 75283366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 75314331Speter{ 754102814Siedowse char *path; 755102814Siedowse int error; 75614331Speter 757102814Siedowse LCONVPATHEXIST(td, args->path, &path); 75814331Speter 75914331Speter#ifdef DEBUG 76072543Sjlemon if (ldebug(rmdir)) 761102814Siedowse printf(ARGS(rmdir, "%s"), path); 76214331Speter#endif 763102814Siedowse error = kern_rmdir(td, path, UIO_SYSSPACE); 764102814Siedowse LFREEPATH(path); 765102814Siedowse return (error); 76614331Speter} 76714331Speter 76814331Speterint 76983366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 77014331Speter{ 771102814Siedowse char *from, *to; 772102814Siedowse int error; 77314331Speter 774102814Siedowse LCONVPATHEXIST(td, args->from, &from); 775102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 776177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 777102814Siedowse if (to == NULL) { 778102814Siedowse LFREEPATH(from); 779102814Siedowse return (error); 780102814Siedowse } 78114331Speter 78214331Speter#ifdef DEBUG 78372543Sjlemon if (ldebug(rename)) 784102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 78514331Speter#endif 786102814Siedowse error = kern_rename(td, from, to, UIO_SYSSPACE); 787102814Siedowse LFREEPATH(from); 788102814Siedowse LFREEPATH(to); 789102814Siedowse return (error); 79014331Speter} 79114331Speter 79214331Speterint 793177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args) 794177997Skib{ 795177997Skib char *from, *to; 796177997Skib int error, olddfd, newdfd; 797177997Skib 798177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 799177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 800177997Skib LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 801177997Skib /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 802177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 803177997Skib if (to == NULL) { 804177997Skib LFREEPATH(from); 805177997Skib return (error); 806177997Skib } 807177997Skib 808177997Skib#ifdef DEBUG 809177997Skib if (ldebug(renameat)) 810177997Skib printf(ARGS(renameat, "%s, %s"), from, to); 811177997Skib#endif 812177997Skib error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 813177997Skib LFREEPATH(from); 814177997Skib LFREEPATH(to); 815177997Skib return (error); 816177997Skib} 817177997Skib 818177997Skibint 81983366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 82014331Speter{ 821102814Siedowse char *path, *to; 822102814Siedowse int error; 82314331Speter 824102814Siedowse LCONVPATHEXIST(td, args->path, &path); 825102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 826177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 827102814Siedowse if (to == NULL) { 828102814Siedowse LFREEPATH(path); 829102814Siedowse return (error); 830102814Siedowse } 83114331Speter 83214331Speter#ifdef DEBUG 83372543Sjlemon if (ldebug(symlink)) 834102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 83514331Speter#endif 836102814Siedowse error = kern_symlink(td, path, to, UIO_SYSSPACE); 837102814Siedowse LFREEPATH(path); 838102814Siedowse LFREEPATH(to); 839102814Siedowse return (error); 84014331Speter} 84114331Speter 84214331Speterint 843177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 844177997Skib{ 845177997Skib char *path, *to; 846177997Skib int error, dfd; 847177997Skib 848177997Skib dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 849177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); 850177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 851177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 852177997Skib if (to == NULL) { 853177997Skib LFREEPATH(path); 854177997Skib return (error); 855177997Skib } 856177997Skib 857177997Skib#ifdef DEBUG 858177997Skib if (ldebug(symlinkat)) 859177997Skib printf(ARGS(symlinkat, "%s, %s"), path, to); 860177997Skib#endif 861177997Skib 862177997Skib error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 863177997Skib LFREEPATH(path); 864177997Skib LFREEPATH(to); 865177997Skib return (error); 866177997Skib} 867177997Skib 868177997Skibint 86983366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 87014331Speter{ 871102814Siedowse char *name; 872102814Siedowse int error; 87314331Speter 874102814Siedowse LCONVPATHEXIST(td, args->name, &name); 87514331Speter 87614331Speter#ifdef DEBUG 87772543Sjlemon if (ldebug(readlink)) 878102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 879102814Siedowse args->count); 88014331Speter#endif 881102814Siedowse error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 882102814Siedowse args->count); 883102814Siedowse LFREEPATH(name); 884102814Siedowse return (error); 88514331Speter} 88614331Speter 88714331Speterint 888177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 889177997Skib{ 890177997Skib char *name; 891177997Skib int error, dfd; 892177997Skib 893177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 894177997Skib LCONVPATHEXIST_AT(td, args->path, &name, dfd); 895177997Skib 896177997Skib#ifdef DEBUG 897177997Skib if (ldebug(readlinkat)) 898177997Skib printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 899177997Skib args->bufsiz); 900177997Skib#endif 901177997Skib 902177997Skib error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 903177997Skib UIO_USERSPACE, args->bufsiz); 904177997Skib LFREEPATH(name); 905177997Skib return (error); 906177997Skib} 907178439Srdivacky 908177997Skibint 90983366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 91014331Speter{ 911102814Siedowse char *path; 912102814Siedowse int error; 91314331Speter 914102814Siedowse LCONVPATHEXIST(td, args->path, &path); 91514331Speter 91614331Speter#ifdef DEBUG 91772543Sjlemon if (ldebug(truncate)) 918102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 91914331Speter#endif 92014331Speter 921102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 922102814Siedowse LFREEPATH(path); 923102814Siedowse return (error); 92414331Speter} 92514331Speter 92649662Smarcelint 927178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args) 928178439Srdivacky{ 929178439Srdivacky char *path; 930178439Srdivacky int error; 931178439Srdivacky 932178439Srdivacky LCONVPATHEXIST(td, args->path, &path); 933178439Srdivacky 934178439Srdivacky#ifdef DEBUG 935178439Srdivacky if (ldebug(truncate64)) 936178439Srdivacky printf(ARGS(truncate64, "%s, %jd"), path, args->length); 937178439Srdivacky#endif 938178439Srdivacky 939178439Srdivacky error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 940178439Srdivacky LFREEPATH(path); 941178439Srdivacky return (error); 942178439Srdivacky} 943178439Srdivackyint 944156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 945156842Snetchild{ 946156842Snetchild struct ftruncate_args /* { 947156842Snetchild int fd; 948156842Snetchild int pad; 949156842Snetchild off_t length; 950156842Snetchild } */ nuap; 951156842Snetchild 952156842Snetchild nuap.fd = args->fd; 953156842Snetchild nuap.length = args->length; 954225617Skmacy return (sys_ftruncate(td, &nuap)); 955156842Snetchild} 956156842Snetchild 957156842Snetchildint 95883366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 95949662Smarcel{ 960102814Siedowse char *path, *to; 961102814Siedowse int error; 96249662Smarcel 963102814Siedowse LCONVPATHEXIST(td, args->path, &path); 964102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 965177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 966102814Siedowse if (to == NULL) { 967102814Siedowse LFREEPATH(path); 968102814Siedowse return (error); 969102814Siedowse } 97049662Smarcel 97149662Smarcel#ifdef DEBUG 97272543Sjlemon if (ldebug(link)) 973102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 97449662Smarcel#endif 975102814Siedowse error = kern_link(td, path, to, UIO_SYSSPACE); 976102814Siedowse LFREEPATH(path); 977102814Siedowse LFREEPATH(to); 978102814Siedowse return (error); 97949662Smarcel} 98049788Smarcel 98153713Smarcelint 982177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args) 983177997Skib{ 984177997Skib char *path, *to; 985227693Sed int error, olddfd, newdfd, follow; 986177997Skib 987227693Sed if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) 988177997Skib return (EINVAL); 989177997Skib 990177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 991177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 992177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 993177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 994177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 995177997Skib if (to == NULL) { 996177997Skib LFREEPATH(path); 997177997Skib return (error); 998177997Skib } 999177997Skib 1000177997Skib#ifdef DEBUG 1001177997Skib if (ldebug(linkat)) 1002177997Skib printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 1003227693Sed args->newdfd, to, args->flag); 1004177997Skib#endif 1005177997Skib 1006227693Sed follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : 1007227693Sed FOLLOW; 1008227693Sed error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); 1009177997Skib LFREEPATH(path); 1010177997Skib LFREEPATH(to); 1011177997Skib return (error); 1012177997Skib} 1013177997Skib 1014177997Skibint 101583366Sjulianlinux_fdatasync(td, uap) 101683366Sjulian struct thread *td; 101753713Smarcel struct linux_fdatasync_args *uap; 101853713Smarcel{ 101953713Smarcel struct fsync_args bsd; 102053713Smarcel 102153713Smarcel bsd.fd = uap->fd; 1022225617Skmacy return sys_fsync(td, &bsd); 102353713Smarcel} 102463285Smarcel 102563285Smarcelint 102683366Sjulianlinux_pread(td, uap) 102783366Sjulian struct thread *td; 102863285Smarcel struct linux_pread_args *uap; 102963285Smarcel{ 103063285Smarcel struct pread_args bsd; 1031255219Spjd cap_rights_t rights; 1032162585Snetchild struct vnode *vp; 1033162585Snetchild int error; 103463285Smarcel 103563285Smarcel bsd.fd = uap->fd; 103663285Smarcel bsd.buf = uap->buf; 103763285Smarcel bsd.nbyte = uap->nbyte; 103863285Smarcel bsd.offset = uap->offset; 1039162585Snetchild 1040225617Skmacy error = sys_pread(td, &bsd); 1041162585Snetchild 1042162585Snetchild if (error == 0) { 1043247602Spjd /* This seems to violate POSIX but linux does it */ 1044255219Spjd error = fgetvp(td, uap->fd, 1045255219Spjd cap_rights_init(&rights, CAP_PREAD), &vp); 1046255219Spjd if (error != 0) 1047247602Spjd return (error); 1048162585Snetchild if (vp->v_type == VDIR) { 1049247602Spjd vrele(vp); 1050162585Snetchild return (EISDIR); 1051162585Snetchild } 1052162585Snetchild vrele(vp); 1053162585Snetchild } 1054162585Snetchild 1055162585Snetchild return (error); 105663285Smarcel} 105763285Smarcel 105863285Smarcelint 105983366Sjulianlinux_pwrite(td, uap) 106083366Sjulian struct thread *td; 106163285Smarcel struct linux_pwrite_args *uap; 106263285Smarcel{ 106363285Smarcel struct pwrite_args bsd; 106463285Smarcel 106563285Smarcel bsd.fd = uap->fd; 106663285Smarcel bsd.buf = uap->buf; 106763285Smarcel bsd.nbyte = uap->nbyte; 106863285Smarcel bsd.offset = uap->offset; 1069225617Skmacy return sys_pwrite(td, &bsd); 107063285Smarcel} 107172538Sjlemon 107272538Sjlemonint 107383366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 107472538Sjlemon{ 107572538Sjlemon struct ufs_args ufs; 1076111798Sdes char fstypename[MFSNAMELEN]; 1077111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 107873286Sadrian int error; 107973286Sadrian int fsflags; 108073286Sadrian void *fsdata; 108172538Sjlemon 1082111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 108373286Sadrian NULL); 108472538Sjlemon if (error) 1085111798Sdes return (error); 1086127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 108772538Sjlemon if (error) 1088111798Sdes return (error); 1089127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 109072538Sjlemon if (error) 1091111798Sdes return (error); 109272538Sjlemon 109372538Sjlemon#ifdef DEBUG 109472538Sjlemon if (ldebug(mount)) 109572538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 109672538Sjlemon fstypename, mntfromname, mntonname); 109772538Sjlemon#endif 109872538Sjlemon 109972538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 1100127059Stjr strcpy(fstypename, "ext2fs"); 110173286Sadrian fsdata = &ufs; 110272538Sjlemon ufs.fspec = mntfromname; 110372538Sjlemon#define DEFAULT_ROOTID -2 110472538Sjlemon ufs.export.ex_root = DEFAULT_ROOTID; 110572538Sjlemon ufs.export.ex_flags = 110672538Sjlemon args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 110772538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 1108127059Stjr strcpy(fstypename, "linprocfs"); 110973286Sadrian fsdata = NULL; 1110190445Sambrisko } else if (strcmp(fstypename, "vfat") == 0) { 1111190445Sambrisko strcpy(fstypename, "msdosfs"); 1112190445Sambrisko fsdata = NULL; 111372538Sjlemon } else { 111472538Sjlemon return (ENODEV); 111572538Sjlemon } 111672538Sjlemon 111773286Sadrian fsflags = 0; 111872538Sjlemon 111972538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 112072538Sjlemon /* 112172538Sjlemon * Linux SYNC flag is not included; the closest equivalent 112272538Sjlemon * FreeBSD has is !ASYNC, which is our default. 112372538Sjlemon */ 112472538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 1125111798Sdes fsflags |= MNT_RDONLY; 112672538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 1127111798Sdes fsflags |= MNT_NOSUID; 112872538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 1129111798Sdes fsflags |= MNT_NOEXEC; 113072538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 1131111798Sdes fsflags |= MNT_UPDATE; 113272538Sjlemon } 113372538Sjlemon 1134127059Stjr if (strcmp(fstypename, "linprocfs") == 0) { 1135132708Sphk error = kernel_vmount(fsflags, 1136132708Sphk "fstype", fstypename, 1137132708Sphk "fspath", mntonname, 1138132708Sphk NULL); 1139190445Sambrisko } else if (strcmp(fstypename, "msdosfs") == 0) { 1140190445Sambrisko error = kernel_vmount(fsflags, 1141190445Sambrisko "fstype", fstypename, 1142190445Sambrisko "fspath", mntonname, 1143190445Sambrisko "from", mntfromname, 1144190445Sambrisko NULL); 1145127059Stjr } else 1146138353Sphk error = EOPNOTSUPP; 1147127059Stjr return (error); 114872538Sjlemon} 114972538Sjlemon 115072538Sjlemonint 115183366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 115272538Sjlemon{ 115383221Smarcel struct linux_umount_args args2; 115472538Sjlemon 115572538Sjlemon args2.path = args->path; 115672538Sjlemon args2.flags = 0; 115783366Sjulian return (linux_umount(td, &args2)); 115872538Sjlemon} 115972538Sjlemon 116072538Sjlemonint 116183366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 116272538Sjlemon{ 116372538Sjlemon struct unmount_args bsd; 116472538Sjlemon 116572538Sjlemon bsd.path = args->path; 116672538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 1167225617Skmacy return (sys_unmount(td, &bsd)); 116872538Sjlemon} 116983221Smarcel 117083221Smarcel/* 117183221Smarcel * fcntl family of syscalls 117283221Smarcel */ 117383221Smarcel 117483221Smarcelstruct l_flock { 117583221Smarcel l_short l_type; 117683221Smarcel l_short l_whence; 117783221Smarcel l_off_t l_start; 117883221Smarcel l_off_t l_len; 117983221Smarcel l_pid_t l_pid; 1180133816Stjr} 1181140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1182133816Stjr__packed 1183133816Stjr#endif 1184133816Stjr; 118583221Smarcel 118683221Smarcelstatic void 118783221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 118883221Smarcel{ 118983221Smarcel switch (linux_flock->l_type) { 119083221Smarcel case LINUX_F_RDLCK: 119183221Smarcel bsd_flock->l_type = F_RDLCK; 119283221Smarcel break; 119383221Smarcel case LINUX_F_WRLCK: 119483221Smarcel bsd_flock->l_type = F_WRLCK; 119583221Smarcel break; 119683221Smarcel case LINUX_F_UNLCK: 119783221Smarcel bsd_flock->l_type = F_UNLCK; 119883221Smarcel break; 119983221Smarcel default: 120083221Smarcel bsd_flock->l_type = -1; 120183221Smarcel break; 120283221Smarcel } 120383221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 120483221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 120583221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 120683221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1207177633Sdfr bsd_flock->l_sysid = 0; 120883221Smarcel} 120983221Smarcel 121083221Smarcelstatic void 121183221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 121283221Smarcel{ 121383221Smarcel switch (bsd_flock->l_type) { 121483221Smarcel case F_RDLCK: 121583221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 121683221Smarcel break; 121783221Smarcel case F_WRLCK: 121883221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 121983221Smarcel break; 122083221Smarcel case F_UNLCK: 122183221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 122283221Smarcel break; 122383221Smarcel } 122483221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 122583221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 122683221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 122783221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 122883221Smarcel} 122983221Smarcel 1230140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 123183221Smarcelstruct l_flock64 { 123283221Smarcel l_short l_type; 123383221Smarcel l_short l_whence; 123483221Smarcel l_loff_t l_start; 123583221Smarcel l_loff_t l_len; 123683221Smarcel l_pid_t l_pid; 1237133816Stjr} 1238140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1239133816Stjr__packed 1240133816Stjr#endif 1241133816Stjr; 124283221Smarcel 124383221Smarcelstatic void 124483221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 124583221Smarcel{ 124683221Smarcel switch (linux_flock->l_type) { 124783221Smarcel case LINUX_F_RDLCK: 124883221Smarcel bsd_flock->l_type = F_RDLCK; 124983221Smarcel break; 125083221Smarcel case LINUX_F_WRLCK: 125183221Smarcel bsd_flock->l_type = F_WRLCK; 125283221Smarcel break; 125383221Smarcel case LINUX_F_UNLCK: 125483221Smarcel bsd_flock->l_type = F_UNLCK; 125583221Smarcel break; 125683221Smarcel default: 125783221Smarcel bsd_flock->l_type = -1; 125883221Smarcel break; 125983221Smarcel } 126083221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 126183221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 126283221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 126383221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1264177633Sdfr bsd_flock->l_sysid = 0; 126583221Smarcel} 126683221Smarcel 126783221Smarcelstatic void 126883221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 126983221Smarcel{ 127083221Smarcel switch (bsd_flock->l_type) { 127183221Smarcel case F_RDLCK: 127283221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 127383221Smarcel break; 127483221Smarcel case F_WRLCK: 127583221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 127683221Smarcel break; 127783221Smarcel case F_UNLCK: 127883221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 127983221Smarcel break; 128083221Smarcel } 128183221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 128283221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 128383221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 128483221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 128583221Smarcel} 1286133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 128783221Smarcel 128883221Smarcelstatic int 128983366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args) 129083221Smarcel{ 1291107680Siedowse struct l_flock linux_flock; 1292107680Siedowse struct flock bsd_flock; 1293255219Spjd cap_rights_t rights; 129483221Smarcel struct file *fp; 1295102872Siedowse long arg; 129683221Smarcel int error, result; 129783221Smarcel 129883221Smarcel switch (args->cmd) { 129983221Smarcel case LINUX_F_DUPFD: 1300102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 130183221Smarcel 130283221Smarcel case LINUX_F_GETFD: 1303102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 130483221Smarcel 130583221Smarcel case LINUX_F_SETFD: 1306102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 130783221Smarcel 130883221Smarcel case LINUX_F_GETFL: 1309102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 131083366Sjulian result = td->td_retval[0]; 131183366Sjulian td->td_retval[0] = 0; 131283221Smarcel if (result & O_RDONLY) 131383366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 131483221Smarcel if (result & O_WRONLY) 131583366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 131683221Smarcel if (result & O_RDWR) 131783366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 131883221Smarcel if (result & O_NDELAY) 131983366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 132083221Smarcel if (result & O_APPEND) 132183366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 132283221Smarcel if (result & O_FSYNC) 132383366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 132483221Smarcel if (result & O_ASYNC) 132583366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1326144987Smdodd#ifdef LINUX_O_NOFOLLOW 1327144987Smdodd if (result & O_NOFOLLOW) 1328144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1329144987Smdodd#endif 1330144987Smdodd#ifdef LINUX_O_DIRECT 1331144987Smdodd if (result & O_DIRECT) 1332144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1333144987Smdodd#endif 133483221Smarcel return (error); 133583221Smarcel 133683221Smarcel case LINUX_F_SETFL: 1337102872Siedowse arg = 0; 133883221Smarcel if (args->arg & LINUX_O_NDELAY) 1339102872Siedowse arg |= O_NONBLOCK; 134083221Smarcel if (args->arg & LINUX_O_APPEND) 1341102872Siedowse arg |= O_APPEND; 134283221Smarcel if (args->arg & LINUX_O_SYNC) 1343102872Siedowse arg |= O_FSYNC; 134483221Smarcel if (args->arg & LINUX_FASYNC) 1345102872Siedowse arg |= O_ASYNC; 1346144987Smdodd#ifdef LINUX_O_NOFOLLOW 1347144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1348144987Smdodd arg |= O_NOFOLLOW; 1349144987Smdodd#endif 1350144987Smdodd#ifdef LINUX_O_DIRECT 1351144987Smdodd if (args->arg & LINUX_O_DIRECT) 1352144987Smdodd arg |= O_DIRECT; 1353144987Smdodd#endif 1354102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 135583221Smarcel 1356107680Siedowse case LINUX_F_GETLK: 1357111797Sdes error = copyin((void *)args->arg, &linux_flock, 1358107680Siedowse sizeof(linux_flock)); 1359107680Siedowse if (error) 1360107680Siedowse return (error); 1361107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1362107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1363107680Siedowse if (error) 1364107680Siedowse return (error); 1365107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1366111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1367107680Siedowse sizeof(linux_flock))); 1368107680Siedowse 1369107680Siedowse case LINUX_F_SETLK: 1370111797Sdes error = copyin((void *)args->arg, &linux_flock, 1371107680Siedowse sizeof(linux_flock)); 1372107680Siedowse if (error) 1373107680Siedowse return (error); 1374107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1375107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1376107680Siedowse (intptr_t)&bsd_flock)); 1377107680Siedowse 1378107680Siedowse case LINUX_F_SETLKW: 1379111797Sdes error = copyin((void *)args->arg, &linux_flock, 1380107680Siedowse sizeof(linux_flock)); 1381107680Siedowse if (error) 1382107680Siedowse return (error); 1383107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1384107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1385107680Siedowse (intptr_t)&bsd_flock)); 1386107680Siedowse 138783221Smarcel case LINUX_F_GETOWN: 1388102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 138983221Smarcel 139083221Smarcel case LINUX_F_SETOWN: 139183221Smarcel /* 139283221Smarcel * XXX some Linux applications depend on F_SETOWN having no 139383221Smarcel * significant effect for pipes (SIGIO is not delivered for 139483221Smarcel * pipes under Linux-2.2.35 at least). 139583221Smarcel */ 1396255219Spjd error = fget(td, args->fd, 1397255219Spjd cap_rights_init(&rights, CAP_FCNTL), &fp); 139889319Salfred if (error) 139989319Salfred return (error); 140089306Salfred if (fp->f_type == DTYPE_PIPE) { 140189306Salfred fdrop(fp, td); 140283221Smarcel return (EINVAL); 140389306Salfred } 140489306Salfred fdrop(fp, td); 140583221Smarcel 1406102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 140783221Smarcel } 140883221Smarcel 140983221Smarcel return (EINVAL); 141083221Smarcel} 141183221Smarcel 141283221Smarcelint 141383366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 141483221Smarcel{ 141583221Smarcel struct linux_fcntl64_args args64; 141683221Smarcel 141783221Smarcel#ifdef DEBUG 141883221Smarcel if (ldebug(fcntl)) 141983221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 142083221Smarcel#endif 142183221Smarcel 142283221Smarcel args64.fd = args->fd; 142383221Smarcel args64.cmd = args->cmd; 142483221Smarcel args64.arg = args->arg; 142583366Sjulian return (fcntl_common(td, &args64)); 142683221Smarcel} 142783221Smarcel 1428140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 142983221Smarcelint 143083366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 143183221Smarcel{ 143283221Smarcel struct l_flock64 linux_flock; 1433102872Siedowse struct flock bsd_flock; 143483221Smarcel int error; 143583221Smarcel 143683221Smarcel#ifdef DEBUG 143783221Smarcel if (ldebug(fcntl64)) 143883221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 143983221Smarcel#endif 144083221Smarcel 144183221Smarcel switch (args->cmd) { 144299687Srobert case LINUX_F_GETLK64: 1443111797Sdes error = copyin((void *)args->arg, &linux_flock, 144483221Smarcel sizeof(linux_flock)); 144583221Smarcel if (error) 144683221Smarcel return (error); 1447102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1448102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 144983221Smarcel if (error) 145083221Smarcel return (error); 1451102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1452111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1453111797Sdes sizeof(linux_flock))); 145483221Smarcel 145599687Srobert case LINUX_F_SETLK64: 1456111797Sdes error = copyin((void *)args->arg, &linux_flock, 145783221Smarcel sizeof(linux_flock)); 145883221Smarcel if (error) 145983221Smarcel return (error); 1460102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1461102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1462102872Siedowse (intptr_t)&bsd_flock)); 146383221Smarcel 146499687Srobert case LINUX_F_SETLKW64: 1465111797Sdes error = copyin((void *)args->arg, &linux_flock, 146683221Smarcel sizeof(linux_flock)); 146783221Smarcel if (error) 146883221Smarcel return (error); 1469102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1470102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1471102872Siedowse (intptr_t)&bsd_flock)); 147283221Smarcel } 147383221Smarcel 147483366Sjulian return (fcntl_common(td, args)); 147583221Smarcel} 1476133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 147785022Smarcel 147885022Smarcelint 147985022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 148085022Smarcel{ 1481102814Siedowse char *path; 1482102814Siedowse int error; 148385022Smarcel 1484102814Siedowse LCONVPATHEXIST(td, args->path, &path); 148585022Smarcel 148685022Smarcel#ifdef DEBUG 148785022Smarcel if (ldebug(chown)) 1488102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 148985022Smarcel#endif 1490102814Siedowse error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1491102814Siedowse LFREEPATH(path); 1492102814Siedowse return (error); 149385022Smarcel} 149485022Smarcel 149585022Smarcelint 1496177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1497177997Skib{ 1498177997Skib char *path; 1499227693Sed int error, dfd, flag; 1500177997Skib 1501177997Skib if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1502177997Skib return (EINVAL); 1503177997Skib 1504177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1505177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1506177997Skib 1507177997Skib#ifdef DEBUG 1508177997Skib if (ldebug(fchownat)) 1509177997Skib printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1510177997Skib#endif 1511177997Skib 1512227693Sed flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1513177997Skib AT_SYMLINK_NOFOLLOW; 1514177997Skib error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1515227693Sed flag); 1516177997Skib LFREEPATH(path); 1517177997Skib return (error); 1518177997Skib} 1519177997Skib 1520177997Skibint 152185022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 152285022Smarcel{ 1523102814Siedowse char *path; 1524102814Siedowse int error; 152585022Smarcel 1526102814Siedowse LCONVPATHEXIST(td, args->path, &path); 152785022Smarcel 152885022Smarcel#ifdef DEBUG 152985022Smarcel if (ldebug(lchown)) 1530102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 153185022Smarcel#endif 1532102814Siedowse error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1533102814Siedowse LFREEPATH(path); 1534102814Siedowse return (error); 153585022Smarcel} 1536228957Sjhb 1537228957Sjhbstatic int 1538228957Sjhbconvert_fadvice(int advice) 1539228957Sjhb{ 1540228957Sjhb switch (advice) { 1541228957Sjhb case LINUX_POSIX_FADV_NORMAL: 1542228957Sjhb return (POSIX_FADV_NORMAL); 1543228957Sjhb case LINUX_POSIX_FADV_RANDOM: 1544228957Sjhb return (POSIX_FADV_RANDOM); 1545228957Sjhb case LINUX_POSIX_FADV_SEQUENTIAL: 1546228957Sjhb return (POSIX_FADV_SEQUENTIAL); 1547228957Sjhb case LINUX_POSIX_FADV_WILLNEED: 1548228957Sjhb return (POSIX_FADV_WILLNEED); 1549228957Sjhb case LINUX_POSIX_FADV_DONTNEED: 1550228957Sjhb return (POSIX_FADV_DONTNEED); 1551228957Sjhb case LINUX_POSIX_FADV_NOREUSE: 1552228957Sjhb return (POSIX_FADV_NOREUSE); 1553228957Sjhb default: 1554228957Sjhb return (-1); 1555228957Sjhb } 1556228957Sjhb} 1557228957Sjhb 1558228957Sjhbint 1559228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) 1560228957Sjhb{ 1561228957Sjhb int advice; 1562228957Sjhb 1563228957Sjhb advice = convert_fadvice(args->advice); 1564228957Sjhb if (advice == -1) 1565228957Sjhb return (EINVAL); 1566228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1567228957Sjhb advice)); 1568228957Sjhb} 1569228957Sjhb 1570228957Sjhbint 1571228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) 1572228957Sjhb{ 1573228957Sjhb int advice; 1574228957Sjhb 1575228957Sjhb advice = convert_fadvice(args->advice); 1576228957Sjhb if (advice == -1) 1577228957Sjhb return (EINVAL); 1578228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1579228957Sjhb advice)); 1580228957Sjhb} 1581234352Sjkim 1582234352Sjkimint 1583234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args) 1584234352Sjkim{ 1585234352Sjkim int fildes[2]; 1586234352Sjkim int error; 1587234352Sjkim 1588234352Sjkim#ifdef DEBUG 1589234352Sjkim if (ldebug(pipe)) 1590234352Sjkim printf(ARGS(pipe, "*")); 1591234352Sjkim#endif 1592234352Sjkim 1593248951Sjilles error = kern_pipe2(td, fildes, 0); 1594234352Sjkim if (error) 1595234352Sjkim return (error); 1596234352Sjkim 1597234352Sjkim /* XXX: Close descriptors on error. */ 1598234352Sjkim return (copyout(fildes, args->pipefds, sizeof(fildes))); 1599234352Sjkim} 1600234352Sjkim 1601234352Sjkimint 1602234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args) 1603234352Sjkim{ 1604234352Sjkim int fildes[2]; 1605234352Sjkim int error, flags; 1606234352Sjkim 1607234352Sjkim#ifdef DEBUG 1608234352Sjkim if (ldebug(pipe2)) 1609234352Sjkim printf(ARGS(pipe2, "*, %d"), args->flags); 1610234352Sjkim#endif 1611234352Sjkim 1612234352Sjkim if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) 1613234352Sjkim return (EINVAL); 1614234352Sjkim 1615234352Sjkim flags = 0; 1616234352Sjkim if ((args->flags & LINUX_O_NONBLOCK) != 0) 1617234352Sjkim flags |= O_NONBLOCK; 1618234352Sjkim if ((args->flags & LINUX_O_CLOEXEC) != 0) 1619234352Sjkim flags |= O_CLOEXEC; 1620248951Sjilles error = kern_pipe2(td, fildes, flags); 1621234352Sjkim if (error) 1622234352Sjkim return (error); 1623234352Sjkim 1624234352Sjkim /* XXX: Close descriptors on error. */ 1625234352Sjkim return (copyout(fildes, args->pipefds, sizeof(fildes))); 1626234352Sjkim} 1627