19313Ssos/*- 2330997Semaste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330997Semaste * 4230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt 59313Ssos * All rights reserved. 69313Ssos * 79313Ssos * Redistribution and use in source and binary forms, with or without 89313Ssos * modification, are permitted provided that the following conditions 99313Ssos * are met: 109313Ssos * 1. Redistributions of source code must retain the above copyright 11330997Semaste * notice, this list of conditions and the following disclaimer. 129313Ssos * 2. Redistributions in binary form must reproduce the above copyright 139313Ssos * notice, this list of conditions and the following disclaimer in the 149313Ssos * documentation and/or other materials provided with the distribution. 159313Ssos * 16330997Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17330997Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18330997Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19330997Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20330997Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21330997Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22330997Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23330997Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24330997Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25330997Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26330997Semaste * SUCH DAMAGE. 279313Ssos */ 289313Ssos 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_file.c 346832 2019-04-28 14:03:32Z dchagin $"); 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 71346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 729313Ssosint 7383366Sjulianlinux_creat(struct thread *td, struct linux_creat_args *args) 749313Ssos{ 75300411Sdchagin char *path; 76300411Sdchagin int error; 779313Ssos 78300411Sdchagin LCONVPATHEXIST(td, args->path, &path); 799313Ssos#ifdef DEBUG 8072543Sjlemon if (ldebug(creat)) 81102814Siedowse printf(ARGS(creat, "%s, %d"), path, args->mode); 829313Ssos#endif 83300411Sdchagin error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, 84300411Sdchagin O_WRONLY | O_CREAT | O_TRUNC, args->mode); 85300411Sdchagin LFREEPATH(path); 86300411Sdchagin return (error); 879313Ssos} 88346832Sdchagin#endif 899313Ssos 90168014Sjulianstatic int 91177997Skiblinux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 929313Ssos{ 93300411Sdchagin cap_rights_t rights; 94300411Sdchagin struct proc *p = td->td_proc; 95300411Sdchagin struct file *fp; 96300411Sdchagin int fd; 97300411Sdchagin int bsd_flags, error; 9814331Speter 99300411Sdchagin bsd_flags = 0; 100300411Sdchagin switch (l_flags & LINUX_O_ACCMODE) { 101300411Sdchagin case LINUX_O_WRONLY: 102300411Sdchagin bsd_flags |= O_WRONLY; 103300411Sdchagin break; 104300411Sdchagin case LINUX_O_RDWR: 105300411Sdchagin bsd_flags |= O_RDWR; 106300411Sdchagin break; 107300411Sdchagin default: 108300411Sdchagin bsd_flags |= O_RDONLY; 109300411Sdchagin } 110300411Sdchagin if (l_flags & LINUX_O_NDELAY) 111300411Sdchagin bsd_flags |= O_NONBLOCK; 112300411Sdchagin if (l_flags & LINUX_O_APPEND) 113300411Sdchagin bsd_flags |= O_APPEND; 114300411Sdchagin if (l_flags & LINUX_O_SYNC) 115300411Sdchagin bsd_flags |= O_FSYNC; 116300411Sdchagin if (l_flags & LINUX_O_NONBLOCK) 117300411Sdchagin bsd_flags |= O_NONBLOCK; 118300411Sdchagin if (l_flags & LINUX_FASYNC) 119300411Sdchagin bsd_flags |= O_ASYNC; 120300411Sdchagin if (l_flags & LINUX_O_CREAT) 121300411Sdchagin bsd_flags |= O_CREAT; 122300411Sdchagin if (l_flags & LINUX_O_TRUNC) 123300411Sdchagin bsd_flags |= O_TRUNC; 124300411Sdchagin if (l_flags & LINUX_O_EXCL) 125300411Sdchagin bsd_flags |= O_EXCL; 126300411Sdchagin if (l_flags & LINUX_O_NOCTTY) 127300411Sdchagin bsd_flags |= O_NOCTTY; 128300411Sdchagin if (l_flags & LINUX_O_DIRECT) 129300411Sdchagin bsd_flags |= O_DIRECT; 130300411Sdchagin if (l_flags & LINUX_O_NOFOLLOW) 131300411Sdchagin bsd_flags |= O_NOFOLLOW; 132300411Sdchagin if (l_flags & LINUX_O_DIRECTORY) 133300411Sdchagin bsd_flags |= O_DIRECTORY; 134300411Sdchagin /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 1359313Ssos 136300411Sdchagin error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 137300411Sdchagin if (error != 0) 138300411Sdchagin goto done; 139300411Sdchagin if (bsd_flags & O_NOCTTY) 140300411Sdchagin goto done; 141178036Srdivacky 142300411Sdchagin /* 143300411Sdchagin * XXX In between kern_open() and fget(), another process 144300411Sdchagin * having the same filedesc could use that fd without 145300411Sdchagin * checking below. 146300411Sdchagin */ 147300411Sdchagin fd = td->td_retval[0]; 148300411Sdchagin if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) { 149300411Sdchagin if (fp->f_type != DTYPE_VNODE) { 150300411Sdchagin fdrop(fp, td); 151300411Sdchagin goto done; 152300411Sdchagin } 153300411Sdchagin sx_slock(&proctree_lock); 154300411Sdchagin PROC_LOCK(p); 155300411Sdchagin if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 156300411Sdchagin PROC_UNLOCK(p); 157300411Sdchagin sx_sunlock(&proctree_lock); 158300411Sdchagin /* XXXPJD: Verify if TIOCSCTTY is allowed. */ 159300411Sdchagin (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 160300411Sdchagin td->td_ucred, td); 161300411Sdchagin } else { 162300411Sdchagin PROC_UNLOCK(p); 163300411Sdchagin sx_sunlock(&proctree_lock); 164300411Sdchagin } 165300411Sdchagin fdrop(fp, td); 166300411Sdchagin } 167281726Strasz 168281726Straszdone: 16914331Speter#ifdef DEBUG 170346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 171300411Sdchagin if (ldebug(open)) 172346832Sdchagin#else 173346832Sdchagin if (ldebug(openat)) 174346832Sdchagin#endif 175300411Sdchagin printf(LMSG("open returns error %d"), error); 17614331Speter#endif 177300411Sdchagin LFREEPATH(path); 178300411Sdchagin return (error); 1799313Ssos} 1809313Ssos 1819313Ssosint 182168014Sjulianlinux_openat(struct thread *td, struct linux_openat_args *args) 183168014Sjulian{ 184177997Skib char *path; 185177997Skib int dfd; 186168014Sjulian 187177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 188177997Skib if (args->flags & LINUX_O_CREAT) 189177997Skib LCONVPATH_AT(td, args->filename, &path, 1, dfd); 190177997Skib else 191177997Skib LCONVPATH_AT(td, args->filename, &path, 0, dfd); 192168014Sjulian#ifdef DEBUG 193168014Sjulian if (ldebug(openat)) 194168014Sjulian printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 195177997Skib path, args->flags, args->mode); 196168014Sjulian#endif 197177997Skib return (linux_common_open(td, dfd, path, args->flags, args->mode)); 198168014Sjulian} 199168014Sjulian 200346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 201168014Sjulianint 202168014Sjulianlinux_open(struct thread *td, struct linux_open_args *args) 203168014Sjulian{ 204300411Sdchagin char *path; 205168014Sjulian 206300411Sdchagin if (args->flags & LINUX_O_CREAT) 207300411Sdchagin LCONVPATHCREAT(td, args->path, &path); 208300411Sdchagin else 209300411Sdchagin LCONVPATHEXIST(td, args->path, &path); 210168014Sjulian#ifdef DEBUG 211168014Sjulian if (ldebug(open)) 212168014Sjulian printf(ARGS(open, "%s, 0x%x, 0x%x"), 213168014Sjulian path, args->flags, args->mode); 214168014Sjulian#endif 215178036Srdivacky return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 216168014Sjulian} 217346832Sdchagin#endif 218168014Sjulian 219168014Sjulianint 22083366Sjulianlinux_lseek(struct thread *td, struct linux_lseek_args *args) 2219313Ssos{ 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 228315550Strasz return (kern_lseek(td, args->fdes, args->off, args->whence)); 2299313Ssos} 2309313Ssos 231283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 23214331Speterint 23383366Sjulianlinux_llseek(struct thread *td, struct linux_llseek_args *args) 23414331Speter{ 23514331Speter int error; 23614331Speter off_t off; 23714331Speter 23814331Speter#ifdef DEBUG 23972543Sjlemon if (ldebug(llseek)) 24072543Sjlemon printf(ARGS(llseek, "%d, %d:%d, %d"), 24172543Sjlemon args->fd, args->ohigh, args->olow, args->whence); 24214331Speter#endif 24314331Speter off = (args->olow) | (((off_t) args->ohigh) << 32); 24414331Speter 245315550Strasz error = kern_lseek(td, args->fd, off, args->whence); 246315550Strasz if (error != 0) 247300411Sdchagin return (error); 24814331Speter 249315550Strasz error = copyout(td->td_retval, args->res, sizeof(off_t)); 250315550Strasz if (error != 0) 251300411Sdchagin return (error); 25214331Speter 25383366Sjulian td->td_retval[0] = 0; 254300411Sdchagin return (0); 25514331Speter} 256283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 25714331Speter 25883221Smarcel/* 25983221Smarcel * Note that linux_getdents(2) and linux_getdents64(2) have the same 26083221Smarcel * arguments. They only differ in the definition of struct dirent they 261315376Sdchagin * operate on. 262315376Sdchagin * Note that linux_readdir(2) is a special case of linux_getdents(2) 263315376Sdchagin * where count is always equals 1, meaning that the buffer is one 264315376Sdchagin * dirent-structure in size and that the code can't handle more anyway. 265315376Sdchagin * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2) 266315376Sdchagin * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will 267315376Sdchagin * trash user stack. 26883221Smarcel */ 26983221Smarcel 270315376Sdchaginstatic int 271315376Sdchaginlinux_getdents_error(struct thread *td, int fd, int err) 272315376Sdchagin{ 273315376Sdchagin cap_rights_t rights; 274315376Sdchagin struct vnode *vp; 275315376Sdchagin struct file *fp; 276315376Sdchagin int error; 277315376Sdchagin 278315376Sdchagin /* Linux return ENOTDIR in case when fd is not a directory. */ 279315376Sdchagin error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp); 280315376Sdchagin if (error != 0) 281315376Sdchagin return (error); 282315376Sdchagin vp = fp->f_vnode; 283315376Sdchagin if (vp->v_type != VDIR) { 284315376Sdchagin fdrop(fp, td); 285315376Sdchagin return (ENOTDIR); 286315376Sdchagin } 287315376Sdchagin fdrop(fp, td); 288315376Sdchagin return (err); 289315376Sdchagin} 290315376Sdchagin 29183221Smarcelstruct l_dirent { 292179651Srdivacky l_ulong d_ino; 29383221Smarcel l_off_t d_off; 29483221Smarcel l_ushort d_reclen; 29583221Smarcel char d_name[LINUX_NAME_MAX + 1]; 29683221Smarcel}; 29783221Smarcel 29883221Smarcelstruct l_dirent64 { 29983221Smarcel uint64_t d_ino; 30083221Smarcel int64_t d_off; 30183221Smarcel l_ushort d_reclen; 30283221Smarcel u_char d_type; 30383221Smarcel char d_name[LINUX_NAME_MAX + 1]; 30483221Smarcel}; 30583221Smarcel 306182892Srdivacky/* 307182892Srdivacky * Linux uses the last byte in the dirent buffer to store d_type, 308182892Srdivacky * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. 309182892Srdivacky */ 310182892Srdivacky#define LINUX_RECLEN(namlen) \ 311298482Spfg roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) 31283221Smarcel 313182892Srdivacky#define LINUX_RECLEN64(namlen) \ 314298482Spfg roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ 315182892Srdivacky sizeof(uint64_t)) 316182892Srdivacky 317315376Sdchagin/* 318315376Sdchagin * Linux l_dirent is bigger than FreeBSD dirent, thus the buffer size 319315376Sdchagin * passed to kern_getdirentries() must be smaller than the one passed 320315376Sdchagin * to linux_getdents() by certain factor. 321315376Sdchagin */ 322315376Sdchagin#define LINUX_RECLEN_RATIO(X) X * offsetof(struct dirent, d_name) / \ 323315376Sdchagin offsetof(struct l_dirent, d_name); 324315376Sdchagin#define LINUX_RECLEN64_RATIO(X) X * offsetof(struct dirent, d_name) / \ 325315376Sdchagin offsetof(struct l_dirent64, d_name); 326315376Sdchagin 327346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 328315376Sdchaginint 329315376Sdchaginlinux_getdents(struct thread *td, struct linux_getdents_args *args) 33014331Speter{ 331111798Sdes struct dirent *bdp; 33283221Smarcel caddr_t inp, buf; /* BSD-format */ 33383221Smarcel int len, reclen; /* BSD-format */ 33483221Smarcel caddr_t outp; /* Linux-format */ 335315376Sdchagin int resid, linuxreclen; /* Linux-format */ 336182892Srdivacky caddr_t lbuf; /* Linux-format */ 337315376Sdchagin long base; 338182892Srdivacky struct l_dirent *linux_dirent; 339315376Sdchagin int buflen, error; 340315376Sdchagin size_t retval; 3419313Ssos 342315376Sdchagin#ifdef DEBUG 343315376Sdchagin if (ldebug(getdents)) 344315376Sdchagin printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 345315376Sdchagin#endif 346315376Sdchagin buflen = LINUX_RECLEN_RATIO(args->count); 347315376Sdchagin buflen = min(buflen, MAXBSIZE); 348315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 349160276Sjhb 350315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 351315376Sdchagin &base, NULL, UIO_SYSSPACE); 352315376Sdchagin if (error != 0) { 353315376Sdchagin error = linux_getdents_error(td, args->fd, error); 354315376Sdchagin goto out1; 35589306Salfred } 3569313Ssos 357315376Sdchagin lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 358315376Sdchagin 359315376Sdchagin len = td->td_retval[0]; 360315376Sdchagin inp = buf; 361315376Sdchagin outp = (caddr_t)args->dent; 362315376Sdchagin resid = args->count; 363315376Sdchagin retval = 0; 364315376Sdchagin 365315376Sdchagin while (len > 0) { 366315376Sdchagin bdp = (struct dirent *) inp; 367315376Sdchagin reclen = bdp->d_reclen; 368315376Sdchagin linuxreclen = LINUX_RECLEN(bdp->d_namlen); 369315376Sdchagin /* 370315376Sdchagin * No more space in the user supplied dirent buffer. 371315376Sdchagin * Return EINVAL. 372315376Sdchagin */ 373315376Sdchagin if (resid < linuxreclen) { 374315376Sdchagin error = EINVAL; 375315376Sdchagin goto out; 376315376Sdchagin } 377315376Sdchagin 378315376Sdchagin linux_dirent = (struct l_dirent*)lbuf; 379315376Sdchagin linux_dirent->d_ino = bdp->d_fileno; 380315376Sdchagin linux_dirent->d_off = base + reclen; 381315376Sdchagin linux_dirent->d_reclen = linuxreclen; 382315376Sdchagin /* 383315376Sdchagin * Copy d_type to last byte of l_dirent buffer 384315376Sdchagin */ 385315376Sdchagin lbuf[linuxreclen - 1] = bdp->d_type; 386315376Sdchagin strlcpy(linux_dirent->d_name, bdp->d_name, 387315376Sdchagin linuxreclen - offsetof(struct l_dirent, d_name)-1); 388315376Sdchagin error = copyout(linux_dirent, outp, linuxreclen); 389315376Sdchagin if (error != 0) 390315376Sdchagin goto out; 391315376Sdchagin 392315376Sdchagin inp += reclen; 393315376Sdchagin base += reclen; 394315376Sdchagin len -= reclen; 395315376Sdchagin 396315376Sdchagin retval += linuxreclen; 397315376Sdchagin outp += linuxreclen; 398315376Sdchagin resid -= linuxreclen; 39989306Salfred } 400315376Sdchagin td->td_retval[0] = retval; 4019313Ssos 402315376Sdchaginout: 403320469Savg free(lbuf, M_TEMP); 404315376Sdchaginout1: 405320469Savg free(buf, M_TEMP); 406315376Sdchagin return (error); 407315376Sdchagin} 408346832Sdchagin#endif 4099313Ssos 410315376Sdchaginint 411315376Sdchaginlinux_getdents64(struct thread *td, struct linux_getdents64_args *args) 412315376Sdchagin{ 413315376Sdchagin struct dirent *bdp; 414315376Sdchagin caddr_t inp, buf; /* BSD-format */ 415315376Sdchagin int len, reclen; /* BSD-format */ 416315376Sdchagin caddr_t outp; /* Linux-format */ 417315376Sdchagin int resid, linuxreclen; /* Linux-format */ 418315376Sdchagin caddr_t lbuf; /* Linux-format */ 419315376Sdchagin long base; 420315376Sdchagin struct l_dirent64 *linux_dirent64; 421315376Sdchagin int buflen, error; 422315376Sdchagin size_t retval; 423315376Sdchagin 424315376Sdchagin#ifdef DEBUG 425315376Sdchagin if (ldebug(getdents64)) 426315376Sdchagin uprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 427315376Sdchagin#endif 428315376Sdchagin buflen = LINUX_RECLEN64_RATIO(args->count); 42983221Smarcel buflen = min(buflen, MAXBSIZE); 430315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 43183221Smarcel 432315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 433315376Sdchagin &base, NULL, UIO_SYSSPACE); 434315376Sdchagin if (error != 0) { 435315376Sdchagin error = linux_getdents_error(td, args->fd, error); 436315376Sdchagin goto out1; 437315376Sdchagin } 4389313Ssos 439315376Sdchagin lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 4409313Ssos 441315376Sdchagin len = td->td_retval[0]; 44283221Smarcel inp = buf; 44383221Smarcel outp = (caddr_t)args->dirent; 444315376Sdchagin resid = args->count; 445315376Sdchagin retval = 0; 4469313Ssos 44783221Smarcel while (len > 0) { 44883221Smarcel bdp = (struct dirent *) inp; 44983221Smarcel reclen = bdp->d_reclen; 450315376Sdchagin linuxreclen = LINUX_RECLEN64(bdp->d_namlen); 451315376Sdchagin /* 452315376Sdchagin * No more space in the user supplied dirent buffer. 453315376Sdchagin * Return EINVAL. 454315376Sdchagin */ 455315376Sdchagin if (resid < linuxreclen) { 456315376Sdchagin error = EINVAL; 45783221Smarcel goto out; 45883221Smarcel } 45983221Smarcel 460315376Sdchagin linux_dirent64 = (struct l_dirent64*)lbuf; 461315376Sdchagin linux_dirent64->d_ino = bdp->d_fileno; 462315376Sdchagin linux_dirent64->d_off = base + reclen; 463315376Sdchagin linux_dirent64->d_reclen = linuxreclen; 464315376Sdchagin linux_dirent64->d_type = bdp->d_type; 465315376Sdchagin strlcpy(linux_dirent64->d_name, bdp->d_name, 466315376Sdchagin linuxreclen - offsetof(struct l_dirent64, d_name)); 467315376Sdchagin error = copyout(linux_dirent64, outp, linuxreclen); 468315376Sdchagin if (error != 0) 46983221Smarcel goto out; 47083221Smarcel 47183221Smarcel inp += reclen; 472315376Sdchagin base += reclen; 473315376Sdchagin len -= reclen; 47483221Smarcel 475315376Sdchagin retval += linuxreclen; 47683221Smarcel outp += linuxreclen; 47783221Smarcel resid -= linuxreclen; 47810355Sswallace } 479315376Sdchagin td->td_retval[0] = retval; 4809313Ssos 4819313Ssosout: 482315376Sdchagin free(lbuf, M_TEMP); 483315376Sdchaginout1: 484315376Sdchagin free(buf, M_TEMP); 48583221Smarcel return (error); 4869313Ssos} 48714331Speter 488315376Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 48983221Smarcelint 490315376Sdchaginlinux_readdir(struct thread *td, struct linux_readdir_args *args) 49183221Smarcel{ 492315376Sdchagin struct dirent *bdp; 493315376Sdchagin caddr_t buf; /* BSD-format */ 494315376Sdchagin int linuxreclen; /* Linux-format */ 495315376Sdchagin caddr_t lbuf; /* Linux-format */ 496315376Sdchagin long base; 497315376Sdchagin struct l_dirent *linux_dirent; 498315376Sdchagin int buflen, error; 49983221Smarcel 50083221Smarcel#ifdef DEBUG 501315376Sdchagin if (ldebug(readdir)) 502315376Sdchagin printf(ARGS(readdir, "%d, *"), args->fd); 50383221Smarcel#endif 504315376Sdchagin buflen = LINUX_RECLEN(LINUX_NAME_MAX); 505315376Sdchagin buflen = LINUX_RECLEN_RATIO(buflen); 506315376Sdchagin buf = malloc(buflen, M_TEMP, M_WAITOK); 50783221Smarcel 508315376Sdchagin error = kern_getdirentries(td, args->fd, buf, buflen, 509315376Sdchagin &base, NULL, UIO_SYSSPACE); 510315376Sdchagin if (error != 0) { 511315376Sdchagin error = linux_getdents_error(td, args->fd, error); 512315376Sdchagin goto out; 513315376Sdchagin } 514315376Sdchagin if (td->td_retval[0] == 0) 515315376Sdchagin goto out; 51683221Smarcel 517315376Sdchagin lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 51883221Smarcel 519315376Sdchagin bdp = (struct dirent *) buf; 520315376Sdchagin linuxreclen = LINUX_RECLEN(bdp->d_namlen); 52183221Smarcel 522315376Sdchagin linux_dirent = (struct l_dirent*)lbuf; 523315376Sdchagin linux_dirent->d_ino = bdp->d_fileno; 524315376Sdchagin linux_dirent->d_off = linuxreclen; 525315376Sdchagin linux_dirent->d_reclen = bdp->d_namlen; 526315376Sdchagin strlcpy(linux_dirent->d_name, bdp->d_name, 527315376Sdchagin linuxreclen - offsetof(struct l_dirent, d_name)); 528315376Sdchagin error = copyout(linux_dirent, args->dent, linuxreclen); 529315376Sdchagin if (error == 0) 530315376Sdchagin td->td_retval[0] = linuxreclen; 531315376Sdchagin 532320469Savg free(lbuf, M_TEMP); 533315376Sdchaginout: 534320469Savg free(buf, M_TEMP); 535315376Sdchagin return (error); 53683221Smarcel} 537315376Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 53883221Smarcel 539315376Sdchagin 54014331Speter/* 54114331Speter * These exist mainly for hooks for doing /compat/linux translation. 54214331Speter */ 54314331Speter 544346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 54514331Speterint 54683366Sjulianlinux_access(struct thread *td, struct linux_access_args *args) 54714331Speter{ 548102814Siedowse char *path; 549102814Siedowse int error; 55014331Speter 551346816Sdchagin /* Linux convention. */ 552227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 553162585Snetchild return (EINVAL); 554162585Snetchild 555102814Siedowse LCONVPATHEXIST(td, args->path, &path); 55614331Speter 55714331Speter#ifdef DEBUG 55872543Sjlemon if (ldebug(access)) 559227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 56014331Speter#endif 561274476Skib error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 562274476Skib args->amode); 563102814Siedowse LFREEPATH(path); 564162585Snetchild 565102814Siedowse return (error); 56614331Speter} 567346832Sdchagin#endif 56814331Speter 56914331Speterint 570177997Skiblinux_faccessat(struct thread *td, struct linux_faccessat_args *args) 571177997Skib{ 572177997Skib char *path; 573283428Sdchagin int error, dfd; 574177997Skib 575346816Sdchagin /* Linux convention. */ 576227691Sed if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 577177997Skib return (EINVAL); 578177997Skib 579177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 580177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 581177997Skib 582177997Skib#ifdef DEBUG 583346831Sdchagin if (ldebug(faccessat)) 584227691Sed printf(ARGS(access, "%s, %d"), path, args->amode); 585177997Skib#endif 586177997Skib 587283428Sdchagin error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); 588177997Skib LFREEPATH(path); 589177997Skib 590177997Skib return (error); 591177997Skib} 592177997Skib 593346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 594177997Skibint 59583366Sjulianlinux_unlink(struct thread *td, struct linux_unlink_args *args) 59614331Speter{ 597102814Siedowse char *path; 598102814Siedowse int error; 599162201Snetchild struct stat st; 60014331Speter 601102814Siedowse LCONVPATHEXIST(td, args->path, &path); 60214331Speter 60314331Speter#ifdef DEBUG 60472543Sjlemon if (ldebug(unlink)) 605102814Siedowse printf(ARGS(unlink, "%s"), path); 60614331Speter#endif 60714331Speter 608274476Skib error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0); 609274476Skib if (error == EPERM) { 610162201Snetchild /* Introduce POSIX noncompliant behaviour of Linux */ 611274476Skib if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, 612274476Skib NULL) == 0) { 613162201Snetchild if (S_ISDIR(st.st_mode)) 614162201Snetchild error = EISDIR; 615274476Skib } 616274476Skib } 617102814Siedowse LFREEPATH(path); 618102814Siedowse return (error); 61914331Speter} 620346832Sdchagin#endif 62114331Speter 62214331Speterint 623177997Skiblinux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 624177997Skib{ 625177997Skib char *path; 626177997Skib int error, dfd; 627177997Skib struct stat st; 628177997Skib 629177997Skib if (args->flag & ~LINUX_AT_REMOVEDIR) 630177997Skib return (EINVAL); 631177997Skib 632177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 633177997Skib LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 634177997Skib 635177997Skib#ifdef DEBUG 636177997Skib if (ldebug(unlinkat)) 637177997Skib printf(ARGS(unlinkat, "%s"), path); 638177997Skib#endif 639177997Skib 640177997Skib if (args->flag & LINUX_AT_REMOVEDIR) 641177997Skib error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); 642177997Skib else 643202113Smckusick error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0); 644177997Skib if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 645177997Skib /* Introduce POSIX noncompliant behaviour of Linux */ 646177997Skib if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 647274476Skib UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) 648177997Skib error = EISDIR; 649177997Skib } 650177997Skib LFREEPATH(path); 651177997Skib return (error); 652177997Skib} 653177997Skibint 65483366Sjulianlinux_chdir(struct thread *td, struct linux_chdir_args *args) 65514331Speter{ 656102814Siedowse char *path; 657102814Siedowse int error; 65814331Speter 659102814Siedowse LCONVPATHEXIST(td, args->path, &path); 66014331Speter 66114331Speter#ifdef DEBUG 66272543Sjlemon if (ldebug(chdir)) 663102814Siedowse printf(ARGS(chdir, "%s"), path); 66414331Speter#endif 665102814Siedowse error = kern_chdir(td, path, UIO_SYSSPACE); 666102814Siedowse LFREEPATH(path); 667102814Siedowse return (error); 66814331Speter} 66914331Speter 670346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 67114331Speterint 67283366Sjulianlinux_chmod(struct thread *td, struct linux_chmod_args *args) 67314331Speter{ 674102814Siedowse char *path; 675102814Siedowse int error; 67614331Speter 677102814Siedowse LCONVPATHEXIST(td, args->path, &path); 67814331Speter 67914331Speter#ifdef DEBUG 68072543Sjlemon if (ldebug(chmod)) 681102814Siedowse printf(ARGS(chmod, "%s, %d"), path, args->mode); 68214331Speter#endif 683274476Skib error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, 684274476Skib args->mode, 0); 685102814Siedowse LFREEPATH(path); 686102814Siedowse return (error); 68714331Speter} 688346832Sdchagin#endif 68914331Speter 69014331Speterint 691177997Skiblinux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 692177997Skib{ 693177997Skib char *path; 694177997Skib int error, dfd; 695177997Skib 696177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 697177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 698177997Skib 699177997Skib#ifdef DEBUG 700177997Skib if (ldebug(fchmodat)) 701177997Skib printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 702177997Skib#endif 703177997Skib 704177997Skib error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 705177997Skib LFREEPATH(path); 706177997Skib return (error); 707177997Skib} 708177997Skib 709346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 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} 726346832Sdchagin#endif 72714331Speter 72814331Speterint 729177997Skiblinux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 730177997Skib{ 731177997Skib char *path; 732177997Skib int error, dfd; 733177997Skib 734177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 735177997Skib LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 736177997Skib 737177997Skib#ifdef DEBUG 738177997Skib if (ldebug(mkdirat)) 739177997Skib printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 740177997Skib#endif 741177997Skib error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 742177997Skib LFREEPATH(path); 743177997Skib return (error); 744177997Skib} 745177997Skib 746346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 747177997Skibint 74883366Sjulianlinux_rmdir(struct thread *td, struct linux_rmdir_args *args) 74914331Speter{ 750102814Siedowse char *path; 751102814Siedowse int error; 75214331Speter 753102814Siedowse LCONVPATHEXIST(td, args->path, &path); 75414331Speter 75514331Speter#ifdef DEBUG 75672543Sjlemon if (ldebug(rmdir)) 757102814Siedowse printf(ARGS(rmdir, "%s"), path); 75814331Speter#endif 759274476Skib error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE); 760102814Siedowse LFREEPATH(path); 761102814Siedowse return (error); 76214331Speter} 76314331Speter 76414331Speterint 76583366Sjulianlinux_rename(struct thread *td, struct linux_rename_args *args) 76614331Speter{ 767102814Siedowse char *from, *to; 768102814Siedowse int error; 76914331Speter 770102814Siedowse LCONVPATHEXIST(td, args->from, &from); 771102814Siedowse /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 772177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 773102814Siedowse if (to == NULL) { 774102814Siedowse LFREEPATH(from); 775102814Siedowse return (error); 776102814Siedowse } 77714331Speter 77814331Speter#ifdef DEBUG 77972543Sjlemon if (ldebug(rename)) 780102814Siedowse printf(ARGS(rename, "%s, %s"), from, to); 78114331Speter#endif 782274476Skib error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); 783102814Siedowse LFREEPATH(from); 784102814Siedowse LFREEPATH(to); 785102814Siedowse return (error); 78614331Speter} 787346832Sdchagin#endif 78814331Speter 78914331Speterint 790177997Skiblinux_renameat(struct thread *td, struct linux_renameat_args *args) 791177997Skib{ 792177997Skib char *from, *to; 793177997Skib int error, olddfd, newdfd; 794177997Skib 795177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 796177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 797177997Skib LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 798177997Skib /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 799177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 800177997Skib if (to == NULL) { 801177997Skib LFREEPATH(from); 802177997Skib return (error); 803177997Skib } 804177997Skib 805177997Skib#ifdef DEBUG 806177997Skib if (ldebug(renameat)) 807177997Skib printf(ARGS(renameat, "%s, %s"), from, to); 808177997Skib#endif 809177997Skib error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 810177997Skib LFREEPATH(from); 811177997Skib LFREEPATH(to); 812177997Skib return (error); 813177997Skib} 814177997Skib 815346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 816177997Skibint 81783366Sjulianlinux_symlink(struct thread *td, struct linux_symlink_args *args) 81814331Speter{ 819102814Siedowse char *path, *to; 820102814Siedowse int error; 82114331Speter 822102814Siedowse LCONVPATHEXIST(td, args->path, &path); 823102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 824177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 825102814Siedowse if (to == NULL) { 826102814Siedowse LFREEPATH(path); 827102814Siedowse return (error); 828102814Siedowse } 82914331Speter 83014331Speter#ifdef DEBUG 83172543Sjlemon if (ldebug(symlink)) 832102814Siedowse printf(ARGS(symlink, "%s, %s"), path, to); 83314331Speter#endif 834274476Skib error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); 835102814Siedowse LFREEPATH(path); 836102814Siedowse LFREEPATH(to); 837102814Siedowse return (error); 83814331Speter} 839346832Sdchagin#endif 84014331Speter 84114331Speterint 842177997Skiblinux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 843177997Skib{ 844177997Skib char *path, *to; 845177997Skib int error, dfd; 846177997Skib 847177997Skib dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 848319573Sdchagin LCONVPATHEXIST(td, args->oldname, &path); 849177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 850177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 851177997Skib if (to == NULL) { 852177997Skib LFREEPATH(path); 853177997Skib return (error); 854177997Skib } 855177997Skib 856177997Skib#ifdef DEBUG 857177997Skib if (ldebug(symlinkat)) 858177997Skib printf(ARGS(symlinkat, "%s, %s"), path, to); 859177997Skib#endif 860177997Skib 861177997Skib error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 862177997Skib LFREEPATH(path); 863177997Skib LFREEPATH(to); 864177997Skib return (error); 865177997Skib} 866177997Skib 867346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 868177997Skibint 86983366Sjulianlinux_readlink(struct thread *td, struct linux_readlink_args *args) 87014331Speter{ 871102814Siedowse char *name; 872102814Siedowse int error; 87314331Speter 874102814Siedowse LCONVPATHEXIST(td, args->name, &name); 87514331Speter 87614331Speter#ifdef DEBUG 87772543Sjlemon if (ldebug(readlink)) 878102814Siedowse printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 879102814Siedowse args->count); 88014331Speter#endif 881274476Skib error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, 882274476Skib args->buf, UIO_USERSPACE, args->count); 883102814Siedowse LFREEPATH(name); 884102814Siedowse return (error); 88514331Speter} 886346832Sdchagin#endif 88714331Speter 88814331Speterint 889177997Skiblinux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 890177997Skib{ 891177997Skib char *name; 892177997Skib int error, dfd; 893177997Skib 894177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 895177997Skib LCONVPATHEXIST_AT(td, args->path, &name, dfd); 896177997Skib 897177997Skib#ifdef DEBUG 898177997Skib if (ldebug(readlinkat)) 899177997Skib printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 900177997Skib args->bufsiz); 901177997Skib#endif 902177997Skib 903177997Skib error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 904177997Skib UIO_USERSPACE, args->bufsiz); 905177997Skib LFREEPATH(name); 906177997Skib return (error); 907177997Skib} 908178439Srdivacky 909177997Skibint 91083366Sjulianlinux_truncate(struct thread *td, struct linux_truncate_args *args) 91114331Speter{ 912102814Siedowse char *path; 913102814Siedowse int error; 91414331Speter 915102814Siedowse LCONVPATHEXIST(td, args->path, &path); 91614331Speter 91714331Speter#ifdef DEBUG 91872543Sjlemon if (ldebug(truncate)) 919102814Siedowse printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 92014331Speter#endif 92114331Speter 922102814Siedowse error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 923102814Siedowse LFREEPATH(path); 924102814Siedowse return (error); 92514331Speter} 92614331Speter 927283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 92849662Smarcelint 929178439Srdivackylinux_truncate64(struct thread *td, struct linux_truncate64_args *args) 930178439Srdivacky{ 931178439Srdivacky char *path; 932178439Srdivacky int error; 933178439Srdivacky 934178439Srdivacky LCONVPATHEXIST(td, args->path, &path); 935178439Srdivacky 936178439Srdivacky#ifdef DEBUG 937178439Srdivacky if (ldebug(truncate64)) 938178439Srdivacky printf(ARGS(truncate64, "%s, %jd"), path, args->length); 939178439Srdivacky#endif 940178439Srdivacky 941178439Srdivacky error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 942178439Srdivacky LFREEPATH(path); 943178439Srdivacky return (error); 944178439Srdivacky} 945283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 946283415Sdchagin 947178439Srdivackyint 948156842Snetchildlinux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 949156842Snetchild{ 950300411Sdchagin 951315548Strasz return (kern_ftruncate(td, args->fd, args->length)); 952156842Snetchild} 953156842Snetchild 954346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 955156842Snetchildint 95683366Sjulianlinux_link(struct thread *td, struct linux_link_args *args) 95749662Smarcel{ 958102814Siedowse char *path, *to; 959102814Siedowse int error; 96049662Smarcel 961102814Siedowse LCONVPATHEXIST(td, args->path, &path); 962102814Siedowse /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 963177997Skib error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 964102814Siedowse if (to == NULL) { 965102814Siedowse LFREEPATH(path); 966102814Siedowse return (error); 967102814Siedowse } 96849662Smarcel 96949662Smarcel#ifdef DEBUG 97072543Sjlemon if (ldebug(link)) 971102814Siedowse printf(ARGS(link, "%s, %s"), path, to); 97249662Smarcel#endif 973274476Skib error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, 974274476Skib FOLLOW); 975102814Siedowse LFREEPATH(path); 976102814Siedowse LFREEPATH(to); 977102814Siedowse return (error); 97849662Smarcel} 979346832Sdchagin#endif 98049788Smarcel 98153713Smarcelint 982177997Skiblinux_linkat(struct thread *td, struct linux_linkat_args *args) 983177997Skib{ 984177997Skib char *path, *to; 985227693Sed int error, olddfd, newdfd, follow; 986177997Skib 987227693Sed if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) 988177997Skib return (EINVAL); 989177997Skib 990177997Skib olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 991177997Skib newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 992177997Skib LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 993177997Skib /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 994177997Skib error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 995177997Skib if (to == NULL) { 996177997Skib LFREEPATH(path); 997177997Skib return (error); 998177997Skib } 999177997Skib 1000177997Skib#ifdef DEBUG 1001177997Skib if (ldebug(linkat)) 1002177997Skib printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 1003227693Sed args->newdfd, to, args->flag); 1004177997Skib#endif 1005177997Skib 1006227693Sed follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : 1007227693Sed FOLLOW; 1008227693Sed error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); 1009177997Skib LFREEPATH(path); 1010177997Skib LFREEPATH(to); 1011177997Skib return (error); 1012177997Skib} 1013177997Skib 1014177997Skibint 101583366Sjulianlinux_fdatasync(td, uap) 101683366Sjulian struct thread *td; 101753713Smarcel struct linux_fdatasync_args *uap; 101853713Smarcel{ 101953713Smarcel 1020304987Skib return (kern_fsync(td, uap->fd, false)); 102153713Smarcel} 102263285Smarcel 102363285Smarcelint 1024315553Straszlinux_pread(struct thread *td, struct linux_pread_args *uap) 102563285Smarcel{ 1026255219Spjd cap_rights_t rights; 1027162585Snetchild struct vnode *vp; 1028162585Snetchild int error; 102963285Smarcel 1030315553Strasz error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset); 1031162585Snetchild if (error == 0) { 1032346816Sdchagin /* This seems to violate POSIX but Linux does it. */ 1033255219Spjd error = fgetvp(td, uap->fd, 1034255219Spjd cap_rights_init(&rights, CAP_PREAD), &vp); 1035255219Spjd if (error != 0) 1036247602Spjd return (error); 1037162585Snetchild if (vp->v_type == VDIR) { 1038247602Spjd vrele(vp); 1039162585Snetchild return (EISDIR); 1040162585Snetchild } 1041162585Snetchild vrele(vp); 1042162585Snetchild } 1043162585Snetchild return (error); 104463285Smarcel} 104563285Smarcel 104663285Smarcelint 1047315553Straszlinux_pwrite(struct thread *td, struct linux_pwrite_args *uap) 104863285Smarcel{ 104963285Smarcel 1050315553Strasz return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset)); 105163285Smarcel} 105272538Sjlemon 105372538Sjlemonint 1054314909Smmokhilinux_preadv(struct thread *td, struct linux_preadv_args *uap) 1055314909Smmokhi{ 1056314909Smmokhi struct uio *auio; 1057314909Smmokhi int error; 1058314909Smmokhi off_t offset; 1059314909Smmokhi 1060314909Smmokhi /* 1061314909Smmokhi * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES 1062314909Smmokhi * pos_l and pos_h, respectively, contain the 1063314909Smmokhi * low order and high order 32 bits of offset. 1064314909Smmokhi */ 1065314909Smmokhi offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1066314909Smmokhi (sizeof(offset) * 4)) | uap->pos_l; 1067314909Smmokhi if (offset < 0) 1068314909Smmokhi return (EINVAL); 1069314909Smmokhi#ifdef COMPAT_LINUX32 1070314909Smmokhi error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1071314909Smmokhi#else 1072314909Smmokhi error = copyinuio(uap->vec, uap->vlen, &auio); 1073314909Smmokhi#endif 1074314909Smmokhi if (error != 0) 1075314909Smmokhi return (error); 1076314909Smmokhi error = kern_preadv(td, uap->fd, auio, offset); 1077314909Smmokhi free(auio, M_IOV); 1078314909Smmokhi return (error); 1079314909Smmokhi} 1080314909Smmokhi 1081314909Smmokhiint 1082314909Smmokhilinux_pwritev(struct thread *td, struct linux_pwritev_args *uap) 1083314909Smmokhi{ 1084314909Smmokhi struct uio *auio; 1085314909Smmokhi int error; 1086314909Smmokhi off_t offset; 1087314909Smmokhi 1088314909Smmokhi /* 1089314909Smmokhi * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES 1090314909Smmokhi * pos_l and pos_h, respectively, contain the 1091314909Smmokhi * low order and high order 32 bits of offset. 1092314909Smmokhi */ 1093314909Smmokhi offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1094314909Smmokhi (sizeof(offset) * 4)) | uap->pos_l; 1095314909Smmokhi if (offset < 0) 1096314909Smmokhi return (EINVAL); 1097314909Smmokhi#ifdef COMPAT_LINUX32 1098314909Smmokhi error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1099314909Smmokhi#else 1100314909Smmokhi error = copyinuio(uap->vec, uap->vlen, &auio); 1101314909Smmokhi#endif 1102314909Smmokhi if (error != 0) 1103314909Smmokhi return (error); 1104314909Smmokhi error = kern_pwritev(td, uap->fd, auio, offset); 1105314909Smmokhi free(auio, M_IOV); 1106314909Smmokhi return (error); 1107314909Smmokhi} 1108314909Smmokhi 1109314909Smmokhiint 111083366Sjulianlinux_mount(struct thread *td, struct linux_mount_args *args) 111172538Sjlemon{ 1112111798Sdes char fstypename[MFSNAMELEN]; 1113111798Sdes char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 111473286Sadrian int error; 111573286Sadrian int fsflags; 111672538Sjlemon 1117111798Sdes error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 111873286Sadrian NULL); 111972538Sjlemon if (error) 1120111798Sdes return (error); 1121127057Stjr error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 112272538Sjlemon if (error) 1123111798Sdes return (error); 1124127057Stjr error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 112572538Sjlemon if (error) 1126111798Sdes return (error); 112772538Sjlemon 112872538Sjlemon#ifdef DEBUG 112972538Sjlemon if (ldebug(mount)) 113072538Sjlemon printf(ARGS(mount, "%s, %s, %s"), 113172538Sjlemon fstypename, mntfromname, mntonname); 113272538Sjlemon#endif 113372538Sjlemon 113472538Sjlemon if (strcmp(fstypename, "ext2") == 0) { 1135127059Stjr strcpy(fstypename, "ext2fs"); 113672538Sjlemon } else if (strcmp(fstypename, "proc") == 0) { 1137127059Stjr strcpy(fstypename, "linprocfs"); 1138190445Sambrisko } else if (strcmp(fstypename, "vfat") == 0) { 1139190445Sambrisko strcpy(fstypename, "msdosfs"); 114072538Sjlemon } 114172538Sjlemon 114273286Sadrian fsflags = 0; 114372538Sjlemon 114472538Sjlemon if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 114572538Sjlemon /* 114672538Sjlemon * Linux SYNC flag is not included; the closest equivalent 114772538Sjlemon * FreeBSD has is !ASYNC, which is our default. 114872538Sjlemon */ 114972538Sjlemon if (args->rwflag & LINUX_MS_RDONLY) 1150111798Sdes fsflags |= MNT_RDONLY; 115172538Sjlemon if (args->rwflag & LINUX_MS_NOSUID) 1152111798Sdes fsflags |= MNT_NOSUID; 115372538Sjlemon if (args->rwflag & LINUX_MS_NOEXEC) 1154111798Sdes fsflags |= MNT_NOEXEC; 115572538Sjlemon if (args->rwflag & LINUX_MS_REMOUNT) 1156111798Sdes fsflags |= MNT_UPDATE; 115772538Sjlemon } 115872538Sjlemon 1159281689Strasz error = kernel_vmount(fsflags, 1160281689Strasz "fstype", fstypename, 1161281689Strasz "fspath", mntonname, 1162281689Strasz "from", mntfromname, 1163281689Strasz NULL); 1164127059Stjr return (error); 116572538Sjlemon} 116672538Sjlemon 1167283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 116872538Sjlemonint 116983366Sjulianlinux_oldumount(struct thread *td, struct linux_oldumount_args *args) 117072538Sjlemon{ 117183221Smarcel struct linux_umount_args args2; 117272538Sjlemon 117372538Sjlemon args2.path = args->path; 117472538Sjlemon args2.flags = 0; 117583366Sjulian return (linux_umount(td, &args2)); 117672538Sjlemon} 1177283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 117872538Sjlemon 1179346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 118072538Sjlemonint 118183366Sjulianlinux_umount(struct thread *td, struct linux_umount_args *args) 118272538Sjlemon{ 118372538Sjlemon struct unmount_args bsd; 118472538Sjlemon 118572538Sjlemon bsd.path = args->path; 118672538Sjlemon bsd.flags = args->flags; /* XXX correct? */ 1187225617Skmacy return (sys_unmount(td, &bsd)); 118872538Sjlemon} 1189346832Sdchagin#endif 119083221Smarcel 119183221Smarcel/* 119283221Smarcel * fcntl family of syscalls 119383221Smarcel */ 119483221Smarcel 119583221Smarcelstruct l_flock { 119683221Smarcel l_short l_type; 119783221Smarcel l_short l_whence; 119883221Smarcel l_off_t l_start; 119983221Smarcel l_off_t l_len; 120083221Smarcel l_pid_t l_pid; 1201133816Stjr} 1202140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1203133816Stjr__packed 1204133816Stjr#endif 1205133816Stjr; 120683221Smarcel 120783221Smarcelstatic void 120883221Smarcellinux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 120983221Smarcel{ 121083221Smarcel switch (linux_flock->l_type) { 121183221Smarcel case LINUX_F_RDLCK: 121283221Smarcel bsd_flock->l_type = F_RDLCK; 121383221Smarcel break; 121483221Smarcel case LINUX_F_WRLCK: 121583221Smarcel bsd_flock->l_type = F_WRLCK; 121683221Smarcel break; 121783221Smarcel case LINUX_F_UNLCK: 121883221Smarcel bsd_flock->l_type = F_UNLCK; 121983221Smarcel break; 122083221Smarcel default: 122183221Smarcel bsd_flock->l_type = -1; 122283221Smarcel break; 122383221Smarcel } 122483221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 122583221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 122683221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 122783221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1228177633Sdfr bsd_flock->l_sysid = 0; 122983221Smarcel} 123083221Smarcel 123183221Smarcelstatic void 123283221Smarcelbsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 123383221Smarcel{ 123483221Smarcel switch (bsd_flock->l_type) { 123583221Smarcel case F_RDLCK: 123683221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 123783221Smarcel break; 123883221Smarcel case F_WRLCK: 123983221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 124083221Smarcel break; 124183221Smarcel case F_UNLCK: 124283221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 124383221Smarcel break; 124483221Smarcel } 124583221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 124683221Smarcel linux_flock->l_start = (l_off_t)bsd_flock->l_start; 124783221Smarcel linux_flock->l_len = (l_off_t)bsd_flock->l_len; 124883221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 124983221Smarcel} 125083221Smarcel 1251140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 125283221Smarcelstruct l_flock64 { 125383221Smarcel l_short l_type; 125483221Smarcel l_short l_whence; 125583221Smarcel l_loff_t l_start; 125683221Smarcel l_loff_t l_len; 125783221Smarcel l_pid_t l_pid; 1258133816Stjr} 1259140214Sobrien#if defined(__amd64__) && defined(COMPAT_LINUX32) 1260133816Stjr__packed 1261133816Stjr#endif 1262133816Stjr; 126383221Smarcel 126483221Smarcelstatic void 126583221Smarcellinux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 126683221Smarcel{ 126783221Smarcel switch (linux_flock->l_type) { 126883221Smarcel case LINUX_F_RDLCK: 126983221Smarcel bsd_flock->l_type = F_RDLCK; 127083221Smarcel break; 127183221Smarcel case LINUX_F_WRLCK: 127283221Smarcel bsd_flock->l_type = F_WRLCK; 127383221Smarcel break; 127483221Smarcel case LINUX_F_UNLCK: 127583221Smarcel bsd_flock->l_type = F_UNLCK; 127683221Smarcel break; 127783221Smarcel default: 127883221Smarcel bsd_flock->l_type = -1; 127983221Smarcel break; 128083221Smarcel } 128183221Smarcel bsd_flock->l_whence = linux_flock->l_whence; 128283221Smarcel bsd_flock->l_start = (off_t)linux_flock->l_start; 128383221Smarcel bsd_flock->l_len = (off_t)linux_flock->l_len; 128483221Smarcel bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1285177633Sdfr bsd_flock->l_sysid = 0; 128683221Smarcel} 128783221Smarcel 128883221Smarcelstatic void 128983221Smarcelbsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 129083221Smarcel{ 129183221Smarcel switch (bsd_flock->l_type) { 129283221Smarcel case F_RDLCK: 129383221Smarcel linux_flock->l_type = LINUX_F_RDLCK; 129483221Smarcel break; 129583221Smarcel case F_WRLCK: 129683221Smarcel linux_flock->l_type = LINUX_F_WRLCK; 129783221Smarcel break; 129883221Smarcel case F_UNLCK: 129983221Smarcel linux_flock->l_type = LINUX_F_UNLCK; 130083221Smarcel break; 130183221Smarcel } 130283221Smarcel linux_flock->l_whence = bsd_flock->l_whence; 130383221Smarcel linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 130483221Smarcel linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 130583221Smarcel linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 130683221Smarcel} 1307133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 130883221Smarcel 130983221Smarcelstatic int 1310283415Sdchaginfcntl_common(struct thread *td, struct linux_fcntl_args *args) 131183221Smarcel{ 1312107680Siedowse struct l_flock linux_flock; 1313107680Siedowse struct flock bsd_flock; 1314255219Spjd cap_rights_t rights; 131583221Smarcel struct file *fp; 1316102872Siedowse long arg; 131783221Smarcel int error, result; 131883221Smarcel 131983221Smarcel switch (args->cmd) { 132083221Smarcel case LINUX_F_DUPFD: 1321102872Siedowse return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 132283221Smarcel 132383221Smarcel case LINUX_F_GETFD: 1324102872Siedowse return (kern_fcntl(td, args->fd, F_GETFD, 0)); 132583221Smarcel 132683221Smarcel case LINUX_F_SETFD: 1327102872Siedowse return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 132883221Smarcel 132983221Smarcel case LINUX_F_GETFL: 1330102872Siedowse error = kern_fcntl(td, args->fd, F_GETFL, 0); 133183366Sjulian result = td->td_retval[0]; 133283366Sjulian td->td_retval[0] = 0; 133383221Smarcel if (result & O_RDONLY) 133483366Sjulian td->td_retval[0] |= LINUX_O_RDONLY; 133583221Smarcel if (result & O_WRONLY) 133683366Sjulian td->td_retval[0] |= LINUX_O_WRONLY; 133783221Smarcel if (result & O_RDWR) 133883366Sjulian td->td_retval[0] |= LINUX_O_RDWR; 133983221Smarcel if (result & O_NDELAY) 134083366Sjulian td->td_retval[0] |= LINUX_O_NONBLOCK; 134183221Smarcel if (result & O_APPEND) 134283366Sjulian td->td_retval[0] |= LINUX_O_APPEND; 134383221Smarcel if (result & O_FSYNC) 134483366Sjulian td->td_retval[0] |= LINUX_O_SYNC; 134583221Smarcel if (result & O_ASYNC) 134683366Sjulian td->td_retval[0] |= LINUX_FASYNC; 1347144987Smdodd#ifdef LINUX_O_NOFOLLOW 1348144987Smdodd if (result & O_NOFOLLOW) 1349144987Smdodd td->td_retval[0] |= LINUX_O_NOFOLLOW; 1350144987Smdodd#endif 1351144987Smdodd#ifdef LINUX_O_DIRECT 1352144987Smdodd if (result & O_DIRECT) 1353144987Smdodd td->td_retval[0] |= LINUX_O_DIRECT; 1354144987Smdodd#endif 135583221Smarcel return (error); 135683221Smarcel 135783221Smarcel case LINUX_F_SETFL: 1358102872Siedowse arg = 0; 135983221Smarcel if (args->arg & LINUX_O_NDELAY) 1360102872Siedowse arg |= O_NONBLOCK; 136183221Smarcel if (args->arg & LINUX_O_APPEND) 1362102872Siedowse arg |= O_APPEND; 136383221Smarcel if (args->arg & LINUX_O_SYNC) 1364102872Siedowse arg |= O_FSYNC; 136583221Smarcel if (args->arg & LINUX_FASYNC) 1366102872Siedowse arg |= O_ASYNC; 1367144987Smdodd#ifdef LINUX_O_NOFOLLOW 1368144987Smdodd if (args->arg & LINUX_O_NOFOLLOW) 1369144987Smdodd arg |= O_NOFOLLOW; 1370144987Smdodd#endif 1371144987Smdodd#ifdef LINUX_O_DIRECT 1372144987Smdodd if (args->arg & LINUX_O_DIRECT) 1373144987Smdodd arg |= O_DIRECT; 1374144987Smdodd#endif 1375102872Siedowse return (kern_fcntl(td, args->fd, F_SETFL, arg)); 137683221Smarcel 1377107680Siedowse case LINUX_F_GETLK: 1378111797Sdes error = copyin((void *)args->arg, &linux_flock, 1379107680Siedowse sizeof(linux_flock)); 1380107680Siedowse if (error) 1381107680Siedowse return (error); 1382107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1383107680Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1384107680Siedowse if (error) 1385107680Siedowse return (error); 1386107680Siedowse bsd_to_linux_flock(&bsd_flock, &linux_flock); 1387111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1388107680Siedowse sizeof(linux_flock))); 1389107680Siedowse 1390107680Siedowse case LINUX_F_SETLK: 1391111797Sdes error = copyin((void *)args->arg, &linux_flock, 1392107680Siedowse sizeof(linux_flock)); 1393107680Siedowse if (error) 1394107680Siedowse return (error); 1395107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1396107680Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1397107680Siedowse (intptr_t)&bsd_flock)); 1398107680Siedowse 1399107680Siedowse case LINUX_F_SETLKW: 1400111797Sdes error = copyin((void *)args->arg, &linux_flock, 1401107680Siedowse sizeof(linux_flock)); 1402107680Siedowse if (error) 1403107680Siedowse return (error); 1404107680Siedowse linux_to_bsd_flock(&linux_flock, &bsd_flock); 1405107680Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1406107680Siedowse (intptr_t)&bsd_flock)); 1407107680Siedowse 140883221Smarcel case LINUX_F_GETOWN: 1409102872Siedowse return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 141083221Smarcel 141183221Smarcel case LINUX_F_SETOWN: 141283221Smarcel /* 141383221Smarcel * XXX some Linux applications depend on F_SETOWN having no 141483221Smarcel * significant effect for pipes (SIGIO is not delivered for 141583221Smarcel * pipes under Linux-2.2.35 at least). 141683221Smarcel */ 1417255219Spjd error = fget(td, args->fd, 1418255219Spjd cap_rights_init(&rights, CAP_FCNTL), &fp); 141989319Salfred if (error) 142089319Salfred return (error); 142189306Salfred if (fp->f_type == DTYPE_PIPE) { 142289306Salfred fdrop(fp, td); 142383221Smarcel return (EINVAL); 142489306Salfred } 142589306Salfred fdrop(fp, td); 142683221Smarcel 1427102872Siedowse return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1428283439Sdchagin 1429283439Sdchagin case LINUX_F_DUPFD_CLOEXEC: 1430283439Sdchagin return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); 143183221Smarcel } 143283221Smarcel 143383221Smarcel return (EINVAL); 143483221Smarcel} 143583221Smarcel 143683221Smarcelint 143783366Sjulianlinux_fcntl(struct thread *td, struct linux_fcntl_args *args) 143883221Smarcel{ 143983221Smarcel 144083221Smarcel#ifdef DEBUG 144183221Smarcel if (ldebug(fcntl)) 144283221Smarcel printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 144383221Smarcel#endif 144483221Smarcel 1445283415Sdchagin return (fcntl_common(td, args)); 144683221Smarcel} 144783221Smarcel 1448140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 144983221Smarcelint 145083366Sjulianlinux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 145183221Smarcel{ 145283221Smarcel struct l_flock64 linux_flock; 1453102872Siedowse struct flock bsd_flock; 1454283415Sdchagin struct linux_fcntl_args fcntl_args; 145583221Smarcel int error; 145683221Smarcel 145783221Smarcel#ifdef DEBUG 145883221Smarcel if (ldebug(fcntl64)) 145983221Smarcel printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 146083221Smarcel#endif 146183221Smarcel 146283221Smarcel switch (args->cmd) { 146399687Srobert case LINUX_F_GETLK64: 1464111797Sdes error = copyin((void *)args->arg, &linux_flock, 146583221Smarcel sizeof(linux_flock)); 146683221Smarcel if (error) 146783221Smarcel return (error); 1468102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1469102872Siedowse error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 147083221Smarcel if (error) 147183221Smarcel return (error); 1472102872Siedowse bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1473111797Sdes return (copyout(&linux_flock, (void *)args->arg, 1474111797Sdes sizeof(linux_flock))); 147583221Smarcel 147699687Srobert case LINUX_F_SETLK64: 1477111797Sdes error = copyin((void *)args->arg, &linux_flock, 147883221Smarcel sizeof(linux_flock)); 147983221Smarcel if (error) 148083221Smarcel return (error); 1481102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1482102872Siedowse return (kern_fcntl(td, args->fd, F_SETLK, 1483102872Siedowse (intptr_t)&bsd_flock)); 148483221Smarcel 148599687Srobert case LINUX_F_SETLKW64: 1486111797Sdes error = copyin((void *)args->arg, &linux_flock, 148783221Smarcel sizeof(linux_flock)); 148883221Smarcel if (error) 148983221Smarcel return (error); 1490102872Siedowse linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1491102872Siedowse return (kern_fcntl(td, args->fd, F_SETLKW, 1492102872Siedowse (intptr_t)&bsd_flock)); 149383221Smarcel } 149483221Smarcel 1495283415Sdchagin fcntl_args.fd = args->fd; 1496283415Sdchagin fcntl_args.cmd = args->cmd; 1497283415Sdchagin fcntl_args.arg = args->arg; 1498283415Sdchagin return (fcntl_common(td, &fcntl_args)); 149983221Smarcel} 1500133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 150185022Smarcel 1502346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 150385022Smarcelint 150485022Smarcellinux_chown(struct thread *td, struct linux_chown_args *args) 150585022Smarcel{ 1506102814Siedowse char *path; 1507102814Siedowse int error; 150885022Smarcel 1509102814Siedowse LCONVPATHEXIST(td, args->path, &path); 151085022Smarcel 151185022Smarcel#ifdef DEBUG 151285022Smarcel if (ldebug(chown)) 1513102814Siedowse printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 151485022Smarcel#endif 1515274476Skib error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1516274476Skib args->gid, 0); 1517102814Siedowse LFREEPATH(path); 1518102814Siedowse return (error); 151985022Smarcel} 1520346832Sdchagin#endif 152185022Smarcel 152285022Smarcelint 1523177997Skiblinux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1524177997Skib{ 1525177997Skib char *path; 1526227693Sed int error, dfd, flag; 1527177997Skib 1528177997Skib if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1529177997Skib return (EINVAL); 1530177997Skib 1531177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1532177997Skib LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1533177997Skib 1534177997Skib#ifdef DEBUG 1535177997Skib if (ldebug(fchownat)) 1536177997Skib printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1537177997Skib#endif 1538177997Skib 1539227693Sed flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1540177997Skib AT_SYMLINK_NOFOLLOW; 1541177997Skib error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1542227693Sed flag); 1543177997Skib LFREEPATH(path); 1544177997Skib return (error); 1545177997Skib} 1546177997Skib 1547346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 1548177997Skibint 154985022Smarcellinux_lchown(struct thread *td, struct linux_lchown_args *args) 155085022Smarcel{ 1551102814Siedowse char *path; 1552102814Siedowse int error; 155385022Smarcel 1554102814Siedowse LCONVPATHEXIST(td, args->path, &path); 155585022Smarcel 155685022Smarcel#ifdef DEBUG 155785022Smarcel if (ldebug(lchown)) 1558102814Siedowse printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 155985022Smarcel#endif 1560274476Skib error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1561274476Skib args->gid, AT_SYMLINK_NOFOLLOW); 1562102814Siedowse LFREEPATH(path); 1563102814Siedowse return (error); 156485022Smarcel} 1565346832Sdchagin#endif 1566228957Sjhb 1567228957Sjhbstatic int 1568228957Sjhbconvert_fadvice(int advice) 1569228957Sjhb{ 1570228957Sjhb switch (advice) { 1571228957Sjhb case LINUX_POSIX_FADV_NORMAL: 1572228957Sjhb return (POSIX_FADV_NORMAL); 1573228957Sjhb case LINUX_POSIX_FADV_RANDOM: 1574228957Sjhb return (POSIX_FADV_RANDOM); 1575228957Sjhb case LINUX_POSIX_FADV_SEQUENTIAL: 1576228957Sjhb return (POSIX_FADV_SEQUENTIAL); 1577228957Sjhb case LINUX_POSIX_FADV_WILLNEED: 1578228957Sjhb return (POSIX_FADV_WILLNEED); 1579228957Sjhb case LINUX_POSIX_FADV_DONTNEED: 1580228957Sjhb return (POSIX_FADV_DONTNEED); 1581228957Sjhb case LINUX_POSIX_FADV_NOREUSE: 1582228957Sjhb return (POSIX_FADV_NOREUSE); 1583228957Sjhb default: 1584228957Sjhb return (-1); 1585228957Sjhb } 1586228957Sjhb} 1587228957Sjhb 1588228957Sjhbint 1589228957Sjhblinux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) 1590228957Sjhb{ 1591228957Sjhb int advice; 1592228957Sjhb 1593228957Sjhb advice = convert_fadvice(args->advice); 1594228957Sjhb if (advice == -1) 1595228957Sjhb return (EINVAL); 1596228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1597228957Sjhb advice)); 1598228957Sjhb} 1599228957Sjhb 1600283415Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1601228957Sjhbint 1602228957Sjhblinux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) 1603228957Sjhb{ 1604228957Sjhb int advice; 1605228957Sjhb 1606228957Sjhb advice = convert_fadvice(args->advice); 1607228957Sjhb if (advice == -1) 1608228957Sjhb return (EINVAL); 1609228957Sjhb return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1610228957Sjhb advice)); 1611228957Sjhb} 1612283415Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1613234352Sjkim 1614346832Sdchagin#ifdef LINUX_LEGACY_SYSCALLS 1615234352Sjkimint 1616234352Sjkimlinux_pipe(struct thread *td, struct linux_pipe_args *args) 1617234352Sjkim{ 1618234352Sjkim int fildes[2]; 1619234352Sjkim int error; 1620234352Sjkim 1621234352Sjkim#ifdef DEBUG 1622234352Sjkim if (ldebug(pipe)) 1623234352Sjkim printf(ARGS(pipe, "*")); 1624234352Sjkim#endif 1625234352Sjkim 1626286021Sed error = kern_pipe(td, fildes, 0, NULL, NULL); 1627315538Strasz if (error != 0) 1628234352Sjkim return (error); 1629234352Sjkim 1630315538Strasz error = copyout(fildes, args->pipefds, sizeof(fildes)); 1631315538Strasz if (error != 0) { 1632315538Strasz (void)kern_close(td, fildes[0]); 1633315538Strasz (void)kern_close(td, fildes[1]); 1634315538Strasz } 1635315538Strasz 1636315538Strasz return (error); 1637234352Sjkim} 1638346832Sdchagin#endif 1639234352Sjkim 1640234352Sjkimint 1641234352Sjkimlinux_pipe2(struct thread *td, struct linux_pipe2_args *args) 1642234352Sjkim{ 1643234352Sjkim int fildes[2]; 1644234352Sjkim int error, flags; 1645234352Sjkim 1646234352Sjkim#ifdef DEBUG 1647234352Sjkim if (ldebug(pipe2)) 1648234352Sjkim printf(ARGS(pipe2, "*, %d"), args->flags); 1649234352Sjkim#endif 1650234352Sjkim 1651234352Sjkim if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) 1652234352Sjkim return (EINVAL); 1653234352Sjkim 1654234352Sjkim flags = 0; 1655234352Sjkim if ((args->flags & LINUX_O_NONBLOCK) != 0) 1656234352Sjkim flags |= O_NONBLOCK; 1657234352Sjkim if ((args->flags & LINUX_O_CLOEXEC) != 0) 1658234352Sjkim flags |= O_CLOEXEC; 1659286021Sed error = kern_pipe(td, fildes, flags, NULL, NULL); 1660315538Strasz if (error != 0) 1661234352Sjkim return (error); 1662234352Sjkim 1663315538Strasz error = copyout(fildes, args->pipefds, sizeof(fildes)); 1664315538Strasz if (error != 0) { 1665315538Strasz (void)kern_close(td, fildes[0]); 1666315538Strasz (void)kern_close(td, fildes[1]); 1667315538Strasz } 1668315538Strasz 1669315538Strasz return (error); 1670234352Sjkim} 1671283399Sdchagin 1672283399Sdchaginint 1673283399Sdchaginlinux_dup3(struct thread *td, struct linux_dup3_args *args) 1674283399Sdchagin{ 1675283399Sdchagin int cmd; 1676283399Sdchagin intptr_t newfd; 1677283399Sdchagin 1678283399Sdchagin if (args->oldfd == args->newfd) 1679283399Sdchagin return (EINVAL); 1680283399Sdchagin if ((args->flags & ~LINUX_O_CLOEXEC) != 0) 1681283399Sdchagin return (EINVAL); 1682283399Sdchagin if (args->flags & LINUX_O_CLOEXEC) 1683283399Sdchagin cmd = F_DUP2FD_CLOEXEC; 1684283399Sdchagin else 1685283399Sdchagin cmd = F_DUP2FD; 1686283399Sdchagin 1687283399Sdchagin newfd = args->newfd; 1688283399Sdchagin return (kern_fcntl(td, args->oldfd, cmd, newfd)); 1689283399Sdchagin} 1690283465Sdchagin 1691283465Sdchaginint 1692283465Sdchaginlinux_fallocate(struct thread *td, struct linux_fallocate_args *args) 1693283465Sdchagin{ 1694283465Sdchagin 1695283465Sdchagin /* 1696283465Sdchagin * We emulate only posix_fallocate system call for which 1697283465Sdchagin * mode should be 0. 1698283465Sdchagin */ 1699283465Sdchagin if (args->mode != 0) 1700283465Sdchagin return (ENOSYS); 1701283465Sdchagin 1702283465Sdchagin return (kern_posix_fallocate(td, args->fd, args->offset, 1703283465Sdchagin args->len)); 1704283465Sdchagin} 1705