]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linux/linux_stats.c
Relax compat.linux.osrelease checks. This way one can do eg
[FreeBSD/FreeBSD.git] / sys / compat / linux / linux_stats.c
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 (vp->v_type == VCHR && vp->v_rdev != NULL &&
69             linux_driver_get_major_minor(devtoname(vp->v_rdev),
70             &major, &minor) == 0) {
71                 sb->st_rdev = (major << 8 | minor);
72         }
73 }
74
75 static int
76 linux_kern_statat(struct thread *td, int flag, int fd, char *path,
77     enum uio_seg pathseg, struct stat *sbp)
78 {
79
80         return (kern_statat(td, flag, fd, path, pathseg, sbp,
81             translate_vnhook_major_minor));
82 }
83
84 #ifdef LINUX_LEGACY_SYSCALLS
85 static int
86 linux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
87     struct stat *sbp)
88 {
89
90         return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
91 }
92
93 static int
94 linux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
95     struct stat *sbp)
96 {
97
98         return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
99             pathseg, sbp));
100 }
101 #endif
102
103 static void
104 translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
105 {
106         struct file *fp;
107         struct vnode *vp;
108         int major, minor;
109
110         /*
111          * No capability rights required here.
112          */
113         if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
114             fget(td, fd, &cap_no_rights, &fp) != 0)
115                 return;
116         vp = fp->f_vnode;
117         if (vp != NULL && vp->v_rdev != NULL &&
118             linux_driver_get_major_minor(devtoname(vp->v_rdev),
119                                          &major, &minor) == 0) {
120                 buf->st_rdev = (major << 8 | minor);
121         } else if (fp->f_type == DTYPE_PTS) {
122                 struct tty *tp = fp->f_data;
123
124                 /* Convert the numbers for the slave device. */
125                 if (linux_driver_get_major_minor(devtoname(tp->t_dev),
126                                          &major, &minor) == 0) {
127                         buf->st_rdev = (major << 8 | minor);
128                 }
129         }
130         fdrop(fp, td);
131 }
132
133 /*
134  * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
135  * truncation of a dev_t to 16 bits gives the same result as unpacking
136  * using major() and minor() and repacking in the l_dev_t format.  This
137  * detail is hidden in dev_to_ldev().  Overflow in conversions of dev_t's
138  * are not checked for, as for other fields.
139  *
140  * dev_to_ldev() is only used for translating st_dev.  When we convert
141  * st_rdev for copying it out, it isn't really a dev_t, but has already
142  * been translated to an l_dev_t in a nontrivial way.  Translating it
143  * again would be illogical but would have no effect since the low 16
144  * bits have the same encoding.
145  *
146  * The nontrivial translation for st_rdev renumbers some devices, but not
147  * ones that can be mounted on, so it is consistent with the translation
148  * for st_dev except when the renumbering or truncation causes conflicts.
149  */
150 #define dev_to_ldev(d)  ((uint16_t)(d))
151
152 static int
153 newstat_copyout(struct stat *buf, void *ubuf)
154 {
155         struct l_newstat tbuf;
156
157         bzero(&tbuf, sizeof(tbuf));
158         tbuf.st_dev = dev_to_ldev(buf->st_dev);
159         tbuf.st_ino = buf->st_ino;
160         tbuf.st_mode = buf->st_mode;
161         tbuf.st_nlink = buf->st_nlink;
162         tbuf.st_uid = buf->st_uid;
163         tbuf.st_gid = buf->st_gid;
164         tbuf.st_rdev = buf->st_rdev;
165         tbuf.st_size = buf->st_size;
166         tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
167         tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
168         tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
169         tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
170         tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
171         tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
172         tbuf.st_blksize = buf->st_blksize;
173         tbuf.st_blocks = buf->st_blocks;
174
175         return (copyout(&tbuf, ubuf, sizeof(tbuf)));
176 }
177
178 #ifdef LINUX_LEGACY_SYSCALLS
179 int
180 linux_newstat(struct thread *td, struct linux_newstat_args *args)
181 {
182         struct stat buf;
183         char *path;
184         int error;
185
186         LCONVPATHEXIST(td, args->path, &path);
187
188         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
189         LFREEPATH(path);
190         if (error)
191                 return (error);
192         return (newstat_copyout(&buf, args->buf));
193 }
194
195 int
196 linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
197 {
198         struct stat sb;
199         char *path;
200         int error;
201
202         LCONVPATHEXIST(td, args->path, &path);
203
204         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
205         LFREEPATH(path);
206         if (error)
207                 return (error);
208         return (newstat_copyout(&sb, args->buf));
209 }
210 #endif
211
212 int
213 linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
214 {
215         struct stat buf;
216         int error;
217
218         error = kern_fstat(td, args->fd, &buf);
219         translate_fd_major_minor(td, args->fd, &buf);
220         if (!error)
221                 error = newstat_copyout(&buf, args->buf);
222
223         return (error);
224 }
225
226 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
227 static int
228 stat_copyout(struct stat *buf, void *ubuf)
229 {
230         struct l_stat lbuf;
231
232         bzero(&lbuf, sizeof(lbuf));
233         lbuf.st_dev = dev_to_ldev(buf->st_dev);
234         lbuf.st_ino = buf->st_ino;
235         lbuf.st_mode = buf->st_mode;
236         lbuf.st_nlink = buf->st_nlink;
237         lbuf.st_uid = buf->st_uid;
238         lbuf.st_gid = buf->st_gid;
239         lbuf.st_rdev = buf->st_rdev;
240         lbuf.st_size = MIN(buf->st_size, INT32_MAX);
241         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
242         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
243         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
244         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
245         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
246         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
247         lbuf.st_blksize = buf->st_blksize;
248         lbuf.st_blocks = buf->st_blocks;
249         lbuf.st_flags = buf->st_flags;
250         lbuf.st_gen = buf->st_gen;
251
252         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
253 }
254
255 int
256 linux_stat(struct thread *td, struct linux_stat_args *args)
257 {
258         struct stat buf;
259         char *path;
260         int error;
261
262         LCONVPATHEXIST(td, args->path, &path);
263
264         error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
265         if (error) {
266                 LFREEPATH(path);
267                 return (error);
268         }
269         LFREEPATH(path);
270         return (stat_copyout(&buf, args->up));
271 }
272
273 int
274 linux_lstat(struct thread *td, struct linux_lstat_args *args)
275 {
276         struct stat buf;
277         char *path;
278         int error;
279
280         LCONVPATHEXIST(td, args->path, &path);
281
282         error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
283         if (error) {
284                 LFREEPATH(path);
285                 return (error);
286         }
287         LFREEPATH(path);
288         return (stat_copyout(&buf, args->up));
289 }
290 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
291
292 struct l_statfs {
293         l_long          f_type;
294         l_long          f_bsize;
295         l_long          f_blocks;
296         l_long          f_bfree;
297         l_long          f_bavail;
298         l_long          f_files;
299         l_long          f_ffree;
300         l_fsid_t        f_fsid;
301         l_long          f_namelen;
302         l_long          f_frsize;
303         l_long          f_flags;
304         l_long          f_spare[4];
305 };
306
307 #define LINUX_CODA_SUPER_MAGIC  0x73757245L
308 #define LINUX_EXT2_SUPER_MAGIC  0xEF53L
309 #define LINUX_HPFS_SUPER_MAGIC  0xf995e849L
310 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L
311 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L
312 #define LINUX_NCP_SUPER_MAGIC   0x564cL
313 #define LINUX_NFS_SUPER_MAGIC   0x6969L
314 #define LINUX_NTFS_SUPER_MAGIC  0x5346544EL
315 #define LINUX_PROC_SUPER_MAGIC  0x9fa0L
316 #define LINUX_UFS_SUPER_MAGIC   0x00011954L     /* XXX - UFS_MAGIC in Linux */
317 #define LINUX_ZFS_SUPER_MAGIC   0x2FC12FC1
318 #define LINUX_DEVFS_SUPER_MAGIC 0x1373L
319 #define LINUX_SHMFS_MAGIC       0x01021994
320
321 static long
322 bsd_to_linux_ftype(const char *fstypename)
323 {
324         int i;
325         static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
326                 {"ufs",     LINUX_UFS_SUPER_MAGIC},
327                 {"zfs",     LINUX_ZFS_SUPER_MAGIC},
328                 {"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
329                 {"nfs",     LINUX_NFS_SUPER_MAGIC},
330                 {"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
331                 {"procfs",  LINUX_PROC_SUPER_MAGIC},
332                 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
333                 {"ntfs",    LINUX_NTFS_SUPER_MAGIC},
334                 {"nwfs",    LINUX_NCP_SUPER_MAGIC},
335                 {"hpfs",    LINUX_HPFS_SUPER_MAGIC},
336                 {"coda",    LINUX_CODA_SUPER_MAGIC},
337                 {"devfs",   LINUX_DEVFS_SUPER_MAGIC},
338                 {"tmpfs",   LINUX_SHMFS_MAGIC},
339                 {NULL,      0L}};
340
341         for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
342                 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
343                         return (b2l_tbl[i].linux_type);
344
345         return (0L);
346 }
347
348 static int
349 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
350 {
351 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
352         uint64_t tmp;
353
354 #define LINUX_HIBITS    0xffffffff00000000ULL
355
356         tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
357             bsd_statfs->f_bsize;
358         if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
359             (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
360             (tmp & LINUX_HIBITS))
361                 return (EOVERFLOW);
362 #undef  LINUX_HIBITS
363 #endif
364         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
365         linux_statfs->f_bsize = bsd_statfs->f_bsize;
366         linux_statfs->f_blocks = bsd_statfs->f_blocks;
367         linux_statfs->f_bfree = bsd_statfs->f_bfree;
368         linux_statfs->f_bavail = bsd_statfs->f_bavail;
369         linux_statfs->f_ffree = bsd_statfs->f_ffree;
370         linux_statfs->f_files = bsd_statfs->f_files;
371         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
372         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
373         linux_statfs->f_namelen = MAXNAMLEN;
374         linux_statfs->f_frsize = bsd_statfs->f_bsize;
375         linux_statfs->f_flags = 0;
376         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
377
378         return (0);
379 }
380
381 int
382 linux_statfs(struct thread *td, struct linux_statfs_args *args)
383 {
384         struct l_statfs linux_statfs;
385         struct statfs *bsd_statfs;
386         char *path;
387         int error;
388
389         LCONVPATHEXIST(td, args->path, &path);
390
391         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
392         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
393         LFREEPATH(path);
394         if (error == 0)
395                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
396         free(bsd_statfs, M_STATFS);
397         if (error != 0)
398                 return (error);
399         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
400 }
401
402 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
403 static void
404 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
405 {
406
407         linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
408         linux_statfs->f_bsize = bsd_statfs->f_bsize;
409         linux_statfs->f_blocks = bsd_statfs->f_blocks;
410         linux_statfs->f_bfree = bsd_statfs->f_bfree;
411         linux_statfs->f_bavail = bsd_statfs->f_bavail;
412         linux_statfs->f_ffree = bsd_statfs->f_ffree;
413         linux_statfs->f_files = bsd_statfs->f_files;
414         linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
415         linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
416         linux_statfs->f_namelen = MAXNAMLEN;
417         linux_statfs->f_frsize = bsd_statfs->f_bsize;
418         linux_statfs->f_flags = 0;
419         memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
420 }
421
422 int
423 linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
424 {
425         struct l_statfs64 linux_statfs;
426         struct statfs *bsd_statfs;
427         char *path;
428         int error;
429
430         if (args->bufsize != sizeof(struct l_statfs64))
431                 return (EINVAL);
432
433         LCONVPATHEXIST(td, args->path, &path);
434
435         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
436         error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
437         LFREEPATH(path);
438         if (error == 0)
439                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
440         free(bsd_statfs, M_STATFS);
441         if (error != 0)
442                 return (error);
443         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
444 }
445
446 int
447 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
448 {
449         struct l_statfs64 linux_statfs;
450         struct statfs *bsd_statfs;
451         int error;
452
453         if (args->bufsize != sizeof(struct l_statfs64))
454                 return (EINVAL);
455
456         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
457         error = kern_fstatfs(td, args->fd, bsd_statfs);
458         if (error == 0)
459                 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
460         free(bsd_statfs, M_STATFS);
461         if (error != 0)
462                 return (error);
463         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
464 }
465 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
466
467 int
468 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
469 {
470         struct l_statfs linux_statfs;
471         struct statfs *bsd_statfs;
472         int error;
473
474         bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
475         error = kern_fstatfs(td, args->fd, bsd_statfs);
476         if (error == 0)
477                 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
478         free(bsd_statfs, M_STATFS);
479         if (error != 0)
480                 return (error);
481         return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
482 }
483
484 struct l_ustat
485 {
486         l_daddr_t       f_tfree;
487         l_ino_t         f_tinode;
488         char            f_fname[6];
489         char            f_fpack[6];
490 };
491
492 #ifdef LINUX_LEGACY_SYSCALLS
493 int
494 linux_ustat(struct thread *td, struct linux_ustat_args *args)
495 {
496
497         return (EOPNOTSUPP);
498 }
499 #endif
500
501 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
502
503 static int
504 stat64_copyout(struct stat *buf, void *ubuf)
505 {
506         struct l_stat64 lbuf;
507
508         bzero(&lbuf, sizeof(lbuf));
509         lbuf.st_dev = dev_to_ldev(buf->st_dev);
510         lbuf.st_ino = buf->st_ino;
511         lbuf.st_mode = buf->st_mode;
512         lbuf.st_nlink = buf->st_nlink;
513         lbuf.st_uid = buf->st_uid;
514         lbuf.st_gid = buf->st_gid;
515         lbuf.st_rdev = buf->st_rdev;
516         lbuf.st_size = buf->st_size;
517         lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
518         lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
519         lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
520         lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
521         lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
522         lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
523         lbuf.st_blksize = buf->st_blksize;
524         lbuf.st_blocks = buf->st_blocks;
525
526         /*
527          * The __st_ino field makes all the difference. In the Linux kernel
528          * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
529          * but without the assignment to __st_ino the runtime linker refuses
530          * to mmap(2) any shared libraries. I guess it's broken alright :-)
531          */
532         lbuf.__st_ino = buf->st_ino;
533
534         return (copyout(&lbuf, ubuf, sizeof(lbuf)));
535 }
536
537 int
538 linux_stat64(struct thread *td, struct linux_stat64_args *args)
539 {
540         struct stat buf;
541         char *filename;
542         int error;
543
544         LCONVPATHEXIST(td, args->filename, &filename);
545
546         error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
547         LFREEPATH(filename);
548         if (error)
549                 return (error);
550         return (stat64_copyout(&buf, args->statbuf));
551 }
552
553 int
554 linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
555 {
556         struct stat sb;
557         char *filename;
558         int error;
559
560         LCONVPATHEXIST(td, args->filename, &filename);
561
562         error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
563         LFREEPATH(filename);
564         if (error)
565                 return (error);
566         return (stat64_copyout(&sb, args->statbuf));
567 }
568
569 int
570 linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
571 {
572         struct stat buf;
573         int error;
574
575         error = kern_fstat(td, args->fd, &buf);
576         translate_fd_major_minor(td, args->fd, &buf);
577         if (!error)
578                 error = stat64_copyout(&buf, args->statbuf);
579
580         return (error);
581 }
582
583 int
584 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
585 {
586         char *path;
587         int error, dfd, flag;
588         struct stat buf;
589
590         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
591                 return (EINVAL);
592         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
593             AT_SYMLINK_NOFOLLOW : 0;
594
595         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
596         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
597
598         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
599         if (!error)
600                 error = stat64_copyout(&buf, args->statbuf);
601         LFREEPATH(path);
602
603         return (error);
604 }
605
606 #else /* __amd64__ && !COMPAT_LINUX32 */
607
608 int
609 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
610 {
611         char *path;
612         int error, dfd, flag;
613         struct stat buf;
614
615         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
616                 return (EINVAL);
617         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
618             AT_SYMLINK_NOFOLLOW : 0;
619
620         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
621         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
622
623         error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
624         if (error == 0)
625                 error = newstat_copyout(&buf, args->statbuf);
626         LFREEPATH(path);
627
628         return (error);
629 }
630
631 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
632
633 int
634 linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
635 {
636         struct mount *mp;
637         struct vnode *vp;
638         int error, save;
639
640         error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
641         if (error != 0)
642                 /*
643                  * Linux syncfs() returns only EBADF, however fgetvp()
644                  * can return EINVAL in case of file descriptor does
645                  * not represent a vnode. XXX.
646                  */
647                 return (error);
648
649         mp = vp->v_mount;
650         mtx_lock(&mountlist_mtx);
651         error = vfs_busy(mp, MBF_MNTLSTLOCK);
652         if (error != 0) {
653                 /* See comment above. */
654                 mtx_unlock(&mountlist_mtx);
655                 goto out;
656         }
657         if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
658             vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
659                 save = curthread_pflags_set(TDP_SYNCIO);
660                 vfs_msync(mp, MNT_NOWAIT);
661                 VFS_SYNC(mp, MNT_NOWAIT);
662                 curthread_pflags_restore(save);
663                 vn_finished_write(mp);
664         }
665         vfs_unbusy(mp);
666
667  out:
668         vrele(vp);
669         return (error);
670 }