19313Ssos/*- 2230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 9111798Sdes * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 1597748Sschweikh * derived from this software without specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos */ 289313Ssos 29116173Sobrien#include <sys/cdefs.h> 30116173Sobrien__FBSDID("$FreeBSD$"); 31116173Sobrien 32156874Sru#include "opt_compat.h" 33101189Srwatson 349313Ssos#include <sys/param.h> 359313Ssos#include <sys/dirent.h> 369313Ssos#include <sys/file.h> 379313Ssos#include <sys/filedesc.h> 389313Ssos#include <sys/proc.h> 39102954Sbde#include <sys/malloc.h> 409313Ssos#include <sys/mount.h> 419313Ssos#include <sys/namei.h> 429313Ssos#include <sys/stat.h> 43141473Sjhb#include <sys/syscallsubr.h> 4453758Smarcel#include <sys/systm.h> 45181905Sed#include <sys/tty.h> 469313Ssos#include <sys/vnode.h> 47158311Sambrisko#include <sys/conf.h> 48158311Sambrisko#include <sys/fcntl.h> 499313Ssos 50140214Sobrien#ifdef COMPAT_LINUX32 51140214Sobrien#include <machine/../linux32/linux.h> 52140214Sobrien#include <machine/../linux32/linux32_proto.h> 53140214Sobrien#else 5464913Smarcel#include <machine/../linux/linux.h> 5568583Smarcel#include <machine/../linux/linux_proto.h> 56133816Stjr#endif 57102954Sbde 5864913Smarcel#include <compat/linux/linux_util.h> 59177997Skib#include <compat/linux/linux_file.h> 609313Ssos 61218497Snetchild#define LINUX_SHMFS_MAGIC 0x01021994 62218497Snetchild 63188849Sedstatic void 64188849Sedtranslate_vnhook_major_minor(struct vnode *vp, struct stat *sb) 65188849Sed{ 66188849Sed int major, minor; 67188849Sed 68188849Sed if (vp->v_type == VCHR && vp->v_rdev != NULL && 69231378Sed linux_driver_get_major_minor(devtoname(vp->v_rdev), 70188849Sed &major, &minor) == 0) { 71188849Sed sb->st_rdev = (major << 8 | minor); 72188849Sed } 73188849Sed} 74188849Sed 75188849Sedstatic int 76188849Sedlinux_kern_statat(struct thread *td, int flag, int fd, char *path, 77188849Sed enum uio_seg pathseg, struct stat *sbp) 78188849Sed{ 79188849Sed 80188849Sed return (kern_statat_vnhook(td, flag, fd, path, pathseg, sbp, 81188849Sed translate_vnhook_major_minor)); 82188849Sed} 83188849Sed 84188849Sedstatic int 85188849Sedlinux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg, 86188849Sed struct stat *sbp) 87188849Sed{ 88188849Sed 89188849Sed return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp)); 90188849Sed} 91188849Sed 92188849Sedstatic int 93188849Sedlinux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, 94188849Sed struct stat *sbp) 95188849Sed{ 96188849Sed 97188849Sed return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, 98188849Sed pathseg, sbp)); 99188849Sed} 100188849Sed 101143635Sphk/* 102143635Sphk * XXX: This was removed from newstat_copyout(), and almost identical 103143635Sphk * XXX: code was in stat64_copyout(). findcdev() needs to be replaced 104143635Sphk * XXX: with something that does lookup and locking properly. 105143635Sphk * XXX: When somebody fixes this: please try to avoid duplicating it. 106143635Sphk */ 107143635Sphk#if 0 108143635Sphkstatic void 109143635Sphkdisk_foo(struct somestat *tbuf) 1109313Ssos{ 11171048Sjoe struct cdevsw *cdevsw; 112130585Sphk struct cdev *dev; 1139313Ssos 11471048Sjoe /* Lie about disk drives which are character devices 11571048Sjoe * in FreeBSD but block devices under Linux. 11671048Sjoe */ 11783221Smarcel if (S_ISCHR(tbuf.st_mode) && 118130640Sphk (dev = findcdev(buf->st_rdev)) != NULL) { 119135715Sphk cdevsw = dev_refthread(dev); 120135715Sphk if (cdevsw != NULL) { 121135715Sphk if (cdevsw->d_flags & D_DISK) { 122135715Sphk tbuf.st_mode &= ~S_IFMT; 123135715Sphk tbuf.st_mode |= S_IFBLK; 12450356Smarcel 125135715Sphk /* XXX this may not be quite right */ 126135715Sphk /* Map major number to 0 */ 127187830Sed tbuf.st_dev = minor(buf->st_dev) & 0xf; 128135715Sphk tbuf.st_rdev = buf->st_rdev & 0xff; 129135715Sphk } 130135715Sphk dev_relthread(dev); 13171048Sjoe } 13270458Spaul } 13370458Spaul 134143635Sphk} 135143635Sphk#endif 136143635Sphk 137158311Sambriskostatic void 138158311Sambriskotranslate_fd_major_minor(struct thread *td, int fd, struct stat *buf) 139158311Sambrisko{ 140158311Sambrisko struct file *fp; 141188849Sed struct vnode *vp; 142158311Sambrisko int major, minor; 143158311Sambrisko 144224778Srwatson /* 145224778Srwatson * No capability rights required here. 146224778Srwatson */ 147164890Sjkim if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || 148224778Srwatson fget(td, fd, 0, &fp) != 0) 149158311Sambrisko return; 150188849Sed vp = fp->f_vnode; 151188849Sed if (vp != NULL && vp->v_rdev != NULL && 152231378Sed linux_driver_get_major_minor(devtoname(vp->v_rdev), 153181905Sed &major, &minor) == 0) { 154164890Sjkim buf->st_rdev = (major << 8 | minor); 155181905Sed } else if (fp->f_type == DTYPE_PTS) { 156181905Sed struct tty *tp = fp->f_data; 157181905Sed 158181905Sed /* Convert the numbers for the slave device. */ 159231378Sed if (linux_driver_get_major_minor(devtoname(tp->t_dev), 160181905Sed &major, &minor) == 0) { 161181905Sed buf->st_rdev = (major << 8 | minor); 162181905Sed } 163181905Sed } 164158311Sambrisko fdrop(fp, td); 165158311Sambrisko} 166158311Sambrisko 167143635Sphkstatic int 168143635Sphknewstat_copyout(struct stat *buf, void *ubuf) 169143635Sphk{ 170143635Sphk struct l_newstat tbuf; 171143635Sphk 172143635Sphk bzero(&tbuf, sizeof(tbuf)); 173187830Sed tbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8); 174143635Sphk tbuf.st_ino = buf->st_ino; 175143635Sphk tbuf.st_mode = buf->st_mode; 176143635Sphk tbuf.st_nlink = buf->st_nlink; 177143635Sphk tbuf.st_uid = buf->st_uid; 178143635Sphk tbuf.st_gid = buf->st_gid; 179143635Sphk tbuf.st_rdev = buf->st_rdev; 180143635Sphk tbuf.st_size = buf->st_size; 181205792Sed tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 182205792Sed tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 183205792Sed tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 184205792Sed tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 185205792Sed tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 186205792Sed tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 187143635Sphk tbuf.st_blksize = buf->st_blksize; 188143635Sphk tbuf.st_blocks = buf->st_blocks; 189143635Sphk 19050356Smarcel return (copyout(&tbuf, ubuf, sizeof(tbuf))); 1919313Ssos} 1929313Ssos 1939313Ssosint 19483366Sjulianlinux_newstat(struct thread *td, struct linux_newstat_args *args) 1959313Ssos{ 19650356Smarcel struct stat buf; 197102814Siedowse char *path; 19850356Smarcel int error; 19914331Speter 200102814Siedowse LCONVPATHEXIST(td, args->path, &path); 20150356Smarcel 2029313Ssos#ifdef DEBUG 20372543Sjlemon if (ldebug(newstat)) 204102814Siedowse printf(ARGS(newstat, "%s, *"), path); 2059313Ssos#endif 20650356Smarcel 207188849Sed error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 208102814Siedowse LFREEPATH(path); 20950356Smarcel if (error) 21050356Smarcel return (error); 21150356Smarcel return (newstat_copyout(&buf, args->buf)); 2129313Ssos} 2139313Ssos 2149313Ssosint 21583366Sjulianlinux_newlstat(struct thread *td, struct linux_newlstat_args *args) 2169313Ssos{ 21750356Smarcel struct stat sb; 218102814Siedowse char *path; 219141473Sjhb int error; 22014331Speter 221102814Siedowse LCONVPATHEXIST(td, args->path, &path); 22250356Smarcel 2239313Ssos#ifdef DEBUG 22472543Sjlemon if (ldebug(newlstat)) 225102814Siedowse printf(ARGS(newlstat, "%s, *"), path); 2269313Ssos#endif 22750356Smarcel 228188849Sed error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb); 229102814Siedowse LFREEPATH(path); 23014331Speter if (error) 23114331Speter return (error); 23283221Smarcel return (newstat_copyout(&sb, args->buf)); 2339313Ssos} 2349313Ssos 2359313Ssosint 23683366Sjulianlinux_newfstat(struct thread *td, struct linux_newfstat_args *args) 2379313Ssos{ 23850356Smarcel struct stat buf; 23950356Smarcel int error; 24050356Smarcel 2419313Ssos#ifdef DEBUG 24272543Sjlemon if (ldebug(newfstat)) 24372543Sjlemon printf(ARGS(newfstat, "%d, *"), args->fd); 2449313Ssos#endif 24550356Smarcel 246141473Sjhb error = kern_fstat(td, args->fd, &buf); 247158311Sambrisko translate_fd_major_minor(td, args->fd, &buf); 24850356Smarcel if (!error) 24950356Smarcel error = newstat_copyout(&buf, args->buf); 25050356Smarcel 25150356Smarcel return (error); 2529313Ssos} 2539313Ssos 254156842Snetchildstatic int 255156842Snetchildstat_copyout(struct stat *buf, void *ubuf) 256156842Snetchild{ 257156842Snetchild struct l_stat lbuf; 258156842Snetchild 259156842Snetchild bzero(&lbuf, sizeof(lbuf)); 260156842Snetchild lbuf.st_dev = buf->st_dev; 261156842Snetchild lbuf.st_ino = buf->st_ino; 262156842Snetchild lbuf.st_mode = buf->st_mode; 263156842Snetchild lbuf.st_nlink = buf->st_nlink; 264156842Snetchild lbuf.st_uid = buf->st_uid; 265156842Snetchild lbuf.st_gid = buf->st_gid; 266156842Snetchild lbuf.st_rdev = buf->st_rdev; 267156842Snetchild if (buf->st_size < (quad_t)1 << 32) 268156842Snetchild lbuf.st_size = buf->st_size; 269156842Snetchild else 270156842Snetchild lbuf.st_size = -2; 271205792Sed lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 272205792Sed lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 273205792Sed lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 274205792Sed lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 275205792Sed lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 276205792Sed lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 277156842Snetchild lbuf.st_blksize = buf->st_blksize; 278156842Snetchild lbuf.st_blocks = buf->st_blocks; 279156842Snetchild lbuf.st_flags = buf->st_flags; 280156842Snetchild lbuf.st_gen = buf->st_gen; 281156842Snetchild 282156842Snetchild return (copyout(&lbuf, ubuf, sizeof(lbuf))); 283156842Snetchild} 284156842Snetchild 285156842Snetchildint 286156842Snetchildlinux_stat(struct thread *td, struct linux_stat_args *args) 287156842Snetchild{ 288156842Snetchild struct stat buf; 289174974Skib char *path; 290156842Snetchild int error; 291174974Skib 292174974Skib LCONVPATHEXIST(td, args->path, &path); 293174974Skib 294156842Snetchild#ifdef DEBUG 295156842Snetchild if (ldebug(stat)) 296175107Skib printf(ARGS(stat, "%s, *"), path); 297156842Snetchild#endif 298188849Sed error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 299175107Skib if (error) { 300175107Skib LFREEPATH(path); 301175107Skib return (error); 302175107Skib } 303174974Skib LFREEPATH(path); 304156842Snetchild return(stat_copyout(&buf, args->up)); 305156842Snetchild} 306156842Snetchild 307156842Snetchildint 308156842Snetchildlinux_lstat(struct thread *td, struct linux_lstat_args *args) 309156842Snetchild{ 310156842Snetchild struct stat buf; 311174974Skib char *path; 312156842Snetchild int error; 313156842Snetchild 314174974Skib LCONVPATHEXIST(td, args->path, &path); 315174974Skib 316156842Snetchild#ifdef DEBUG 317156842Snetchild if (ldebug(lstat)) 318175107Skib printf(ARGS(lstat, "%s, *"), path); 319156842Snetchild#endif 320188849Sed error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf); 321175107Skib if (error) { 322175107Skib LFREEPATH(path); 323175107Skib return (error); 324175107Skib } 325174974Skib LFREEPATH(path); 326156842Snetchild return(stat_copyout(&buf, args->up)); 327156842Snetchild} 328156842Snetchild 32983221Smarcel/* XXX - All fields of type l_int are defined as l_long on i386 */ 33083221Smarcelstruct l_statfs { 33183221Smarcel l_int f_type; 33283221Smarcel l_int f_bsize; 33383221Smarcel l_int f_blocks; 33483221Smarcel l_int f_bfree; 33583221Smarcel l_int f_bavail; 33683221Smarcel l_int f_files; 33783221Smarcel l_int f_ffree; 33883221Smarcel l_fsid_t f_fsid; 33983221Smarcel l_int f_namelen; 34083221Smarcel l_int f_spare[6]; 3419313Ssos}; 3429313Ssos 34355629Smarcel#define LINUX_CODA_SUPER_MAGIC 0x73757245L 34455629Smarcel#define LINUX_EXT2_SUPER_MAGIC 0xEF53L 34555629Smarcel#define LINUX_HPFS_SUPER_MAGIC 0xf995e849L 34655629Smarcel#define LINUX_ISOFS_SUPER_MAGIC 0x9660L 34755629Smarcel#define LINUX_MSDOS_SUPER_MAGIC 0x4d44L 34855629Smarcel#define LINUX_NCP_SUPER_MAGIC 0x564cL 34955629Smarcel#define LINUX_NFS_SUPER_MAGIC 0x6969L 35055629Smarcel#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL 35155629Smarcel#define LINUX_PROC_SUPER_MAGIC 0x9fa0L 35255629Smarcel#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ 353154834Scognet#define LINUX_DEVFS_SUPER_MAGIC 0x1373L 35455629Smarcel 35555629Smarcelstatic long 35683667Ssobomaxbsd_to_linux_ftype(const char *fstypename) 35755629Smarcel{ 35883667Ssobomax int i; 35983667Ssobomax static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = { 36083667Ssobomax {"ufs", LINUX_UFS_SUPER_MAGIC}, 36183667Ssobomax {"cd9660", LINUX_ISOFS_SUPER_MAGIC}, 36283667Ssobomax {"nfs", LINUX_NFS_SUPER_MAGIC}, 36383667Ssobomax {"ext2fs", LINUX_EXT2_SUPER_MAGIC}, 36483667Ssobomax {"procfs", LINUX_PROC_SUPER_MAGIC}, 36583667Ssobomax {"msdosfs", LINUX_MSDOS_SUPER_MAGIC}, 36683667Ssobomax {"ntfs", LINUX_NTFS_SUPER_MAGIC}, 36783667Ssobomax {"nwfs", LINUX_NCP_SUPER_MAGIC}, 36883667Ssobomax {"hpfs", LINUX_HPFS_SUPER_MAGIC}, 36983667Ssobomax {"coda", LINUX_CODA_SUPER_MAGIC}, 370154834Scognet {"devfs", LINUX_DEVFS_SUPER_MAGIC}, 37183667Ssobomax {NULL, 0L}}; 37255629Smarcel 37383667Ssobomax for (i = 0; b2l_tbl[i].bsd_name != NULL; i++) 37483667Ssobomax if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0) 37583667Ssobomax return (b2l_tbl[i].linux_type); 37655629Smarcel 37755629Smarcel return (0L); 37855629Smarcel} 37955629Smarcel 380141473Sjhbstatic void 381146695Spjdbsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs) 382141473Sjhb{ 383141473Sjhb 384141473Sjhb linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 385141473Sjhb linux_statfs->f_bsize = bsd_statfs->f_bsize; 386141473Sjhb linux_statfs->f_blocks = bsd_statfs->f_blocks; 387141473Sjhb linux_statfs->f_bfree = bsd_statfs->f_bfree; 388141473Sjhb linux_statfs->f_bavail = bsd_statfs->f_bavail; 389141473Sjhb linux_statfs->f_ffree = bsd_statfs->f_ffree; 390141473Sjhb linux_statfs->f_files = bsd_statfs->f_files; 391146502Spjd linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 392146502Spjd linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 393141473Sjhb linux_statfs->f_namelen = MAXNAMLEN; 394141473Sjhb} 395141473Sjhb 3969313Ssosint 39783366Sjulianlinux_statfs(struct thread *td, struct linux_statfs_args *args) 3989313Ssos{ 39983221Smarcel struct l_statfs linux_statfs; 400141473Sjhb struct statfs bsd_statfs; 401102814Siedowse char *path; 402218497Snetchild int error, dev_shm; 4039313Ssos 404102814Siedowse LCONVPATHEXIST(td, args->path, &path); 40514331Speter 4069313Ssos#ifdef DEBUG 40772543Sjlemon if (ldebug(statfs)) 408102814Siedowse printf(ARGS(statfs, "%s, *"), path); 4099313Ssos#endif 410218497Snetchild dev_shm = 0; 411141473Sjhb error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs); 412218497Snetchild if (strncmp(path, "/dev/shm", sizeof("/dev/shm") - 1) == 0) 413218497Snetchild dev_shm = (path[8] == '\0' 414218497Snetchild || (path[8] == '/' && path[9] == '\0')); 415102814Siedowse LFREEPATH(path); 41646571Speter if (error) 417101189Srwatson return (error); 418146695Spjd bsd_to_linux_statfs(&bsd_statfs, &linux_statfs); 419218497Snetchild if (dev_shm) 420218497Snetchild linux_statfs.f_type = LINUX_SHMFS_MAGIC; 421111797Sdes return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); 4229313Ssos} 4239313Ssos 424161665Snetchildstatic void 425161665Snetchildbsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs) 426161665Snetchild{ 427161665Snetchild 428161665Snetchild linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 429161665Snetchild linux_statfs->f_bsize = bsd_statfs->f_bsize; 430161665Snetchild linux_statfs->f_blocks = bsd_statfs->f_blocks; 431161665Snetchild linux_statfs->f_bfree = bsd_statfs->f_bfree; 432161665Snetchild linux_statfs->f_bavail = bsd_statfs->f_bavail; 433161665Snetchild linux_statfs->f_ffree = bsd_statfs->f_ffree; 434161665Snetchild linux_statfs->f_files = bsd_statfs->f_files; 435161665Snetchild linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 436161665Snetchild linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 437161665Snetchild linux_statfs->f_namelen = MAXNAMLEN; 438161665Snetchild} 439161665Snetchild 4409313Ssosint 441161665Snetchildlinux_statfs64(struct thread *td, struct linux_statfs64_args *args) 442161665Snetchild{ 443161665Snetchild struct l_statfs64 linux_statfs; 444161665Snetchild struct statfs bsd_statfs; 445161665Snetchild char *path; 446161665Snetchild int error; 447161665Snetchild 448172220Sdwmalone if (args->bufsize != sizeof(struct l_statfs64)) 449172220Sdwmalone return EINVAL; 450172220Sdwmalone 451161665Snetchild LCONVPATHEXIST(td, args->path, &path); 452161665Snetchild 453161665Snetchild#ifdef DEBUG 454161665Snetchild if (ldebug(statfs64)) 455161665Snetchild printf(ARGS(statfs64, "%s, *"), path); 456161665Snetchild#endif 457161665Snetchild error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs); 458161665Snetchild LFREEPATH(path); 459161665Snetchild if (error) 460161665Snetchild return (error); 461161665Snetchild bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs); 462161665Snetchild return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); 463161665Snetchild} 464161665Snetchild 465161665Snetchildint 46683366Sjulianlinux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) 4679313Ssos{ 46883221Smarcel struct l_statfs linux_statfs; 469141473Sjhb struct statfs bsd_statfs; 4709313Ssos int error; 4719313Ssos 4729313Ssos#ifdef DEBUG 47372543Sjlemon if (ldebug(fstatfs)) 47472543Sjlemon printf(ARGS(fstatfs, "%d, *"), args->fd); 4759313Ssos#endif 476141473Sjhb error = kern_fstatfs(td, args->fd, &bsd_statfs); 47746571Speter if (error) 4789313Ssos return error; 479146695Spjd bsd_to_linux_statfs(&bsd_statfs, &linux_statfs); 480141473Sjhb return copyout(&linux_statfs, args->buf, sizeof(linux_statfs)); 4819313Ssos} 48253758Smarcel 483111798Sdesstruct l_ustat 48483221Smarcel{ 48583221Smarcel l_daddr_t f_tfree; 48683221Smarcel l_ino_t f_tinode; 48783221Smarcel char f_fname[6]; 48883221Smarcel char f_fpack[6]; 48983221Smarcel}; 49083221Smarcel 49153758Smarcelint 49283366Sjulianlinux_ustat(struct thread *td, struct linux_ustat_args *args) 49353758Smarcel{ 494142220Sphk#ifdef DEBUG 495142220Sphk if (ldebug(ustat)) 496142220Sphk printf(ARGS(ustat, "%d, *"), args->dev); 497142220Sphk#endif 498142220Sphk 499142220Sphk return (EOPNOTSUPP); 50053758Smarcel} 50183221Smarcel 502140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 50383221Smarcel 50483221Smarcelstatic int 50583221Smarcelstat64_copyout(struct stat *buf, void *ubuf) 50683221Smarcel{ 50783221Smarcel struct l_stat64 lbuf; 50883221Smarcel 50983221Smarcel bzero(&lbuf, sizeof(lbuf)); 510187830Sed lbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8); 51183221Smarcel lbuf.st_ino = buf->st_ino; 51283221Smarcel lbuf.st_mode = buf->st_mode; 51383221Smarcel lbuf.st_nlink = buf->st_nlink; 51483221Smarcel lbuf.st_uid = buf->st_uid; 51583221Smarcel lbuf.st_gid = buf->st_gid; 51683221Smarcel lbuf.st_rdev = buf->st_rdev; 51783221Smarcel lbuf.st_size = buf->st_size; 518205792Sed lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 519205792Sed lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 520205792Sed lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 521205792Sed lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 522205792Sed lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 523205792Sed lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 52483221Smarcel lbuf.st_blksize = buf->st_blksize; 52583221Smarcel lbuf.st_blocks = buf->st_blocks; 52683221Smarcel 52783221Smarcel /* 52883221Smarcel * The __st_ino field makes all the difference. In the Linux kernel 52983221Smarcel * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO, 53083221Smarcel * but without the assignment to __st_ino the runtime linker refuses 53183221Smarcel * to mmap(2) any shared libraries. I guess it's broken alright :-) 53283221Smarcel */ 53383221Smarcel lbuf.__st_ino = buf->st_ino; 53483221Smarcel 53583221Smarcel return (copyout(&lbuf, ubuf, sizeof(lbuf))); 53683221Smarcel} 53783221Smarcel 53883221Smarcelint 53983366Sjulianlinux_stat64(struct thread *td, struct linux_stat64_args *args) 54083221Smarcel{ 54183221Smarcel struct stat buf; 542141473Sjhb char *filename; 54383221Smarcel int error; 54483221Smarcel 545102814Siedowse LCONVPATHEXIST(td, args->filename, &filename); 54683221Smarcel 54783221Smarcel#ifdef DEBUG 54883221Smarcel if (ldebug(stat64)) 549102814Siedowse printf(ARGS(stat64, "%s, *"), filename); 55083221Smarcel#endif 55183221Smarcel 552188849Sed error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf); 553102814Siedowse LFREEPATH(filename); 55483221Smarcel if (error) 55583221Smarcel return (error); 55683221Smarcel return (stat64_copyout(&buf, args->statbuf)); 55783221Smarcel} 55883221Smarcel 55983221Smarcelint 56083366Sjulianlinux_lstat64(struct thread *td, struct linux_lstat64_args *args) 56183221Smarcel{ 56283221Smarcel struct stat sb; 563102814Siedowse char *filename; 564141473Sjhb int error; 56583221Smarcel 566102814Siedowse LCONVPATHEXIST(td, args->filename, &filename); 56783221Smarcel 56883221Smarcel#ifdef DEBUG 56983221Smarcel if (ldebug(lstat64)) 57083221Smarcel printf(ARGS(lstat64, "%s, *"), args->filename); 57183221Smarcel#endif 57283221Smarcel 573188849Sed error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb); 574102814Siedowse LFREEPATH(filename); 57583221Smarcel if (error) 57683221Smarcel return (error); 57783221Smarcel return (stat64_copyout(&sb, args->statbuf)); 57883221Smarcel} 57983221Smarcel 58083221Smarcelint 58183366Sjulianlinux_fstat64(struct thread *td, struct linux_fstat64_args *args) 58283221Smarcel{ 58383221Smarcel struct stat buf; 58483221Smarcel int error; 58583221Smarcel 58683221Smarcel#ifdef DEBUG 58783221Smarcel if (ldebug(fstat64)) 58883221Smarcel printf(ARGS(fstat64, "%d, *"), args->fd); 58983221Smarcel#endif 59083221Smarcel 591141473Sjhb error = kern_fstat(td, args->fd, &buf); 592158311Sambrisko translate_fd_major_minor(td, args->fd, &buf); 59383221Smarcel if (!error) 59483221Smarcel error = stat64_copyout(&buf, args->statbuf); 59583221Smarcel 59683221Smarcel return (error); 59783221Smarcel} 59883221Smarcel 599177997Skibint 600177997Skiblinux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) 601177997Skib{ 602177997Skib char *path; 603177997Skib int error, dfd, flag; 604177997Skib struct stat buf; 605177997Skib 606177997Skib if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 607177997Skib return (EINVAL); 608177997Skib flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 609177997Skib AT_SYMLINK_NOFOLLOW : 0; 610177997Skib 611177997Skib dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 612177997Skib LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 613177997Skib 614177997Skib#ifdef DEBUG 615177997Skib if (ldebug(fstatat64)) 616177997Skib printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag); 617177997Skib#endif 618177997Skib 619188849Sed error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); 620177997Skib if (!error) 621177997Skib error = stat64_copyout(&buf, args->statbuf); 622177997Skib LFREEPATH(path); 623177997Skib 624177997Skib return (error); 625177997Skib} 626177997Skib 627140214Sobrien#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 628