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