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