linux_file.c revision 179651
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 179651 2008-06-08 11:09:25Z rdivacky $"); 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> 70177997Skib#include <compat/linux/linux_file.h> 719313Ssos 729313Ssosint 7383366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 749313Ssos{ 75102814Siedowse char *path; 76102814Siedowse int error; 779313Ssos 78102814Siedowse LCONVPATHEXIST(td, args->path, &path); 7914331Speter 809313Ssos#ifdef DEBUG 8172543Sjlemon if (ldebug(creat)) 82102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 839313Ssos#endif 84102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 85102814Siedowse args->mode); 86102814Siedowse LFREEPATH(path); 87102814Siedowse return (error); 889313Ssos} 899313Ssos 90168014Sjulian 91168014Sjulianstatic int 92177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 939313Ssos{ 9483382Sjhb struct proc *p = td->td_proc; 95166085Skib struct file *fp; 96166085Skib int fd; 97102814Siedowse int bsd_flags, error; 9814331Speter 99102814Siedowse bsd_flags = 0; 100168014Sjulian switch (l_flags & LINUX_O_ACCMODE) { 101168014Sjulian case LINUX_O_WRONLY: 102102814Siedowse bsd_flags |= O_WRONLY; 103168014Sjulian break; 104168014Sjulian case LINUX_O_RDWR: 105102814Siedowse bsd_flags |= O_RDWR; 106168014Sjulian break; 107168014Sjulian default: 108168014Sjulian bsd_flags |= O_RDONLY; 109168014Sjulian } 110168014Sjulian if (l_flags & LINUX_O_NDELAY) 111102814Siedowse bsd_flags |= O_NONBLOCK; 112168014Sjulian if (l_flags & LINUX_O_APPEND) 113102814Siedowse bsd_flags |= O_APPEND; 114168014Sjulian if (l_flags & LINUX_O_SYNC) 115102814Siedowse bsd_flags |= O_FSYNC; 116168014Sjulian if (l_flags & LINUX_O_NONBLOCK) 117102814Siedowse bsd_flags |= O_NONBLOCK; 118168014Sjulian if (l_flags & LINUX_FASYNC) 119102814Siedowse bsd_flags |= O_ASYNC; 120168014Sjulian if (l_flags & LINUX_O_CREAT) 121102814Siedowse bsd_flags |= O_CREAT; 122168014Sjulian if (l_flags & LINUX_O_TRUNC) 123102814Siedowse bsd_flags |= O_TRUNC; 124168014Sjulian if (l_flags & LINUX_O_EXCL) 125102814Siedowse bsd_flags |= O_EXCL; 126168014Sjulian if (l_flags & LINUX_O_NOCTTY) 127102814Siedowse bsd_flags |= O_NOCTTY; 128168014Sjulian if (l_flags & LINUX_O_DIRECT) 129166085Skib bsd_flags |= O_DIRECT; 130168014Sjulian if (l_flags & LINUX_O_NOFOLLOW) 131166085Skib bsd_flags |= O_NOFOLLOW; 132166085Skib /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1339313Ssos 134178036Srdivacky error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 135178036Srdivacky 136166085Skib if (!error) { 137166085Skib fd = td->td_retval[0]; 138166085Skib /* 139166085Skib * XXX In between kern_open() and fget(), another process 140166085Skib * having the same filedesc could use that fd without 141166085Skib * checking below. 142166085Skib */ 143166085Skib error = fget(td, fd, &fp); 144166085Skib if (!error) { 145166085Skib sx_slock(&proctree_lock); 146166085Skib PROC_LOCK(p); 147166085Skib if (!(bsd_flags & O_NOCTTY) && 148166085Skib SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 149166085Skib PROC_UNLOCK(p); 150166085Skib sx_unlock(&proctree_lock); 151166085Skib if (fp->f_type == DTYPE_VNODE) 152166085Skib (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 153166085Skib td->td_ucred, td); 154166085Skib } else { 155166085Skib PROC_UNLOCK(p); 156166085Skib sx_sunlock(&proctree_lock); 157166085Skib } 158168014Sjulian if (l_flags & LINUX_O_DIRECTORY) { 159166085Skib if (fp->f_type != DTYPE_VNODE || 160166085Skib fp->f_vnode->v_type != VDIR) { 161166085Skib error = ENOTDIR; 162166085Skib } 163166085Skib } 164166085Skib fdrop(fp, td); 165166085Skib /* 166166085Skib * XXX as above, fdrop()/kern_close() pair is racy. 167166085Skib */ 168166085Skib if (error) 169166085Skib kern_close(td, fd); 170166085Skib } 171166085Skib } 1729313Ssos 17314331Speter#ifdef DEBUG 174166085Skib if (ldebug(open)) 175166085Skib printf(LMSG("open returns error %d"), error); 17614331Speter#endif 177177997Skib LFREEPATH(path); 178177997Skib return (error); 1799313Ssos} 1809313Ssos 1819313Ssosint 182168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args) 183168014Sjulian{ 184177997Skib char *path; 185177997Skib int dfd; 186168014Sjulian 187177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 188177997Skib if (args->flags & LINUX_O_CREAT) 189177997Skib LCONVPATH_AT(td, args->filename, &path, 1, dfd); 190177997Skib else 191177997Skib LCONVPATH_AT(td, args->filename, &path, 0, dfd); 192168014Sjulian#ifdef DEBUG 193168014Sjulian if (ldebug(openat)) 194168014Sjulian printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 195177997Skib path, args->flags, args->mode); 196168014Sjulian#endif 197177997Skib return (linux_common_open(td, dfd, path, args->flags, args->mode)); 198168014Sjulian} 199168014Sjulian 200168014Sjulianint 201168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 202168014Sjulian{ 203168014Sjulian char *path; 204168014Sjulian 205168014Sjulian if (args->flags & LINUX_O_CREAT) 206168014Sjulian LCONVPATHCREAT(td, args->path, &path); 207168014Sjulian else 208168014Sjulian LCONVPATHEXIST(td, args->path, &path); 209168014Sjulian 210168014Sjulian#ifdef DEBUG 211168014Sjulian if (ldebug(open)) 212168014Sjulian printf(ARGS(open, "%s, 0x%x, 0x%x"), 213168014Sjulian path, args->flags, args->mode); 214168014Sjulian#endif 215168014Sjulian 216178036Srdivacky return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 217168014Sjulian} 218168014Sjulian 219168014Sjulianint 22083366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 2219313Ssos{ 2229313Ssos 22312858Speter struct lseek_args /* { 22412858Speter int fd; 2259313Ssos int pad; 22612858Speter off_t offset; 2279313Ssos int whence; 22812858Speter } */ tmp_args; 2299313Ssos int error; 2309313Ssos 2319313Ssos#ifdef DEBUG 23272543Sjlemon if (ldebug(lseek)) 23372543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 23483221Smarcel args->fdes, (long)args->off, args->whence); 2359313Ssos#endif 23612858Speter tmp_args.fd = args->fdes; 23712858Speter tmp_args.offset = (off_t)args->off; 2389313Ssos tmp_args.whence = args->whence; 23983366Sjulian error = lseek(td, &tmp_args); 2409313Ssos return error; 2419313Ssos} 2429313Ssos 24314331Speterint 24483366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 24514331Speter{ 24614331Speter struct lseek_args bsd_args; 24714331Speter int error; 24814331Speter off_t off; 24914331Speter 25014331Speter#ifdef DEBUG 25172543Sjlemon if (ldebug(llseek)) 25272543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 25372543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 25414331Speter#endif 25514331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 25614331Speter 25714331Speter bsd_args.fd = args->fd; 25814331Speter bsd_args.offset = off; 25914331Speter bsd_args.whence = args->whence; 26014331Speter 26183366Sjulian if ((error = lseek(td, &bsd_args))) 26214331Speter return error; 26314331Speter 264111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 26514331Speter return error; 26614331Speter 26783366Sjulian td->td_retval[0] = 0; 26814331Speter return 0; 26914331Speter} 27014331Speter 2719313Ssosint 27283366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args) 2739313Ssos{ 27414331Speter struct linux_getdents_args lda; 27514331Speter 27614331Speter lda.fd = args->fd; 27714331Speter lda.dent = args->dent; 27814331Speter lda.count = 1; 27983366Sjulian return linux_getdents(td, &lda); 28014331Speter} 28114331Speter 28283221Smarcel/* 28383221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 28483221Smarcel * arguments. They only differ in the definition of struct dirent they 28583221Smarcel * operate on. We use this to common the code, with the exception of 28683221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented 28783221Smarcel * by means of linux_getdents(2). In this case we never operate on 28883221Smarcel * struct dirent64 and thus don't need to handle it... 28983221Smarcel */ 29083221Smarcel 29183221Smarcelstruct l_dirent { 292179651Srdivacky l_ulong d_ino; 29383221Smarcel l_off_t d_off; 29483221Smarcel l_ushort d_reclen; 29583221Smarcel char d_name[LINUX_NAME_MAX + 1]; 29683221Smarcel}; 29783221Smarcel 29883221Smarcelstruct l_dirent64 { 29983221Smarcel uint64_t d_ino; 30083221Smarcel int64_t d_off; 30183221Smarcel l_ushort d_reclen; 30283221Smarcel u_char d_type; 30383221Smarcel char d_name[LINUX_NAME_MAX + 1]; 30483221Smarcel}; 30583221Smarcel 30683221Smarcel#define LINUX_RECLEN(de,namlen) \ 30783221Smarcel ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 30883221Smarcel 30983221Smarcel#define LINUX_DIRBLKSIZ 512 31083221Smarcel 31183221Smarcelstatic int 31283366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args, 31383221Smarcel int is64bit) 31414331Speter{ 315111798Sdes struct dirent *bdp; 31683221Smarcel struct vnode *vp; 31783221Smarcel caddr_t inp, buf; /* BSD-format */ 31883221Smarcel int len, reclen; /* BSD-format */ 31983221Smarcel caddr_t outp; /* Linux-format */ 32083221Smarcel int resid, linuxreclen=0; /* Linux-format */ 32183221Smarcel struct file *fp; 32283221Smarcel struct uio auio; 32383221Smarcel struct iovec aiov; 32483221Smarcel off_t off; 32583221Smarcel struct l_dirent linux_dirent; 32683221Smarcel struct l_dirent64 linux_dirent64; 32783221Smarcel int buflen, error, eofflag, nbytes, justone; 32883221Smarcel u_long *cookies = NULL, *cookiep; 329160276Sjhb int ncookies, vfslocked; 3309313Ssos 331160276Sjhb nbytes = args->count; 332160276Sjhb if (nbytes == 1) { 333160276Sjhb /* readdir(2) case. Always struct dirent. */ 334160276Sjhb if (is64bit) 335160276Sjhb return (EINVAL); 336160276Sjhb nbytes = sizeof(linux_dirent); 337160276Sjhb justone = 1; 338160276Sjhb } else 339160276Sjhb justone = 0; 340160276Sjhb 34183366Sjulian if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 34283221Smarcel return (error); 3439313Ssos 34489306Salfred if ((fp->f_flag & FREAD) == 0) { 34589306Salfred fdrop(fp, td); 34683221Smarcel return (EBADF); 34789306Salfred } 3489313Ssos 349116678Sphk vp = fp->f_vnode; 350160276Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 35189306Salfred if (vp->v_type != VDIR) { 352160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 35389306Salfred fdrop(fp, td); 35483221Smarcel return (EINVAL); 35589306Salfred } 3569313Ssos 35783221Smarcel off = fp->f_offset; 3589313Ssos 35983221Smarcel buflen = max(LINUX_DIRBLKSIZ, nbytes); 36083221Smarcel buflen = min(buflen, MAXBSIZE); 361111119Simp buf = malloc(buflen, M_TEMP, M_WAITOK); 362175202Sattilio vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 36383221Smarcel 3649313Ssosagain: 36583221Smarcel aiov.iov_base = buf; 36683221Smarcel aiov.iov_len = buflen; 36783221Smarcel auio.uio_iov = &aiov; 36883221Smarcel auio.uio_iovcnt = 1; 36983221Smarcel auio.uio_rw = UIO_READ; 37083221Smarcel auio.uio_segflg = UIO_SYSSPACE; 37183366Sjulian auio.uio_td = td; 37283221Smarcel auio.uio_resid = buflen; 37383221Smarcel auio.uio_offset = off; 3749313Ssos 37583221Smarcel if (cookies) { 37683221Smarcel free(cookies, M_TEMP); 37783221Smarcel cookies = NULL; 37883221Smarcel } 37924654Sdfr 380101189Srwatson#ifdef MAC 381101189Srwatson /* 382101189Srwatson * Do directory search MAC check using non-cached credentials. 383101189Srwatson */ 384172930Srwatson if ((error = mac_vnode_check_readdir(td->td_ucred, vp))) 385101189Srwatson goto out; 386101189Srwatson#endif /* MAC */ 38783221Smarcel if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 38883221Smarcel &cookies))) 38983221Smarcel goto out; 3909313Ssos 39183221Smarcel inp = buf; 39283221Smarcel outp = (caddr_t)args->dirent; 39383221Smarcel resid = nbytes; 39483221Smarcel if ((len = buflen - auio.uio_resid) <= 0) 39583221Smarcel goto eof; 3969313Ssos 39783221Smarcel cookiep = cookies; 39824654Sdfr 39983221Smarcel if (cookies) { 40083221Smarcel /* 40183221Smarcel * When using cookies, the vfs has the option of reading from 40283221Smarcel * a different offset than that supplied (UFS truncates the 40383221Smarcel * offset to a block boundary to make sure that it never reads 40483221Smarcel * partway through a directory entry, even if the directory 40583221Smarcel * has been compacted). 40683221Smarcel */ 40783221Smarcel while (len > 0 && ncookies > 0 && *cookiep <= off) { 40883221Smarcel bdp = (struct dirent *) inp; 40983221Smarcel len -= bdp->d_reclen; 41083221Smarcel inp += bdp->d_reclen; 41183221Smarcel cookiep++; 41283221Smarcel ncookies--; 41383221Smarcel } 41424654Sdfr } 41524654Sdfr 41683221Smarcel while (len > 0) { 41783221Smarcel if (cookiep && ncookies == 0) 41883221Smarcel break; 41983221Smarcel bdp = (struct dirent *) inp; 42083221Smarcel reclen = bdp->d_reclen; 42183221Smarcel if (reclen & 3) { 42283221Smarcel error = EFAULT; 42383221Smarcel goto out; 42483221Smarcel } 42583221Smarcel 42683221Smarcel if (bdp->d_fileno == 0) { 42783221Smarcel inp += reclen; 42883221Smarcel if (cookiep) { 42983221Smarcel off = *cookiep++; 43083221Smarcel ncookies--; 43183221Smarcel } else 43283221Smarcel off += reclen; 43383221Smarcel 43483221Smarcel len -= reclen; 43583221Smarcel continue; 43683221Smarcel } 43783221Smarcel 43883221Smarcel linuxreclen = (is64bit) 43983221Smarcel ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) 44083221Smarcel : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 44183221Smarcel 44283221Smarcel if (reclen > len || resid < linuxreclen) { 44383221Smarcel outp++; 44483221Smarcel break; 44583221Smarcel } 44683221Smarcel 44783221Smarcel if (justone) { 44883221Smarcel /* readdir(2) case. */ 449179651Srdivacky linux_dirent.d_ino = bdp->d_fileno; 45083221Smarcel linux_dirent.d_off = (l_off_t)linuxreclen; 45183221Smarcel linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 45283221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 45383221Smarcel error = copyout(&linux_dirent, outp, linuxreclen); 45483221Smarcel } else { 45583221Smarcel if (is64bit) { 45683221Smarcel linux_dirent64.d_ino = bdp->d_fileno; 45783221Smarcel linux_dirent64.d_off = (cookiep) 45883221Smarcel ? (l_off_t)*cookiep 45983221Smarcel : (l_off_t)(off + reclen); 46083221Smarcel linux_dirent64.d_reclen = 46183221Smarcel (l_ushort)linuxreclen; 46283221Smarcel linux_dirent64.d_type = bdp->d_type; 46383221Smarcel strcpy(linux_dirent64.d_name, bdp->d_name); 46483221Smarcel error = copyout(&linux_dirent64, outp, 46583221Smarcel linuxreclen); 46683221Smarcel } else { 46783221Smarcel linux_dirent.d_ino = bdp->d_fileno; 46883221Smarcel linux_dirent.d_off = (cookiep) 46983221Smarcel ? (l_off_t)*cookiep 47083221Smarcel : (l_off_t)(off + reclen); 47183221Smarcel linux_dirent.d_reclen = (l_ushort)linuxreclen; 47283221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 47383221Smarcel error = copyout(&linux_dirent, outp, 47483221Smarcel linuxreclen); 47583221Smarcel } 47683221Smarcel } 47783221Smarcel if (error) 47883221Smarcel goto out; 47983221Smarcel 48083221Smarcel inp += reclen; 48183221Smarcel if (cookiep) { 48283221Smarcel off = *cookiep++; 48383221Smarcel ncookies--; 48483221Smarcel } else 48583221Smarcel off += reclen; 48683221Smarcel 48783221Smarcel outp += linuxreclen; 48883221Smarcel resid -= linuxreclen; 48983221Smarcel len -= reclen; 49083221Smarcel if (justone) 49183221Smarcel break; 49210355Sswallace } 4939313Ssos 49483221Smarcel if (outp == (caddr_t)args->dirent) 49583221Smarcel goto again; 4969313Ssos 49783221Smarcel fp->f_offset = off; 49883221Smarcel if (justone) 49983221Smarcel nbytes = resid + linuxreclen; 50010355Sswallace 5019313Ssoseof: 50283366Sjulian td->td_retval[0] = nbytes - resid; 50383221Smarcel 5049313Ssosout: 50583221Smarcel if (cookies) 50683221Smarcel free(cookies, M_TEMP); 50783221Smarcel 508175294Sattilio VOP_UNLOCK(vp, 0); 509160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 51089306Salfred fdrop(fp, td); 51183221Smarcel free(buf, M_TEMP); 51283221Smarcel return (error); 5139313Ssos} 51414331Speter 51583221Smarcelint 51683366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args) 51783221Smarcel{ 51883221Smarcel 51983221Smarcel#ifdef DEBUG 52083221Smarcel if (ldebug(getdents)) 52183221Smarcel printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 52283221Smarcel#endif 52383221Smarcel 52483366Sjulian return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 52583221Smarcel} 52683221Smarcel 52783221Smarcelint 52883366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 52983221Smarcel{ 53083221Smarcel 53183221Smarcel#ifdef DEBUG 53283221Smarcel if (ldebug(getdents64)) 53383221Smarcel printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 53483221Smarcel#endif 53583221Smarcel 53683366Sjulian return (getdents_common(td, args, 1)); 53783221Smarcel} 53883221Smarcel 53914331Speter/* 54014331Speter * These exist mainly for hooks for doing /compat/linux translation. 54114331Speter */ 54214331Speter 54314331Speterint 54483366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 54514331Speter{ 546102814Siedowse char *path; 547102814Siedowse int error; 54814331Speter 549162585Snetchild /* linux convention */ 550162585Snetchild if (args->flags & ~(F_OK | X_OK | W_OK | R_OK)) 551162585Snetchild return (EINVAL); 552162585Snetchild 553102814Siedowse LCONVPATHEXIST(td, args->path, &path); 55414331Speter 55514331Speter#ifdef DEBUG 55672543Sjlemon if (ldebug(access)) 557102814Siedowse printf(ARGS(access, "%s, %d"), path, args->flags); 55814331Speter#endif 559102814Siedowse error = kern_access(td, path, UIO_SYSSPACE, args->flags); 560102814Siedowse LFREEPATH(path); 561162585Snetchild 562102814Siedowse return (error); 56314331Speter} 56414331Speter 56514331Speterint 566177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args) 567177997Skib{ 568177997Skib char *path; 569177997Skib int error, dfd; 570177997Skib 571177997Skib /* linux convention */ 572177997Skib if (args->mode & ~(F_OK | X_OK | W_OK | R_OK)) 573177997Skib return (EINVAL); 574177997Skib 575177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 576177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 577177997Skib 578177997Skib#ifdef DEBUG 579177997Skib if (ldebug(access)) 580177997Skib printf(ARGS(access, "%s, %d"), path, args->mode); 581177997Skib#endif 582177997Skib 583177997Skib error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */, 584177997Skib args->mode); 585177997Skib LFREEPATH(path); 586177997Skib 587177997Skib return (error); 588177997Skib} 589177997Skib 590177997Skibint 59183366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 59214331Speter{ 593102814Siedowse char *path; 594102814Siedowse int error; 595162201Snetchild struct stat st; 59614331Speter 597102814Siedowse LCONVPATHEXIST(td, args->path, &path); 59814331Speter 59914331Speter#ifdef DEBUG 60072543Sjlemon if (ldebug(unlink)) 601102814Siedowse printf(ARGS(unlink, "%s"), path); 60214331Speter#endif 60314331Speter 604102814Siedowse error = kern_unlink(td, path, UIO_SYSSPACE); 605162201Snetchild if (error == EPERM) 606162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 607162201Snetchild if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 608162201Snetchild if (S_ISDIR(st.st_mode)) 609162201Snetchild error = EISDIR; 610102814Siedowse LFREEPATH(path); 611102814Siedowse return (error); 61214331Speter} 61314331Speter 61414331Speterint 615177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 616177997Skib{ 617177997Skib char *path; 618177997Skib int error, dfd; 619177997Skib struct stat st; 620177997Skib 621177997Skib if (args->flag & ~LINUX_AT_REMOVEDIR) 622177997Skib return (EINVAL); 623177997Skib 624177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 625177997Skib LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 626177997Skib 627177997Skib#ifdef DEBUG 628177997Skib if (ldebug(unlinkat)) 629177997Skib printf(ARGS(unlinkat, "%s"), path); 630177997Skib#endif 631177997Skib 632177997Skib if (args->flag & LINUX_AT_REMOVEDIR) 633177997Skib error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); 634177997Skib else 635177997Skib error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE); 636177997Skib if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 637177997Skib /* Introduce POSIX noncompliant behaviour of Linux */ 638177997Skib if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 639177997Skib UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode)) 640177997Skib error = EISDIR; 641177997Skib } 642177997Skib LFREEPATH(path); 643177997Skib return (error); 644177997Skib} 645177997Skibint 64683366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 64714331Speter{ 648102814Siedowse char *path; 649102814Siedowse int error; 65014331Speter 651102814Siedowse LCONVPATHEXIST(td, args->path, &path); 65214331Speter 65314331Speter#ifdef DEBUG 65472543Sjlemon if (ldebug(chdir)) 655102814Siedowse printf(ARGS(chdir, "%s"), path); 65614331Speter#endif 657102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 658102814Siedowse LFREEPATH(path); 659102814Siedowse return (error); 66014331Speter} 66114331Speter 66214331Speterint 66383366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 66414331Speter{ 665102814Siedowse char *path; 666102814Siedowse int error; 66714331Speter 668102814Siedowse LCONVPATHEXIST(td, args->path, &path); 66914331Speter 67014331Speter#ifdef DEBUG 67172543Sjlemon if (ldebug(chmod)) 672102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 67314331Speter#endif 674102814Siedowse error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 675102814Siedowse LFREEPATH(path); 676102814Siedowse return (error); 67714331Speter} 67814331Speter 67914331Speterint 680177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 681177997Skib{ 682177997Skib char *path; 683177997Skib int error, dfd; 684177997Skib 685177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 686177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 687177997Skib 688177997Skib#ifdef DEBUG 689177997Skib if (ldebug(fchmodat)) 690177997Skib printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 691177997Skib#endif 692177997Skib 693177997Skib error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 694177997Skib LFREEPATH(path); 695177997Skib return (error); 696177997Skib} 697177997Skib 698177997Skibint 69983366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 70014331Speter{ 701102814Siedowse char *path; 702102814Siedowse int error; 70314331Speter 704102814Siedowse LCONVPATHCREAT(td, args->path, &path); 70514331Speter 70614331Speter#ifdef DEBUG 70772543Sjlemon if (ldebug(mkdir)) 708102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 70914331Speter#endif 710102814Siedowse error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 711102814Siedowse LFREEPATH(path); 712102814Siedowse return (error); 71314331Speter} 71414331Speter 71514331Speterint 716177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 717177997Skib{ 718177997Skib char *path; 719177997Skib int error, dfd; 720177997Skib 721177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 722177997Skib LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 723177997Skib 724177997Skib#ifdef DEBUG 725177997Skib if (ldebug(mkdirat)) 726177997Skib printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 727177997Skib#endif 728177997Skib error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 729177997Skib LFREEPATH(path); 730177997Skib return (error); 731177997Skib} 732177997Skib 733177997Skibint 73483366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 73514331Speter{ 736102814Siedowse char *path; 737102814Siedowse int error; 73814331Speter 739102814Siedowse LCONVPATHEXIST(td, args->path, &path); 74014331Speter 74114331Speter#ifdef DEBUG 74272543Sjlemon if (ldebug(rmdir)) 743102814Siedowse printf(ARGS(rmdir, "%s"), path); 74414331Speter#endif 745102814Siedowse error = kern_rmdir(td, path, UIO_SYSSPACE); 746102814Siedowse LFREEPATH(path); 747102814Siedowse return (error); 74814331Speter} 74914331Speter 75014331Speterint 75183366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 75214331Speter{ 753102814Siedowse char *from, *to; 754102814Siedowse int error; 75514331Speter 756102814Siedowse LCONVPATHEXIST(td, args->from, &from); 757102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 758177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 759102814Siedowse if (to == NULL) { 760102814Siedowse LFREEPATH(from); 761102814Siedowse return (error); 762102814Siedowse } 76314331Speter 76414331Speter#ifdef DEBUG 76572543Sjlemon if (ldebug(rename)) 766102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 76714331Speter#endif 768102814Siedowse error = kern_rename(td, from, to, UIO_SYSSPACE); 769102814Siedowse LFREEPATH(from); 770102814Siedowse LFREEPATH(to); 771102814Siedowse return (error); 77214331Speter} 77314331Speter 77414331Speterint 775177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args) 776177997Skib{ 777177997Skib char *from, *to; 778177997Skib int error, olddfd, newdfd; 779177997Skib 780177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 781177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 782177997Skib LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 783177997Skib /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 784177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 785177997Skib if (to == NULL) { 786177997Skib LFREEPATH(from); 787177997Skib return (error); 788177997Skib } 789177997Skib 790177997Skib#ifdef DEBUG 791177997Skib if (ldebug(renameat)) 792177997Skib printf(ARGS(renameat, "%s, %s"), from, to); 793177997Skib#endif 794177997Skib error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 795177997Skib LFREEPATH(from); 796177997Skib LFREEPATH(to); 797177997Skib return (error); 798177997Skib} 799177997Skib 800177997Skibint 80183366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 80214331Speter{ 803102814Siedowse char *path, *to; 804102814Siedowse int error; 80514331Speter 806102814Siedowse LCONVPATHEXIST(td, args->path, &path); 807102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 808177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 809102814Siedowse if (to == NULL) { 810102814Siedowse LFREEPATH(path); 811102814Siedowse return (error); 812102814Siedowse } 81314331Speter 81414331Speter#ifdef DEBUG 81572543Sjlemon if (ldebug(symlink)) 816102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 81714331Speter#endif 818102814Siedowse error = kern_symlink(td, path, to, UIO_SYSSPACE); 819102814Siedowse LFREEPATH(path); 820102814Siedowse LFREEPATH(to); 821102814Siedowse return (error); 82214331Speter} 82314331Speter 82414331Speterint 825177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 826177997Skib{ 827177997Skib char *path, *to; 828177997Skib int error, dfd; 829177997Skib 830177997Skib dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 831177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); 832177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 833177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 834177997Skib if (to == NULL) { 835177997Skib LFREEPATH(path); 836177997Skib return (error); 837177997Skib } 838177997Skib 839177997Skib#ifdef DEBUG 840177997Skib if (ldebug(symlinkat)) 841177997Skib printf(ARGS(symlinkat, "%s, %s"), path, to); 842177997Skib#endif 843177997Skib 844177997Skib error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 845177997Skib LFREEPATH(path); 846177997Skib LFREEPATH(to); 847177997Skib return (error); 848177997Skib} 849177997Skib 850177997Skibint 85183366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 85214331Speter{ 853102814Siedowse char *name; 854102814Siedowse int error; 85514331Speter 856102814Siedowse LCONVPATHEXIST(td, args->name, &name); 85714331Speter 85814331Speter#ifdef DEBUG 85972543Sjlemon if (ldebug(readlink)) 860102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 861102814Siedowse args->count); 86214331Speter#endif 863102814Siedowse error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 864102814Siedowse args->count); 865102814Siedowse LFREEPATH(name); 866102814Siedowse return (error); 86714331Speter} 86814331Speter 86914331Speterint 870177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 871177997Skib{ 872177997Skib char *name; 873177997Skib int error, dfd; 874177997Skib 875177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 876177997Skib LCONVPATHEXIST_AT(td, args->path, &name, dfd); 877177997Skib 878177997Skib#ifdef DEBUG 879177997Skib if (ldebug(readlinkat)) 880177997Skib printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 881177997Skib args->bufsiz); 882177997Skib#endif 883177997Skib 884177997Skib error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 885177997Skib UIO_USERSPACE, args->bufsiz); 886177997Skib LFREEPATH(name); 887177997Skib return (error); 888177997Skib} 889178439Srdivacky 890177997Skibint 89183366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 89214331Speter{ 893102814Siedowse char *path; 894102814Siedowse int error; 89514331Speter 896102814Siedowse LCONVPATHEXIST(td, args->path, &path); 89714331Speter 89814331Speter#ifdef DEBUG 89972543Sjlemon if (ldebug(truncate)) 900102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 90114331Speter#endif 90214331Speter 903102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 904102814Siedowse LFREEPATH(path); 905102814Siedowse return (error); 90614331Speter} 90714331Speter 90849662Smarcelint 909178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args) 910178439Srdivacky{ 911178439Srdivacky char *path; 912178439Srdivacky int error; 913178439Srdivacky 914178439Srdivacky LCONVPATHEXIST(td, args->path, &path); 915178439Srdivacky 916178439Srdivacky#ifdef DEBUG 917178439Srdivacky if (ldebug(truncate64)) 918178439Srdivacky printf(ARGS(truncate64, "%s, %jd"), path, args->length); 919178439Srdivacky#endif 920178439Srdivacky 921178439Srdivacky error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 922178439Srdivacky LFREEPATH(path); 923178439Srdivacky return (error); 924178439Srdivacky} 925178439Srdivackyint 926156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 927156842Snetchild{ 928156842Snetchild struct ftruncate_args /* { 929156842Snetchild int fd; 930156842Snetchild int pad; 931156842Snetchild off_t length; 932156842Snetchild } */ nuap; 933156842Snetchild 934156842Snetchild nuap.fd = args->fd; 935156842Snetchild nuap.length = args->length; 936156842Snetchild return (ftruncate(td, &nuap)); 937156842Snetchild} 938156842Snetchild 939156842Snetchildint 94083366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 94149662Smarcel{ 942102814Siedowse char *path, *to; 943102814Siedowse int error; 94449662Smarcel 945102814Siedowse LCONVPATHEXIST(td, args->path, &path); 946102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 947177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 948102814Siedowse if (to == NULL) { 949102814Siedowse LFREEPATH(path); 950102814Siedowse return (error); 951102814Siedowse } 95249662Smarcel 95349662Smarcel#ifdef DEBUG 95472543Sjlemon if (ldebug(link)) 955102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 95649662Smarcel#endif 957102814Siedowse error = kern_link(td, path, to, UIO_SYSSPACE); 958102814Siedowse LFREEPATH(path); 959102814Siedowse LFREEPATH(to); 960102814Siedowse return (error); 96149662Smarcel} 96249788Smarcel 96353713Smarcelint 964177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args) 965177997Skib{ 966177997Skib char *path, *to; 967177997Skib int error, olddfd, newdfd; 968177997Skib 969177997Skib /* 970177997Skib * They really introduced flags argument which is forbidden to 971177997Skib * use. 972177997Skib */ 973177997Skib if (args->flags != 0) 974177997Skib return (EINVAL); 975177997Skib 976177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 977177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 978177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 979177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 980177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 981177997Skib if (to == NULL) { 982177997Skib LFREEPATH(path); 983177997Skib return (error); 984177997Skib } 985177997Skib 986177997Skib#ifdef DEBUG 987177997Skib if (ldebug(linkat)) 988177997Skib printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 989177997Skib args->newdfd, to, args->flags); 990177997Skib#endif 991177997Skib 992177997Skib error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW); 993177997Skib LFREEPATH(path); 994177997Skib LFREEPATH(to); 995177997Skib return (error); 996177997Skib} 997177997Skib 998177997Skibint 99983366Sjulianlinux_fdatasync(td, uap) 100083366Sjulian struct thread *td; 100153713Smarcel struct linux_fdatasync_args *uap; 100253713Smarcel{ 100353713Smarcel struct fsync_args bsd; 100453713Smarcel 100553713Smarcel bsd.fd = uap->fd; 100683366Sjulian return fsync(td, &bsd); 100753713Smarcel} 100863285Smarcel 100963285Smarcelint 101083366Sjulianlinux_pread(td, uap) 101183366Sjulian struct thread *td; 101263285Smarcel struct linux_pread_args *uap; 101363285Smarcel{ 101463285Smarcel struct pread_args bsd; 1015162585Snetchild struct vnode *vp; 1016162585Snetchild int error; 101763285Smarcel 101863285Smarcel bsd.fd = uap->fd; 101963285Smarcel bsd.buf = uap->buf; 102063285Smarcel bsd.nbyte = uap->nbyte; 102163285Smarcel bsd.offset = uap->offset; 1022162585Snetchild 1023162585Snetchild error = pread(td, &bsd); 1024162585Snetchild 1025162585Snetchild if (error == 0) { 1026162585Snetchild /* This seems to violate POSIX but linux does it */ 1027162585Snetchild if ((error = fgetvp(td, uap->fd, &vp)) != 0) 1028162585Snetchild return (error); 1029162585Snetchild if (vp->v_type == VDIR) { 1030162585Snetchild vrele(vp); 1031162585Snetchild return (EISDIR); 1032162585Snetchild } 1033162585Snetchild vrele(vp); 1034162585Snetchild } 1035162585Snetchild 1036162585Snetchild return (error); 103763285Smarcel} 103863285Smarcel 103963285Smarcelint 104083366Sjulianlinux_pwrite(td, uap) 104183366Sjulian struct thread *td; 104263285Smarcel struct linux_pwrite_args *uap; 104363285Smarcel{ 104463285Smarcel struct pwrite_args bsd; 104563285Smarcel 104663285Smarcel bsd.fd = uap->fd; 104763285Smarcel bsd.buf = uap->buf; 104863285Smarcel bsd.nbyte = uap->nbyte; 104963285Smarcel bsd.offset = uap->offset; 105083366Sjulian return pwrite(td, &bsd); 105163285Smarcel} 105272538Sjlemon 105372538Sjlemonint 105483366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 105572538Sjlemon{ 105672538Sjlemon struct ufs_args ufs; 1057111798Sdes char fstypename[MFSNAMELEN]; 1058111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 105973286Sadrian int error; 106073286Sadrian int fsflags; 106173286Sadrian void *fsdata; 106272538Sjlemon 1063111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 106473286Sadrian NULL); 106572538Sjlemon if (error) 1066111798Sdes return (error); 1067127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 106872538Sjlemon if (error) 1069111798Sdes return (error); 1070127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 107172538Sjlemon if (error) 1072111798Sdes return (error); 107372538Sjlemon 107472538Sjlemon#ifdef DEBUG 107572538Sjlemon if (ldebug(mount)) 107672538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 107772538Sjlemon fstypename, mntfromname, mntonname); 107872538Sjlemon#endif 107972538Sjlemon 108072538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 1081127059Stjr strcpy(fstypename, "ext2fs"); 108273286Sadrian fsdata = &ufs; 108372538Sjlemon ufs.fspec = mntfromname; 108472538Sjlemon#define DEFAULT_ROOTID -2 108572538Sjlemon ufs.export.ex_root = DEFAULT_ROOTID; 108672538Sjlemon ufs.export.ex_flags = 108772538Sjlemon args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 108872538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 1089127059Stjr strcpy(fstypename, "linprocfs"); 109073286Sadrian fsdata = NULL; 109172538Sjlemon } else { 109272538Sjlemon return (ENODEV); 109372538Sjlemon } 109472538Sjlemon 109573286Sadrian fsflags = 0; 109672538Sjlemon 109772538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 109872538Sjlemon /* 109972538Sjlemon * Linux SYNC flag is not included; the closest equivalent 110072538Sjlemon * FreeBSD has is !ASYNC, which is our default. 110172538Sjlemon */ 110272538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 1103111798Sdes fsflags |= MNT_RDONLY; 110472538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 1105111798Sdes fsflags |= MNT_NOSUID; 110672538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 1107111798Sdes fsflags |= MNT_NOEXEC; 110872538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 1109111798Sdes fsflags |= MNT_UPDATE; 111072538Sjlemon } 111172538Sjlemon 1112127059Stjr if (strcmp(fstypename, "linprocfs") == 0) { 1113132708Sphk error = kernel_vmount(fsflags, 1114132708Sphk "fstype", fstypename, 1115132708Sphk "fspath", mntonname, 1116132708Sphk NULL); 1117127059Stjr } else 1118138353Sphk error = EOPNOTSUPP; 1119127059Stjr return (error); 112072538Sjlemon} 112172538Sjlemon 112272538Sjlemonint 112383366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 112472538Sjlemon{ 112583221Smarcel struct linux_umount_args args2; 112672538Sjlemon 112772538Sjlemon args2.path = args->path; 112872538Sjlemon args2.flags = 0; 112983366Sjulian return (linux_umount(td, &args2)); 113072538Sjlemon} 113172538Sjlemon 113272538Sjlemonint 113383366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 113472538Sjlemon{ 113572538Sjlemon struct unmount_args bsd; 113672538Sjlemon 113772538Sjlemon bsd.path = args->path; 113872538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 113983366Sjulian return (unmount(td, &bsd)); 114072538Sjlemon} 114183221Smarcel 114283221Smarcel/* 114383221Smarcel * fcntl family of syscalls 114483221Smarcel */ 114583221Smarcel 114683221Smarcelstruct l_flock { 114783221Smarcel l_short l_type; 114883221Smarcel l_short l_whence; 114983221Smarcel l_off_t l_start; 115083221Smarcel l_off_t l_len; 115183221Smarcel l_pid_t l_pid; 1152133816Stjr} 1153140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1154133816Stjr__packed 1155133816Stjr#endif 1156133816Stjr; 115783221Smarcel 115883221Smarcelstatic void 115983221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 116083221Smarcel{ 116183221Smarcel switch (linux_flock->l_type) { 116283221Smarcel case LINUX_F_RDLCK: 116383221Smarcel bsd_flock->l_type = F_RDLCK; 116483221Smarcel break; 116583221Smarcel case LINUX_F_WRLCK: 116683221Smarcel bsd_flock->l_type = F_WRLCK; 116783221Smarcel break; 116883221Smarcel case LINUX_F_UNLCK: 116983221Smarcel bsd_flock->l_type = F_UNLCK; 117083221Smarcel break; 117183221Smarcel default: 117283221Smarcel bsd_flock->l_type = -1; 117383221Smarcel break; 117483221Smarcel } 117583221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 117683221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 117783221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 117883221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1179177633Sdfr bsd_flock->l_sysid = 0; 118083221Smarcel} 118183221Smarcel 118283221Smarcelstatic void 118383221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 118483221Smarcel{ 118583221Smarcel switch (bsd_flock->l_type) { 118683221Smarcel case F_RDLCK: 118783221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 118883221Smarcel break; 118983221Smarcel case F_WRLCK: 119083221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 119183221Smarcel break; 119283221Smarcel case F_UNLCK: 119383221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 119483221Smarcel break; 119583221Smarcel } 119683221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 119783221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 119883221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 119983221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 120083221Smarcel} 120183221Smarcel 1202140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 120383221Smarcelstruct l_flock64 { 120483221Smarcel l_short l_type; 120583221Smarcel l_short l_whence; 120683221Smarcel l_loff_t l_start; 120783221Smarcel l_loff_t l_len; 120883221Smarcel l_pid_t l_pid; 1209133816Stjr} 1210140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1211133816Stjr__packed 1212133816Stjr#endif 1213133816Stjr; 121483221Smarcel 121583221Smarcelstatic void 121683221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 121783221Smarcel{ 121883221Smarcel switch (linux_flock->l_type) { 121983221Smarcel case LINUX_F_RDLCK: 122083221Smarcel bsd_flock->l_type = F_RDLCK; 122183221Smarcel break; 122283221Smarcel case LINUX_F_WRLCK: 122383221Smarcel bsd_flock->l_type = F_WRLCK; 122483221Smarcel break; 122583221Smarcel case LINUX_F_UNLCK: 122683221Smarcel bsd_flock->l_type = F_UNLCK; 122783221Smarcel break; 122883221Smarcel default: 122983221Smarcel bsd_flock->l_type = -1; 123083221Smarcel break; 123183221Smarcel } 123283221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 123383221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 123483221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 123583221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1236177633Sdfr bsd_flock->l_sysid = 0; 123783221Smarcel} 123883221Smarcel 123983221Smarcelstatic void 124083221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 124183221Smarcel{ 124283221Smarcel switch (bsd_flock->l_type) { 124383221Smarcel case F_RDLCK: 124483221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 124583221Smarcel break; 124683221Smarcel case F_WRLCK: 124783221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 124883221Smarcel break; 124983221Smarcel case F_UNLCK: 125083221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 125183221Smarcel break; 125283221Smarcel } 125383221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 125483221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 125583221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 125683221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 125783221Smarcel} 1258133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 125983221Smarcel 126083221Smarcelstatic int 126183366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args) 126283221Smarcel{ 1263107680Siedowse struct l_flock linux_flock; 1264107680Siedowse struct flock bsd_flock; 126583221Smarcel struct file *fp; 1266102872Siedowse long arg; 126783221Smarcel int error, result; 126883221Smarcel 126983221Smarcel switch (args->cmd) { 127083221Smarcel case LINUX_F_DUPFD: 1271102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 127283221Smarcel 127383221Smarcel case LINUX_F_GETFD: 1274102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 127583221Smarcel 127683221Smarcel case LINUX_F_SETFD: 1277102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 127883221Smarcel 127983221Smarcel case LINUX_F_GETFL: 1280102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 128183366Sjulian result = td->td_retval[0]; 128283366Sjulian td->td_retval[0] = 0; 128383221Smarcel if (result & O_RDONLY) 128483366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 128583221Smarcel if (result & O_WRONLY) 128683366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 128783221Smarcel if (result & O_RDWR) 128883366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 128983221Smarcel if (result & O_NDELAY) 129083366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 129183221Smarcel if (result & O_APPEND) 129283366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 129383221Smarcel if (result & O_FSYNC) 129483366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 129583221Smarcel if (result & O_ASYNC) 129683366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1297144987Smdodd#ifdef LINUX_O_NOFOLLOW 1298144987Smdodd if (result & O_NOFOLLOW) 1299144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1300144987Smdodd#endif 1301144987Smdodd#ifdef LINUX_O_DIRECT 1302144987Smdodd if (result & O_DIRECT) 1303144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1304144987Smdodd#endif 130583221Smarcel return (error); 130683221Smarcel 130783221Smarcel case LINUX_F_SETFL: 1308102872Siedowse arg = 0; 130983221Smarcel if (args->arg & LINUX_O_NDELAY) 1310102872Siedowse arg |= O_NONBLOCK; 131183221Smarcel if (args->arg & LINUX_O_APPEND) 1312102872Siedowse arg |= O_APPEND; 131383221Smarcel if (args->arg & LINUX_O_SYNC) 1314102872Siedowse arg |= O_FSYNC; 131583221Smarcel if (args->arg & LINUX_FASYNC) 1316102872Siedowse arg |= O_ASYNC; 1317144987Smdodd#ifdef LINUX_O_NOFOLLOW 1318144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1319144987Smdodd arg |= O_NOFOLLOW; 1320144987Smdodd#endif 1321144987Smdodd#ifdef LINUX_O_DIRECT 1322144987Smdodd if (args->arg & LINUX_O_DIRECT) 1323144987Smdodd arg |= O_DIRECT; 1324144987Smdodd#endif 1325102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 132683221Smarcel 1327107680Siedowse case LINUX_F_GETLK: 1328111797Sdes error = copyin((void *)args->arg, &linux_flock, 1329107680Siedowse sizeof(linux_flock)); 1330107680Siedowse if (error) 1331107680Siedowse return (error); 1332107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1333107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1334107680Siedowse if (error) 1335107680Siedowse return (error); 1336107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1337111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1338107680Siedowse sizeof(linux_flock))); 1339107680Siedowse 1340107680Siedowse case LINUX_F_SETLK: 1341111797Sdes error = copyin((void *)args->arg, &linux_flock, 1342107680Siedowse sizeof(linux_flock)); 1343107680Siedowse if (error) 1344107680Siedowse return (error); 1345107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1346107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1347107680Siedowse (intptr_t)&bsd_flock)); 1348107680Siedowse 1349107680Siedowse case LINUX_F_SETLKW: 1350111797Sdes error = copyin((void *)args->arg, &linux_flock, 1351107680Siedowse sizeof(linux_flock)); 1352107680Siedowse if (error) 1353107680Siedowse return (error); 1354107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1355107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1356107680Siedowse (intptr_t)&bsd_flock)); 1357107680Siedowse 135883221Smarcel case LINUX_F_GETOWN: 1359102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 136083221Smarcel 136183221Smarcel case LINUX_F_SETOWN: 136283221Smarcel /* 136383221Smarcel * XXX some Linux applications depend on F_SETOWN having no 136483221Smarcel * significant effect for pipes (SIGIO is not delivered for 136583221Smarcel * pipes under Linux-2.2.35 at least). 136683221Smarcel */ 136789319Salfred error = fget(td, args->fd, &fp); 136889319Salfred if (error) 136989319Salfred return (error); 137089306Salfred if (fp->f_type == DTYPE_PIPE) { 137189306Salfred fdrop(fp, td); 137283221Smarcel return (EINVAL); 137389306Salfred } 137489306Salfred fdrop(fp, td); 137583221Smarcel 1376102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 137783221Smarcel } 137883221Smarcel 137983221Smarcel return (EINVAL); 138083221Smarcel} 138183221Smarcel 138283221Smarcelint 138383366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 138483221Smarcel{ 138583221Smarcel struct linux_fcntl64_args args64; 138683221Smarcel 138783221Smarcel#ifdef DEBUG 138883221Smarcel if (ldebug(fcntl)) 138983221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 139083221Smarcel#endif 139183221Smarcel 139283221Smarcel args64.fd = args->fd; 139383221Smarcel args64.cmd = args->cmd; 139483221Smarcel args64.arg = args->arg; 139583366Sjulian return (fcntl_common(td, &args64)); 139683221Smarcel} 139783221Smarcel 1398140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 139983221Smarcelint 140083366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 140183221Smarcel{ 140283221Smarcel struct l_flock64 linux_flock; 1403102872Siedowse struct flock bsd_flock; 140483221Smarcel int error; 140583221Smarcel 140683221Smarcel#ifdef DEBUG 140783221Smarcel if (ldebug(fcntl64)) 140883221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 140983221Smarcel#endif 141083221Smarcel 141183221Smarcel switch (args->cmd) { 141299687Srobert case LINUX_F_GETLK64: 1413111797Sdes error = copyin((void *)args->arg, &linux_flock, 141483221Smarcel sizeof(linux_flock)); 141583221Smarcel if (error) 141683221Smarcel return (error); 1417102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1418102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 141983221Smarcel if (error) 142083221Smarcel return (error); 1421102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1422111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1423111797Sdes sizeof(linux_flock))); 142483221Smarcel 142599687Srobert case LINUX_F_SETLK64: 1426111797Sdes error = copyin((void *)args->arg, &linux_flock, 142783221Smarcel sizeof(linux_flock)); 142883221Smarcel if (error) 142983221Smarcel return (error); 1430102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1431102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1432102872Siedowse (intptr_t)&bsd_flock)); 143383221Smarcel 143499687Srobert case LINUX_F_SETLKW64: 1435111797Sdes error = copyin((void *)args->arg, &linux_flock, 143683221Smarcel sizeof(linux_flock)); 143783221Smarcel if (error) 143883221Smarcel return (error); 1439102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1440102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1441102872Siedowse (intptr_t)&bsd_flock)); 144283221Smarcel } 144383221Smarcel 144483366Sjulian return (fcntl_common(td, args)); 144583221Smarcel} 1446133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 144785022Smarcel 144885022Smarcelint 144985022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 145085022Smarcel{ 1451102814Siedowse char *path; 1452102814Siedowse int error; 145385022Smarcel 1454102814Siedowse LCONVPATHEXIST(td, args->path, &path); 145585022Smarcel 145685022Smarcel#ifdef DEBUG 145785022Smarcel if (ldebug(chown)) 1458102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 145985022Smarcel#endif 1460102814Siedowse error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1461102814Siedowse LFREEPATH(path); 1462102814Siedowse return (error); 146385022Smarcel} 146485022Smarcel 146585022Smarcelint 1466177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1467177997Skib{ 1468177997Skib char *path; 1469177997Skib int error, dfd, follow; 1470177997Skib 1471177997Skib if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1472177997Skib return (EINVAL); 1473177997Skib 1474177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1475177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1476177997Skib 1477177997Skib#ifdef DEBUG 1478177997Skib if (ldebug(fchownat)) 1479177997Skib printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1480177997Skib#endif 1481177997Skib 1482177997Skib follow = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1483177997Skib AT_SYMLINK_NOFOLLOW; 1484177997Skib error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1485177997Skib follow); 1486177997Skib LFREEPATH(path); 1487177997Skib return (error); 1488177997Skib} 1489177997Skib 1490177997Skibint 149185022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 149285022Smarcel{ 1493102814Siedowse char *path; 1494102814Siedowse int error; 149585022Smarcel 1496102814Siedowse LCONVPATHEXIST(td, args->path, &path); 149785022Smarcel 149885022Smarcel#ifdef DEBUG 149985022Smarcel if (ldebug(lchown)) 1500102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 150185022Smarcel#endif 1502102814Siedowse error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1503102814Siedowse LFREEPATH(path); 1504102814Siedowse return (error); 150585022Smarcel} 1506