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