xref: /freebsd/sys/compat/linux/linux_stats.c (revision 166e2e5a9e87d32dbfc7838903904673873f1e71)
1c21dee17SSøren Schmidt /*-
20ba1b365SEd Maste  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37f2d13d6SPedro F. Giffuni  *
49a14aa01SUlrich Spörlein  * Copyright (c) 1994-1995 Søren Schmidt
5c21dee17SSøren Schmidt  * All rights reserved.
6c21dee17SSøren Schmidt  *
7c21dee17SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
8c21dee17SSøren Schmidt  * modification, are permitted provided that the following conditions
9c21dee17SSøren Schmidt  * are met:
10c21dee17SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
110ba1b365SEd Maste  *    notice, this list of conditions and the following disclaimer.
12c21dee17SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
13c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
14c21dee17SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
15c21dee17SSøren Schmidt  *
160ba1b365SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170ba1b365SEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180ba1b365SEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190ba1b365SEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200ba1b365SEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210ba1b365SEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220ba1b365SEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230ba1b365SEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240ba1b365SEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250ba1b365SEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260ba1b365SEd Maste  * SUCH DAMAGE.
27c21dee17SSøren Schmidt  */
28c21dee17SSøren Schmidt 
2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h>
3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$");
3116dbc7f2SDavid E. O'Brien 
32cb858340SDmitry Chagin #include "opt_ktrace.h"
33cb858340SDmitry Chagin 
34c21dee17SSøren Schmidt #include <sys/param.h>
359802eb9eSDmitry Chagin #include <sys/capsicum.h>
36c21dee17SSøren Schmidt #include <sys/dirent.h>
37d8e53d94SDmitry Chagin #include <sys/lock.h>
3885422e62SBruce Evans #include <sys/malloc.h>
39d8e53d94SDmitry Chagin #include <sys/mutex.h>
40cb858340SDmitry Chagin #include <sys/namei.h>
41d8e53d94SDmitry Chagin #include <sys/proc.h>
42c21dee17SSøren Schmidt #include <sys/stat.h>
43f7a25872SJohn Baldwin #include <sys/syscallsubr.h>
44bc093719SEd Schouten #include <sys/tty.h>
45c21dee17SSøren Schmidt #include <sys/vnode.h>
46cb858340SDmitry Chagin #ifdef KTRACE
47cb858340SDmitry Chagin #include <sys/ktrace.h>
48cb858340SDmitry Chagin #endif
49c21dee17SSøren Schmidt 
50994ed958SDmitry Chagin #include <security/audit/audit.h>
51994ed958SDmitry Chagin 
521997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
534af27623STim J. Robbins #include <machine/../linux32/linux.h>
544af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
551997c537SDavid E. O'Brien #else
561997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
571997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
584af27623STim J. Robbins #endif
5985422e62SBruce Evans 
60*166e2e5aSDmitry Chagin #include <compat/linux/linux.h>
6148b05c3fSKonstantin Belousov #include <compat/linux/linux_file.h>
622a38f51cSDmitry Chagin #include <compat/linux/linux_util.h>
63762e6b85SEivind Eklund 
640eee862aSEd Schouten 
650eee862aSEd Schouten static int
66994ed958SDmitry Chagin linux_kern_fstat(struct thread *td, int fd, struct stat *sbp)
67994ed958SDmitry Chagin {
68994ed958SDmitry Chagin 	struct vnode *vp;
69994ed958SDmitry Chagin 	struct file *fp;
70994ed958SDmitry Chagin 	int error;
71994ed958SDmitry Chagin 
72994ed958SDmitry Chagin 	AUDIT_ARG_FD(fd);
73994ed958SDmitry Chagin 
74994ed958SDmitry Chagin 	error = fget(td, fd, &cap_fstat_rights, &fp);
75994ed958SDmitry Chagin 	if (__predict_false(error != 0))
76994ed958SDmitry Chagin 		return (error);
77994ed958SDmitry Chagin 
78994ed958SDmitry Chagin 	AUDIT_ARG_FILE(td->td_proc, fp);
79994ed958SDmitry Chagin 
80994ed958SDmitry Chagin 	error = fo_stat(fp, sbp, td->td_ucred);
81994ed958SDmitry Chagin 	if (error == 0 && (vp = fp->f_vnode) != NULL)
82994ed958SDmitry Chagin 		translate_vnhook_major_minor(vp, sbp);
83994ed958SDmitry Chagin 	fdrop(fp, td);
84994ed958SDmitry Chagin #ifdef KTRACE
85994ed958SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
86994ed958SDmitry Chagin 		ktrstat_error(sbp, error);
87994ed958SDmitry Chagin #endif
88994ed958SDmitry Chagin 	return (error);
89994ed958SDmitry Chagin }
90994ed958SDmitry Chagin 
91994ed958SDmitry Chagin static int
92a125ed50SMateusz Guzik linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
930eee862aSEd Schouten     enum uio_seg pathseg, struct stat *sbp)
940eee862aSEd Schouten {
95cb858340SDmitry Chagin 	struct nameidata nd;
96cb858340SDmitry Chagin 	int error;
970eee862aSEd Schouten 
98cb858340SDmitry Chagin 	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
99cb858340SDmitry Chagin 	    AT_EMPTY_PATH)) != 0)
100cb858340SDmitry Chagin 		return (EINVAL);
101cb858340SDmitry Chagin 
102cb858340SDmitry Chagin 	NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH |
103cb858340SDmitry Chagin 	    AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF |
104cb858340SDmitry Chagin 	    AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights);
105cb858340SDmitry Chagin 
106cb858340SDmitry Chagin 	if ((error = namei(&nd)) != 0) {
107cb858340SDmitry Chagin 		if (error == ENOTDIR &&
108cb858340SDmitry Chagin 		    (nd.ni_resflags & NIRES_EMPTYPATH) != 0)
109994ed958SDmitry Chagin 			error = linux_kern_fstat(td, fd, sbp);
110cb858340SDmitry Chagin 		return (error);
111cb858340SDmitry Chagin 	}
112cb858340SDmitry Chagin 	error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED);
113cb858340SDmitry Chagin 	if (error == 0)
114cb858340SDmitry Chagin 		translate_vnhook_major_minor(nd.ni_vp, sbp);
115cb858340SDmitry Chagin 	NDFREE_PNBUF(&nd);
116cb858340SDmitry Chagin 	vput(nd.ni_vp);
117cb858340SDmitry Chagin #ifdef KTRACE
118cb858340SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
119cb858340SDmitry Chagin 		ktrstat_error(sbp, error);
120cb858340SDmitry Chagin #endif
121cb858340SDmitry Chagin 	return (error);
1220eee862aSEd Schouten }
1230eee862aSEd Schouten 
124931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
1250eee862aSEd Schouten static int
126a125ed50SMateusz Guzik linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg,
1270eee862aSEd Schouten     struct stat *sbp)
1280eee862aSEd Schouten {
1290eee862aSEd Schouten 
1300eee862aSEd Schouten 	return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
1310eee862aSEd Schouten }
1320eee862aSEd Schouten 
1330eee862aSEd Schouten static int
134a125ed50SMateusz Guzik linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
1350eee862aSEd Schouten     struct stat *sbp)
1360eee862aSEd Schouten {
1370eee862aSEd Schouten 
1380eee862aSEd Schouten 	return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
1390eee862aSEd Schouten 	    pathseg, sbp));
1400eee862aSEd Schouten }
141931e2a1aSEd Maste #endif
1420eee862aSEd Schouten 
143bbbc2d96SPoul-Henning Kamp static int
144bbbc2d96SPoul-Henning Kamp newstat_copyout(struct stat *buf, void *ubuf)
145bbbc2d96SPoul-Henning Kamp {
146bbbc2d96SPoul-Henning Kamp 	struct l_newstat tbuf;
147bbbc2d96SPoul-Henning Kamp 
148bbbc2d96SPoul-Henning Kamp 	bzero(&tbuf, sizeof(tbuf));
149*166e2e5aSDmitry Chagin 	tbuf.st_dev = linux_new_encode_dev(buf->st_dev);
150bbbc2d96SPoul-Henning Kamp 	tbuf.st_ino = buf->st_ino;
151bbbc2d96SPoul-Henning Kamp 	tbuf.st_mode = buf->st_mode;
152bbbc2d96SPoul-Henning Kamp 	tbuf.st_nlink = buf->st_nlink;
153bbbc2d96SPoul-Henning Kamp 	tbuf.st_uid = buf->st_uid;
154bbbc2d96SPoul-Henning Kamp 	tbuf.st_gid = buf->st_gid;
155*166e2e5aSDmitry Chagin 	tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
156bbbc2d96SPoul-Henning Kamp 	tbuf.st_size = buf->st_size;
157510ea843SEd Schouten 	tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
158510ea843SEd Schouten 	tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
159510ea843SEd Schouten 	tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
160510ea843SEd Schouten 	tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
161510ea843SEd Schouten 	tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
162510ea843SEd Schouten 	tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
163bbbc2d96SPoul-Henning Kamp 	tbuf.st_blksize = buf->st_blksize;
164bbbc2d96SPoul-Henning Kamp 	tbuf.st_blocks = buf->st_blocks;
165bbbc2d96SPoul-Henning Kamp 
1664e0eaf69SMarcel Moolenaar 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
167c21dee17SSøren Schmidt }
168c21dee17SSøren Schmidt 
1692362ad45SPhilippe Michaud-Boudreault 
170931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
171c21dee17SSøren Schmidt int
172b40ce416SJulian Elischer linux_newstat(struct thread *td, struct linux_newstat_args *args)
173c21dee17SSøren Schmidt {
174c21dee17SSøren Schmidt 	struct stat buf;
175206a5d3aSIan Dowse 	char *path;
176c21dee17SSøren Schmidt 	int error;
177d66a5066SPeter Wemm 
178a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
179a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
180a125ed50SMateusz Guzik 	} else {
181af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
1820eee862aSEd Schouten 		error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
183206a5d3aSIan Dowse 		LFREEPATH(path);
184a125ed50SMateusz Guzik 	}
1854e0eaf69SMarcel Moolenaar 	if (error)
1864e0eaf69SMarcel Moolenaar 		return (error);
1874e0eaf69SMarcel Moolenaar 	return (newstat_copyout(&buf, args->buf));
188c21dee17SSøren Schmidt }
189c21dee17SSøren Schmidt 
190c21dee17SSøren Schmidt int
191b40ce416SJulian Elischer linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
192c21dee17SSøren Schmidt {
1934e0eaf69SMarcel Moolenaar 	struct stat sb;
194206a5d3aSIan Dowse 	char *path;
195f7a25872SJohn Baldwin 	int error;
196d66a5066SPeter Wemm 
197a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
198a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
199a125ed50SMateusz Guzik 	} else {
200af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2010eee862aSEd Schouten 		error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
202206a5d3aSIan Dowse 		LFREEPATH(path);
203a125ed50SMateusz Guzik 	}
204d66a5066SPeter Wemm 	if (error)
205d66a5066SPeter Wemm 		return (error);
2065002a60fSMarcel Moolenaar 	return (newstat_copyout(&sb, args->buf));
207d66a5066SPeter Wemm }
208931e2a1aSEd Maste #endif
209c21dee17SSøren Schmidt 
210c21dee17SSøren Schmidt int
211b40ce416SJulian Elischer linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
212c21dee17SSøren Schmidt {
213c21dee17SSøren Schmidt 	struct stat buf;
214c21dee17SSøren Schmidt 	int error;
215c21dee17SSøren Schmidt 
216994ed958SDmitry Chagin 	error = linux_kern_fstat(td, args->fd, &buf);
217c21dee17SSøren Schmidt 	if (!error)
218c21dee17SSøren Schmidt 		error = newstat_copyout(&buf, args->buf);
2194e0eaf69SMarcel Moolenaar 
2204e0eaf69SMarcel Moolenaar 	return (error);
221c21dee17SSøren Schmidt }
222c21dee17SSøren Schmidt 
2237f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
224*166e2e5aSDmitry Chagin 
225*166e2e5aSDmitry Chagin static __inline uint16_t
226*166e2e5aSDmitry Chagin linux_old_encode_dev(dev_t _dev)
227*166e2e5aSDmitry Chagin {
228*166e2e5aSDmitry Chagin 
229*166e2e5aSDmitry Chagin 	return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
230*166e2e5aSDmitry Chagin }
231*166e2e5aSDmitry Chagin 
2325c8919adSAlexander Leidinger static int
233a408fc09SDmitry Chagin old_stat_copyout(struct stat *buf, void *ubuf)
2345c8919adSAlexander Leidinger {
235a408fc09SDmitry Chagin 	struct l_old_stat lbuf;
2365c8919adSAlexander Leidinger 
2375c8919adSAlexander Leidinger 	bzero(&lbuf, sizeof(lbuf));
238*166e2e5aSDmitry Chagin 	lbuf.st_dev = linux_old_encode_dev(buf->st_dev);
2395c8919adSAlexander Leidinger 	lbuf.st_ino = buf->st_ino;
2405c8919adSAlexander Leidinger 	lbuf.st_mode = buf->st_mode;
2415c8919adSAlexander Leidinger 	lbuf.st_nlink = buf->st_nlink;
2425c8919adSAlexander Leidinger 	lbuf.st_uid = buf->st_uid;
2435c8919adSAlexander Leidinger 	lbuf.st_gid = buf->st_gid;
244*166e2e5aSDmitry Chagin 	lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev);
245372639f9SBruce Evans 	lbuf.st_size = MIN(buf->st_size, INT32_MAX);
246510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
247510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
248510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
249510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
250510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
251510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
2525c8919adSAlexander Leidinger 	lbuf.st_blksize = buf->st_blksize;
2535c8919adSAlexander Leidinger 	lbuf.st_blocks = buf->st_blocks;
2545c8919adSAlexander Leidinger 	lbuf.st_flags = buf->st_flags;
2555c8919adSAlexander Leidinger 	lbuf.st_gen = buf->st_gen;
2565c8919adSAlexander Leidinger 
2575c8919adSAlexander Leidinger 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
2585c8919adSAlexander Leidinger }
2595c8919adSAlexander Leidinger 
2605c8919adSAlexander Leidinger int
2615c8919adSAlexander Leidinger linux_stat(struct thread *td, struct linux_stat_args *args)
2625c8919adSAlexander Leidinger {
2635c8919adSAlexander Leidinger 	struct stat buf;
26415b78ac5SKonstantin Belousov 	char *path;
2655c8919adSAlexander Leidinger 	int error;
26615b78ac5SKonstantin Belousov 
267a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
268a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
269a125ed50SMateusz Guzik 	} else {
270af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2710eee862aSEd Schouten 		error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
27215b78ac5SKonstantin Belousov 		LFREEPATH(path);
273a125ed50SMateusz Guzik 	}
274a125ed50SMateusz Guzik 	if (error) {
2755c8919adSAlexander Leidinger 		return (error);
276d075105dSKonstantin Belousov 	}
277a408fc09SDmitry Chagin 	return (old_stat_copyout(&buf, args->up));
2785c8919adSAlexander Leidinger }
2795c8919adSAlexander Leidinger 
2805c8919adSAlexander Leidinger int
2815c8919adSAlexander Leidinger linux_lstat(struct thread *td, struct linux_lstat_args *args)
2825c8919adSAlexander Leidinger {
2835c8919adSAlexander Leidinger 	struct stat buf;
28415b78ac5SKonstantin Belousov 	char *path;
2855c8919adSAlexander Leidinger 	int error;
2865c8919adSAlexander Leidinger 
287a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
288a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
289a125ed50SMateusz Guzik 	} else {
290af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2910eee862aSEd Schouten 		error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
29215b78ac5SKonstantin Belousov 		LFREEPATH(path);
293a125ed50SMateusz Guzik 	}
294a125ed50SMateusz Guzik 	if (error) {
2955c8919adSAlexander Leidinger 		return (error);
296d075105dSKonstantin Belousov 	}
297a408fc09SDmitry Chagin 	return (old_stat_copyout(&buf, args->up));
2985c8919adSAlexander Leidinger }
2997f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
3005c8919adSAlexander Leidinger 
3015002a60fSMarcel Moolenaar struct l_statfs {
302297f61ccSDmitry Chagin 	l_long		f_type;
303297f61ccSDmitry Chagin 	l_long		f_bsize;
304297f61ccSDmitry Chagin 	l_long		f_blocks;
305297f61ccSDmitry Chagin 	l_long		f_bfree;
306297f61ccSDmitry Chagin 	l_long		f_bavail;
307297f61ccSDmitry Chagin 	l_long		f_files;
308297f61ccSDmitry Chagin 	l_long		f_ffree;
3095002a60fSMarcel Moolenaar 	l_fsid_t	f_fsid;
310297f61ccSDmitry Chagin 	l_long		f_namelen;
311e801ac78SEdward Tomasz Napierala 	l_long		f_frsize;
312e801ac78SEdward Tomasz Napierala 	l_long		f_flags;
313e801ac78SEdward Tomasz Napierala 	l_long		f_spare[4];
314c21dee17SSøren Schmidt };
315c21dee17SSøren Schmidt 
316dca60efcSMarcel Moolenaar #define	LINUX_CODA_SUPER_MAGIC	0x73757245L
317dca60efcSMarcel Moolenaar #define	LINUX_EXT2_SUPER_MAGIC	0xEF53L
318dca60efcSMarcel Moolenaar #define	LINUX_HPFS_SUPER_MAGIC	0xf995e849L
319dca60efcSMarcel Moolenaar #define	LINUX_ISOFS_SUPER_MAGIC	0x9660L
320dca60efcSMarcel Moolenaar #define	LINUX_MSDOS_SUPER_MAGIC	0x4d44L
321dca60efcSMarcel Moolenaar #define	LINUX_NCP_SUPER_MAGIC	0x564cL
322dca60efcSMarcel Moolenaar #define	LINUX_NFS_SUPER_MAGIC	0x6969L
323dca60efcSMarcel Moolenaar #define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
324dca60efcSMarcel Moolenaar #define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
325dca60efcSMarcel Moolenaar #define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
326dbaa9ebfSEd Maste #define	LINUX_ZFS_SUPER_MAGIC	0x2FC12FC1
327e83d253bSOlivier Houchard #define	LINUX_DEVFS_SUPER_MAGIC	0x1373L
3282166e4e0SDmitry Chagin #define	LINUX_SHMFS_MAGIC	0x01021994
329dca60efcSMarcel Moolenaar 
330dca60efcSMarcel Moolenaar static long
331962cf420SMaxim Sobolev bsd_to_linux_ftype(const char *fstypename)
332dca60efcSMarcel Moolenaar {
333962cf420SMaxim Sobolev 	int i;
334962cf420SMaxim Sobolev 	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
335962cf420SMaxim Sobolev 		{"ufs",     LINUX_UFS_SUPER_MAGIC},
336dbaa9ebfSEd Maste 		{"zfs",     LINUX_ZFS_SUPER_MAGIC},
337962cf420SMaxim Sobolev 		{"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
338962cf420SMaxim Sobolev 		{"nfs",     LINUX_NFS_SUPER_MAGIC},
339962cf420SMaxim Sobolev 		{"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
340962cf420SMaxim Sobolev 		{"procfs",  LINUX_PROC_SUPER_MAGIC},
341962cf420SMaxim Sobolev 		{"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
342962cf420SMaxim Sobolev 		{"ntfs",    LINUX_NTFS_SUPER_MAGIC},
343962cf420SMaxim Sobolev 		{"nwfs",    LINUX_NCP_SUPER_MAGIC},
344962cf420SMaxim Sobolev 		{"hpfs",    LINUX_HPFS_SUPER_MAGIC},
345962cf420SMaxim Sobolev 		{"coda",    LINUX_CODA_SUPER_MAGIC},
346e83d253bSOlivier Houchard 		{"devfs",   LINUX_DEVFS_SUPER_MAGIC},
3472166e4e0SDmitry Chagin 		{"tmpfs",   LINUX_SHMFS_MAGIC},
348962cf420SMaxim Sobolev 		{NULL,      0L}};
349dca60efcSMarcel Moolenaar 
350962cf420SMaxim Sobolev 	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
351962cf420SMaxim Sobolev 		if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
352962cf420SMaxim Sobolev 			return (b2l_tbl[i].linux_type);
353dca60efcSMarcel Moolenaar 
354dca60efcSMarcel Moolenaar 	return (0L);
355dca60efcSMarcel Moolenaar }
356dca60efcSMarcel Moolenaar 
357525c9796SDmitry Chagin static int
3589922bccbSDmitry Chagin bsd_to_linux_mnt_flags(int f_flags)
3599922bccbSDmitry Chagin {
3609922bccbSDmitry Chagin 	int flags = LINUX_ST_VALID;
3619922bccbSDmitry Chagin 
3629922bccbSDmitry Chagin 	if (f_flags & MNT_RDONLY)
3639922bccbSDmitry Chagin 		flags |= LINUX_ST_RDONLY;
3649922bccbSDmitry Chagin 	if (f_flags & MNT_NOEXEC)
3659922bccbSDmitry Chagin 		flags |= LINUX_ST_NOEXEC;
3669922bccbSDmitry Chagin 	if (f_flags & MNT_NOSUID)
3679922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSUID;
3689922bccbSDmitry Chagin 	if (f_flags & MNT_NOATIME)
3699922bccbSDmitry Chagin 		flags |= LINUX_ST_NOATIME;
3709922bccbSDmitry Chagin 	if (f_flags & MNT_NOSYMFOLLOW)
3719922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSYMFOLLOW;
3729922bccbSDmitry Chagin 	if (f_flags & MNT_SYNCHRONOUS)
3739922bccbSDmitry Chagin 		flags |= LINUX_ST_SYNCHRONOUS;
3749922bccbSDmitry Chagin 
3759922bccbSDmitry Chagin 	return (flags);
3769922bccbSDmitry Chagin }
3779922bccbSDmitry Chagin 
3789922bccbSDmitry Chagin static int
379d0cad55dSPawel Jakub Dawidek bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
380f7a25872SJohn Baldwin {
381953688e8SDmitry Chagin 
382525c9796SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
383953688e8SDmitry Chagin 	statfs_scale_blocks(bsd_statfs, INT32_MAX);
384525c9796SDmitry Chagin #endif
385f7a25872SJohn Baldwin 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
386f7a25872SJohn Baldwin 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
387f7a25872SJohn Baldwin 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
388f7a25872SJohn Baldwin 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
389f7a25872SJohn Baldwin 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
390953688e8SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
391953688e8SDmitry Chagin 	linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
392953688e8SDmitry Chagin 	linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
393953688e8SDmitry Chagin #else
394f7a25872SJohn Baldwin 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
395f7a25872SJohn Baldwin 	linux_statfs->f_files = bsd_statfs->f_files;
396953688e8SDmitry Chagin #endif
397f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
398f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
399f7a25872SJohn Baldwin 	linux_statfs->f_namelen = MAXNAMLEN;
400e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
4019922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
402e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
403525c9796SDmitry Chagin 
404525c9796SDmitry Chagin 	return (0);
405f7a25872SJohn Baldwin }
406f7a25872SJohn Baldwin 
407c21dee17SSøren Schmidt int
408b40ce416SJulian Elischer linux_statfs(struct thread *td, struct linux_statfs_args *args)
409c21dee17SSøren Schmidt {
4105002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
4112f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
412206a5d3aSIan Dowse 	char *path;
4132166e4e0SDmitry Chagin 	int error;
414d66a5066SPeter Wemm 
415a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
416a125ed50SMateusz Guzik 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
417a125ed50SMateusz Guzik 		error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
418a125ed50SMateusz Guzik 	} else {
419af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
4202f304845SKonstantin Belousov 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4212f304845SKonstantin Belousov 		error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
422206a5d3aSIan Dowse 		LFREEPATH(path);
423a125ed50SMateusz Guzik 	}
4242f304845SKonstantin Belousov 	if (error == 0)
4252f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
4262f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4272f304845SKonstantin Belousov 	if (error != 0)
4282ad02313SDmitry Chagin 		return (error);
4297958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
430c21dee17SSøren Schmidt }
431c21dee17SSøren Schmidt 
4327f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
433835e5061SAlexander Leidinger static void
434835e5061SAlexander Leidinger bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
435835e5061SAlexander Leidinger {
436835e5061SAlexander Leidinger 
437835e5061SAlexander Leidinger 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
438835e5061SAlexander Leidinger 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
439835e5061SAlexander Leidinger 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
440835e5061SAlexander Leidinger 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
441835e5061SAlexander Leidinger 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
442835e5061SAlexander Leidinger 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
443835e5061SAlexander Leidinger 	linux_statfs->f_files = bsd_statfs->f_files;
444835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
445835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
446835e5061SAlexander Leidinger 	linux_statfs->f_namelen = MAXNAMLEN;
447e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
4489922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
449e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
450835e5061SAlexander Leidinger }
451835e5061SAlexander Leidinger 
452835e5061SAlexander Leidinger int
453835e5061SAlexander Leidinger linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
454835e5061SAlexander Leidinger {
455835e5061SAlexander Leidinger 	struct l_statfs64 linux_statfs;
4562f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
457835e5061SAlexander Leidinger 	char *path;
458835e5061SAlexander Leidinger 	int error;
459835e5061SAlexander Leidinger 
4603ab85269SDavid Malone 	if (args->bufsize != sizeof(struct l_statfs64))
461340f4a8dSEd Maste 		return (EINVAL);
4623ab85269SDavid Malone 
463a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
464a125ed50SMateusz Guzik 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
465a125ed50SMateusz Guzik 		error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
466a125ed50SMateusz Guzik 	} else {
467af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
4682f304845SKonstantin Belousov 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4692f304845SKonstantin Belousov 		error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
470835e5061SAlexander Leidinger 		LFREEPATH(path);
471a125ed50SMateusz Guzik 	}
4722f304845SKonstantin Belousov 	if (error == 0)
4732f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4742f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4752f304845SKonstantin Belousov 	if (error != 0)
476835e5061SAlexander Leidinger 		return (error);
4777958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
478835e5061SAlexander Leidinger }
47999546279SDmitry Chagin 
48099546279SDmitry Chagin int
48199546279SDmitry Chagin linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
48299546279SDmitry Chagin {
48399546279SDmitry Chagin 	struct l_statfs64 linux_statfs;
4842f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
48599546279SDmitry Chagin 	int error;
48699546279SDmitry Chagin 
48799546279SDmitry Chagin 	if (args->bufsize != sizeof(struct l_statfs64))
48899546279SDmitry Chagin 		return (EINVAL);
48999546279SDmitry Chagin 
4902f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4912f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
4922f304845SKonstantin Belousov 	if (error == 0)
4932f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4942f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4952f304845SKonstantin Belousov 	if (error != 0)
4962f304845SKonstantin Belousov 		return (error);
49799546279SDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
49899546279SDmitry Chagin }
4997f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
500835e5061SAlexander Leidinger 
501c21dee17SSøren Schmidt int
502b40ce416SJulian Elischer linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
503c21dee17SSøren Schmidt {
5045002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
5052f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
506c21dee17SSøren Schmidt 	int error;
507c21dee17SSøren Schmidt 
5082f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
5092f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
5102f304845SKonstantin Belousov 	if (error == 0)
5112f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
5122f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
5132f304845SKonstantin Belousov 	if (error != 0)
5142ad02313SDmitry Chagin 		return (error);
5157958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
516c21dee17SSøren Schmidt }
517408da119SMarcel Moolenaar 
5185002a60fSMarcel Moolenaar struct l_ustat
519408da119SMarcel Moolenaar {
5205002a60fSMarcel Moolenaar 	l_daddr_t	f_tfree;
5215002a60fSMarcel Moolenaar 	l_ino_t		f_tinode;
5225002a60fSMarcel Moolenaar 	char		f_fname[6];
5235002a60fSMarcel Moolenaar 	char		f_fpack[6];
5245002a60fSMarcel Moolenaar };
5255002a60fSMarcel Moolenaar 
526931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
5275002a60fSMarcel Moolenaar int
528b40ce416SJulian Elischer linux_ustat(struct thread *td, struct linux_ustat_args *args)
5295002a60fSMarcel Moolenaar {
5301e247cc2SPoul-Henning Kamp 
5311e247cc2SPoul-Henning Kamp 	return (EOPNOTSUPP);
532408da119SMarcel Moolenaar }
533931e2a1aSEd Maste #endif
5345002a60fSMarcel Moolenaar 
5351997c537SDavid E. O'Brien #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
5365002a60fSMarcel Moolenaar 
5375002a60fSMarcel Moolenaar static int
5385002a60fSMarcel Moolenaar stat64_copyout(struct stat *buf, void *ubuf)
5395002a60fSMarcel Moolenaar {
5405002a60fSMarcel Moolenaar 	struct l_stat64 lbuf;
5415002a60fSMarcel Moolenaar 
5425002a60fSMarcel Moolenaar 	bzero(&lbuf, sizeof(lbuf));
543*166e2e5aSDmitry Chagin 	lbuf.st_dev = linux_new_encode_dev(buf->st_dev);
5445002a60fSMarcel Moolenaar 	lbuf.st_ino = buf->st_ino;
5455002a60fSMarcel Moolenaar 	lbuf.st_mode = buf->st_mode;
5465002a60fSMarcel Moolenaar 	lbuf.st_nlink = buf->st_nlink;
5475002a60fSMarcel Moolenaar 	lbuf.st_uid = buf->st_uid;
5485002a60fSMarcel Moolenaar 	lbuf.st_gid = buf->st_gid;
549*166e2e5aSDmitry Chagin 	lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
5505002a60fSMarcel Moolenaar 	lbuf.st_size = buf->st_size;
551510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
552510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
553510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
554510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
555510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
556510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
5575002a60fSMarcel Moolenaar 	lbuf.st_blksize = buf->st_blksize;
5585002a60fSMarcel Moolenaar 	lbuf.st_blocks = buf->st_blocks;
5595002a60fSMarcel Moolenaar 
5605002a60fSMarcel Moolenaar 	/*
5615002a60fSMarcel Moolenaar 	 * The __st_ino field makes all the difference. In the Linux kernel
5625002a60fSMarcel Moolenaar 	 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
5635002a60fSMarcel Moolenaar 	 * but without the assignment to __st_ino the runtime linker refuses
5645002a60fSMarcel Moolenaar 	 * to mmap(2) any shared libraries. I guess it's broken alright :-)
5655002a60fSMarcel Moolenaar 	 */
5665002a60fSMarcel Moolenaar 	lbuf.__st_ino = buf->st_ino;
5675002a60fSMarcel Moolenaar 
5685002a60fSMarcel Moolenaar 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
5695002a60fSMarcel Moolenaar }
5705002a60fSMarcel Moolenaar 
5715002a60fSMarcel Moolenaar int
572b40ce416SJulian Elischer linux_stat64(struct thread *td, struct linux_stat64_args *args)
5735002a60fSMarcel Moolenaar {
5745002a60fSMarcel Moolenaar 	struct stat buf;
575206a5d3aSIan Dowse 	char *filename;
576f7a25872SJohn Baldwin 	int error;
5775002a60fSMarcel Moolenaar 
578a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
579a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
580a125ed50SMateusz Guzik 	} else {
581af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->filename, &filename);
5820eee862aSEd Schouten 		error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
583206a5d3aSIan Dowse 		LFREEPATH(filename);
584a125ed50SMateusz Guzik 	}
5855002a60fSMarcel Moolenaar 	if (error)
5865002a60fSMarcel Moolenaar 		return (error);
5875002a60fSMarcel Moolenaar 	return (stat64_copyout(&buf, args->statbuf));
5885002a60fSMarcel Moolenaar }
5895002a60fSMarcel Moolenaar 
5905002a60fSMarcel Moolenaar int
591b40ce416SJulian Elischer linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
5925002a60fSMarcel Moolenaar {
5935002a60fSMarcel Moolenaar 	struct stat sb;
594206a5d3aSIan Dowse 	char *filename;
595f7a25872SJohn Baldwin 	int error;
5965002a60fSMarcel Moolenaar 
597a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
598a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
599a125ed50SMateusz Guzik 	} else {
600af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->filename, &filename);
6010eee862aSEd Schouten 		error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
602206a5d3aSIan Dowse 		LFREEPATH(filename);
603a125ed50SMateusz Guzik 	}
6045002a60fSMarcel Moolenaar 	if (error)
6055002a60fSMarcel Moolenaar 		return (error);
6065002a60fSMarcel Moolenaar 	return (stat64_copyout(&sb, args->statbuf));
6075002a60fSMarcel Moolenaar }
6085002a60fSMarcel Moolenaar 
6095002a60fSMarcel Moolenaar int
610b40ce416SJulian Elischer linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
6115002a60fSMarcel Moolenaar {
6125002a60fSMarcel Moolenaar 	struct stat buf;
6135002a60fSMarcel Moolenaar 	int error;
6145002a60fSMarcel Moolenaar 
615994ed958SDmitry Chagin 	error = linux_kern_fstat(td, args->fd, &buf);
6165002a60fSMarcel Moolenaar 	if (!error)
6175002a60fSMarcel Moolenaar 		error = stat64_copyout(&buf, args->statbuf);
6185002a60fSMarcel Moolenaar 
6195002a60fSMarcel Moolenaar 	return (error);
6205002a60fSMarcel Moolenaar }
6215002a60fSMarcel Moolenaar 
62248b05c3fSKonstantin Belousov int
62348b05c3fSKonstantin Belousov linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
62448b05c3fSKonstantin Belousov {
62548b05c3fSKonstantin Belousov 	char *path;
6269d167945SEdward Tomasz Napierala 	int error, dfd, flag, unsupported;
62748b05c3fSKonstantin Belousov 	struct stat buf;
62848b05c3fSKonstantin Belousov 
6299d167945SEdward Tomasz Napierala 	unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
6309d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
6319d167945SEdward Tomasz Napierala 		linux_msg(td, "fstatat64 unsupported flag 0x%x", unsupported);
63248b05c3fSKonstantin Belousov 		return (EINVAL);
6334b45c2bbSEdward Tomasz Napierala 	}
63448b05c3fSKonstantin Belousov 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
63548b05c3fSKonstantin Belousov 	    AT_SYMLINK_NOFOLLOW : 0;
6364b45c2bbSEdward Tomasz Napierala 	flag |= (args->flag & LINUX_AT_EMPTY_PATH) ?
6374b45c2bbSEdward Tomasz Napierala 	    AT_EMPTY_PATH : 0;
63848b05c3fSKonstantin Belousov 
63948b05c3fSKonstantin Belousov 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
640a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
641a125ed50SMateusz Guzik 		error = linux_kern_statat(td, flag, dfd, args->pathname,
642a125ed50SMateusz Guzik 		    UIO_USERSPACE, &buf);
643a125ed50SMateusz Guzik 	} else {
644af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dfd);
6450eee862aSEd Schouten 		error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
64648b05c3fSKonstantin Belousov 		LFREEPATH(path);
647a125ed50SMateusz Guzik 	}
648a125ed50SMateusz Guzik 	if (error == 0)
649a125ed50SMateusz Guzik 		error = stat64_copyout(&buf, args->statbuf);
65048b05c3fSKonstantin Belousov 
65148b05c3fSKonstantin Belousov 	return (error);
65248b05c3fSKonstantin Belousov }
65348b05c3fSKonstantin Belousov 
654606bcc17SDmitry Chagin #else /* __amd64__ && !COMPAT_LINUX32 */
655606bcc17SDmitry Chagin 
656606bcc17SDmitry Chagin int
657606bcc17SDmitry Chagin linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
658606bcc17SDmitry Chagin {
659606bcc17SDmitry Chagin 	char *path;
6609d167945SEdward Tomasz Napierala 	int error, dfd, flag, unsupported;
661606bcc17SDmitry Chagin 	struct stat buf;
662606bcc17SDmitry Chagin 
6639d167945SEdward Tomasz Napierala 	unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
6649d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
6659d167945SEdward Tomasz Napierala 		linux_msg(td, "fstatat unsupported flag 0x%x", unsupported);
666606bcc17SDmitry Chagin 		return (EINVAL);
6674b45c2bbSEdward Tomasz Napierala 	}
6684b45c2bbSEdward Tomasz Napierala 
669606bcc17SDmitry Chagin 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
670606bcc17SDmitry Chagin 	    AT_SYMLINK_NOFOLLOW : 0;
6714b45c2bbSEdward Tomasz Napierala 	flag |= (args->flag & LINUX_AT_EMPTY_PATH) ?
6724b45c2bbSEdward Tomasz Napierala 	    AT_EMPTY_PATH : 0;
673606bcc17SDmitry Chagin 
674606bcc17SDmitry Chagin 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
675a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
676a125ed50SMateusz Guzik 		error = linux_kern_statat(td, flag, dfd, args->pathname,
677a125ed50SMateusz Guzik 		    UIO_USERSPACE, &buf);
678a125ed50SMateusz Guzik 	} else {
679af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dfd);
680606bcc17SDmitry Chagin 		error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
681a125ed50SMateusz Guzik 		LFREEPATH(path);
682a125ed50SMateusz Guzik 	}
683606bcc17SDmitry Chagin 	if (error == 0)
684606bcc17SDmitry Chagin 		error = newstat_copyout(&buf, args->statbuf);
685606bcc17SDmitry Chagin 
686606bcc17SDmitry Chagin 	return (error);
687606bcc17SDmitry Chagin }
688606bcc17SDmitry Chagin 
6891997c537SDavid E. O'Brien #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
6909802eb9eSDmitry Chagin 
6919802eb9eSDmitry Chagin int
6929802eb9eSDmitry Chagin linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
6939802eb9eSDmitry Chagin {
6949802eb9eSDmitry Chagin 	struct mount *mp;
6959802eb9eSDmitry Chagin 	struct vnode *vp;
6969802eb9eSDmitry Chagin 	int error, save;
6979802eb9eSDmitry Chagin 
698cbd92ce6SMatt Macy 	error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
6999802eb9eSDmitry Chagin 	if (error != 0)
7009802eb9eSDmitry Chagin 		/*
7019802eb9eSDmitry Chagin 		 * Linux syncfs() returns only EBADF, however fgetvp()
7029802eb9eSDmitry Chagin 		 * can return EINVAL in case of file descriptor does
7039802eb9eSDmitry Chagin 		 * not represent a vnode. XXX.
7049802eb9eSDmitry Chagin 		 */
7059802eb9eSDmitry Chagin 		return (error);
7069802eb9eSDmitry Chagin 
7079802eb9eSDmitry Chagin 	mp = vp->v_mount;
7089802eb9eSDmitry Chagin 	mtx_lock(&mountlist_mtx);
7099802eb9eSDmitry Chagin 	error = vfs_busy(mp, MBF_MNTLSTLOCK);
7109802eb9eSDmitry Chagin 	if (error != 0) {
7119802eb9eSDmitry Chagin 		/* See comment above. */
7129802eb9eSDmitry Chagin 		mtx_unlock(&mountlist_mtx);
7139802eb9eSDmitry Chagin 		goto out;
7149802eb9eSDmitry Chagin 	}
7159802eb9eSDmitry Chagin 	if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7169802eb9eSDmitry Chagin 	    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
7179802eb9eSDmitry Chagin 		save = curthread_pflags_set(TDP_SYNCIO);
718c8b3463dSMateusz Guzik 		vfs_periodic(mp, MNT_NOWAIT);
7199802eb9eSDmitry Chagin 		VFS_SYNC(mp, MNT_NOWAIT);
7209802eb9eSDmitry Chagin 		curthread_pflags_restore(save);
7219802eb9eSDmitry Chagin 		vn_finished_write(mp);
7229802eb9eSDmitry Chagin 	}
7239802eb9eSDmitry Chagin 	vfs_unbusy(mp);
7249802eb9eSDmitry Chagin 
7259802eb9eSDmitry Chagin  out:
7269802eb9eSDmitry Chagin 	vrele(vp);
7279802eb9eSDmitry Chagin 	return (error);
7289802eb9eSDmitry Chagin }
7292362ad45SPhilippe Michaud-Boudreault 
730e9204c5cSDmitry Chagin static int
731e9204c5cSDmitry Chagin statx_copyout(struct stat *buf, void *ubuf)
732e9204c5cSDmitry Chagin {
733e9204c5cSDmitry Chagin 	struct l_statx tbuf;
734e9204c5cSDmitry Chagin 
735e9204c5cSDmitry Chagin 	bzero(&tbuf, sizeof(tbuf));
736e9204c5cSDmitry Chagin 	tbuf.stx_mask = STATX_ALL;
737e9204c5cSDmitry Chagin 	tbuf.stx_blksize = buf->st_blksize;
738e9204c5cSDmitry Chagin 	tbuf.stx_attributes = 0;
739e9204c5cSDmitry Chagin 	tbuf.stx_nlink = buf->st_nlink;
740e9204c5cSDmitry Chagin 	tbuf.stx_uid = buf->st_uid;
741e9204c5cSDmitry Chagin 	tbuf.stx_gid = buf->st_gid;
742e9204c5cSDmitry Chagin 	tbuf.stx_mode = buf->st_mode;
743e9204c5cSDmitry Chagin 	tbuf.stx_ino = buf->st_ino;
744e9204c5cSDmitry Chagin 	tbuf.stx_size = buf->st_size;
745e9204c5cSDmitry Chagin 	tbuf.stx_blocks = buf->st_blocks;
746e9204c5cSDmitry Chagin 
747e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
748e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
749e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
750e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
751e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
752e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
753e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
754e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
755*166e2e5aSDmitry Chagin 	tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev);
756*166e2e5aSDmitry Chagin 	tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev);
757*166e2e5aSDmitry Chagin 	tbuf.stx_dev_major = linux_encode_major(buf->st_dev);
758*166e2e5aSDmitry Chagin 	tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev);
759e9204c5cSDmitry Chagin 
760e9204c5cSDmitry Chagin 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
761e9204c5cSDmitry Chagin }
762e9204c5cSDmitry Chagin 
7632362ad45SPhilippe Michaud-Boudreault int
7642362ad45SPhilippe Michaud-Boudreault linux_statx(struct thread *td, struct linux_statx_args *args)
7652362ad45SPhilippe Michaud-Boudreault {
7662362ad45SPhilippe Michaud-Boudreault 	char *path;
7679d167945SEdward Tomasz Napierala 	int error, dirfd, flags, unsupported;
7682362ad45SPhilippe Michaud-Boudreault 	struct stat buf;
7692362ad45SPhilippe Michaud-Boudreault 
770ff39d74aSDmitry Chagin 	unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW |
771ff39d74aSDmitry Chagin 	    LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT);
7729d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
7739d167945SEdward Tomasz Napierala 		linux_msg(td, "statx unsupported flags 0x%x", unsupported);
7742362ad45SPhilippe Michaud-Boudreault 		return (EINVAL);
7752362ad45SPhilippe Michaud-Boudreault 	}
7762362ad45SPhilippe Michaud-Boudreault 
7772362ad45SPhilippe Michaud-Boudreault 	flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ?
7782362ad45SPhilippe Michaud-Boudreault 	    AT_SYMLINK_NOFOLLOW : 0;
7792362ad45SPhilippe Michaud-Boudreault 	flags |= (args->flags & LINUX_AT_EMPTY_PATH) ?
7802362ad45SPhilippe Michaud-Boudreault 	    AT_EMPTY_PATH : 0;
7812362ad45SPhilippe Michaud-Boudreault 
7822362ad45SPhilippe Michaud-Boudreault 	dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
7832362ad45SPhilippe Michaud-Boudreault 	if (!LUSECONVPATH(td)) {
7842362ad45SPhilippe Michaud-Boudreault 		error = linux_kern_statat(td, flags, dirfd, args->pathname,
7852362ad45SPhilippe Michaud-Boudreault 		    UIO_USERSPACE, &buf);
7862362ad45SPhilippe Michaud-Boudreault 	} else {
787af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dirfd);
7882362ad45SPhilippe Michaud-Boudreault 		error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf);
7892362ad45SPhilippe Michaud-Boudreault 		LFREEPATH(path);
7902362ad45SPhilippe Michaud-Boudreault 	}
7912362ad45SPhilippe Michaud-Boudreault 	if (error == 0)
7922362ad45SPhilippe Michaud-Boudreault 		error = statx_copyout(&buf, args->statxbuf);
7932362ad45SPhilippe Michaud-Boudreault 
7942362ad45SPhilippe Michaud-Boudreault 	return (error);
7952362ad45SPhilippe Michaud-Boudreault }
796