xref: /freebsd/sys/compat/linux/linux_stats.c (revision b99954433d42d978b257e846dbfe568e9af7b140)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 "opt_ktrace.h"
30 
31 #include <sys/param.h>
32 #include <sys/capsicum.h>
33 #include <sys/dirent.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/namei.h>
38 #include <sys/proc.h>
39 #include <sys/stat.h>
40 #include <sys/syscallsubr.h>
41 #include <sys/tty.h>
42 #include <sys/vnode.h>
43 #ifdef KTRACE
44 #include <sys/ktrace.h>
45 #endif
46 
47 #include <security/audit/audit.h>
48 
49 #ifdef COMPAT_LINUX32
50 #include <machine/../linux32/linux.h>
51 #include <machine/../linux32/linux32_proto.h>
52 #else
53 #include <machine/../linux/linux.h>
54 #include <machine/../linux/linux_proto.h>
55 #endif
56 
57 #include <compat/linux/linux.h>
58 #include <compat/linux/linux_file.h>
59 #include <compat/linux/linux_util.h>
60 
61 /*
62  * Linux dev_t conversion routines.
63  *
64  * As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity
65  * with 12 bits set asaid for the major number and 20 for the minor number.
66  * The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the
67  * major number and m is a hex digit of the minor number.
68  * The user-space dev_t encoded as mmmM MMmm, where M and m is the major
69  * and minor numbers accordingly. This is downward compatible with legacy
70  * systems where dev_t is 16 bits wide, encoded as MMmm.
71  * In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers,
72  * encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux
73  * kernel and with legacy systems where dev_t is 16 bits wide.
74  *
75  * In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers
76  * are encoded as MMMmmmMm, therefore conversion of the device numbers between
77  * Linux user-space and FreeBSD kernel required.
78  */
79 static l_dev_t
80 linux_encode_dev(int _major, int _minor)
81 {
82 
83 	return ((_minor & 0xff) | ((_major & 0xfff) << 8) |
84 	    (((_minor & ~0xff) << 12) & 0xfff00000));
85 }
86 
87 static l_dev_t
88 linux_new_encode_dev(dev_t _dev)
89 {
90 
91 	return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
92 }
93 
94 static int
95 linux_encode_major(dev_t _dev)
96 {
97 
98 	return (_dev == NODEV ? 0 : major(_dev) & 0xfff);
99 }
100 
101 static int
102 linux_encode_minor(dev_t _dev)
103 {
104 
105 	return (_dev == NODEV ? 0 : minor(_dev) & 0xfffff);
106 }
107 
108 static int
109 linux_kern_fstat(struct thread *td, int fd, struct stat *sbp)
110 {
111 	struct vnode *vp;
112 	struct file *fp;
113 	int error;
114 
115 	AUDIT_ARG_FD(fd);
116 
117 	error = fget(td, fd, &cap_fstat_rights, &fp);
118 	if (__predict_false(error != 0))
119 		return (error);
120 
121 	AUDIT_ARG_FILE(td->td_proc, fp);
122 
123 	error = fo_stat(fp, sbp, td->td_ucred);
124 	if (error == 0 && (vp = fp->f_vnode) != NULL)
125 		translate_vnhook_major_minor(vp, sbp);
126 	fdrop(fp, td);
127 #ifdef KTRACE
128 	if (KTRPOINT(td, KTR_STRUCT))
129 		ktrstat_error(sbp, error);
130 #endif
131 	return (error);
132 }
133 
134 static int
135 linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
136     enum uio_seg pathseg, struct stat *sbp)
137 {
138 	struct nameidata nd;
139 	int error;
140 
141 	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
142 	    AT_EMPTY_PATH)) != 0)
143 		return (EINVAL);
144 
145 	NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH |
146 	    AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF |
147 	    AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights);
148 
149 	if ((error = namei(&nd)) != 0) {
150 		if (error == ENOTDIR &&
151 		    (nd.ni_resflags & NIRES_EMPTYPATH) != 0)
152 			error = linux_kern_fstat(td, fd, sbp);
153 		return (error);
154 	}
155 	error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED);
156 	if (error == 0)
157 		translate_vnhook_major_minor(nd.ni_vp, sbp);
158 	NDFREE_PNBUF(&nd);
159 	vput(nd.ni_vp);
160 #ifdef KTRACE
161 	if (KTRPOINT(td, KTR_STRUCT))
162 		ktrstat_error(sbp, error);
163 #endif
164 	return (error);
165 }
166 
167 #ifdef LINUX_LEGACY_SYSCALLS
168 static int
169 linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg,
170     struct stat *sbp)
171 {
172 
173 	return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
174 }
175 
176 static int
177 linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
178     struct stat *sbp)
179 {
180 
181 	return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
182 	    pathseg, sbp));
183 }
184 #endif
185 
186 static int
187 newstat_copyout(struct stat *buf, void *ubuf)
188 {
189 	struct l_newstat tbuf;
190 
191 	bzero(&tbuf, sizeof(tbuf));
192 	tbuf.st_dev = linux_new_encode_dev(buf->st_dev);
193 	tbuf.st_ino = buf->st_ino;
194 	tbuf.st_mode = buf->st_mode;
195 	tbuf.st_nlink = buf->st_nlink;
196 	tbuf.st_uid = buf->st_uid;
197 	tbuf.st_gid = buf->st_gid;
198 	tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
199 	tbuf.st_size = buf->st_size;
200 	tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
201 	tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
202 	tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
203 	tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
204 	tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
205 	tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
206 	tbuf.st_blksize = buf->st_blksize;
207 	tbuf.st_blocks = buf->st_blocks;
208 
209 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
210 }
211 
212 
213 #ifdef LINUX_LEGACY_SYSCALLS
214 int
215 linux_newstat(struct thread *td, struct linux_newstat_args *args)
216 {
217 	struct stat buf;
218 	int error;
219 
220 	error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
221 	if (error)
222 		return (error);
223 	return (newstat_copyout(&buf, args->buf));
224 }
225 
226 int
227 linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
228 {
229 	struct stat sb;
230 	int error;
231 
232 	error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
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 = linux_kern_fstat(td, args->fd, &buf);
246 	if (!error)
247 		error = newstat_copyout(&buf, args->buf);
248 
249 	return (error);
250 }
251 
252 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
253 
254 static __inline uint16_t
255 linux_old_encode_dev(dev_t _dev)
256 {
257 
258 	return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
259 }
260 
261 static int
262 old_stat_copyout(struct stat *buf, void *ubuf)
263 {
264 	struct l_old_stat lbuf;
265 
266 	bzero(&lbuf, sizeof(lbuf));
267 	lbuf.st_dev = linux_old_encode_dev(buf->st_dev);
268 	lbuf.st_ino = buf->st_ino;
269 	lbuf.st_mode = buf->st_mode;
270 	lbuf.st_nlink = buf->st_nlink;
271 	lbuf.st_uid = buf->st_uid;
272 	lbuf.st_gid = buf->st_gid;
273 	lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev);
274 	lbuf.st_size = MIN(buf->st_size, INT32_MAX);
275 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
276 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
277 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
278 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
279 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
280 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
281 	lbuf.st_blksize = buf->st_blksize;
282 	lbuf.st_blocks = buf->st_blocks;
283 	lbuf.st_flags = buf->st_flags;
284 	lbuf.st_gen = buf->st_gen;
285 
286 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
287 }
288 
289 int
290 linux_stat(struct thread *td, struct linux_stat_args *args)
291 {
292 	struct stat buf;
293 	int error;
294 
295 	error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
296 	if (error) {
297 		return (error);
298 	}
299 	return (old_stat_copyout(&buf, args->up));
300 }
301 
302 int
303 linux_lstat(struct thread *td, struct linux_lstat_args *args)
304 {
305 	struct stat buf;
306 	int error;
307 
308 	error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
309 	if (error) {
310 		return (error);
311 	}
312 	return (old_stat_copyout(&buf, args->up));
313 }
314 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
315 
316 struct l_statfs {
317 	l_long		f_type;
318 	l_long		f_bsize;
319 	l_long		f_blocks;
320 	l_long		f_bfree;
321 	l_long		f_bavail;
322 	l_long		f_files;
323 	l_long		f_ffree;
324 	l_fsid_t	f_fsid;
325 	l_long		f_namelen;
326 	l_long		f_frsize;
327 	l_long		f_flags;
328 	l_long		f_spare[4];
329 };
330 
331 #define	LINUX_CODA_SUPER_MAGIC	0x73757245L
332 #define	LINUX_EXT2_SUPER_MAGIC	0xEF53L
333 #define	LINUX_HPFS_SUPER_MAGIC	0xf995e849L
334 #define	LINUX_ISOFS_SUPER_MAGIC	0x9660L
335 #define	LINUX_MSDOS_SUPER_MAGIC	0x4d44L
336 #define	LINUX_NCP_SUPER_MAGIC	0x564cL
337 #define	LINUX_NFS_SUPER_MAGIC	0x6969L
338 #define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
339 #define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
340 #define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
341 #define	LINUX_ZFS_SUPER_MAGIC	0x2FC12FC1
342 #define	LINUX_DEVFS_SUPER_MAGIC	0x1373L
343 #define	LINUX_SHMFS_MAGIC	0x01021994
344 #define	LINUX_SYSFS_MAGIC	0x62656572
345 
346 static long
347 bsd_to_linux_ftype(const char *fstypename)
348 {
349 	int i;
350 	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
351 		{"ufs",      LINUX_UFS_SUPER_MAGIC},
352 		{"zfs",      LINUX_ZFS_SUPER_MAGIC},
353 		{"cd9660",   LINUX_ISOFS_SUPER_MAGIC},
354 		{"nfs",      LINUX_NFS_SUPER_MAGIC},
355 		{"ext2fs",   LINUX_EXT2_SUPER_MAGIC},
356 		{"procfs",   LINUX_PROC_SUPER_MAGIC},
357 		{"msdosfs",  LINUX_MSDOS_SUPER_MAGIC},
358 		{"ntfs",     LINUX_NTFS_SUPER_MAGIC},
359 		{"nwfs",     LINUX_NCP_SUPER_MAGIC},
360 		{"hpfs",     LINUX_HPFS_SUPER_MAGIC},
361 		{"coda",     LINUX_CODA_SUPER_MAGIC},
362 		{"devfs",    LINUX_DEVFS_SUPER_MAGIC},
363 		{"tmpfs",    LINUX_SHMFS_MAGIC},
364 		{"linsysfs", LINUX_SYSFS_MAGIC},
365 		{NULL,       0L}};
366 
367 	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
368 		if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
369 			return (b2l_tbl[i].linux_type);
370 
371 	return (0L);
372 }
373 
374 static int
375 bsd_to_linux_mnt_flags(int f_flags)
376 {
377 	int flags = LINUX_ST_VALID;
378 
379 	if (f_flags & MNT_RDONLY)
380 		flags |= LINUX_ST_RDONLY;
381 	if (f_flags & MNT_NOEXEC)
382 		flags |= LINUX_ST_NOEXEC;
383 	if (f_flags & MNT_NOSUID)
384 		flags |= LINUX_ST_NOSUID;
385 	if (f_flags & MNT_NOATIME)
386 		flags |= LINUX_ST_NOATIME;
387 	if (f_flags & MNT_NOSYMFOLLOW)
388 		flags |= LINUX_ST_NOSYMFOLLOW;
389 	if (f_flags & MNT_SYNCHRONOUS)
390 		flags |= LINUX_ST_SYNCHRONOUS;
391 
392 	return (flags);
393 }
394 
395 static int
396 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
397 {
398 
399 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
400 	statfs_scale_blocks(bsd_statfs, INT32_MAX);
401 #endif
402 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
403 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
404 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
405 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
406 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
407 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
408 	linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
409 	linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
410 #else
411 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
412 	linux_statfs->f_files = bsd_statfs->f_files;
413 #endif
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 = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
419 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
420 
421 	return (0);
422 }
423 
424 int
425 linux_statfs(struct thread *td, struct linux_statfs_args *args)
426 {
427 	struct l_statfs linux_statfs;
428 	struct statfs *bsd_statfs;
429 	int error;
430 
431 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
432 	error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
433 	if (error == 0)
434 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
435 	free(bsd_statfs, M_STATFS);
436 	if (error != 0)
437 		return (error);
438 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
439 }
440 
441 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
442 static void
443 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
444 {
445 
446 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
447 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
448 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
449 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
450 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
451 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
452 	linux_statfs->f_files = bsd_statfs->f_files;
453 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
454 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
455 	linux_statfs->f_namelen = MAXNAMLEN;
456 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
457 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
458 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
459 }
460 
461 int
462 linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
463 {
464 	struct l_statfs64 linux_statfs;
465 	struct statfs *bsd_statfs;
466 	int error;
467 
468 	if (args->bufsize != sizeof(struct l_statfs64))
469 		return (EINVAL);
470 
471 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
472 	error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
473 	if (error == 0)
474 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
475 	free(bsd_statfs, M_STATFS);
476 	if (error != 0)
477 		return (error);
478 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
479 }
480 
481 int
482 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
483 {
484 	struct l_statfs64 linux_statfs;
485 	struct statfs *bsd_statfs;
486 	int error;
487 
488 	if (args->bufsize != sizeof(struct l_statfs64))
489 		return (EINVAL);
490 
491 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
492 	error = kern_fstatfs(td, args->fd, bsd_statfs);
493 	if (error == 0)
494 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
495 	free(bsd_statfs, M_STATFS);
496 	if (error != 0)
497 		return (error);
498 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
499 }
500 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
501 
502 int
503 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
504 {
505 	struct l_statfs linux_statfs;
506 	struct statfs *bsd_statfs;
507 	int error;
508 
509 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
510 	error = kern_fstatfs(td, args->fd, bsd_statfs);
511 	if (error == 0)
512 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
513 	free(bsd_statfs, M_STATFS);
514 	if (error != 0)
515 		return (error);
516 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
517 }
518 
519 struct l_ustat
520 {
521 	l_daddr_t	f_tfree;
522 	l_ino_t		f_tinode;
523 	char		f_fname[6];
524 	char		f_fpack[6];
525 };
526 
527 #ifdef LINUX_LEGACY_SYSCALLS
528 int
529 linux_ustat(struct thread *td, struct linux_ustat_args *args)
530 {
531 
532 	return (EOPNOTSUPP);
533 }
534 #endif
535 
536 /*
537  * Convert Linux stat flags to BSD flags.  Return value indicates successful
538  * conversion (no unknown flags).
539  */
540 static bool
541 linux_to_bsd_stat_flags(int linux_flags, int *out_flags)
542 {
543 	int flags, unsupported;
544 
545 	unsupported = linux_flags & ~(LINUX_AT_SYMLINK_NOFOLLOW |
546 	    LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT);
547 	if (unsupported != 0) {
548 		*out_flags = unsupported;
549 		return (false);
550 	}
551 
552 	flags = 0;
553 	if (linux_flags & LINUX_AT_SYMLINK_NOFOLLOW)
554 		flags |= AT_SYMLINK_NOFOLLOW;
555 	if (linux_flags & LINUX_AT_EMPTY_PATH)
556 		flags |= AT_EMPTY_PATH;
557 	*out_flags = flags;
558 	return (true);
559 }
560 
561 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
562 
563 static int
564 stat64_copyout(struct stat *buf, void *ubuf)
565 {
566 	struct l_stat64 lbuf;
567 
568 	bzero(&lbuf, sizeof(lbuf));
569 	lbuf.st_dev = linux_new_encode_dev(buf->st_dev);
570 	lbuf.st_ino = buf->st_ino;
571 	lbuf.st_mode = buf->st_mode;
572 	lbuf.st_nlink = buf->st_nlink;
573 	lbuf.st_uid = buf->st_uid;
574 	lbuf.st_gid = buf->st_gid;
575 	lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
576 	lbuf.st_size = buf->st_size;
577 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
578 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
579 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
580 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
581 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
582 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
583 	lbuf.st_blksize = buf->st_blksize;
584 	lbuf.st_blocks = buf->st_blocks;
585 
586 	/*
587 	 * The __st_ino field makes all the difference. In the Linux kernel
588 	 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
589 	 * but without the assignment to __st_ino the runtime linker refuses
590 	 * to mmap(2) any shared libraries. I guess it's broken alright :-)
591 	 */
592 	lbuf.__st_ino = buf->st_ino;
593 
594 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
595 }
596 
597 int
598 linux_stat64(struct thread *td, struct linux_stat64_args *args)
599 {
600 	struct stat buf;
601 	int error;
602 
603 	error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
604 	if (error)
605 		return (error);
606 	return (stat64_copyout(&buf, args->statbuf));
607 }
608 
609 int
610 linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
611 {
612 	struct stat sb;
613 	int error;
614 
615 	error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
616 	if (error)
617 		return (error);
618 	return (stat64_copyout(&sb, args->statbuf));
619 }
620 
621 int
622 linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
623 {
624 	struct stat buf;
625 	int error;
626 
627 	error = linux_kern_fstat(td, args->fd, &buf);
628 	if (!error)
629 		error = stat64_copyout(&buf, args->statbuf);
630 
631 	return (error);
632 }
633 
634 int
635 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
636 {
637 	int error, dfd, flags;
638 	struct stat buf;
639 
640 	if (!linux_to_bsd_stat_flags(args->flag, &flags)) {
641 		linux_msg(td, "fstatat64 unsupported flags 0x%x", flags);
642 		return (EINVAL);
643 	}
644 
645 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
646 	error = linux_kern_statat(td, flags, dfd, args->pathname,
647 	    UIO_USERSPACE, &buf);
648 	if (error == 0)
649 		error = stat64_copyout(&buf, args->statbuf);
650 
651 	return (error);
652 }
653 
654 #else /* __amd64__ && !COMPAT_LINUX32 */
655 
656 int
657 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
658 {
659 	int error, dfd, flags;
660 	struct stat buf;
661 
662 	if (!linux_to_bsd_stat_flags(args->flag, &flags)) {
663 		linux_msg(td, "fstatat unsupported flags 0x%x", flags);
664 		return (EINVAL);
665 	}
666 
667 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
668 	error = linux_kern_statat(td, flags, dfd, args->pathname,
669 	    UIO_USERSPACE, &buf);
670 	if (error == 0)
671 		error = newstat_copyout(&buf, args->statbuf);
672 
673 	return (error);
674 }
675 
676 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
677 
678 int
679 linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
680 {
681 	struct mount *mp;
682 	struct vnode *vp;
683 	int error, save;
684 
685 	error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
686 	if (error != 0)
687 		/*
688 		 * Linux syncfs() returns only EBADF, however fgetvp()
689 		 * can return EINVAL in case of file descriptor does
690 		 * not represent a vnode. XXX.
691 		 */
692 		return (error);
693 
694 	mp = vp->v_mount;
695 	mtx_lock(&mountlist_mtx);
696 	error = vfs_busy(mp, MBF_MNTLSTLOCK);
697 	if (error != 0) {
698 		/* See comment above. */
699 		mtx_unlock(&mountlist_mtx);
700 		goto out;
701 	}
702 	if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
703 	    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
704 		save = curthread_pflags_set(TDP_SYNCIO);
705 		vfs_periodic(mp, MNT_NOWAIT);
706 		VFS_SYNC(mp, MNT_NOWAIT);
707 		curthread_pflags_restore(save);
708 		vn_finished_write(mp);
709 	}
710 	vfs_unbusy(mp);
711 
712  out:
713 	vrele(vp);
714 	return (error);
715 }
716 
717 static int
718 statx_copyout(struct stat *buf, void *ubuf)
719 {
720 	struct l_statx tbuf;
721 
722 	bzero(&tbuf, sizeof(tbuf));
723 	tbuf.stx_mask = STATX_ALL;
724 	tbuf.stx_blksize = buf->st_blksize;
725 	tbuf.stx_attributes = 0;
726 	tbuf.stx_nlink = buf->st_nlink;
727 	tbuf.stx_uid = buf->st_uid;
728 	tbuf.stx_gid = buf->st_gid;
729 	tbuf.stx_mode = buf->st_mode;
730 	tbuf.stx_ino = buf->st_ino;
731 	tbuf.stx_size = buf->st_size;
732 	tbuf.stx_blocks = buf->st_blocks;
733 
734 	tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
735 	tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
736 	tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
737 	tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
738 	tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
739 	tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
740 	tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
741 	tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
742 	tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev);
743 	tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev);
744 	tbuf.stx_dev_major = linux_encode_major(buf->st_dev);
745 	tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev);
746 
747 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
748 }
749 
750 int
751 linux_statx(struct thread *td, struct linux_statx_args *args)
752 {
753 	int error, dirfd, flags;
754 	struct stat buf;
755 
756 	if (!linux_to_bsd_stat_flags(args->flags, &flags)) {
757 		linux_msg(td, "statx unsupported flags 0x%x", flags);
758 		return (EINVAL);
759 	}
760 
761 	dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
762 	error = linux_kern_statat(td, flags, dirfd, args->pathname,
763 	    UIO_USERSPACE, &buf);
764 	if (error == 0)
765 		error = statx_copyout(&buf, args->statxbuf);
766 
767 	return (error);
768 }
769