linux_file.c revision 162585
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 162585 2006-09-23 19:06:54Z netchild $"); 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> 43101189Srwatson#include <sys/mac.h> 449313Ssos#include <sys/malloc.h> 4572538Sjlemon#include <sys/mount.h> 4676166Smarkm#include <sys/mutex.h> 4776166Smarkm#include <sys/proc.h> 48162201Snetchild#include <sys/stat.h> 49102814Siedowse#include <sys/syscallsubr.h> 5076166Smarkm#include <sys/sysproto.h> 5114331Speter#include <sys/tty.h> 52162585Snetchild#include <sys/unistd.h> 5376166Smarkm#include <sys/vnode.h> 5412458Sbde 5572538Sjlemon#include <ufs/ufs/extattr.h> 5672538Sjlemon#include <ufs/ufs/quota.h> 5772538Sjlemon#include <ufs/ufs/ufsmount.h> 5872538Sjlemon 59140214Sobrien#ifdef COMPAT_LINUX32 60140214Sobrien#include <machine/../linux32/linux.h> 61140214Sobrien#include <machine/../linux32/linux32_proto.h> 62140214Sobrien#else 6364905Smarcel#include <machine/../linux/linux.h> 6468583Smarcel#include <machine/../linux/linux_proto.h> 65133816Stjr#endif 6664905Smarcel#include <compat/linux/linux_util.h> 679313Ssos 689313Ssosint 6983366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 709313Ssos{ 71102814Siedowse char *path; 72102814Siedowse int error; 739313Ssos 74102814Siedowse LCONVPATHEXIST(td, args->path, &path); 7514331Speter 769313Ssos#ifdef DEBUG 7772543Sjlemon if (ldebug(creat)) 78102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 799313Ssos#endif 80102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 81102814Siedowse args->mode); 82102814Siedowse LFREEPATH(path); 83102814Siedowse return (error); 849313Ssos} 859313Ssos 869313Ssosint 8783366Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 889313Ssos{ 8983382Sjhb struct proc *p = td->td_proc; 90102814Siedowse char *path; 91102814Siedowse int bsd_flags, error; 9214331Speter 9314331Speter if (args->flags & LINUX_O_CREAT) 94102814Siedowse LCONVPATHCREAT(td, args->path, &path); 9514331Speter else 96102814Siedowse LCONVPATHEXIST(td, args->path, &path); 9714331Speter 989313Ssos#ifdef DEBUG 9972543Sjlemon if (ldebug(open)) 10072543Sjlemon printf(ARGS(open, "%s, 0x%x, 0x%x"), 101102814Siedowse path, args->flags, args->mode); 1029313Ssos#endif 103102814Siedowse bsd_flags = 0; 1049313Ssos if (args->flags & LINUX_O_RDONLY) 105102814Siedowse bsd_flags |= O_RDONLY; 106111798Sdes if (args->flags & LINUX_O_WRONLY) 107102814Siedowse bsd_flags |= O_WRONLY; 1089313Ssos if (args->flags & LINUX_O_RDWR) 109102814Siedowse bsd_flags |= O_RDWR; 1109313Ssos if (args->flags & LINUX_O_NDELAY) 111102814Siedowse bsd_flags |= O_NONBLOCK; 1129313Ssos if (args->flags & LINUX_O_APPEND) 113102814Siedowse bsd_flags |= O_APPEND; 1149313Ssos if (args->flags & LINUX_O_SYNC) 115102814Siedowse bsd_flags |= O_FSYNC; 1169313Ssos if (args->flags & LINUX_O_NONBLOCK) 117102814Siedowse bsd_flags |= O_NONBLOCK; 1189313Ssos if (args->flags & LINUX_FASYNC) 119102814Siedowse bsd_flags |= O_ASYNC; 1209313Ssos if (args->flags & LINUX_O_CREAT) 121102814Siedowse bsd_flags |= O_CREAT; 1229313Ssos if (args->flags & LINUX_O_TRUNC) 123102814Siedowse bsd_flags |= O_TRUNC; 1249313Ssos if (args->flags & LINUX_O_EXCL) 125102814Siedowse bsd_flags |= O_EXCL; 1269313Ssos if (args->flags & LINUX_O_NOCTTY) 127102814Siedowse bsd_flags |= O_NOCTTY; 1289313Ssos 129102814Siedowse error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode); 13070061Sjhb PROC_LOCK(p); 131102814Siedowse if (!error && !(bsd_flags & O_NOCTTY) && 1329313Ssos SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 13389306Salfred struct file *fp; 1349313Ssos 135113917Sjhb PROC_UNLOCK(p); 13689319Salfred error = fget(td, td->td_retval[0], &fp); 13789319Salfred if (!error) { 13889319Salfred if (fp->f_type == DTYPE_VNODE) 139102003Srwatson fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 140102003Srwatson td); 14189319Salfred fdrop(fp, td); 14289319Salfred } 14391140Stanimura } else { 14470061Sjhb PROC_UNLOCK(p); 14514331Speter#ifdef DEBUG 14672543Sjlemon if (ldebug(open)) 14772543Sjlemon printf(LMSG("open returns error %d"), error); 14814331Speter#endif 14991140Stanimura } 150102814Siedowse LFREEPATH(path); 1519313Ssos return error; 1529313Ssos} 1539313Ssos 1549313Ssosint 15583366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 1569313Ssos{ 1579313Ssos 15812858Speter struct lseek_args /* { 15912858Speter int fd; 1609313Ssos int pad; 16112858Speter off_t offset; 1629313Ssos int whence; 16312858Speter } */ tmp_args; 1649313Ssos int error; 1659313Ssos 1669313Ssos#ifdef DEBUG 16772543Sjlemon if (ldebug(lseek)) 16872543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 16983221Smarcel args->fdes, (long)args->off, args->whence); 1709313Ssos#endif 17112858Speter tmp_args.fd = args->fdes; 17212858Speter tmp_args.offset = (off_t)args->off; 1739313Ssos tmp_args.whence = args->whence; 17483366Sjulian error = lseek(td, &tmp_args); 1759313Ssos return error; 1769313Ssos} 1779313Ssos 17814331Speterint 17983366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 18014331Speter{ 18114331Speter struct lseek_args bsd_args; 18214331Speter int error; 18314331Speter off_t off; 18414331Speter 18514331Speter#ifdef DEBUG 18672543Sjlemon if (ldebug(llseek)) 18772543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 18872543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 18914331Speter#endif 19014331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 19114331Speter 19214331Speter bsd_args.fd = args->fd; 19314331Speter bsd_args.offset = off; 19414331Speter bsd_args.whence = args->whence; 19514331Speter 19683366Sjulian if ((error = lseek(td, &bsd_args))) 19714331Speter return error; 19814331Speter 199111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 20014331Speter return error; 20114331Speter 20283366Sjulian td->td_retval[0] = 0; 20314331Speter return 0; 20414331Speter} 20514331Speter 2069313Ssosint 20783366Sjulianlinux_readdir(struct thread *td, struct linux_readdir_args *args) 2089313Ssos{ 20914331Speter struct linux_getdents_args lda; 21014331Speter 21114331Speter lda.fd = args->fd; 21214331Speter lda.dent = args->dent; 21314331Speter lda.count = 1; 21483366Sjulian return linux_getdents(td, &lda); 21514331Speter} 21614331Speter 21783221Smarcel/* 21883221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 21983221Smarcel * arguments. They only differ in the definition of struct dirent they 22083221Smarcel * operate on. We use this to common the code, with the exception of 22183221Smarcel * accessing struct dirent. Note that linux_readdir(2) is implemented 22283221Smarcel * by means of linux_getdents(2). In this case we never operate on 22383221Smarcel * struct dirent64 and thus don't need to handle it... 22483221Smarcel */ 22583221Smarcel 22683221Smarcelstruct l_dirent { 22783221Smarcel l_long d_ino; 22883221Smarcel l_off_t d_off; 22983221Smarcel l_ushort d_reclen; 23083221Smarcel char d_name[LINUX_NAME_MAX + 1]; 23183221Smarcel}; 23283221Smarcel 23383221Smarcelstruct l_dirent64 { 23483221Smarcel uint64_t d_ino; 23583221Smarcel int64_t d_off; 23683221Smarcel l_ushort d_reclen; 23783221Smarcel u_char d_type; 23883221Smarcel char d_name[LINUX_NAME_MAX + 1]; 23983221Smarcel}; 24083221Smarcel 24183221Smarcel#define LINUX_RECLEN(de,namlen) \ 24283221Smarcel ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 24383221Smarcel 24483221Smarcel#define LINUX_DIRBLKSIZ 512 24583221Smarcel 24683221Smarcelstatic int 24783366Sjuliangetdents_common(struct thread *td, struct linux_getdents64_args *args, 24883221Smarcel int is64bit) 24914331Speter{ 250111798Sdes struct dirent *bdp; 25183221Smarcel struct vnode *vp; 25283221Smarcel caddr_t inp, buf; /* BSD-format */ 25383221Smarcel int len, reclen; /* BSD-format */ 25483221Smarcel caddr_t outp; /* Linux-format */ 25583221Smarcel int resid, linuxreclen=0; /* Linux-format */ 25683221Smarcel struct file *fp; 25783221Smarcel struct uio auio; 25883221Smarcel struct iovec aiov; 25983221Smarcel off_t off; 26083221Smarcel struct l_dirent linux_dirent; 26183221Smarcel struct l_dirent64 linux_dirent64; 26283221Smarcel int buflen, error, eofflag, nbytes, justone; 26383221Smarcel u_long *cookies = NULL, *cookiep; 264160276Sjhb int ncookies, vfslocked; 2659313Ssos 266160276Sjhb nbytes = args->count; 267160276Sjhb if (nbytes == 1) { 268160276Sjhb /* readdir(2) case. Always struct dirent. */ 269160276Sjhb if (is64bit) 270160276Sjhb return (EINVAL); 271160276Sjhb nbytes = sizeof(linux_dirent); 272160276Sjhb justone = 1; 273160276Sjhb } else 274160276Sjhb justone = 0; 275160276Sjhb 27683366Sjulian if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 27783221Smarcel return (error); 2789313Ssos 27989306Salfred if ((fp->f_flag & FREAD) == 0) { 28089306Salfred fdrop(fp, td); 28183221Smarcel return (EBADF); 28289306Salfred } 2839313Ssos 284116678Sphk vp = fp->f_vnode; 285160276Sjhb vfslocked = VFS_LOCK_GIANT(vp->v_mount); 28689306Salfred if (vp->v_type != VDIR) { 287160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 28889306Salfred fdrop(fp, td); 28983221Smarcel return (EINVAL); 29089306Salfred } 2919313Ssos 29283221Smarcel off = fp->f_offset; 2939313Ssos 29483221Smarcel buflen = max(LINUX_DIRBLKSIZ, nbytes); 29583221Smarcel buflen = min(buflen, MAXBSIZE); 296111119Simp buf = malloc(buflen, M_TEMP, M_WAITOK); 29783366Sjulian vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 29883221Smarcel 2999313Ssosagain: 30083221Smarcel aiov.iov_base = buf; 30183221Smarcel aiov.iov_len = buflen; 30283221Smarcel auio.uio_iov = &aiov; 30383221Smarcel auio.uio_iovcnt = 1; 30483221Smarcel auio.uio_rw = UIO_READ; 30583221Smarcel auio.uio_segflg = UIO_SYSSPACE; 30683366Sjulian auio.uio_td = td; 30783221Smarcel auio.uio_resid = buflen; 30883221Smarcel auio.uio_offset = off; 3099313Ssos 31083221Smarcel if (cookies) { 31183221Smarcel free(cookies, M_TEMP); 31283221Smarcel cookies = NULL; 31383221Smarcel } 31424654Sdfr 315101189Srwatson#ifdef MAC 316101189Srwatson /* 317101189Srwatson * Do directory search MAC check using non-cached credentials. 318101189Srwatson */ 319112451Sjhb if ((error = mac_check_vnode_readdir(td->td_ucred, vp))) 320101189Srwatson goto out; 321101189Srwatson#endif /* MAC */ 32283221Smarcel if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 32383221Smarcel &cookies))) 32483221Smarcel goto out; 3259313Ssos 32683221Smarcel inp = buf; 32783221Smarcel outp = (caddr_t)args->dirent; 32883221Smarcel resid = nbytes; 32983221Smarcel if ((len = buflen - auio.uio_resid) <= 0) 33083221Smarcel goto eof; 3319313Ssos 33283221Smarcel cookiep = cookies; 33324654Sdfr 33483221Smarcel if (cookies) { 33583221Smarcel /* 33683221Smarcel * When using cookies, the vfs has the option of reading from 33783221Smarcel * a different offset than that supplied (UFS truncates the 33883221Smarcel * offset to a block boundary to make sure that it never reads 33983221Smarcel * partway through a directory entry, even if the directory 34083221Smarcel * has been compacted). 34183221Smarcel */ 34283221Smarcel while (len > 0 && ncookies > 0 && *cookiep <= off) { 34383221Smarcel bdp = (struct dirent *) inp; 34483221Smarcel len -= bdp->d_reclen; 34583221Smarcel inp += bdp->d_reclen; 34683221Smarcel cookiep++; 34783221Smarcel ncookies--; 34883221Smarcel } 34924654Sdfr } 35024654Sdfr 35183221Smarcel while (len > 0) { 35283221Smarcel if (cookiep && ncookies == 0) 35383221Smarcel break; 35483221Smarcel bdp = (struct dirent *) inp; 35583221Smarcel reclen = bdp->d_reclen; 35683221Smarcel if (reclen & 3) { 35783221Smarcel error = EFAULT; 35883221Smarcel goto out; 35983221Smarcel } 36083221Smarcel 36183221Smarcel if (bdp->d_fileno == 0) { 36283221Smarcel inp += reclen; 36383221Smarcel if (cookiep) { 36483221Smarcel off = *cookiep++; 36583221Smarcel ncookies--; 36683221Smarcel } else 36783221Smarcel off += reclen; 36883221Smarcel 36983221Smarcel len -= reclen; 37083221Smarcel continue; 37183221Smarcel } 37283221Smarcel 37383221Smarcel linuxreclen = (is64bit) 37483221Smarcel ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) 37583221Smarcel : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 37683221Smarcel 37783221Smarcel if (reclen > len || resid < linuxreclen) { 37883221Smarcel outp++; 37983221Smarcel break; 38083221Smarcel } 38183221Smarcel 38283221Smarcel if (justone) { 38383221Smarcel /* readdir(2) case. */ 38483221Smarcel linux_dirent.d_ino = (l_long)bdp->d_fileno; 38583221Smarcel linux_dirent.d_off = (l_off_t)linuxreclen; 38683221Smarcel linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 38783221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 38883221Smarcel error = copyout(&linux_dirent, outp, linuxreclen); 38983221Smarcel } else { 39083221Smarcel if (is64bit) { 39183221Smarcel linux_dirent64.d_ino = bdp->d_fileno; 39283221Smarcel linux_dirent64.d_off = (cookiep) 39383221Smarcel ? (l_off_t)*cookiep 39483221Smarcel : (l_off_t)(off + reclen); 39583221Smarcel linux_dirent64.d_reclen = 39683221Smarcel (l_ushort)linuxreclen; 39783221Smarcel linux_dirent64.d_type = bdp->d_type; 39883221Smarcel strcpy(linux_dirent64.d_name, bdp->d_name); 39983221Smarcel error = copyout(&linux_dirent64, outp, 40083221Smarcel linuxreclen); 40183221Smarcel } else { 40283221Smarcel linux_dirent.d_ino = bdp->d_fileno; 40383221Smarcel linux_dirent.d_off = (cookiep) 40483221Smarcel ? (l_off_t)*cookiep 40583221Smarcel : (l_off_t)(off + reclen); 40683221Smarcel linux_dirent.d_reclen = (l_ushort)linuxreclen; 40783221Smarcel strcpy(linux_dirent.d_name, bdp->d_name); 40883221Smarcel error = copyout(&linux_dirent, outp, 40983221Smarcel linuxreclen); 41083221Smarcel } 41183221Smarcel } 41283221Smarcel if (error) 41383221Smarcel goto out; 41483221Smarcel 41583221Smarcel inp += reclen; 41683221Smarcel if (cookiep) { 41783221Smarcel off = *cookiep++; 41883221Smarcel ncookies--; 41983221Smarcel } else 42083221Smarcel off += reclen; 42183221Smarcel 42283221Smarcel outp += linuxreclen; 42383221Smarcel resid -= linuxreclen; 42483221Smarcel len -= reclen; 42583221Smarcel if (justone) 42683221Smarcel break; 42710355Sswallace } 4289313Ssos 42983221Smarcel if (outp == (caddr_t)args->dirent) 43083221Smarcel goto again; 4319313Ssos 43283221Smarcel fp->f_offset = off; 43383221Smarcel if (justone) 43483221Smarcel nbytes = resid + linuxreclen; 43510355Sswallace 4369313Ssoseof: 43783366Sjulian td->td_retval[0] = nbytes - resid; 43883221Smarcel 4399313Ssosout: 44083221Smarcel if (cookies) 44183221Smarcel free(cookies, M_TEMP); 44283221Smarcel 44383366Sjulian VOP_UNLOCK(vp, 0, td); 444160276Sjhb VFS_UNLOCK_GIANT(vfslocked); 44589306Salfred fdrop(fp, td); 44683221Smarcel free(buf, M_TEMP); 44783221Smarcel return (error); 4489313Ssos} 44914331Speter 45083221Smarcelint 45183366Sjulianlinux_getdents(struct thread *td, struct linux_getdents_args *args) 45283221Smarcel{ 45383221Smarcel 45483221Smarcel#ifdef DEBUG 45583221Smarcel if (ldebug(getdents)) 45683221Smarcel printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 45783221Smarcel#endif 45883221Smarcel 45983366Sjulian return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 46083221Smarcel} 46183221Smarcel 46283221Smarcelint 46383366Sjulianlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 46483221Smarcel{ 46583221Smarcel 46683221Smarcel#ifdef DEBUG 46783221Smarcel if (ldebug(getdents64)) 46883221Smarcel printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 46983221Smarcel#endif 47083221Smarcel 47183366Sjulian return (getdents_common(td, args, 1)); 47283221Smarcel} 47383221Smarcel 47414331Speter/* 47514331Speter * These exist mainly for hooks for doing /compat/linux translation. 47614331Speter */ 47714331Speter 47814331Speterint 47983366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 48014331Speter{ 481102814Siedowse char *path; 482102814Siedowse int error; 48314331Speter 484162585Snetchild /* linux convention */ 485162585Snetchild if (args->flags & ~(F_OK | X_OK | W_OK | R_OK)) 486162585Snetchild return (EINVAL); 487162585Snetchild 488102814Siedowse LCONVPATHEXIST(td, args->path, &path); 48914331Speter 49014331Speter#ifdef DEBUG 49172543Sjlemon if (ldebug(access)) 492102814Siedowse printf(ARGS(access, "%s, %d"), path, args->flags); 49314331Speter#endif 494102814Siedowse error = kern_access(td, path, UIO_SYSSPACE, args->flags); 495102814Siedowse LFREEPATH(path); 496162585Snetchild 497102814Siedowse return (error); 49814331Speter} 49914331Speter 50014331Speterint 50183366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 50214331Speter{ 503102814Siedowse char *path; 504102814Siedowse int error; 505162201Snetchild struct stat st; 50614331Speter 507102814Siedowse LCONVPATHEXIST(td, args->path, &path); 50814331Speter 50914331Speter#ifdef DEBUG 51072543Sjlemon if (ldebug(unlink)) 511102814Siedowse printf(ARGS(unlink, "%s"), path); 51214331Speter#endif 51314331Speter 514102814Siedowse error = kern_unlink(td, path, UIO_SYSSPACE); 515162201Snetchild if (error == EPERM) 516162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 517162201Snetchild if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 518162201Snetchild if (S_ISDIR(st.st_mode)) 519162201Snetchild error = EISDIR; 520102814Siedowse LFREEPATH(path); 521102814Siedowse return (error); 52214331Speter} 52314331Speter 52414331Speterint 52583366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 52614331Speter{ 527102814Siedowse char *path; 528102814Siedowse int error; 52914331Speter 530102814Siedowse LCONVPATHEXIST(td, args->path, &path); 53114331Speter 53214331Speter#ifdef DEBUG 53372543Sjlemon if (ldebug(chdir)) 534102814Siedowse printf(ARGS(chdir, "%s"), path); 53514331Speter#endif 536102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 537102814Siedowse LFREEPATH(path); 538102814Siedowse return (error); 53914331Speter} 54014331Speter 54114331Speterint 54283366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 54314331Speter{ 544102814Siedowse char *path; 545102814Siedowse int error; 54614331Speter 547102814Siedowse LCONVPATHEXIST(td, args->path, &path); 54814331Speter 54914331Speter#ifdef DEBUG 55072543Sjlemon if (ldebug(chmod)) 551102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 55214331Speter#endif 553102814Siedowse error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 554102814Siedowse LFREEPATH(path); 555102814Siedowse return (error); 55614331Speter} 55714331Speter 55814331Speterint 55983366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 56014331Speter{ 561102814Siedowse char *path; 562102814Siedowse int error; 56314331Speter 564102814Siedowse LCONVPATHCREAT(td, args->path, &path); 56514331Speter 56614331Speter#ifdef DEBUG 56772543Sjlemon if (ldebug(mkdir)) 568102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 56914331Speter#endif 570102814Siedowse error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 571102814Siedowse LFREEPATH(path); 572102814Siedowse return (error); 57314331Speter} 57414331Speter 57514331Speterint 57683366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 57714331Speter{ 578102814Siedowse char *path; 579102814Siedowse int error; 58014331Speter 581102814Siedowse LCONVPATHEXIST(td, args->path, &path); 58214331Speter 58314331Speter#ifdef DEBUG 58472543Sjlemon if (ldebug(rmdir)) 585102814Siedowse printf(ARGS(rmdir, "%s"), path); 58614331Speter#endif 587102814Siedowse error = kern_rmdir(td, path, UIO_SYSSPACE); 588102814Siedowse LFREEPATH(path); 589102814Siedowse return (error); 59014331Speter} 59114331Speter 59214331Speterint 59383366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 59414331Speter{ 595102814Siedowse char *from, *to; 596102814Siedowse int error; 59714331Speter 598102814Siedowse LCONVPATHEXIST(td, args->from, &from); 599102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 600102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 601102814Siedowse if (to == NULL) { 602102814Siedowse LFREEPATH(from); 603102814Siedowse return (error); 604102814Siedowse } 60514331Speter 60614331Speter#ifdef DEBUG 60772543Sjlemon if (ldebug(rename)) 608102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 60914331Speter#endif 610102814Siedowse error = kern_rename(td, from, to, UIO_SYSSPACE); 611102814Siedowse LFREEPATH(from); 612102814Siedowse LFREEPATH(to); 613102814Siedowse return (error); 61414331Speter} 61514331Speter 61614331Speterint 61783366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 61814331Speter{ 619102814Siedowse char *path, *to; 620102814Siedowse int error; 62114331Speter 622102814Siedowse LCONVPATHEXIST(td, args->path, &path); 623102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 624102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 625102814Siedowse if (to == NULL) { 626102814Siedowse LFREEPATH(path); 627102814Siedowse return (error); 628102814Siedowse } 62914331Speter 63014331Speter#ifdef DEBUG 63172543Sjlemon if (ldebug(symlink)) 632102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 63314331Speter#endif 634102814Siedowse error = kern_symlink(td, path, to, UIO_SYSSPACE); 635102814Siedowse LFREEPATH(path); 636102814Siedowse LFREEPATH(to); 637102814Siedowse return (error); 63814331Speter} 63914331Speter 64014331Speterint 64183366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 64214331Speter{ 643102814Siedowse char *name; 644102814Siedowse int error; 64514331Speter 646102814Siedowse LCONVPATHEXIST(td, args->name, &name); 64714331Speter 64814331Speter#ifdef DEBUG 64972543Sjlemon if (ldebug(readlink)) 650102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 651102814Siedowse args->count); 65214331Speter#endif 653102814Siedowse error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 654102814Siedowse args->count); 655102814Siedowse LFREEPATH(name); 656102814Siedowse return (error); 65714331Speter} 65814331Speter 65914331Speterint 66083366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 66114331Speter{ 662102814Siedowse char *path; 663102814Siedowse int error; 66414331Speter 665102814Siedowse LCONVPATHEXIST(td, args->path, &path); 66614331Speter 66714331Speter#ifdef DEBUG 66872543Sjlemon if (ldebug(truncate)) 669102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 67014331Speter#endif 67114331Speter 672102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 673102814Siedowse LFREEPATH(path); 674102814Siedowse return (error); 67514331Speter} 67614331Speter 67749662Smarcelint 678156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 679156842Snetchild{ 680156842Snetchild struct ftruncate_args /* { 681156842Snetchild int fd; 682156842Snetchild int pad; 683156842Snetchild off_t length; 684156842Snetchild } */ nuap; 685156842Snetchild 686156842Snetchild nuap.fd = args->fd; 687156842Snetchild nuap.pad = 0; 688156842Snetchild nuap.length = args->length; 689156842Snetchild return (ftruncate(td, &nuap)); 690156842Snetchild} 691156842Snetchild 692156842Snetchildint 69383366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 69449662Smarcel{ 695102814Siedowse char *path, *to; 696102814Siedowse int error; 69749662Smarcel 698102814Siedowse LCONVPATHEXIST(td, args->path, &path); 699102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 700102814Siedowse error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 701102814Siedowse if (to == NULL) { 702102814Siedowse LFREEPATH(path); 703102814Siedowse return (error); 704102814Siedowse } 70549662Smarcel 70649662Smarcel#ifdef DEBUG 70772543Sjlemon if (ldebug(link)) 708102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 70949662Smarcel#endif 710102814Siedowse error = kern_link(td, path, to, UIO_SYSSPACE); 711102814Siedowse LFREEPATH(path); 712102814Siedowse LFREEPATH(to); 713102814Siedowse return (error); 71449662Smarcel} 71549788Smarcel 71653713Smarcelint 71783366Sjulianlinux_fdatasync(td, uap) 71883366Sjulian struct thread *td; 71953713Smarcel struct linux_fdatasync_args *uap; 72053713Smarcel{ 72153713Smarcel struct fsync_args bsd; 72253713Smarcel 72353713Smarcel bsd.fd = uap->fd; 72483366Sjulian return fsync(td, &bsd); 72553713Smarcel} 72663285Smarcel 72763285Smarcelint 72883366Sjulianlinux_pread(td, uap) 72983366Sjulian struct thread *td; 73063285Smarcel struct linux_pread_args *uap; 73163285Smarcel{ 73263285Smarcel struct pread_args bsd; 733162585Snetchild struct vnode *vp; 734162585Snetchild int error; 73563285Smarcel 73663285Smarcel bsd.fd = uap->fd; 73763285Smarcel bsd.buf = uap->buf; 73863285Smarcel bsd.nbyte = uap->nbyte; 73963285Smarcel bsd.offset = uap->offset; 740162585Snetchild 741162585Snetchild error = pread(td, &bsd); 742162585Snetchild 743162585Snetchild if (error == 0) { 744162585Snetchild /* This seems to violate POSIX but linux does it */ 745162585Snetchild if ((error = fgetvp(td, uap->fd, &vp)) != 0) 746162585Snetchild return (error); 747162585Snetchild if (vp->v_type == VDIR) { 748162585Snetchild vrele(vp); 749162585Snetchild return (EISDIR); 750162585Snetchild } 751162585Snetchild vrele(vp); 752162585Snetchild } 753162585Snetchild 754162585Snetchild return (error); 75563285Smarcel} 75663285Smarcel 75763285Smarcelint 75883366Sjulianlinux_pwrite(td, uap) 75983366Sjulian struct thread *td; 76063285Smarcel struct linux_pwrite_args *uap; 76163285Smarcel{ 76263285Smarcel struct pwrite_args bsd; 76363285Smarcel 76463285Smarcel bsd.fd = uap->fd; 76563285Smarcel bsd.buf = uap->buf; 76663285Smarcel bsd.nbyte = uap->nbyte; 76763285Smarcel bsd.offset = uap->offset; 76883366Sjulian return pwrite(td, &bsd); 76963285Smarcel} 77072538Sjlemon 77172538Sjlemonint 77283366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 77372538Sjlemon{ 77472538Sjlemon struct ufs_args ufs; 775111798Sdes char fstypename[MFSNAMELEN]; 776111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 77773286Sadrian int error; 77873286Sadrian int fsflags; 77973286Sadrian void *fsdata; 78072538Sjlemon 781111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 78273286Sadrian NULL); 78372538Sjlemon if (error) 784111798Sdes return (error); 785127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 78672538Sjlemon if (error) 787111798Sdes return (error); 788127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 78972538Sjlemon if (error) 790111798Sdes return (error); 79172538Sjlemon 79272538Sjlemon#ifdef DEBUG 79372538Sjlemon if (ldebug(mount)) 79472538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 79572538Sjlemon fstypename, mntfromname, mntonname); 79672538Sjlemon#endif 79772538Sjlemon 79872538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 799127059Stjr strcpy(fstypename, "ext2fs"); 80073286Sadrian fsdata = &ufs; 80172538Sjlemon ufs.fspec = mntfromname; 80272538Sjlemon#define DEFAULT_ROOTID -2 80372538Sjlemon ufs.export.ex_root = DEFAULT_ROOTID; 80472538Sjlemon ufs.export.ex_flags = 80572538Sjlemon args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 80672538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 807127059Stjr strcpy(fstypename, "linprocfs"); 80873286Sadrian fsdata = NULL; 80972538Sjlemon } else { 81072538Sjlemon return (ENODEV); 81172538Sjlemon } 81272538Sjlemon 81373286Sadrian fsflags = 0; 81472538Sjlemon 81572538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 81672538Sjlemon /* 81772538Sjlemon * Linux SYNC flag is not included; the closest equivalent 81872538Sjlemon * FreeBSD has is !ASYNC, which is our default. 81972538Sjlemon */ 82072538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 821111798Sdes fsflags |= MNT_RDONLY; 82272538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 823111798Sdes fsflags |= MNT_NOSUID; 82472538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 825111798Sdes fsflags |= MNT_NOEXEC; 82672538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 827111798Sdes fsflags |= MNT_UPDATE; 82872538Sjlemon } 82972538Sjlemon 830127059Stjr if (strcmp(fstypename, "linprocfs") == 0) { 831132708Sphk error = kernel_vmount(fsflags, 832132708Sphk "fstype", fstypename, 833132708Sphk "fspath", mntonname, 834132708Sphk NULL); 835127059Stjr } else 836138353Sphk error = EOPNOTSUPP; 837127059Stjr return (error); 83872538Sjlemon} 83972538Sjlemon 84072538Sjlemonint 84183366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 84272538Sjlemon{ 84383221Smarcel struct linux_umount_args args2; 84472538Sjlemon 84572538Sjlemon args2.path = args->path; 84672538Sjlemon args2.flags = 0; 84783366Sjulian return (linux_umount(td, &args2)); 84872538Sjlemon} 84972538Sjlemon 85072538Sjlemonint 85183366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 85272538Sjlemon{ 85372538Sjlemon struct unmount_args bsd; 85472538Sjlemon 85572538Sjlemon bsd.path = args->path; 85672538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 85783366Sjulian return (unmount(td, &bsd)); 85872538Sjlemon} 85983221Smarcel 86083221Smarcel/* 86183221Smarcel * fcntl family of syscalls 86283221Smarcel */ 86383221Smarcel 86483221Smarcelstruct l_flock { 86583221Smarcel l_short l_type; 86683221Smarcel l_short l_whence; 86783221Smarcel l_off_t l_start; 86883221Smarcel l_off_t l_len; 86983221Smarcel l_pid_t l_pid; 870133816Stjr} 871140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 872133816Stjr__packed 873133816Stjr#endif 874133816Stjr; 87583221Smarcel 87683221Smarcelstatic void 87783221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 87883221Smarcel{ 87983221Smarcel switch (linux_flock->l_type) { 88083221Smarcel case LINUX_F_RDLCK: 88183221Smarcel bsd_flock->l_type = F_RDLCK; 88283221Smarcel break; 88383221Smarcel case LINUX_F_WRLCK: 88483221Smarcel bsd_flock->l_type = F_WRLCK; 88583221Smarcel break; 88683221Smarcel case LINUX_F_UNLCK: 88783221Smarcel bsd_flock->l_type = F_UNLCK; 88883221Smarcel break; 88983221Smarcel default: 89083221Smarcel bsd_flock->l_type = -1; 89183221Smarcel break; 89283221Smarcel } 89383221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 89483221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 89583221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 89683221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 89783221Smarcel} 89883221Smarcel 89983221Smarcelstatic void 90083221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 90183221Smarcel{ 90283221Smarcel switch (bsd_flock->l_type) { 90383221Smarcel case F_RDLCK: 90483221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 90583221Smarcel break; 90683221Smarcel case F_WRLCK: 90783221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 90883221Smarcel break; 90983221Smarcel case F_UNLCK: 91083221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 91183221Smarcel break; 91283221Smarcel } 91383221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 91483221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 91583221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 91683221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 91783221Smarcel} 91883221Smarcel 919140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 92083221Smarcelstruct l_flock64 { 92183221Smarcel l_short l_type; 92283221Smarcel l_short l_whence; 92383221Smarcel l_loff_t l_start; 92483221Smarcel l_loff_t l_len; 92583221Smarcel l_pid_t l_pid; 926133816Stjr} 927140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 928133816Stjr__packed 929133816Stjr#endif 930133816Stjr; 93183221Smarcel 93283221Smarcelstatic void 93383221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 93483221Smarcel{ 93583221Smarcel switch (linux_flock->l_type) { 93683221Smarcel case LINUX_F_RDLCK: 93783221Smarcel bsd_flock->l_type = F_RDLCK; 93883221Smarcel break; 93983221Smarcel case LINUX_F_WRLCK: 94083221Smarcel bsd_flock->l_type = F_WRLCK; 94183221Smarcel break; 94283221Smarcel case LINUX_F_UNLCK: 94383221Smarcel bsd_flock->l_type = F_UNLCK; 94483221Smarcel break; 94583221Smarcel default: 94683221Smarcel bsd_flock->l_type = -1; 94783221Smarcel break; 94883221Smarcel } 94983221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 95083221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 95183221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 95283221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 95383221Smarcel} 95483221Smarcel 95583221Smarcelstatic void 95683221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 95783221Smarcel{ 95883221Smarcel switch (bsd_flock->l_type) { 95983221Smarcel case F_RDLCK: 96083221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 96183221Smarcel break; 96283221Smarcel case F_WRLCK: 96383221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 96483221Smarcel break; 96583221Smarcel case F_UNLCK: 96683221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 96783221Smarcel break; 96883221Smarcel } 96983221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 97083221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 97183221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 97283221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 97383221Smarcel} 974133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 97583221Smarcel 97683221Smarcelstatic int 97783366Sjulianfcntl_common(struct thread *td, struct linux_fcntl64_args *args) 97883221Smarcel{ 979107680Siedowse struct l_flock linux_flock; 980107680Siedowse struct flock bsd_flock; 98183221Smarcel struct file *fp; 982102872Siedowse long arg; 98383221Smarcel int error, result; 98483221Smarcel 98583221Smarcel switch (args->cmd) { 98683221Smarcel case LINUX_F_DUPFD: 987102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 98883221Smarcel 98983221Smarcel case LINUX_F_GETFD: 990102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 99183221Smarcel 99283221Smarcel case LINUX_F_SETFD: 993102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 99483221Smarcel 99583221Smarcel case LINUX_F_GETFL: 996102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 99783366Sjulian result = td->td_retval[0]; 99883366Sjulian td->td_retval[0] = 0; 99983221Smarcel if (result & O_RDONLY) 100083366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 100183221Smarcel if (result & O_WRONLY) 100283366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 100383221Smarcel if (result & O_RDWR) 100483366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 100583221Smarcel if (result & O_NDELAY) 100683366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 100783221Smarcel if (result & O_APPEND) 100883366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 100983221Smarcel if (result & O_FSYNC) 101083366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 101183221Smarcel if (result & O_ASYNC) 101283366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1013144987Smdodd#ifdef LINUX_O_NOFOLLOW 1014144987Smdodd if (result & O_NOFOLLOW) 1015144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1016144987Smdodd#endif 1017144987Smdodd#ifdef LINUX_O_DIRECT 1018144987Smdodd if (result & O_DIRECT) 1019144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1020144987Smdodd#endif 102183221Smarcel return (error); 102283221Smarcel 102383221Smarcel case LINUX_F_SETFL: 1024102872Siedowse arg = 0; 102583221Smarcel if (args->arg & LINUX_O_NDELAY) 1026102872Siedowse arg |= O_NONBLOCK; 102783221Smarcel if (args->arg & LINUX_O_APPEND) 1028102872Siedowse arg |= O_APPEND; 102983221Smarcel if (args->arg & LINUX_O_SYNC) 1030102872Siedowse arg |= O_FSYNC; 103183221Smarcel if (args->arg & LINUX_FASYNC) 1032102872Siedowse arg |= O_ASYNC; 1033144987Smdodd#ifdef LINUX_O_NOFOLLOW 1034144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1035144987Smdodd arg |= O_NOFOLLOW; 1036144987Smdodd#endif 1037144987Smdodd#ifdef LINUX_O_DIRECT 1038144987Smdodd if (args->arg & LINUX_O_DIRECT) 1039144987Smdodd arg |= O_DIRECT; 1040144987Smdodd#endif 1041102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 104283221Smarcel 1043107680Siedowse case LINUX_F_GETLK: 1044111797Sdes error = copyin((void *)args->arg, &linux_flock, 1045107680Siedowse sizeof(linux_flock)); 1046107680Siedowse if (error) 1047107680Siedowse return (error); 1048107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1049107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1050107680Siedowse if (error) 1051107680Siedowse return (error); 1052107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1053111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1054107680Siedowse sizeof(linux_flock))); 1055107680Siedowse 1056107680Siedowse case LINUX_F_SETLK: 1057111797Sdes error = copyin((void *)args->arg, &linux_flock, 1058107680Siedowse sizeof(linux_flock)); 1059107680Siedowse if (error) 1060107680Siedowse return (error); 1061107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1062107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1063107680Siedowse (intptr_t)&bsd_flock)); 1064107680Siedowse 1065107680Siedowse case LINUX_F_SETLKW: 1066111797Sdes error = copyin((void *)args->arg, &linux_flock, 1067107680Siedowse sizeof(linux_flock)); 1068107680Siedowse if (error) 1069107680Siedowse return (error); 1070107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1071107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1072107680Siedowse (intptr_t)&bsd_flock)); 1073107680Siedowse 107483221Smarcel case LINUX_F_GETOWN: 1075102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 107683221Smarcel 107783221Smarcel case LINUX_F_SETOWN: 107883221Smarcel /* 107983221Smarcel * XXX some Linux applications depend on F_SETOWN having no 108083221Smarcel * significant effect for pipes (SIGIO is not delivered for 108183221Smarcel * pipes under Linux-2.2.35 at least). 108283221Smarcel */ 108389319Salfred error = fget(td, args->fd, &fp); 108489319Salfred if (error) 108589319Salfred return (error); 108689306Salfred if (fp->f_type == DTYPE_PIPE) { 108789306Salfred fdrop(fp, td); 108883221Smarcel return (EINVAL); 108989306Salfred } 109089306Salfred fdrop(fp, td); 109183221Smarcel 1092102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 109383221Smarcel } 109483221Smarcel 109583221Smarcel return (EINVAL); 109683221Smarcel} 109783221Smarcel 109883221Smarcelint 109983366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 110083221Smarcel{ 110183221Smarcel struct linux_fcntl64_args args64; 110283221Smarcel 110383221Smarcel#ifdef DEBUG 110483221Smarcel if (ldebug(fcntl)) 110583221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 110683221Smarcel#endif 110783221Smarcel 110883221Smarcel args64.fd = args->fd; 110983221Smarcel args64.cmd = args->cmd; 111083221Smarcel args64.arg = args->arg; 111183366Sjulian return (fcntl_common(td, &args64)); 111283221Smarcel} 111383221Smarcel 1114140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 111583221Smarcelint 111683366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 111783221Smarcel{ 111883221Smarcel struct l_flock64 linux_flock; 1119102872Siedowse struct flock bsd_flock; 112083221Smarcel int error; 112183221Smarcel 112283221Smarcel#ifdef DEBUG 112383221Smarcel if (ldebug(fcntl64)) 112483221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 112583221Smarcel#endif 112683221Smarcel 112783221Smarcel switch (args->cmd) { 112899687Srobert case LINUX_F_GETLK64: 1129111797Sdes error = copyin((void *)args->arg, &linux_flock, 113083221Smarcel sizeof(linux_flock)); 113183221Smarcel if (error) 113283221Smarcel return (error); 1133102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1134102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 113583221Smarcel if (error) 113683221Smarcel return (error); 1137102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1138111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1139111797Sdes sizeof(linux_flock))); 114083221Smarcel 114199687Srobert case LINUX_F_SETLK64: 1142111797Sdes error = copyin((void *)args->arg, &linux_flock, 114383221Smarcel sizeof(linux_flock)); 114483221Smarcel if (error) 114583221Smarcel return (error); 1146102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1147102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1148102872Siedowse (intptr_t)&bsd_flock)); 114983221Smarcel 115099687Srobert case LINUX_F_SETLKW64: 1151111797Sdes error = copyin((void *)args->arg, &linux_flock, 115283221Smarcel sizeof(linux_flock)); 115383221Smarcel if (error) 115483221Smarcel return (error); 1155102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1156102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1157102872Siedowse (intptr_t)&bsd_flock)); 115883221Smarcel } 115983221Smarcel 116083366Sjulian return (fcntl_common(td, args)); 116183221Smarcel} 1162133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 116385022Smarcel 116485022Smarcelint 116585022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 116685022Smarcel{ 1167102814Siedowse char *path; 1168102814Siedowse int error; 116985022Smarcel 1170102814Siedowse LCONVPATHEXIST(td, args->path, &path); 117185022Smarcel 117285022Smarcel#ifdef DEBUG 117385022Smarcel if (ldebug(chown)) 1174102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 117585022Smarcel#endif 1176102814Siedowse error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1177102814Siedowse LFREEPATH(path); 1178102814Siedowse return (error); 117985022Smarcel} 118085022Smarcel 118185022Smarcelint 118285022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 118385022Smarcel{ 1184102814Siedowse char *path; 1185102814Siedowse int error; 118685022Smarcel 1187102814Siedowse LCONVPATHEXIST(td, args->path, &path); 118885022Smarcel 118985022Smarcel#ifdef DEBUG 119085022Smarcel if (ldebug(lchown)) 1191102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 119285022Smarcel#endif 1193102814Siedowse error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1194102814Siedowse LFREEPATH(path); 1195102814Siedowse return (error); 119685022Smarcel} 1197