The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_stats.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1994-1995 Søren Schmidt
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include "opt_compat.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/capsicum.h>
   36 #include <sys/dirent.h>
   37 #include <sys/file.h>
   38 #include <sys/filedesc.h>
   39 #include <sys/proc.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mount.h>
   42 #include <sys/namei.h>
   43 #include <sys/stat.h>
   44 #include <sys/syscallsubr.h>
   45 #include <sys/systm.h>
   46 #include <sys/tty.h>
   47 #include <sys/vnode.h>
   48 #include <sys/conf.h>
   49 #include <sys/fcntl.h>
   50 
   51 #ifdef COMPAT_LINUX32
   52 #include <machine/../linux32/linux.h>
   53 #include <machine/../linux32/linux32_proto.h>
   54 #else
   55 #include <machine/../linux/linux.h>
   56 #include <machine/../linux/linux_proto.h>
   57 #endif
   58 
   59 #include <compat/linux/linux_util.h>
   60 #include <compat/linux/linux_file.h>
   61 
   62 
   63 static void
   64 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
   65 {
   66         int major, minor;
   67 
   68         if (vn_isdisk(vp, NULL)) {
   69                 sb->st_mode &= ~S_IFMT;
   70                 sb->st_mode |= S_IFBLK;
   71         }
   72 
   73         /*
   74          * Return the same st_dev for every devfs instance.  The reason
   75          * for this is to work around an idiosyncrasy of glibc getttynam()
   76          * implementation: it checks whether st_dev returned for fd 0
   77          * is the same as st_dev returned for the target of /proc/self/fd/0
   78          * symlink, and with linux chroots having their own devfs instance,
   79          * the check will fail if you chroot into it.
   80          */
   81         if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc)
   82                 sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
   83 
   84         if (vp->v_type == VCHR && vp->v_rdev != NULL &&
   85             linux_driver_get_major_minor(devtoname(vp->v_rdev),
   86             &major, &minor) == 0) {
   87                 sb->st_rdev = (major << 8 | minor);
   88         }
   89 }
   90 
   91 static int
   92 linux_kern_statat(struct thread *td, int flag, int fd, char *path,
   93     enum uio_seg pathseg, struct stat *sbp)
   94 {
   95 
   96         return (kern_statat(td, flag, fd, path, pathseg, sbp,
   97             translate_vnhook_major_minor));
   98 }
   99 
  100 #ifdef LINUX_LEGACY_SYSCALLS
  101 static int
  102 linux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
  103     struct stat *sbp)
  104 {
  105 
  106         return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
  107 }
  108 
  109 static int
  110 linux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
  111     struct stat *sbp)
  112 {
  113 
  114         return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
  115             pathseg, sbp));
  116 }
  117 #endif
  118 
  119 static void
  120 translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
  121 {
  122         struct file *fp;
  123         struct vnode *vp;
  124         struct mount *mp;
  125         int major, minor;
  126 
  127         /*
  128          * No capability rights required here.
  129          */
  130         if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
  131             fget(td, fd, &cap_no_rights, &fp) != 0)
  132                 return;
  133         vp = fp->f_vnode;
  134         if (vp != NULL && vn_isdisk(vp, NULL)) {
  135                 buf->st_mode &= ~S_IFMT;
  136                 buf->st_mode |= S_IFBLK;
  137         }
  138         if (vp != NULL && rootdevmp != NULL) {
  139                 mp = vp->v_mount;
  140                 __compiler_membar();
  141                 if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc)
  142                         buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
  143         }
  144         if (vp != NULL && vp->v_rdev != NULL &&
  145             linux_driver_get_major_minor(devtoname(vp->v_rdev),
  146                                          &major, &minor) == 0) {
  147                 buf->st_rdev = (major << 8 | minor);
  148         } else if (fp->f_type == DTYPE_PTS) {
  149                 struct tty *tp = fp->f_data;
  150 
  151                 /* Convert the numbers for the slave device. */
  152                 if (linux_driver_get_major_minor(devtoname(tp->t_dev),
  153                                          &major, &minor) == 0) {
  154                         buf->st_rdev = (major << 8 | minor);
  155                 }
  156         }
  157         fdrop(fp, td);
  158 }
  159 
  160 /*
  161  * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
  162  * truncation of a dev_t to 16 bits gives the same result as unpacking
  163  * using major() and minor() and repacking in the l_dev_t format.  This
  164  * detail is hidden in dev_to_ldev().  Overflow in conversions of dev_t's
  165  * are not checked for, as for other fields.
  166  *
  167  * dev_to_ldev() is only used for translating st_dev.  When we convert
  168  * st_rdev for copying it out, it isn't really a dev_t, but has already
  169  * been translated to an l_dev_t in a nontrivial way.  Translating it
  170  * again would be illogical but would have no effect since the low 16
  171  * bits have the same encoding.
  172  *
  173  * The nontrivial translation for st_rdev renumbers some devices, but not
  174  * ones that can be mounted on, so it is consistent with the translation
  175  * for st_dev except when the renumbering or truncation causes conflicts.
  176  */
  177 #define dev_to_ldev(d)  ((uint16_t)(d))
  178 
  179 static int
  180 newstat_copyout(struct stat *buf, void *ubuf)
  181 {
  182         struct l_newstat tbuf;
  183 
  184         bzero(&tbuf, sizeof(tbuf));
  185         tbuf.st_dev = dev_to_ldev(buf->st_dev);
  186         tbuf.st_ino = buf->st_ino;
  187         tbuf.st_mode = buf->st_mode;
  188         tbuf.st_nlink = buf->st_nlink;
  189         tbuf.st_uid = buf->st_uid;
  190         tbuf.st_gid = buf->st_gid;
  191         tbuf.st_rdev = buf->st_rdev;
  192         tbuf.st_size = buf->st_size;
  193         tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
  194         tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
  195         tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
  196         tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
  197         tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
  198         tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
  199         tbuf.st_blksize = buf->st_blksize;
  200         tbuf.st_blocks = buf->st_blocks;
  201 
  202         return (copyout(&tbuf, ubuf, sizeof(tbuf)));
  203 }
  204 
  205 #ifdef LINUX_LEGACY_SYSCALLS
  206 int
  207 linux_newstat(struct thread *td, struct linux_newstat_args *args)
  208 {
  209         struct stat buf;
  210         char *path;
  211         int error;
  212 
  213         LCONVPATHEXIST(td, args->path, &path);
  214 
  215         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
  216         LFREEPATH(path);
  217         if (error)
  218                 return (error);
  219         return (newstat_copyout(&buf, args->buf));
  220 }
  221 
  222 int
  223 linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
  224 {
  225         struct stat sb;
  226         char *path;
  227         int error;
  228 
  229         LCONVPATHEXIST(td, args->path, &path);
  230 
  231         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
  232         LFREEPATH(path);
  233         if (error)
  234                 return (error);
  235         return (newstat_copyout(&sb, args->buf));
  236 }
  237 #endif
  238 
  239 int
  240 linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
  241 {
  242         struct stat buf;
  243         int error;
  244 
  245         error = kern_fstat(td, args->fd, &buf);
  246         translate_fd_major_minor(td, args->fd, &buf);
  247         if (!error)
  248                 error = newstat_copyout(&buf, args->buf);
  249 
  250         return (error);
  251 }
  252 
  253 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  254 static int
  255 stat_copyout(struct stat *buf, void *ubuf)
  256 {
  257         struct l_stat lbuf;
  258 
  259         bzero(&lbuf, sizeof(lbuf));
  260         lbuf.st_dev = dev_to_ldev(buf->st_dev);
  261         lbuf.st_ino = buf->st_ino;
  262         lbuf.st_mode = buf->st_mode;
  263         lbuf.st_nlink = buf->st_nlink;
  264         lbuf.st_uid = buf->st_uid;
  265         lbuf.st_gid = buf->st_gid;
  266         lbuf.st_rdev = buf->st_rdev;
  267         lbuf.st_size = MIN(buf->st_size, INT32_MAX);
  268         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
  269         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
  270         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
  271         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
  272         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
  273         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
  274         lbuf.st_blksize = buf->st_blksize;
  275         lbuf.st_blocks = buf->st_blocks;
  276         lbuf.st_flags = buf->st_flags;
  277         lbuf.st_gen = buf->st_gen;
  278 
  279         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
  280 }
  281 
  282 int
  283 linux_stat(struct thread *td, struct linux_stat_args *args)
  284 {
  285         struct stat buf;
  286         char *path;
  287         int error;
  288 
  289         LCONVPATHEXIST(td, args->path, &path);
  290 
  291         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
  292         if (error) {
  293                 LFREEPATH(path);
  294                 return (error);
  295         }
  296         LFREEPATH(path);
  297         return (stat_copyout(&buf, args->up));
  298 }
  299 
  300 int
  301 linux_lstat(struct thread *td, struct linux_lstat_args *args)
  302 {
  303         struct stat buf;
  304         char *path;
  305         int error;
  306 
  307         LCONVPATHEXIST(td, args->path, &path);
  308 
  309         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
  310         if (error) {
  311                 LFREEPATH(path);
  312                 return (error);
  313         }
  314         LFREEPATH(path);
  315         return (stat_copyout(&buf, args->up));
  316 }
  317 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  318 
  319 struct l_statfs {
  320         l_long          f_type;
  321         l_long          f_bsize;
  322         l_long          f_blocks;
  323         l_long          f_bfree;
  324         l_long          f_bavail;
  325         l_long          f_files;
  326         l_long          f_ffree;
  327         l_fsid_t        f_fsid;
  328         l_long          f_namelen;
  329         l_long          f_frsize;
  330         l_long          f_flags;
  331         l_long          f_spare[4];
  332 };
  333 
  334 #define LINUX_CODA_SUPER_MAGIC  0x73757245L
  335 #define LINUX_EXT2_SUPER_MAGIC  0xEF53L
  336 #define LINUX_HPFS_SUPER_MAGIC  0xf995e849L
  337 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L
  338 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L
  339 #define LINUX_NCP_SUPER_MAGIC   0x564cL
  340 #define LINUX_NFS_SUPER_MAGIC   0x6969L
  341 #define LINUX_NTFS_SUPER_MAGIC  0x5346544EL
  342 #define LINUX_PROC_SUPER_MAGIC  0x9fa0L
  343 #define LINUX_UFS_SUPER_MAGIC   0x00011954L     /* XXX - UFS_MAGIC in Linux */
  344 #define LINUX_ZFS_SUPER_MAGIC   0x2FC12FC1
  345 #define LINUX_DEVFS_SUPER_MAGIC 0x1373L
  346 #define LINUX_SHMFS_MAGIC       0x01021994
  347 
  348 static long
  349 bsd_to_linux_ftype(const char *fstypename)
  350 {
  351         int i;
  352         static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
  353                 {"ufs",     LINUX_UFS_SUPER_MAGIC},
  354                 {"zfs",     LINUX_ZFS_SUPER_MAGIC},
  355                 {"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
  356                 {"nfs",     LINUX_NFS_SUPER_MAGIC},
  357                 {"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
  358                 {"procfs",  LINUX_PROC_SUPER_MAGIC},
  359                 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
  360                 {"ntfs",    LINUX_NTFS_SUPER_MAGIC},
  361                 {"nwfs",    LINUX_NCP_SUPER_MAGIC},
  362                 {"hpfs",    LINUX_HPFS_SUPER_MAGIC},
  363                 {"coda",    LINUX_CODA_SUPER_MAGIC},
  364                 {"devfs",   LINUX_DEVFS_SUPER_MAGIC},
  365                 {"tmpfs",   LINUX_SHMFS_MAGIC},
  366                 {NULL,      0L}};
  367 
  368         for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
  369                 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
  370                         return (b2l_tbl[i].linux_type);
  371 
  372         return (0L);
  373 }
  374 
  375 static int
  376 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
  377 {
  378 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  379         uint64_t tmp;
  380 
  381 #define LINUX_HIBITS    0xffffffff00000000ULL
  382 
  383         tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
  384             bsd_statfs->f_bsize;
  385         if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
  386             (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
  387             (tmp & LINUX_HIBITS))
  388                 return (EOVERFLOW);
  389 #undef  LINUX_HIBITS
  390 #endif
  391         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
  392         linux_statfs->f_bsize = bsd_statfs->f_bsize;
  393         linux_statfs->f_blocks = bsd_statfs->f_blocks;
  394         linux_statfs->f_bfree = bsd_statfs->f_bfree;
  395         linux_statfs->f_bavail = bsd_statfs->f_bavail;
  396         linux_statfs->f_ffree = bsd_statfs->f_ffree;
  397         linux_statfs->f_files = bsd_statfs->f_files;
  398         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
  399         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
  400         linux_statfs->f_namelen = MAXNAMLEN;
  401         linux_statfs->f_frsize = bsd_statfs->f_bsize;
  402         linux_statfs->f_flags = 0;
  403         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
  404 
  405         return (0);
  406 }
  407 
  408 int
  409 linux_statfs(struct thread *td, struct linux_statfs_args *args)
  410 {
  411         struct l_statfs linux_statfs;
  412         struct statfs *bsd_statfs;
  413         char *path;
  414         int error;
  415 
  416         LCONVPATHEXIST(td, args->path, &path);
  417 
  418         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
  419         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
  420         LFREEPATH(path);
  421         if (error == 0)
  422                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
  423         free(bsd_statfs, M_STATFS);
  424         if (error != 0)
  425                 return (error);
  426         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
  427 }
  428 
  429 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  430 static void
  431 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
  432 {
  433 
  434         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
  435         linux_statfs->f_bsize = bsd_statfs->f_bsize;
  436         linux_statfs->f_blocks = bsd_statfs->f_blocks;
  437         linux_statfs->f_bfree = bsd_statfs->f_bfree;
  438         linux_statfs->f_bavail = bsd_statfs->f_bavail;
  439         linux_statfs->f_ffree = bsd_statfs->f_ffree;
  440         linux_statfs->f_files = bsd_statfs->f_files;
  441         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
  442         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
  443         linux_statfs->f_namelen = MAXNAMLEN;
  444         linux_statfs->f_frsize = bsd_statfs->f_bsize;
  445         linux_statfs->f_flags = 0;
  446         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
  447 }
  448 
  449 int
  450 linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
  451 {
  452         struct l_statfs64 linux_statfs;
  453         struct statfs *bsd_statfs;
  454         char *path;
  455         int error;
  456 
  457         if (args->bufsize != sizeof(struct l_statfs64))
  458                 return (EINVAL);
  459 
  460         LCONVPATHEXIST(td, args->path, &path);
  461 
  462         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
  463         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
  464         LFREEPATH(path);
  465         if (error == 0)
  466                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
  467         free(bsd_statfs, M_STATFS);
  468         if (error != 0)
  469                 return (error);
  470         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
  471 }
  472 
  473 int
  474 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
  475 {
  476         struct l_statfs64 linux_statfs;
  477         struct statfs *bsd_statfs;
  478         int error;
  479 
  480         if (args->bufsize != sizeof(struct l_statfs64))
  481                 return (EINVAL);
  482 
  483         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
  484         error = kern_fstatfs(td, args->fd, bsd_statfs);
  485         if (error == 0)
  486                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
  487         free(bsd_statfs, M_STATFS);
  488         if (error != 0)
  489                 return (error);
  490         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
  491 }
  492 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  493 
  494 int
  495 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
  496 {
  497         struct l_statfs linux_statfs;
  498         struct statfs *bsd_statfs;
  499         int error;
  500 
  501         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
  502         error = kern_fstatfs(td, args->fd, bsd_statfs);
  503         if (error == 0)
  504                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
  505         free(bsd_statfs, M_STATFS);
  506         if (error != 0)
  507                 return (error);
  508         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
  509 }
  510 
  511 struct l_ustat
  512 {
  513         l_daddr_t       f_tfree;
  514         l_ino_t         f_tinode;
  515         char            f_fname[6];
  516         char            f_fpack[6];
  517 };
  518 
  519 #ifdef LINUX_LEGACY_SYSCALLS
  520 int
  521 linux_ustat(struct thread *td, struct linux_ustat_args *args)
  522 {
  523 
  524         return (EOPNOTSUPP);
  525 }
  526 #endif
  527 
  528 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  529 
  530 static int
  531 stat64_copyout(struct stat *buf, void *ubuf)
  532 {
  533         struct l_stat64 lbuf;
  534 
  535         bzero(&lbuf, sizeof(lbuf));
  536         lbuf.st_dev = dev_to_ldev(buf->st_dev);
  537         lbuf.st_ino = buf->st_ino;
  538         lbuf.st_mode = buf->st_mode;
  539         lbuf.st_nlink = buf->st_nlink;
  540         lbuf.st_uid = buf->st_uid;
  541         lbuf.st_gid = buf->st_gid;
  542         lbuf.st_rdev = buf->st_rdev;
  543         lbuf.st_size = buf->st_size;
  544         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
  545         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
  546         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
  547         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
  548         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
  549         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
  550         lbuf.st_blksize = buf->st_blksize;
  551         lbuf.st_blocks = buf->st_blocks;
  552 
  553         /*
  554          * The __st_ino field makes all the difference. In the Linux kernel
  555          * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
  556          * but without the assignment to __st_ino the runtime linker refuses
  557          * to mmap(2) any shared libraries. I guess it's broken alright :-)
  558          */
  559         lbuf.__st_ino = buf->st_ino;
  560 
  561         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
  562 }
  563 
  564 int
  565 linux_stat64(struct thread *td, struct linux_stat64_args *args)
  566 {
  567         struct stat buf;
  568         char *filename;
  569         int error;
  570 
  571         LCONVPATHEXIST(td, args->filename, &filename);
  572 
  573         error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
  574         LFREEPATH(filename);
  575         if (error)
  576                 return (error);
  577         return (stat64_copyout(&buf, args->statbuf));
  578 }
  579 
  580 int
  581 linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
  582 {
  583         struct stat sb;
  584         char *filename;
  585         int error;
  586 
  587         LCONVPATHEXIST(td, args->filename, &filename);
  588 
  589         error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
  590         LFREEPATH(filename);
  591         if (error)
  592                 return (error);
  593         return (stat64_copyout(&sb, args->statbuf));
  594 }
  595 
  596 int
  597 linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
  598 {
  599         struct stat buf;
  600         int error;
  601 
  602         error = kern_fstat(td, args->fd, &buf);
  603         translate_fd_major_minor(td, args->fd, &buf);
  604         if (!error)
  605                 error = stat64_copyout(&buf, args->statbuf);
  606 
  607         return (error);
  608 }
  609 
  610 int
  611 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
  612 {
  613         char *path;
  614         int error, dfd, flag;
  615         struct stat buf;
  616 
  617         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
  618                 return (EINVAL);
  619         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
  620             AT_SYMLINK_NOFOLLOW : 0;
  621 
  622         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  623         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
  624 
  625         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
  626         if (!error)
  627                 error = stat64_copyout(&buf, args->statbuf);
  628         LFREEPATH(path);
  629 
  630         return (error);
  631 }
  632 
  633 #else /* __amd64__ && !COMPAT_LINUX32 */
  634 
  635 int
  636 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
  637 {
  638         char *path;
  639         int error, dfd, flag;
  640         struct stat buf;
  641 
  642         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
  643                 return (EINVAL);
  644         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
  645             AT_SYMLINK_NOFOLLOW : 0;
  646 
  647         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  648         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
  649 
  650         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
  651         if (error == 0)
  652                 error = newstat_copyout(&buf, args->statbuf);
  653         LFREEPATH(path);
  654 
  655         return (error);
  656 }
  657 
  658 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  659 
  660 int
  661 linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
  662 {
  663         struct mount *mp;
  664         struct vnode *vp;
  665         int error, save;
  666 
  667         error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
  668         if (error != 0)
  669                 /*
  670                  * Linux syncfs() returns only EBADF, however fgetvp()
  671                  * can return EINVAL in case of file descriptor does
  672                  * not represent a vnode. XXX.
  673                  */
  674                 return (error);
  675 
  676         mp = vp->v_mount;
  677         mtx_lock(&mountlist_mtx);
  678         error = vfs_busy(mp, MBF_MNTLSTLOCK);
  679         if (error != 0) {
  680                 /* See comment above. */
  681                 mtx_unlock(&mountlist_mtx);
  682                 goto out;
  683         }
  684         if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
  685             vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
  686                 save = curthread_pflags_set(TDP_SYNCIO);
  687                 vfs_msync(mp, MNT_NOWAIT);
  688                 VFS_SYNC(mp, MNT_NOWAIT);
  689                 curthread_pflags_restore(save);
  690                 vn_finished_write(mp);
  691         }
  692         vfs_unbusy(mp);
  693 
  694  out:
  695         vrele(vp);
  696         return (error);
  697 }

Cache object: c332974b2520aa4a01c0b34f633a7be9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.