linux_file.c revision 315538
19313Ssos/*- 2230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 9111798Sdes * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos */ 289313Ssos 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_file.c 315538 2017-03-19 10:32:39Z trasz $"); 31116173Sobrien 32156874Sru#include "opt_compat.h" 3331784Seivind 349313Ssos#include <sys/param.h> 359313Ssos#include <sys/systm.h> 36263233Srwatson#include <sys/capsicum.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 56140214Sobrien#ifdef COMPAT_LINUX32 57140214Sobrien#include <machine/../linux32/linux.h> 58140214Sobrien#include <machine/../linux32/linux32_proto.h> 59140214Sobrien#else 6064905Smarcel#include <machine/../linux/linux.h> 6168583Smarcel#include <machine/../linux/linux_proto.h> 62133816Stjr#endif 63246085Sjhb#include <compat/linux/linux_misc.h> 6464905Smarcel#include <compat/linux/linux_util.h> 65177997Skib#include <compat/linux/linux_file.h> 669313Ssos 67315376Sdchaginstatic int linux_common_open(struct thread *, int, char *, int, int); 68315376Sdchaginstatic int linux_getdents_error(struct thread *, int, int); 69315376Sdchagin 70315376Sdchagin 719313Ssosint 7283366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 739313Ssos{ 74300411Sdchagin char *path; 75300411Sdchagin int error; 769313Ssos 77300411Sdchagin LCONVPATHEXIST(td, args->path, &path); 789313Ssos#ifdef DEBUG 7972543Sjlemon if (ldebug(creat)) 80102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 819313Ssos#endif 82300411Sdchagin error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, 83300411Sdchagin O_WRONLY | O_CREAT | O_TRUNC, args->mode); 84300411Sdchagin LFREEPATH(path); 85300411Sdchagin return (error); 869313Ssos} 879313Ssos 88168014Sjulian 89168014Sjulianstatic int 90177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 919313Ssos{ 92300411Sdchagin cap_rights_t rights; 93300411Sdchagin struct proc *p = td->td_proc; 94300411Sdchagin struct file *fp; 95300411Sdchagin int fd; 96300411Sdchagin int bsd_flags, error; 9714331Speter 98300411Sdchagin bsd_flags = 0; 99300411Sdchagin switch (l_flags & LINUX_O_ACCMODE) { 100300411Sdchagin case LINUX_O_WRONLY: 101300411Sdchagin bsd_flags |= O_WRONLY; 102300411Sdchagin break; 103300411Sdchagin case LINUX_O_RDWR: 104300411Sdchagin bsd_flags |= O_RDWR; 105300411Sdchagin break; 106300411Sdchagin default: 107300411Sdchagin bsd_flags |= O_RDONLY; 108300411Sdchagin } 109300411Sdchagin if (l_flags & LINUX_O_NDELAY) 110300411Sdchagin bsd_flags |= O_NONBLOCK; 111300411Sdchagin if (l_flags & LINUX_O_APPEND) 112300411Sdchagin bsd_flags |= O_APPEND; 113300411Sdchagin if (l_flags & LINUX_O_SYNC) 114300411Sdchagin bsd_flags |= O_FSYNC; 115300411Sdchagin if (l_flags & LINUX_O_NONBLOCK) 116300411Sdchagin bsd_flags |= O_NONBLOCK; 117300411Sdchagin if (l_flags & LINUX_FASYNC) 118300411Sdchagin bsd_flags |= O_ASYNC; 119300411Sdchagin if (l_flags & LINUX_O_CREAT) 120300411Sdchagin bsd_flags |= O_CREAT; 121300411Sdchagin if (l_flags & LINUX_O_TRUNC) 122300411Sdchagin bsd_flags |= O_TRUNC; 123300411Sdchagin if (l_flags & LINUX_O_EXCL) 124300411Sdchagin bsd_flags |= O_EXCL; 125300411Sdchagin if (l_flags & LINUX_O_NOCTTY) 126300411Sdchagin bsd_flags |= O_NOCTTY; 127300411Sdchagin if (l_flags & LINUX_O_DIRECT) 128300411Sdchagin bsd_flags |= O_DIRECT; 129300411Sdchagin if (l_flags & LINUX_O_NOFOLLOW) 130300411Sdchagin bsd_flags |= O_NOFOLLOW; 131300411Sdchagin if (l_flags & LINUX_O_DIRECTORY) 132300411Sdchagin bsd_flags |= O_DIRECTORY; 133300411Sdchagin /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1349313Ssos 135300411Sdchagin error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 136300411Sdchagin if (error != 0) 137300411Sdchagin goto done; 138300411Sdchagin if (bsd_flags & O_NOCTTY) 139300411Sdchagin goto done; 140178036Srdivacky 141300411Sdchagin /* 142300411Sdchagin * XXX In between kern_open() and fget(), another process 143300411Sdchagin * having the same filedesc could use that fd without 144300411Sdchagin * checking below. 145300411Sdchagin */ 146300411Sdchagin fd = td->td_retval[0]; 147300411Sdchagin if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) { 148300411Sdchagin if (fp->f_type != DTYPE_VNODE) { 149300411Sdchagin fdrop(fp, td); 150300411Sdchagin goto done; 151300411Sdchagin } 152300411Sdchagin sx_slock(&proctree_lock); 153300411Sdchagin PROC_LOCK(p); 154300411Sdchagin if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 155300411Sdchagin PROC_UNLOCK(p); 156300411Sdchagin sx_sunlock(&proctree_lock); 157300411Sdchagin /* XXXPJD: Verify if TIOCSCTTY is allowed. */ 158300411Sdchagin (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 159300411Sdchagin td->td_ucred, td); 160300411Sdchagin } else { 161300411Sdchagin PROC_UNLOCK(p); 162300411Sdchagin sx_sunlock(&proctree_lock); 163300411Sdchagin } 164300411Sdchagin fdrop(fp, td); 165300411Sdchagin } 166281726Strasz 167281726Straszdone: 16814331Speter#ifdef DEBUG 169300411Sdchagin if (ldebug(open)) 170300411Sdchagin printf(LMSG("open returns error %d"), error); 17114331Speter#endif 172300411Sdchagin LFREEPATH(path); 173300411Sdchagin return (error); 1749313Ssos} 1759313Ssos 1769313Ssosint 177168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args) 178168014Sjulian{ 179177997Skib char *path; 180177997Skib int dfd; 181168014Sjulian 182177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 183177997Skib if (args->flags & LINUX_O_CREAT) 184177997Skib LCONVPATH_AT(td, args->filename, &path, 1, dfd); 185177997Skib else 186177997Skib LCONVPATH_AT(td, args->filename, &path, 0, dfd); 187168014Sjulian#ifdef DEBUG 188168014Sjulian if (ldebug(openat)) 189168014Sjulian printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 190177997Skib path, args->flags, args->mode); 191168014Sjulian#endif 192177997Skib return (linux_common_open(td, dfd, path, args->flags, args->mode)); 193168014Sjulian} 194168014Sjulian 195168014Sjulianint 196168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 197168014Sjulian{ 198300411Sdchagin char *path; 199168014Sjulian 200300411Sdchagin if (args->flags & LINUX_O_CREAT) 201300411Sdchagin LCONVPATHCREAT(td, args->path, &path); 202300411Sdchagin else 203300411Sdchagin LCONVPATHEXIST(td, args->path, &path); 204168014Sjulian#ifdef DEBUG 205168014Sjulian if (ldebug(open)) 206168014Sjulian printf(ARGS(open, "%s, 0x%x, 0x%x"), 207168014Sjulian path, args->flags, args->mode); 208168014Sjulian#endif 209178036Srdivacky return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 210168014Sjulian} 211168014Sjulian 212168014Sjulianint 21383366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 2149313Ssos{ 215300411Sdchagin struct lseek_args /* { 216300411Sdchagin int fd; 217300411Sdchagin int pad; 218300411Sdchagin off_t offset; 219300411Sdchagin int whence; 220300411Sdchagin } */ tmp_args; 221300411Sdchagin int error; 2229313Ssos 2239313Ssos#ifdef DEBUG 22472543Sjlemon if (ldebug(lseek)) 22572543Sjlemon printf(ARGS(lseek, "%d, %ld, %d"), 22683221Smarcel args->fdes, (long)args->off, args->whence); 2279313Ssos#endif 228300411Sdchagin tmp_args.fd = args->fdes; 229300411Sdchagin tmp_args.offset = (off_t)args->off; 230300411Sdchagin tmp_args.whence = args->whence; 231300411Sdchagin error = sys_lseek(td, &tmp_args); 232300411Sdchagin return (error); 2339313Ssos} 2349313Ssos 235283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 23614331Speterint 23783366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 23814331Speter{ 23914331Speter struct lseek_args bsd_args; 24014331Speter int error; 24114331Speter off_t off; 24214331Speter 24314331Speter#ifdef DEBUG 24472543Sjlemon if (ldebug(llseek)) 24572543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 24672543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 24714331Speter#endif 24814331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 24914331Speter 25014331Speter bsd_args.fd = args->fd; 25114331Speter bsd_args.offset = off; 25214331Speter bsd_args.whence = args->whence; 25314331Speter 254225617Skmacy if ((error = sys_lseek(td, &bsd_args))) 255300411Sdchagin return (error); 25614331Speter 257111797Sdes if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 258300411Sdchagin return (error); 25914331Speter 26083366Sjulian td->td_retval[0] = 0; 261300411Sdchagin return (0); 26214331Speter} 263283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 26414331Speter 26583221Smarcel/* 26683221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 26783221Smarcel * arguments. They only differ in the definition of struct dirent they 268315376Sdchagin * operate on. 269315376Sdchagin * Note that linux_readdir(2) is a special case of linux_getdents(2) 270315376Sdchagin * where count is always equals 1, meaning that the buffer is one 271315376Sdchagin * dirent-structure in size and that the code can't handle more anyway. 272315376Sdchagin * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2) 273315376Sdchagin * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will 274315376Sdchagin * trash user stack. 27583221Smarcel */ 27683221Smarcel 277315376Sdchaginstatic int 278315376Sdchaginlinux_getdents_error(struct thread *td, int fd, int err) 279315376Sdchagin{ 280315376Sdchagin cap_rights_t rights; 281315376Sdchagin struct vnode *vp; 282315376Sdchagin struct file *fp; 283315376Sdchagin int error; 284315376Sdchagin 285315376Sdchagin /* Linux return ENOTDIR in case when fd is not a directory. */ 286315376Sdchagin error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp); 287315376Sdchagin if (error != 0) 288315376Sdchagin return (error); 289315376Sdchagin vp = fp->f_vnode; 290315376Sdchagin if (vp->v_type != VDIR) { 291315376Sdchagin fdrop(fp, td); 292315376Sdchagin return (ENOTDIR); 293315376Sdchagin } 294315376Sdchagin fdrop(fp, td); 295315376Sdchagin return (err); 296315376Sdchagin} 297315376Sdchagin 29883221Smarcelstruct l_dirent { 299179651Srdivacky l_ulong d_ino; 30083221Smarcel l_off_t d_off; 30183221Smarcel l_ushort d_reclen; 30283221Smarcel char d_name[LINUX_NAME_MAX + 1]; 30383221Smarcel}; 30483221Smarcel 30583221Smarcelstruct l_dirent64 { 30683221Smarcel uint64_t d_ino; 30783221Smarcel int64_t d_off; 30883221Smarcel l_ushort d_reclen; 30983221Smarcel u_char d_type; 31083221Smarcel char d_name[LINUX_NAME_MAX + 1]; 31183221Smarcel}; 31283221Smarcel 313182892Srdivacky/* 314182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type, 315182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. 316182892Srdivacky */ 317182892Srdivacky#define LINUX_RECLEN(namlen) \ 318298482Spfg roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) 31983221Smarcel 320182892Srdivacky#define LINUX_RECLEN64(namlen) \ 321298482Spfg roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ 322182892Srdivacky sizeof(uint64_t)) 323182892Srdivacky 32483221Smarcel#define LINUX_DIRBLKSIZ 512 32583221Smarcel 326315376Sdchagin/* 327315376Sdchagin * Linux l_dirent is bigger than FreeBSD dirent, thus the buffer size 328315376Sdchagin * passed to kern_getdirentries() must be smaller than the one passed 329315376Sdchagin * to linux_getdents() by certain factor. 330315376Sdchagin */ 331315376Sdchagin#define LINUX_RECLEN_RATIO(X) X * offsetof(struct dirent, d_name) / \ 332315376Sdchagin offsetof(struct l_dirent, d_name); 333315376Sdchagin#define LINUX_RECLEN64_RATIO(X) X * offsetof(struct dirent, d_name) / \ 334315376Sdchagin offsetof(struct l_dirent64, d_name); 335315376Sdchagin 336315376Sdchaginint 337315376Sdchaginlinux_getdents(struct thread *td, struct linux_getdents_args *args) 33814331Speter{ 339111798Sdes struct dirent *bdp; 34083221Smarcel caddr_t inp, buf; /* BSD-format */ 34183221Smarcel int len, reclen; /* BSD-format */ 34283221Smarcel caddr_t outp; /* Linux-format */ 343315376Sdchagin int resid, linuxreclen; /* Linux-format */ 344182892Srdivacky caddr_t lbuf; /* Linux-format */ 345315376Sdchagin long base; 346182892Srdivacky struct l_dirent *linux_dirent; 347315376Sdchagin int buflen, error; 348315376Sdchagin size_t retval; 3499313Ssos 350315376Sdchagin#ifdef DEBUG 351315376Sdchagin if (ldebug(getdents)) 352315376Sdchagin printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 353315376Sdchagin#endif 354315376Sdchagin buflen = LINUX_RECLEN_RATIO(args->count); 355315376Sdchagin buflen = min(buflen, MAXBSIZE); 356315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 357160276Sjhb 358315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 359315376Sdchagin &base, NULL, UIO_SYSSPACE); 360315376Sdchagin if (error != 0) { 361315376Sdchagin error = linux_getdents_error(td, args->fd, error); 362315376Sdchagin goto out1; 36389306Salfred } 3649313Ssos 365315376Sdchagin lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 366315376Sdchagin 367315376Sdchagin len = td->td_retval[0]; 368315376Sdchagin inp = buf; 369315376Sdchagin outp = (caddr_t)args->dent; 370315376Sdchagin resid = args->count; 371315376Sdchagin retval = 0; 372315376Sdchagin 373315376Sdchagin while (len > 0) { 374315376Sdchagin bdp = (struct dirent *) inp; 375315376Sdchagin reclen = bdp->d_reclen; 376315376Sdchagin linuxreclen = LINUX_RECLEN(bdp->d_namlen); 377315376Sdchagin /* 378315376Sdchagin * No more space in the user supplied dirent buffer. 379315376Sdchagin * Return EINVAL. 380315376Sdchagin */ 381315376Sdchagin if (resid < linuxreclen) { 382315376Sdchagin error = EINVAL; 383315376Sdchagin goto out; 384315376Sdchagin } 385315376Sdchagin 386315376Sdchagin linux_dirent = (struct l_dirent*)lbuf; 387315376Sdchagin linux_dirent->d_ino = bdp->d_fileno; 388315376Sdchagin linux_dirent->d_off = base + reclen; 389315376Sdchagin linux_dirent->d_reclen = linuxreclen; 390315376Sdchagin /* 391315376Sdchagin * Copy d_type to last byte of l_dirent buffer 392315376Sdchagin */ 393315376Sdchagin lbuf[linuxreclen - 1] = bdp->d_type; 394315376Sdchagin strlcpy(linux_dirent->d_name, bdp->d_name, 395315376Sdchagin linuxreclen - offsetof(struct l_dirent, d_name)-1); 396315376Sdchagin error = copyout(linux_dirent, outp, linuxreclen); 397315376Sdchagin if (error != 0) 398315376Sdchagin goto out; 399315376Sdchagin 400315376Sdchagin inp += reclen; 401315376Sdchagin base += reclen; 402315376Sdchagin len -= reclen; 403315376Sdchagin 404315376Sdchagin retval += linuxreclen; 405315376Sdchagin outp += linuxreclen; 406315376Sdchagin resid -= linuxreclen; 40789306Salfred } 408315376Sdchagin td->td_retval[0] = retval; 4099313Ssos 410315376Sdchaginout: 411315376Sdchagin free(lbuf, M_LINUX); 412315376Sdchaginout1: 413315376Sdchagin free(buf, M_LINUX); 414315376Sdchagin return (error); 415315376Sdchagin} 4169313Ssos 417315376Sdchaginint 418315376Sdchaginlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 419315376Sdchagin{ 420315376Sdchagin struct dirent *bdp; 421315376Sdchagin caddr_t inp, buf; /* BSD-format */ 422315376Sdchagin int len, reclen; /* BSD-format */ 423315376Sdchagin caddr_t outp; /* Linux-format */ 424315376Sdchagin int resid, linuxreclen; /* Linux-format */ 425315376Sdchagin caddr_t lbuf; /* Linux-format */ 426315376Sdchagin long base; 427315376Sdchagin struct l_dirent64 *linux_dirent64; 428315376Sdchagin int buflen, error; 429315376Sdchagin size_t retval; 430315376Sdchagin 431315376Sdchagin#ifdef DEBUG 432315376Sdchagin if (ldebug(getdents64)) 433315376Sdchagin uprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 434315376Sdchagin#endif 435315376Sdchagin buflen = LINUX_RECLEN64_RATIO(args->count); 43683221Smarcel buflen = min(buflen, MAXBSIZE); 437315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 43883221Smarcel 439315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 440315376Sdchagin &base, NULL, UIO_SYSSPACE); 441315376Sdchagin if (error != 0) { 442315376Sdchagin error = linux_getdents_error(td, args->fd, error); 443315376Sdchagin goto out1; 444315376Sdchagin } 4459313Ssos 446315376Sdchagin lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 4479313Ssos 448315376Sdchagin len = td->td_retval[0]; 44983221Smarcel inp = buf; 45083221Smarcel outp = (caddr_t)args->dirent; 451315376Sdchagin resid = args->count; 452315376Sdchagin retval = 0; 4539313Ssos 45483221Smarcel while (len > 0) { 45583221Smarcel bdp = (struct dirent *) inp; 45683221Smarcel reclen = bdp->d_reclen; 457315376Sdchagin linuxreclen = LINUX_RECLEN64(bdp->d_namlen); 458315376Sdchagin /* 459315376Sdchagin * No more space in the user supplied dirent buffer. 460315376Sdchagin * Return EINVAL. 461315376Sdchagin */ 462315376Sdchagin if (resid < linuxreclen) { 463315376Sdchagin error = EINVAL; 46483221Smarcel goto out; 46583221Smarcel } 46683221Smarcel 467315376Sdchagin linux_dirent64 = (struct l_dirent64*)lbuf; 468315376Sdchagin linux_dirent64->d_ino = bdp->d_fileno; 469315376Sdchagin linux_dirent64->d_off = base + reclen; 470315376Sdchagin linux_dirent64->d_reclen = linuxreclen; 471315376Sdchagin linux_dirent64->d_type = bdp->d_type; 472315376Sdchagin strlcpy(linux_dirent64->d_name, bdp->d_name, 473315376Sdchagin linuxreclen - offsetof(struct l_dirent64, d_name)); 474315376Sdchagin error = copyout(linux_dirent64, outp, linuxreclen); 475315376Sdchagin if (error != 0) 47683221Smarcel goto out; 47783221Smarcel 47883221Smarcel inp += reclen; 479315376Sdchagin base += reclen; 480315376Sdchagin len -= reclen; 48183221Smarcel 482315376Sdchagin retval += linuxreclen; 48383221Smarcel outp += linuxreclen; 48483221Smarcel resid -= linuxreclen; 48510355Sswallace } 486315376Sdchagin td->td_retval[0] = retval; 4879313Ssos 4889313Ssosout: 489315376Sdchagin free(lbuf, M_TEMP); 490315376Sdchaginout1: 491315376Sdchagin free(buf, M_TEMP); 49283221Smarcel return (error); 4939313Ssos} 49414331Speter 495315376Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 49683221Smarcelint 497315376Sdchaginlinux_readdir(struct thread *td, struct linux_readdir_args *args) 49883221Smarcel{ 499315376Sdchagin struct dirent *bdp; 500315376Sdchagin caddr_t buf; /* BSD-format */ 501315376Sdchagin int linuxreclen; /* Linux-format */ 502315376Sdchagin caddr_t lbuf; /* Linux-format */ 503315376Sdchagin long base; 504315376Sdchagin struct l_dirent *linux_dirent; 505315376Sdchagin int buflen, error; 50683221Smarcel 50783221Smarcel#ifdef DEBUG 508315376Sdchagin if (ldebug(readdir)) 509315376Sdchagin printf(ARGS(readdir, "%d, *"), args->fd); 51083221Smarcel#endif 511315376Sdchagin buflen = LINUX_RECLEN(LINUX_NAME_MAX); 512315376Sdchagin buflen = LINUX_RECLEN_RATIO(buflen); 513315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 51483221Smarcel 515315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 516315376Sdchagin &base, NULL, UIO_SYSSPACE); 517315376Sdchagin if (error != 0) { 518315376Sdchagin error = linux_getdents_error(td, args->fd, error); 519315376Sdchagin goto out; 520315376Sdchagin } 521315376Sdchagin if (td->td_retval[0] == 0) 522315376Sdchagin goto out; 52383221Smarcel 524315376Sdchagin lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 52583221Smarcel 526315376Sdchagin bdp = (struct dirent *) buf; 527315376Sdchagin linuxreclen = LINUX_RECLEN(bdp->d_namlen); 52883221Smarcel 529315376Sdchagin linux_dirent = (struct l_dirent*)lbuf; 530315376Sdchagin linux_dirent->d_ino = bdp->d_fileno; 531315376Sdchagin linux_dirent->d_off = linuxreclen; 532315376Sdchagin linux_dirent->d_reclen = bdp->d_namlen; 533315376Sdchagin strlcpy(linux_dirent->d_name, bdp->d_name, 534315376Sdchagin linuxreclen - offsetof(struct l_dirent, d_name)); 535315376Sdchagin error = copyout(linux_dirent, args->dent, linuxreclen); 536315376Sdchagin if (error == 0) 537315376Sdchagin td->td_retval[0] = linuxreclen; 538315376Sdchagin 539315376Sdchagin free(lbuf, M_LINUX); 540315376Sdchaginout: 541315376Sdchagin free(buf, M_LINUX); 542315376Sdchagin return (error); 54383221Smarcel} 544315376Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 54583221Smarcel 546315376Sdchagin 54714331Speter/* 54814331Speter * These exist mainly for hooks for doing /compat/linux translation. 54914331Speter */ 55014331Speter 55114331Speterint 55283366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 55314331Speter{ 554102814Siedowse char *path; 555102814Siedowse int error; 55614331Speter 557162585Snetchild /* linux convention */ 558227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 559162585Snetchild return (EINVAL); 560162585Snetchild 561102814Siedowse LCONVPATHEXIST(td, args->path, &path); 56214331Speter 56314331Speter#ifdef DEBUG 56472543Sjlemon if (ldebug(access)) 565227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 56614331Speter#endif 567274476Skib error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 568274476Skib args->amode); 569102814Siedowse LFREEPATH(path); 570162585Snetchild 571102814Siedowse return (error); 57214331Speter} 57314331Speter 57414331Speterint 575177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args) 576177997Skib{ 577177997Skib char *path; 578283428Sdchagin int error, dfd; 579177997Skib 580177997Skib /* linux convention */ 581227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 582177997Skib return (EINVAL); 583177997Skib 584177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 585177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 586177997Skib 587177997Skib#ifdef DEBUG 588177997Skib if (ldebug(access)) 589227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 590177997Skib#endif 591177997Skib 592283428Sdchagin error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); 593177997Skib LFREEPATH(path); 594177997Skib 595177997Skib return (error); 596177997Skib} 597177997Skib 598177997Skibint 59983366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 60014331Speter{ 601102814Siedowse char *path; 602102814Siedowse int error; 603162201Snetchild struct stat st; 60414331Speter 605102814Siedowse LCONVPATHEXIST(td, args->path, &path); 60614331Speter 60714331Speter#ifdef DEBUG 60872543Sjlemon if (ldebug(unlink)) 609102814Siedowse printf(ARGS(unlink, "%s"), path); 61014331Speter#endif 61114331Speter 612274476Skib error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0); 613274476Skib if (error == EPERM) { 614162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 615274476Skib if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, 616274476Skib NULL) == 0) { 617162201Snetchild if (S_ISDIR(st.st_mode)) 618162201Snetchild error = EISDIR; 619274476Skib } 620274476Skib } 621102814Siedowse LFREEPATH(path); 622102814Siedowse return (error); 62314331Speter} 62414331Speter 62514331Speterint 626177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 627177997Skib{ 628177997Skib char *path; 629177997Skib int error, dfd; 630177997Skib struct stat st; 631177997Skib 632177997Skib if (args->flag & ~LINUX_AT_REMOVEDIR) 633177997Skib return (EINVAL); 634177997Skib 635177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 636177997Skib LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 637177997Skib 638177997Skib#ifdef DEBUG 639177997Skib if (ldebug(unlinkat)) 640177997Skib printf(ARGS(unlinkat, "%s"), path); 641177997Skib#endif 642177997Skib 643177997Skib if (args->flag & LINUX_AT_REMOVEDIR) 644177997Skib error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); 645177997Skib else 646202113Smckusick error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0); 647177997Skib if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 648177997Skib /* Introduce POSIX noncompliant behaviour of Linux */ 649177997Skib if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 650274476Skib UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) 651177997Skib error = EISDIR; 652177997Skib } 653177997Skib LFREEPATH(path); 654177997Skib return (error); 655177997Skib} 656177997Skibint 65783366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 65814331Speter{ 659102814Siedowse char *path; 660102814Siedowse int error; 66114331Speter 662102814Siedowse LCONVPATHEXIST(td, args->path, &path); 66314331Speter 66414331Speter#ifdef DEBUG 66572543Sjlemon if (ldebug(chdir)) 666102814Siedowse printf(ARGS(chdir, "%s"), path); 66714331Speter#endif 668102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 669102814Siedowse LFREEPATH(path); 670102814Siedowse return (error); 67114331Speter} 67214331Speter 67314331Speterint 67483366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 67514331Speter{ 676102814Siedowse char *path; 677102814Siedowse int error; 67814331Speter 679102814Siedowse LCONVPATHEXIST(td, args->path, &path); 68014331Speter 68114331Speter#ifdef DEBUG 68272543Sjlemon if (ldebug(chmod)) 683102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 68414331Speter#endif 685274476Skib error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, 686274476Skib args->mode, 0); 687102814Siedowse LFREEPATH(path); 688102814Siedowse return (error); 68914331Speter} 69014331Speter 69114331Speterint 692177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 693177997Skib{ 694177997Skib char *path; 695177997Skib int error, dfd; 696177997Skib 697177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 698177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 699177997Skib 700177997Skib#ifdef DEBUG 701177997Skib if (ldebug(fchmodat)) 702177997Skib printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 703177997Skib#endif 704177997Skib 705177997Skib error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 706177997Skib LFREEPATH(path); 707177997Skib return (error); 708177997Skib} 709177997Skib 710177997Skibint 71183366Sjulianlinux_mkdir(struct thread *td, struct linux_mkdir_args *args) 71214331Speter{ 713102814Siedowse char *path; 714102814Siedowse int error; 71514331Speter 716102814Siedowse LCONVPATHCREAT(td, args->path, &path); 71714331Speter 71814331Speter#ifdef DEBUG 71972543Sjlemon if (ldebug(mkdir)) 720102814Siedowse printf(ARGS(mkdir, "%s, %d"), path, args->mode); 72114331Speter#endif 722274476Skib error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); 723102814Siedowse LFREEPATH(path); 724102814Siedowse return (error); 72514331Speter} 72614331Speter 72714331Speterint 728177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 729177997Skib{ 730177997Skib char *path; 731177997Skib int error, dfd; 732177997Skib 733177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 734177997Skib LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 735177997Skib 736177997Skib#ifdef DEBUG 737177997Skib if (ldebug(mkdirat)) 738177997Skib printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 739177997Skib#endif 740177997Skib error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 741177997Skib LFREEPATH(path); 742177997Skib return (error); 743177997Skib} 744177997Skib 745177997Skibint 74683366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 74714331Speter{ 748102814Siedowse char *path; 749102814Siedowse int error; 75014331Speter 751102814Siedowse LCONVPATHEXIST(td, args->path, &path); 75214331Speter 75314331Speter#ifdef DEBUG 75472543Sjlemon if (ldebug(rmdir)) 755102814Siedowse printf(ARGS(rmdir, "%s"), path); 75614331Speter#endif 757274476Skib error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE); 758102814Siedowse LFREEPATH(path); 759102814Siedowse return (error); 76014331Speter} 76114331Speter 76214331Speterint 76383366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 76414331Speter{ 765102814Siedowse char *from, *to; 766102814Siedowse int error; 76714331Speter 768102814Siedowse LCONVPATHEXIST(td, args->from, &from); 769102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 770177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 771102814Siedowse if (to == NULL) { 772102814Siedowse LFREEPATH(from); 773102814Siedowse return (error); 774102814Siedowse } 77514331Speter 77614331Speter#ifdef DEBUG 77772543Sjlemon if (ldebug(rename)) 778102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 77914331Speter#endif 780274476Skib error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); 781102814Siedowse LFREEPATH(from); 782102814Siedowse LFREEPATH(to); 783102814Siedowse return (error); 78414331Speter} 78514331Speter 78614331Speterint 787177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args) 788177997Skib{ 789177997Skib char *from, *to; 790177997Skib int error, olddfd, newdfd; 791177997Skib 792177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 793177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 794177997Skib LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 795177997Skib /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 796177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 797177997Skib if (to == NULL) { 798177997Skib LFREEPATH(from); 799177997Skib return (error); 800177997Skib } 801177997Skib 802177997Skib#ifdef DEBUG 803177997Skib if (ldebug(renameat)) 804177997Skib printf(ARGS(renameat, "%s, %s"), from, to); 805177997Skib#endif 806177997Skib error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 807177997Skib LFREEPATH(from); 808177997Skib LFREEPATH(to); 809177997Skib return (error); 810177997Skib} 811177997Skib 812177997Skibint 81383366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 81414331Speter{ 815102814Siedowse char *path, *to; 816102814Siedowse int error; 81714331Speter 818102814Siedowse LCONVPATHEXIST(td, args->path, &path); 819102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 820177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 821102814Siedowse if (to == NULL) { 822102814Siedowse LFREEPATH(path); 823102814Siedowse return (error); 824102814Siedowse } 82514331Speter 82614331Speter#ifdef DEBUG 82772543Sjlemon if (ldebug(symlink)) 828102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 82914331Speter#endif 830274476Skib error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); 831102814Siedowse LFREEPATH(path); 832102814Siedowse LFREEPATH(to); 833102814Siedowse return (error); 83414331Speter} 83514331Speter 83614331Speterint 837177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 838177997Skib{ 839177997Skib char *path, *to; 840177997Skib int error, dfd; 841177997Skib 842177997Skib dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 843177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); 844177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 845177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 846177997Skib if (to == NULL) { 847177997Skib LFREEPATH(path); 848177997Skib return (error); 849177997Skib } 850177997Skib 851177997Skib#ifdef DEBUG 852177997Skib if (ldebug(symlinkat)) 853177997Skib printf(ARGS(symlinkat, "%s, %s"), path, to); 854177997Skib#endif 855177997Skib 856177997Skib error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 857177997Skib LFREEPATH(path); 858177997Skib LFREEPATH(to); 859177997Skib return (error); 860177997Skib} 861177997Skib 862177997Skibint 86383366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 86414331Speter{ 865102814Siedowse char *name; 866102814Siedowse int error; 86714331Speter 868102814Siedowse LCONVPATHEXIST(td, args->name, &name); 86914331Speter 87014331Speter#ifdef DEBUG 87172543Sjlemon if (ldebug(readlink)) 872102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 873102814Siedowse args->count); 87414331Speter#endif 875274476Skib error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, 876274476Skib args->buf, UIO_USERSPACE, args->count); 877102814Siedowse LFREEPATH(name); 878102814Siedowse return (error); 87914331Speter} 88014331Speter 88114331Speterint 882177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 883177997Skib{ 884177997Skib char *name; 885177997Skib int error, dfd; 886177997Skib 887177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 888177997Skib LCONVPATHEXIST_AT(td, args->path, &name, dfd); 889177997Skib 890177997Skib#ifdef DEBUG 891177997Skib if (ldebug(readlinkat)) 892177997Skib printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 893177997Skib args->bufsiz); 894177997Skib#endif 895177997Skib 896177997Skib error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 897177997Skib UIO_USERSPACE, args->bufsiz); 898177997Skib LFREEPATH(name); 899177997Skib return (error); 900177997Skib} 901178439Srdivacky 902177997Skibint 90383366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 90414331Speter{ 905102814Siedowse char *path; 906102814Siedowse int error; 90714331Speter 908102814Siedowse LCONVPATHEXIST(td, args->path, &path); 90914331Speter 91014331Speter#ifdef DEBUG 91172543Sjlemon if (ldebug(truncate)) 912102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 91314331Speter#endif 91414331Speter 915102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 916102814Siedowse LFREEPATH(path); 917102814Siedowse return (error); 91814331Speter} 91914331Speter 920283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 92149662Smarcelint 922178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args) 923178439Srdivacky{ 924178439Srdivacky char *path; 925178439Srdivacky int error; 926178439Srdivacky 927178439Srdivacky LCONVPATHEXIST(td, args->path, &path); 928178439Srdivacky 929178439Srdivacky#ifdef DEBUG 930178439Srdivacky if (ldebug(truncate64)) 931178439Srdivacky printf(ARGS(truncate64, "%s, %jd"), path, args->length); 932178439Srdivacky#endif 933178439Srdivacky 934178439Srdivacky error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 935178439Srdivacky LFREEPATH(path); 936178439Srdivacky return (error); 937178439Srdivacky} 938283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 939283415Sdchagin 940178439Srdivackyint 941156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 942156842Snetchild{ 943156842Snetchild struct ftruncate_args /* { 944156842Snetchild int fd; 945156842Snetchild int pad; 946156842Snetchild off_t length; 947156842Snetchild } */ nuap; 948300411Sdchagin 949156842Snetchild nuap.fd = args->fd; 950156842Snetchild nuap.length = args->length; 951225617Skmacy return (sys_ftruncate(td, &nuap)); 952156842Snetchild} 953156842Snetchild 954156842Snetchildint 95583366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 95649662Smarcel{ 957102814Siedowse char *path, *to; 958102814Siedowse int error; 95949662Smarcel 960102814Siedowse LCONVPATHEXIST(td, args->path, &path); 961102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 962177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 963102814Siedowse if (to == NULL) { 964102814Siedowse LFREEPATH(path); 965102814Siedowse return (error); 966102814Siedowse } 96749662Smarcel 96849662Smarcel#ifdef DEBUG 96972543Sjlemon if (ldebug(link)) 970102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 97149662Smarcel#endif 972274476Skib error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, 973274476Skib FOLLOW); 974102814Siedowse LFREEPATH(path); 975102814Siedowse LFREEPATH(to); 976102814Siedowse return (error); 97749662Smarcel} 97849788Smarcel 97953713Smarcelint 980177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args) 981177997Skib{ 982177997Skib char *path, *to; 983227693Sed int error, olddfd, newdfd, follow; 984177997Skib 985227693Sed if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) 986177997Skib return (EINVAL); 987177997Skib 988177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 989177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 990177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 991177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 992177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 993177997Skib if (to == NULL) { 994177997Skib LFREEPATH(path); 995177997Skib return (error); 996177997Skib } 997177997Skib 998177997Skib#ifdef DEBUG 999177997Skib if (ldebug(linkat)) 1000177997Skib printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 1001227693Sed args->newdfd, to, args->flag); 1002177997Skib#endif 1003177997Skib 1004227693Sed follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : 1005227693Sed FOLLOW; 1006227693Sed error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); 1007177997Skib LFREEPATH(path); 1008177997Skib LFREEPATH(to); 1009177997Skib return (error); 1010177997Skib} 1011177997Skib 1012177997Skibint 101383366Sjulianlinux_fdatasync(td, uap) 101483366Sjulian struct thread *td; 101553713Smarcel struct linux_fdatasync_args *uap; 101653713Smarcel{ 101753713Smarcel 1018304987Skib return (kern_fsync(td, uap->fd, false)); 101953713Smarcel} 102063285Smarcel 102163285Smarcelint 102283366Sjulianlinux_pread(td, uap) 102383366Sjulian struct thread *td; 102463285Smarcel struct linux_pread_args *uap; 102563285Smarcel{ 102663285Smarcel struct pread_args bsd; 1027255219Spjd cap_rights_t rights; 1028162585Snetchild struct vnode *vp; 1029162585Snetchild int error; 103063285Smarcel 103163285Smarcel bsd.fd = uap->fd; 103263285Smarcel bsd.buf = uap->buf; 103363285Smarcel bsd.nbyte = uap->nbyte; 103463285Smarcel bsd.offset = uap->offset; 1035225617Skmacy error = sys_pread(td, &bsd); 1036162585Snetchild if (error == 0) { 1037247602Spjd /* This seems to violate POSIX but linux does it */ 1038255219Spjd error = fgetvp(td, uap->fd, 1039255219Spjd cap_rights_init(&rights, CAP_PREAD), &vp); 1040255219Spjd if (error != 0) 1041247602Spjd return (error); 1042162585Snetchild if (vp->v_type == VDIR) { 1043247602Spjd vrele(vp); 1044162585Snetchild return (EISDIR); 1045162585Snetchild } 1046162585Snetchild vrele(vp); 1047162585Snetchild } 1048162585Snetchild return (error); 104963285Smarcel} 105063285Smarcel 105163285Smarcelint 105283366Sjulianlinux_pwrite(td, uap) 105383366Sjulian struct thread *td; 105463285Smarcel struct linux_pwrite_args *uap; 105563285Smarcel{ 105663285Smarcel struct pwrite_args bsd; 105763285Smarcel 105863285Smarcel bsd.fd = uap->fd; 105963285Smarcel bsd.buf = uap->buf; 106063285Smarcel bsd.nbyte = uap->nbyte; 106163285Smarcel bsd.offset = uap->offset; 1062300411Sdchagin return (sys_pwrite(td, &bsd)); 106363285Smarcel} 106472538Sjlemon 106572538Sjlemonint 1066314909Smmokhilinux_preadv(struct thread *td, struct linux_preadv_args *uap) 1067314909Smmokhi{ 1068314909Smmokhi struct uio *auio; 1069314909Smmokhi int error; 1070314909Smmokhi off_t offset; 1071314909Smmokhi 1072314909Smmokhi /* 1073314909Smmokhi * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES 1074314909Smmokhi * pos_l and pos_h, respectively, contain the 1075314909Smmokhi * low order and high order 32 bits of offset. 1076314909Smmokhi */ 1077314909Smmokhi offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1078314909Smmokhi (sizeof(offset) * 4)) | uap->pos_l; 1079314909Smmokhi if (offset < 0) 1080314909Smmokhi return (EINVAL); 1081314909Smmokhi#ifdef COMPAT_LINUX32 1082314909Smmokhi error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1083314909Smmokhi#else 1084314909Smmokhi error = copyinuio(uap->vec, uap->vlen, &auio); 1085314909Smmokhi#endif 1086314909Smmokhi if (error != 0) 1087314909Smmokhi return (error); 1088314909Smmokhi error = kern_preadv(td, uap->fd, auio, offset); 1089314909Smmokhi free(auio, M_IOV); 1090314909Smmokhi return (error); 1091314909Smmokhi} 1092314909Smmokhi 1093314909Smmokhiint 1094314909Smmokhilinux_pwritev(struct thread *td, struct linux_pwritev_args *uap) 1095314909Smmokhi{ 1096314909Smmokhi struct uio *auio; 1097314909Smmokhi int error; 1098314909Smmokhi off_t offset; 1099314909Smmokhi 1100314909Smmokhi /* 1101314909Smmokhi * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES 1102314909Smmokhi * pos_l and pos_h, respectively, contain the 1103314909Smmokhi * low order and high order 32 bits of offset. 1104314909Smmokhi */ 1105314909Smmokhi offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1106314909Smmokhi (sizeof(offset) * 4)) | uap->pos_l; 1107314909Smmokhi if (offset < 0) 1108314909Smmokhi return (EINVAL); 1109314909Smmokhi#ifdef COMPAT_LINUX32 1110314909Smmokhi error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1111314909Smmokhi#else 1112314909Smmokhi error = copyinuio(uap->vec, uap->vlen, &auio); 1113314909Smmokhi#endif 1114314909Smmokhi if (error != 0) 1115314909Smmokhi return (error); 1116314909Smmokhi error = kern_pwritev(td, uap->fd, auio, offset); 1117314909Smmokhi free(auio, M_IOV); 1118314909Smmokhi return (error); 1119314909Smmokhi} 1120314909Smmokhi 1121314909Smmokhiint 112283366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 112372538Sjlemon{ 1124111798Sdes char fstypename[MFSNAMELEN]; 1125111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 112673286Sadrian int error; 112773286Sadrian int fsflags; 112872538Sjlemon 1129111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 113073286Sadrian NULL); 113172538Sjlemon if (error) 1132111798Sdes return (error); 1133127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 113472538Sjlemon if (error) 1135111798Sdes return (error); 1136127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 113772538Sjlemon if (error) 1138111798Sdes return (error); 113972538Sjlemon 114072538Sjlemon#ifdef DEBUG 114172538Sjlemon if (ldebug(mount)) 114272538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 114372538Sjlemon fstypename, mntfromname, mntonname); 114472538Sjlemon#endif 114572538Sjlemon 114672538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 1147127059Stjr strcpy(fstypename, "ext2fs"); 114872538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 1149127059Stjr strcpy(fstypename, "linprocfs"); 1150190445Sambrisko } else if (strcmp(fstypename, "vfat") == 0) { 1151190445Sambrisko strcpy(fstypename, "msdosfs"); 115272538Sjlemon } 115372538Sjlemon 115473286Sadrian fsflags = 0; 115572538Sjlemon 115672538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 115772538Sjlemon /* 115872538Sjlemon * Linux SYNC flag is not included; the closest equivalent 115972538Sjlemon * FreeBSD has is !ASYNC, which is our default. 116072538Sjlemon */ 116172538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 1162111798Sdes fsflags |= MNT_RDONLY; 116372538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 1164111798Sdes fsflags |= MNT_NOSUID; 116572538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 1166111798Sdes fsflags |= MNT_NOEXEC; 116772538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 1168111798Sdes fsflags |= MNT_UPDATE; 116972538Sjlemon } 117072538Sjlemon 1171281689Strasz error = kernel_vmount(fsflags, 1172281689Strasz "fstype", fstypename, 1173281689Strasz "fspath", mntonname, 1174281689Strasz "from", mntfromname, 1175281689Strasz NULL); 1176127059Stjr return (error); 117772538Sjlemon} 117872538Sjlemon 1179283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 118072538Sjlemonint 118183366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 118272538Sjlemon{ 118383221Smarcel struct linux_umount_args args2; 118472538Sjlemon 118572538Sjlemon args2.path = args->path; 118672538Sjlemon args2.flags = 0; 118783366Sjulian return (linux_umount(td, &args2)); 118872538Sjlemon} 1189283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 119072538Sjlemon 119172538Sjlemonint 119283366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 119372538Sjlemon{ 119472538Sjlemon struct unmount_args bsd; 119572538Sjlemon 119672538Sjlemon bsd.path = args->path; 119772538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 1198225617Skmacy return (sys_unmount(td, &bsd)); 119972538Sjlemon} 120083221Smarcel 120183221Smarcel/* 120283221Smarcel * fcntl family of syscalls 120383221Smarcel */ 120483221Smarcel 120583221Smarcelstruct l_flock { 120683221Smarcel l_short l_type; 120783221Smarcel l_short l_whence; 120883221Smarcel l_off_t l_start; 120983221Smarcel l_off_t l_len; 121083221Smarcel l_pid_t l_pid; 1211133816Stjr} 1212140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1213133816Stjr__packed 1214133816Stjr#endif 1215133816Stjr; 121683221Smarcel 121783221Smarcelstatic void 121883221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 121983221Smarcel{ 122083221Smarcel switch (linux_flock->l_type) { 122183221Smarcel case LINUX_F_RDLCK: 122283221Smarcel bsd_flock->l_type = F_RDLCK; 122383221Smarcel break; 122483221Smarcel case LINUX_F_WRLCK: 122583221Smarcel bsd_flock->l_type = F_WRLCK; 122683221Smarcel break; 122783221Smarcel case LINUX_F_UNLCK: 122883221Smarcel bsd_flock->l_type = F_UNLCK; 122983221Smarcel break; 123083221Smarcel default: 123183221Smarcel bsd_flock->l_type = -1; 123283221Smarcel break; 123383221Smarcel } 123483221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 123583221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 123683221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 123783221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1238177633Sdfr bsd_flock->l_sysid = 0; 123983221Smarcel} 124083221Smarcel 124183221Smarcelstatic void 124283221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 124383221Smarcel{ 124483221Smarcel switch (bsd_flock->l_type) { 124583221Smarcel case F_RDLCK: 124683221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 124783221Smarcel break; 124883221Smarcel case F_WRLCK: 124983221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 125083221Smarcel break; 125183221Smarcel case F_UNLCK: 125283221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 125383221Smarcel break; 125483221Smarcel } 125583221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 125683221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 125783221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 125883221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 125983221Smarcel} 126083221Smarcel 1261140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 126283221Smarcelstruct l_flock64 { 126383221Smarcel l_short l_type; 126483221Smarcel l_short l_whence; 126583221Smarcel l_loff_t l_start; 126683221Smarcel l_loff_t l_len; 126783221Smarcel l_pid_t l_pid; 1268133816Stjr} 1269140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1270133816Stjr__packed 1271133816Stjr#endif 1272133816Stjr; 127383221Smarcel 127483221Smarcelstatic void 127583221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 127683221Smarcel{ 127783221Smarcel switch (linux_flock->l_type) { 127883221Smarcel case LINUX_F_RDLCK: 127983221Smarcel bsd_flock->l_type = F_RDLCK; 128083221Smarcel break; 128183221Smarcel case LINUX_F_WRLCK: 128283221Smarcel bsd_flock->l_type = F_WRLCK; 128383221Smarcel break; 128483221Smarcel case LINUX_F_UNLCK: 128583221Smarcel bsd_flock->l_type = F_UNLCK; 128683221Smarcel break; 128783221Smarcel default: 128883221Smarcel bsd_flock->l_type = -1; 128983221Smarcel break; 129083221Smarcel } 129183221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 129283221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 129383221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 129483221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1295177633Sdfr bsd_flock->l_sysid = 0; 129683221Smarcel} 129783221Smarcel 129883221Smarcelstatic void 129983221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 130083221Smarcel{ 130183221Smarcel switch (bsd_flock->l_type) { 130283221Smarcel case F_RDLCK: 130383221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 130483221Smarcel break; 130583221Smarcel case F_WRLCK: 130683221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 130783221Smarcel break; 130883221Smarcel case F_UNLCK: 130983221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 131083221Smarcel break; 131183221Smarcel } 131283221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 131383221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 131483221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 131583221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 131683221Smarcel} 1317133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 131883221Smarcel 131983221Smarcelstatic int 1320283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args) 132183221Smarcel{ 1322107680Siedowse struct l_flock linux_flock; 1323107680Siedowse struct flock bsd_flock; 1324255219Spjd cap_rights_t rights; 132583221Smarcel struct file *fp; 1326102872Siedowse long arg; 132783221Smarcel int error, result; 132883221Smarcel 132983221Smarcel switch (args->cmd) { 133083221Smarcel case LINUX_F_DUPFD: 1331102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 133283221Smarcel 133383221Smarcel case LINUX_F_GETFD: 1334102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 133583221Smarcel 133683221Smarcel case LINUX_F_SETFD: 1337102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 133883221Smarcel 133983221Smarcel case LINUX_F_GETFL: 1340102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 134183366Sjulian result = td->td_retval[0]; 134283366Sjulian td->td_retval[0] = 0; 134383221Smarcel if (result & O_RDONLY) 134483366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 134583221Smarcel if (result & O_WRONLY) 134683366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 134783221Smarcel if (result & O_RDWR) 134883366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 134983221Smarcel if (result & O_NDELAY) 135083366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 135183221Smarcel if (result & O_APPEND) 135283366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 135383221Smarcel if (result & O_FSYNC) 135483366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 135583221Smarcel if (result & O_ASYNC) 135683366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1357144987Smdodd#ifdef LINUX_O_NOFOLLOW 1358144987Smdodd if (result & O_NOFOLLOW) 1359144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1360144987Smdodd#endif 1361144987Smdodd#ifdef LINUX_O_DIRECT 1362144987Smdodd if (result & O_DIRECT) 1363144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1364144987Smdodd#endif 136583221Smarcel return (error); 136683221Smarcel 136783221Smarcel case LINUX_F_SETFL: 1368102872Siedowse arg = 0; 136983221Smarcel if (args->arg & LINUX_O_NDELAY) 1370102872Siedowse arg |= O_NONBLOCK; 137183221Smarcel if (args->arg & LINUX_O_APPEND) 1372102872Siedowse arg |= O_APPEND; 137383221Smarcel if (args->arg & LINUX_O_SYNC) 1374102872Siedowse arg |= O_FSYNC; 137583221Smarcel if (args->arg & LINUX_FASYNC) 1376102872Siedowse arg |= O_ASYNC; 1377144987Smdodd#ifdef LINUX_O_NOFOLLOW 1378144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1379144987Smdodd arg |= O_NOFOLLOW; 1380144987Smdodd#endif 1381144987Smdodd#ifdef LINUX_O_DIRECT 1382144987Smdodd if (args->arg & LINUX_O_DIRECT) 1383144987Smdodd arg |= O_DIRECT; 1384144987Smdodd#endif 1385102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 138683221Smarcel 1387107680Siedowse case LINUX_F_GETLK: 1388111797Sdes error = copyin((void *)args->arg, &linux_flock, 1389107680Siedowse sizeof(linux_flock)); 1390107680Siedowse if (error) 1391107680Siedowse return (error); 1392107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1393107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1394107680Siedowse if (error) 1395107680Siedowse return (error); 1396107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1397111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1398107680Siedowse sizeof(linux_flock))); 1399107680Siedowse 1400107680Siedowse case LINUX_F_SETLK: 1401111797Sdes error = copyin((void *)args->arg, &linux_flock, 1402107680Siedowse sizeof(linux_flock)); 1403107680Siedowse if (error) 1404107680Siedowse return (error); 1405107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1406107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1407107680Siedowse (intptr_t)&bsd_flock)); 1408107680Siedowse 1409107680Siedowse case LINUX_F_SETLKW: 1410111797Sdes error = copyin((void *)args->arg, &linux_flock, 1411107680Siedowse sizeof(linux_flock)); 1412107680Siedowse if (error) 1413107680Siedowse return (error); 1414107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1415107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1416107680Siedowse (intptr_t)&bsd_flock)); 1417107680Siedowse 141883221Smarcel case LINUX_F_GETOWN: 1419102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 142083221Smarcel 142183221Smarcel case LINUX_F_SETOWN: 142283221Smarcel /* 142383221Smarcel * XXX some Linux applications depend on F_SETOWN having no 142483221Smarcel * significant effect for pipes (SIGIO is not delivered for 142583221Smarcel * pipes under Linux-2.2.35 at least). 142683221Smarcel */ 1427255219Spjd error = fget(td, args->fd, 1428255219Spjd cap_rights_init(&rights, CAP_FCNTL), &fp); 142989319Salfred if (error) 143089319Salfred return (error); 143189306Salfred if (fp->f_type == DTYPE_PIPE) { 143289306Salfred fdrop(fp, td); 143383221Smarcel return (EINVAL); 143489306Salfred } 143589306Salfred fdrop(fp, td); 143683221Smarcel 1437102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1438283439Sdchagin 1439283439Sdchagin case LINUX_F_DUPFD_CLOEXEC: 1440283439Sdchagin return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); 144183221Smarcel } 144283221Smarcel 144383221Smarcel return (EINVAL); 144483221Smarcel} 144583221Smarcel 144683221Smarcelint 144783366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 144883221Smarcel{ 144983221Smarcel 145083221Smarcel#ifdef DEBUG 145183221Smarcel if (ldebug(fcntl)) 145283221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 145383221Smarcel#endif 145483221Smarcel 1455283415Sdchagin return (fcntl_common(td, args)); 145683221Smarcel} 145783221Smarcel 1458140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 145983221Smarcelint 146083366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 146183221Smarcel{ 146283221Smarcel struct l_flock64 linux_flock; 1463102872Siedowse struct flock bsd_flock; 1464283415Sdchagin struct linux_fcntl_args fcntl_args; 146583221Smarcel int error; 146683221Smarcel 146783221Smarcel#ifdef DEBUG 146883221Smarcel if (ldebug(fcntl64)) 146983221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 147083221Smarcel#endif 147183221Smarcel 147283221Smarcel switch (args->cmd) { 147399687Srobert case LINUX_F_GETLK64: 1474111797Sdes error = copyin((void *)args->arg, &linux_flock, 147583221Smarcel sizeof(linux_flock)); 147683221Smarcel if (error) 147783221Smarcel return (error); 1478102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1479102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 148083221Smarcel if (error) 148183221Smarcel return (error); 1482102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1483111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1484111797Sdes sizeof(linux_flock))); 148583221Smarcel 148699687Srobert case LINUX_F_SETLK64: 1487111797Sdes error = copyin((void *)args->arg, &linux_flock, 148883221Smarcel sizeof(linux_flock)); 148983221Smarcel if (error) 149083221Smarcel return (error); 1491102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1492102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1493102872Siedowse (intptr_t)&bsd_flock)); 149483221Smarcel 149599687Srobert case LINUX_F_SETLKW64: 1496111797Sdes error = copyin((void *)args->arg, &linux_flock, 149783221Smarcel sizeof(linux_flock)); 149883221Smarcel if (error) 149983221Smarcel return (error); 1500102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1501102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1502102872Siedowse (intptr_t)&bsd_flock)); 150383221Smarcel } 150483221Smarcel 1505283415Sdchagin fcntl_args.fd = args->fd; 1506283415Sdchagin fcntl_args.cmd = args->cmd; 1507283415Sdchagin fcntl_args.arg = args->arg; 1508283415Sdchagin return (fcntl_common(td, &fcntl_args)); 150983221Smarcel} 1510133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 151185022Smarcel 151285022Smarcelint 151385022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 151485022Smarcel{ 1515102814Siedowse char *path; 1516102814Siedowse int error; 151785022Smarcel 1518102814Siedowse LCONVPATHEXIST(td, args->path, &path); 151985022Smarcel 152085022Smarcel#ifdef DEBUG 152185022Smarcel if (ldebug(chown)) 1522102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 152385022Smarcel#endif 1524274476Skib error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1525274476Skib args->gid, 0); 1526102814Siedowse LFREEPATH(path); 1527102814Siedowse return (error); 152885022Smarcel} 152985022Smarcel 153085022Smarcelint 1531177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1532177997Skib{ 1533177997Skib char *path; 1534227693Sed int error, dfd, flag; 1535177997Skib 1536177997Skib if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1537177997Skib return (EINVAL); 1538177997Skib 1539177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1540177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1541177997Skib 1542177997Skib#ifdef DEBUG 1543177997Skib if (ldebug(fchownat)) 1544177997Skib printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1545177997Skib#endif 1546177997Skib 1547227693Sed flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1548177997Skib AT_SYMLINK_NOFOLLOW; 1549177997Skib error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1550227693Sed flag); 1551177997Skib LFREEPATH(path); 1552177997Skib return (error); 1553177997Skib} 1554177997Skib 1555177997Skibint 155685022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 155785022Smarcel{ 1558102814Siedowse char *path; 1559102814Siedowse int error; 156085022Smarcel 1561102814Siedowse LCONVPATHEXIST(td, args->path, &path); 156285022Smarcel 156385022Smarcel#ifdef DEBUG 156485022Smarcel if (ldebug(lchown)) 1565102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 156685022Smarcel#endif 1567274476Skib error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1568274476Skib args->gid, AT_SYMLINK_NOFOLLOW); 1569102814Siedowse LFREEPATH(path); 1570102814Siedowse return (error); 157185022Smarcel} 1572228957Sjhb 1573228957Sjhbstatic int 1574228957Sjhbconvert_fadvice(int advice) 1575228957Sjhb{ 1576228957Sjhb switch (advice) { 1577228957Sjhb case LINUX_POSIX_FADV_NORMAL: 1578228957Sjhb return (POSIX_FADV_NORMAL); 1579228957Sjhb case LINUX_POSIX_FADV_RANDOM: 1580228957Sjhb return (POSIX_FADV_RANDOM); 1581228957Sjhb case LINUX_POSIX_FADV_SEQUENTIAL: 1582228957Sjhb return (POSIX_FADV_SEQUENTIAL); 1583228957Sjhb case LINUX_POSIX_FADV_WILLNEED: 1584228957Sjhb return (POSIX_FADV_WILLNEED); 1585228957Sjhb case LINUX_POSIX_FADV_DONTNEED: 1586228957Sjhb return (POSIX_FADV_DONTNEED); 1587228957Sjhb case LINUX_POSIX_FADV_NOREUSE: 1588228957Sjhb return (POSIX_FADV_NOREUSE); 1589228957Sjhb default: 1590228957Sjhb return (-1); 1591228957Sjhb } 1592228957Sjhb} 1593228957Sjhb 1594228957Sjhbint 1595228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) 1596228957Sjhb{ 1597228957Sjhb int advice; 1598228957Sjhb 1599228957Sjhb advice = convert_fadvice(args->advice); 1600228957Sjhb if (advice == -1) 1601228957Sjhb return (EINVAL); 1602228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1603228957Sjhb advice)); 1604228957Sjhb} 1605228957Sjhb 1606283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1607228957Sjhbint 1608228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) 1609228957Sjhb{ 1610228957Sjhb int advice; 1611228957Sjhb 1612228957Sjhb advice = convert_fadvice(args->advice); 1613228957Sjhb if (advice == -1) 1614228957Sjhb return (EINVAL); 1615228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1616228957Sjhb advice)); 1617228957Sjhb} 1618283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1619234352Sjkim 1620234352Sjkimint 1621234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args) 1622234352Sjkim{ 1623234352Sjkim int fildes[2]; 1624234352Sjkim int error; 1625234352Sjkim 1626234352Sjkim#ifdef DEBUG 1627234352Sjkim if (ldebug(pipe)) 1628234352Sjkim printf(ARGS(pipe, "*")); 1629234352Sjkim#endif 1630234352Sjkim 1631286021Sed error = kern_pipe(td, fildes, 0, NULL, NULL); 1632315538Strasz if (error != 0) 1633234352Sjkim return (error); 1634234352Sjkim 1635315538Strasz error = copyout(fildes, args->pipefds, sizeof(fildes)); 1636315538Strasz if (error != 0) { 1637315538Strasz (void)kern_close(td, fildes[0]); 1638315538Strasz (void)kern_close(td, fildes[1]); 1639315538Strasz } 1640315538Strasz 1641315538Strasz return (error); 1642234352Sjkim} 1643234352Sjkim 1644234352Sjkimint 1645234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args) 1646234352Sjkim{ 1647234352Sjkim int fildes[2]; 1648234352Sjkim int error, flags; 1649234352Sjkim 1650234352Sjkim#ifdef DEBUG 1651234352Sjkim if (ldebug(pipe2)) 1652234352Sjkim printf(ARGS(pipe2, "*, %d"), args->flags); 1653234352Sjkim#endif 1654234352Sjkim 1655234352Sjkim if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) 1656234352Sjkim return (EINVAL); 1657234352Sjkim 1658234352Sjkim flags = 0; 1659234352Sjkim if ((args->flags & LINUX_O_NONBLOCK) != 0) 1660234352Sjkim flags |= O_NONBLOCK; 1661234352Sjkim if ((args->flags & LINUX_O_CLOEXEC) != 0) 1662234352Sjkim flags |= O_CLOEXEC; 1663286021Sed error = kern_pipe(td, fildes, flags, NULL, NULL); 1664315538Strasz if (error != 0) 1665234352Sjkim return (error); 1666234352Sjkim 1667315538Strasz error = copyout(fildes, args->pipefds, sizeof(fildes)); 1668315538Strasz if (error != 0) { 1669315538Strasz (void)kern_close(td, fildes[0]); 1670315538Strasz (void)kern_close(td, fildes[1]); 1671315538Strasz } 1672315538Strasz 1673315538Strasz return (error); 1674234352Sjkim} 1675283399Sdchagin 1676283399Sdchaginint 1677283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args) 1678283399Sdchagin{ 1679283399Sdchagin int cmd; 1680283399Sdchagin intptr_t newfd; 1681283399Sdchagin 1682283399Sdchagin if (args->oldfd == args->newfd) 1683283399Sdchagin return (EINVAL); 1684283399Sdchagin if ((args->flags & ~LINUX_O_CLOEXEC) != 0) 1685283399Sdchagin return (EINVAL); 1686283399Sdchagin if (args->flags & LINUX_O_CLOEXEC) 1687283399Sdchagin cmd = F_DUP2FD_CLOEXEC; 1688283399Sdchagin else 1689283399Sdchagin cmd = F_DUP2FD; 1690283399Sdchagin 1691283399Sdchagin newfd = args->newfd; 1692283399Sdchagin return (kern_fcntl(td, args->oldfd, cmd, newfd)); 1693283399Sdchagin} 1694283465Sdchagin 1695283465Sdchaginint 1696283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args) 1697283465Sdchagin{ 1698283465Sdchagin 1699283465Sdchagin /* 1700283465Sdchagin * We emulate only posix_fallocate system call for which 1701283465Sdchagin * mode should be 0. 1702283465Sdchagin */ 1703283465Sdchagin if (args->mode != 0) 1704283465Sdchagin return (ENOSYS); 1705283465Sdchagin 1706283465Sdchagin return (kern_posix_fallocate(td, args->fd, args->offset, 1707283465Sdchagin args->len)); 1708283465Sdchagin} 1709