xref: /freebsd/sys/compat/linux/linux_stats.c (revision e9204c5c2c5c471ad2182ec6358a46be74c9ebb6)
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 
32c21dee17SSøren Schmidt #include <sys/param.h>
339802eb9eSDmitry Chagin #include <sys/capsicum.h>
34c21dee17SSøren Schmidt #include <sys/dirent.h>
35d8e53d94SDmitry Chagin #include <sys/lock.h>
3685422e62SBruce Evans #include <sys/malloc.h>
37d8e53d94SDmitry Chagin #include <sys/mutex.h>
38d8e53d94SDmitry Chagin #include <sys/proc.h>
39c21dee17SSøren Schmidt #include <sys/stat.h>
40f7a25872SJohn Baldwin #include <sys/syscallsubr.h>
41bc093719SEd Schouten #include <sys/tty.h>
42c21dee17SSøren Schmidt #include <sys/vnode.h>
43c21dee17SSøren Schmidt 
441997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
454af27623STim J. Robbins #include <machine/../linux32/linux.h>
464af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
471997c537SDavid E. O'Brien #else
481997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
491997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
504af27623STim J. Robbins #endif
5185422e62SBruce Evans 
5248b05c3fSKonstantin Belousov #include <compat/linux/linux_file.h>
532a38f51cSDmitry Chagin #include <compat/linux/linux_util.h>
54762e6b85SEivind Eklund 
550eee862aSEd Schouten 
560eee862aSEd Schouten static int
57a125ed50SMateusz Guzik linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
580eee862aSEd Schouten     enum uio_seg pathseg, struct stat *sbp)
590eee862aSEd Schouten {
600eee862aSEd Schouten 
616e646651SKonstantin Belousov 	return (kern_statat(td, flag, fd, path, pathseg, sbp,
620eee862aSEd Schouten 	    translate_vnhook_major_minor));
630eee862aSEd Schouten }
640eee862aSEd Schouten 
65931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
660eee862aSEd Schouten static int
67a125ed50SMateusz Guzik linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg,
680eee862aSEd Schouten     struct stat *sbp)
690eee862aSEd Schouten {
700eee862aSEd Schouten 
710eee862aSEd Schouten 	return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
720eee862aSEd Schouten }
730eee862aSEd Schouten 
740eee862aSEd Schouten static int
75a125ed50SMateusz Guzik linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
760eee862aSEd Schouten     struct stat *sbp)
770eee862aSEd Schouten {
780eee862aSEd Schouten 
790eee862aSEd Schouten 	return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
800eee862aSEd Schouten 	    pathseg, sbp));
810eee862aSEd Schouten }
82931e2a1aSEd Maste #endif
830eee862aSEd Schouten 
84060e4882SDoug Ambrisko static void
85060e4882SDoug Ambrisko translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
86060e4882SDoug Ambrisko {
87060e4882SDoug Ambrisko 	struct file *fp;
880eee862aSEd Schouten 	struct vnode *vp;
8917f701a3SEdward Tomasz Napierala 	struct mount *mp;
90060e4882SDoug Ambrisko 	int major, minor;
91060e4882SDoug Ambrisko 
92a9d2f8d8SRobert Watson 	/*
93a9d2f8d8SRobert Watson 	 * No capability rights required here.
94a9d2f8d8SRobert Watson 	 */
95b256a1e1SJung-uk Kim 	if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
96cbd92ce6SMatt Macy 	    fget(td, fd, &cap_no_rights, &fp) != 0)
97060e4882SDoug Ambrisko 		return;
980eee862aSEd Schouten 	vp = fp->f_vnode;
997ad2a82dSMateusz Guzik 	if (vp != NULL && vn_isdisk(vp)) {
100273ce4aeSEdward Tomasz Napierala 		buf->st_mode &= ~S_IFMT;
101273ce4aeSEdward Tomasz Napierala 		buf->st_mode |= S_IFBLK;
102273ce4aeSEdward Tomasz Napierala 	}
10317f701a3SEdward Tomasz Napierala 	if (vp != NULL && rootdevmp != NULL) {
10417f701a3SEdward Tomasz Napierala 		mp = vp->v_mount;
10517f701a3SEdward Tomasz Napierala 		__compiler_membar();
10617f701a3SEdward Tomasz Napierala 		if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc)
10717f701a3SEdward Tomasz Napierala 			buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
10817f701a3SEdward Tomasz Napierala 	}
1091a34e9faSEdward Tomasz Napierala 	if (linux_vn_get_major_minor(vp, &major, &minor) == 0) {
110060e4882SDoug Ambrisko 		buf->st_rdev = (major << 8 | minor);
111bc093719SEd Schouten 	} else if (fp->f_type == DTYPE_PTS) {
112bc093719SEd Schouten 		struct tty *tp = fp->f_data;
113bc093719SEd Schouten 
114bc093719SEd Schouten 		/* Convert the numbers for the slave device. */
1157870adb6SEd Schouten 		if (linux_driver_get_major_minor(devtoname(tp->t_dev),
116bc093719SEd Schouten 					 &major, &minor) == 0) {
117bc093719SEd Schouten 			buf->st_rdev = (major << 8 | minor);
118bc093719SEd Schouten 		}
119bc093719SEd Schouten 	}
120060e4882SDoug Ambrisko 	fdrop(fp, td);
121060e4882SDoug Ambrisko }
122060e4882SDoug Ambrisko 
123ab35e1c7SBruce Evans /*
124ab35e1c7SBruce Evans  * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
125407a8126SBruce Evans  * truncation of a dev_t to 16 bits gives the same result as unpacking
126407a8126SBruce Evans  * using major() and minor() and repacking in the l_dev_t format.  This
127407a8126SBruce Evans  * detail is hidden in dev_to_ldev().  Overflow in conversions of dev_t's
128407a8126SBruce Evans  * are not checked for, as for other fields.
129ab35e1c7SBruce Evans  *
130407a8126SBruce Evans  * dev_to_ldev() is only used for translating st_dev.  When we convert
131407a8126SBruce Evans  * st_rdev for copying it out, it isn't really a dev_t, but has already
132407a8126SBruce Evans  * been translated to an l_dev_t in a nontrivial way.  Translating it
133407a8126SBruce Evans  * again would be illogical but would have no effect since the low 16
134407a8126SBruce Evans  * bits have the same encoding.
135407a8126SBruce Evans  *
136407a8126SBruce Evans  * The nontrivial translation for st_rdev renumbers some devices, but not
137407a8126SBruce Evans  * ones that can be mounted on, so it is consistent with the translation
138407a8126SBruce Evans  * for st_dev except when the renumbering or truncation causes conflicts.
139ab35e1c7SBruce Evans  */
140ab35e1c7SBruce Evans #define	dev_to_ldev(d)	((uint16_t)(d))
141ab35e1c7SBruce Evans 
142bbbc2d96SPoul-Henning Kamp static int
143bbbc2d96SPoul-Henning Kamp newstat_copyout(struct stat *buf, void *ubuf)
144bbbc2d96SPoul-Henning Kamp {
145bbbc2d96SPoul-Henning Kamp 	struct l_newstat tbuf;
146bbbc2d96SPoul-Henning Kamp 
147bbbc2d96SPoul-Henning Kamp 	bzero(&tbuf, sizeof(tbuf));
148ab35e1c7SBruce Evans 	tbuf.st_dev = dev_to_ldev(buf->st_dev);
149bbbc2d96SPoul-Henning Kamp 	tbuf.st_ino = buf->st_ino;
150bbbc2d96SPoul-Henning Kamp 	tbuf.st_mode = buf->st_mode;
151bbbc2d96SPoul-Henning Kamp 	tbuf.st_nlink = buf->st_nlink;
152bbbc2d96SPoul-Henning Kamp 	tbuf.st_uid = buf->st_uid;
153bbbc2d96SPoul-Henning Kamp 	tbuf.st_gid = buf->st_gid;
154bbbc2d96SPoul-Henning Kamp 	tbuf.st_rdev = buf->st_rdev;
155bbbc2d96SPoul-Henning Kamp 	tbuf.st_size = buf->st_size;
156510ea843SEd Schouten 	tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
157510ea843SEd Schouten 	tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
158510ea843SEd Schouten 	tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
159510ea843SEd Schouten 	tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
160510ea843SEd Schouten 	tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
161510ea843SEd Schouten 	tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
162bbbc2d96SPoul-Henning Kamp 	tbuf.st_blksize = buf->st_blksize;
163bbbc2d96SPoul-Henning Kamp 	tbuf.st_blocks = buf->st_blocks;
164bbbc2d96SPoul-Henning Kamp 
1654e0eaf69SMarcel Moolenaar 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
166c21dee17SSøren Schmidt }
167c21dee17SSøren Schmidt 
1682362ad45SPhilippe Michaud-Boudreault 
169931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
170c21dee17SSøren Schmidt int
171b40ce416SJulian Elischer linux_newstat(struct thread *td, struct linux_newstat_args *args)
172c21dee17SSøren Schmidt {
173c21dee17SSøren Schmidt 	struct stat buf;
174206a5d3aSIan Dowse 	char *path;
175c21dee17SSøren Schmidt 	int error;
176d66a5066SPeter Wemm 
177a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
178a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
179a125ed50SMateusz Guzik 	} else {
180af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
1810eee862aSEd Schouten 		error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
182206a5d3aSIan Dowse 		LFREEPATH(path);
183a125ed50SMateusz Guzik 	}
1844e0eaf69SMarcel Moolenaar 	if (error)
1854e0eaf69SMarcel Moolenaar 		return (error);
1864e0eaf69SMarcel Moolenaar 	return (newstat_copyout(&buf, args->buf));
187c21dee17SSøren Schmidt }
188c21dee17SSøren Schmidt 
189c21dee17SSøren Schmidt int
190b40ce416SJulian Elischer linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
191c21dee17SSøren Schmidt {
1924e0eaf69SMarcel Moolenaar 	struct stat sb;
193206a5d3aSIan Dowse 	char *path;
194f7a25872SJohn Baldwin 	int error;
195d66a5066SPeter Wemm 
196a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
197a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
198a125ed50SMateusz Guzik 	} else {
199af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2000eee862aSEd Schouten 		error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
201206a5d3aSIan Dowse 		LFREEPATH(path);
202a125ed50SMateusz Guzik 	}
203d66a5066SPeter Wemm 	if (error)
204d66a5066SPeter Wemm 		return (error);
2055002a60fSMarcel Moolenaar 	return (newstat_copyout(&sb, args->buf));
206d66a5066SPeter Wemm }
207931e2a1aSEd Maste #endif
208c21dee17SSøren Schmidt 
209c21dee17SSøren Schmidt int
210b40ce416SJulian Elischer linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
211c21dee17SSøren Schmidt {
212c21dee17SSøren Schmidt 	struct stat buf;
213c21dee17SSøren Schmidt 	int error;
214c21dee17SSøren Schmidt 
215f7a25872SJohn Baldwin 	error = kern_fstat(td, args->fd, &buf);
216060e4882SDoug Ambrisko 	translate_fd_major_minor(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))
2245c8919adSAlexander Leidinger static int
2255c8919adSAlexander Leidinger stat_copyout(struct stat *buf, void *ubuf)
2265c8919adSAlexander Leidinger {
2275c8919adSAlexander Leidinger 	struct l_stat lbuf;
2285c8919adSAlexander Leidinger 
2295c8919adSAlexander Leidinger 	bzero(&lbuf, sizeof(lbuf));
230ab35e1c7SBruce Evans 	lbuf.st_dev = dev_to_ldev(buf->st_dev);
2315c8919adSAlexander Leidinger 	lbuf.st_ino = buf->st_ino;
2325c8919adSAlexander Leidinger 	lbuf.st_mode = buf->st_mode;
2335c8919adSAlexander Leidinger 	lbuf.st_nlink = buf->st_nlink;
2345c8919adSAlexander Leidinger 	lbuf.st_uid = buf->st_uid;
2355c8919adSAlexander Leidinger 	lbuf.st_gid = buf->st_gid;
2365c8919adSAlexander Leidinger 	lbuf.st_rdev = buf->st_rdev;
237372639f9SBruce Evans 	lbuf.st_size = MIN(buf->st_size, INT32_MAX);
238510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
239510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
240510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
241510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
242510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
243510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
2445c8919adSAlexander Leidinger 	lbuf.st_blksize = buf->st_blksize;
2455c8919adSAlexander Leidinger 	lbuf.st_blocks = buf->st_blocks;
2465c8919adSAlexander Leidinger 	lbuf.st_flags = buf->st_flags;
2475c8919adSAlexander Leidinger 	lbuf.st_gen = buf->st_gen;
2485c8919adSAlexander Leidinger 
2495c8919adSAlexander Leidinger 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
2505c8919adSAlexander Leidinger }
2515c8919adSAlexander Leidinger 
2525c8919adSAlexander Leidinger int
2535c8919adSAlexander Leidinger linux_stat(struct thread *td, struct linux_stat_args *args)
2545c8919adSAlexander Leidinger {
2555c8919adSAlexander Leidinger 	struct stat buf;
25615b78ac5SKonstantin Belousov 	char *path;
2575c8919adSAlexander Leidinger 	int error;
25815b78ac5SKonstantin Belousov 
259a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
260a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
261a125ed50SMateusz Guzik 	} else {
262af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2630eee862aSEd Schouten 		error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
26415b78ac5SKonstantin Belousov 		LFREEPATH(path);
265a125ed50SMateusz Guzik 	}
266a125ed50SMateusz Guzik 	if (error) {
2675c8919adSAlexander Leidinger 		return (error);
268d075105dSKonstantin Belousov 	}
2695c8919adSAlexander Leidinger 	return (stat_copyout(&buf, args->up));
2705c8919adSAlexander Leidinger }
2715c8919adSAlexander Leidinger 
2725c8919adSAlexander Leidinger int
2735c8919adSAlexander Leidinger linux_lstat(struct thread *td, struct linux_lstat_args *args)
2745c8919adSAlexander Leidinger {
2755c8919adSAlexander Leidinger 	struct stat buf;
27615b78ac5SKonstantin Belousov 	char *path;
2775c8919adSAlexander Leidinger 	int error;
2785c8919adSAlexander Leidinger 
279a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
280a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
281a125ed50SMateusz Guzik 	} else {
282af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
2830eee862aSEd Schouten 		error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
28415b78ac5SKonstantin Belousov 		LFREEPATH(path);
285a125ed50SMateusz Guzik 	}
286a125ed50SMateusz Guzik 	if (error) {
2875c8919adSAlexander Leidinger 		return (error);
288d075105dSKonstantin Belousov 	}
2895c8919adSAlexander Leidinger 	return (stat_copyout(&buf, args->up));
2905c8919adSAlexander Leidinger }
2917f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
2925c8919adSAlexander Leidinger 
2935002a60fSMarcel Moolenaar struct l_statfs {
294297f61ccSDmitry Chagin 	l_long		f_type;
295297f61ccSDmitry Chagin 	l_long		f_bsize;
296297f61ccSDmitry Chagin 	l_long		f_blocks;
297297f61ccSDmitry Chagin 	l_long		f_bfree;
298297f61ccSDmitry Chagin 	l_long		f_bavail;
299297f61ccSDmitry Chagin 	l_long		f_files;
300297f61ccSDmitry Chagin 	l_long		f_ffree;
3015002a60fSMarcel Moolenaar 	l_fsid_t	f_fsid;
302297f61ccSDmitry Chagin 	l_long		f_namelen;
303e801ac78SEdward Tomasz Napierala 	l_long		f_frsize;
304e801ac78SEdward Tomasz Napierala 	l_long		f_flags;
305e801ac78SEdward Tomasz Napierala 	l_long		f_spare[4];
306c21dee17SSøren Schmidt };
307c21dee17SSøren Schmidt 
308dca60efcSMarcel Moolenaar #define	LINUX_CODA_SUPER_MAGIC	0x73757245L
309dca60efcSMarcel Moolenaar #define	LINUX_EXT2_SUPER_MAGIC	0xEF53L
310dca60efcSMarcel Moolenaar #define	LINUX_HPFS_SUPER_MAGIC	0xf995e849L
311dca60efcSMarcel Moolenaar #define	LINUX_ISOFS_SUPER_MAGIC	0x9660L
312dca60efcSMarcel Moolenaar #define	LINUX_MSDOS_SUPER_MAGIC	0x4d44L
313dca60efcSMarcel Moolenaar #define	LINUX_NCP_SUPER_MAGIC	0x564cL
314dca60efcSMarcel Moolenaar #define	LINUX_NFS_SUPER_MAGIC	0x6969L
315dca60efcSMarcel Moolenaar #define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
316dca60efcSMarcel Moolenaar #define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
317dca60efcSMarcel Moolenaar #define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
318dbaa9ebfSEd Maste #define	LINUX_ZFS_SUPER_MAGIC	0x2FC12FC1
319e83d253bSOlivier Houchard #define	LINUX_DEVFS_SUPER_MAGIC	0x1373L
3202166e4e0SDmitry Chagin #define	LINUX_SHMFS_MAGIC	0x01021994
321dca60efcSMarcel Moolenaar 
322dca60efcSMarcel Moolenaar static long
323962cf420SMaxim Sobolev bsd_to_linux_ftype(const char *fstypename)
324dca60efcSMarcel Moolenaar {
325962cf420SMaxim Sobolev 	int i;
326962cf420SMaxim Sobolev 	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
327962cf420SMaxim Sobolev 		{"ufs",     LINUX_UFS_SUPER_MAGIC},
328dbaa9ebfSEd Maste 		{"zfs",     LINUX_ZFS_SUPER_MAGIC},
329962cf420SMaxim Sobolev 		{"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
330962cf420SMaxim Sobolev 		{"nfs",     LINUX_NFS_SUPER_MAGIC},
331962cf420SMaxim Sobolev 		{"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
332962cf420SMaxim Sobolev 		{"procfs",  LINUX_PROC_SUPER_MAGIC},
333962cf420SMaxim Sobolev 		{"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
334962cf420SMaxim Sobolev 		{"ntfs",    LINUX_NTFS_SUPER_MAGIC},
335962cf420SMaxim Sobolev 		{"nwfs",    LINUX_NCP_SUPER_MAGIC},
336962cf420SMaxim Sobolev 		{"hpfs",    LINUX_HPFS_SUPER_MAGIC},
337962cf420SMaxim Sobolev 		{"coda",    LINUX_CODA_SUPER_MAGIC},
338e83d253bSOlivier Houchard 		{"devfs",   LINUX_DEVFS_SUPER_MAGIC},
3392166e4e0SDmitry Chagin 		{"tmpfs",   LINUX_SHMFS_MAGIC},
340962cf420SMaxim Sobolev 		{NULL,      0L}};
341dca60efcSMarcel Moolenaar 
342962cf420SMaxim Sobolev 	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
343962cf420SMaxim Sobolev 		if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
344962cf420SMaxim Sobolev 			return (b2l_tbl[i].linux_type);
345dca60efcSMarcel Moolenaar 
346dca60efcSMarcel Moolenaar 	return (0L);
347dca60efcSMarcel Moolenaar }
348dca60efcSMarcel Moolenaar 
349525c9796SDmitry Chagin static int
3509922bccbSDmitry Chagin bsd_to_linux_mnt_flags(int f_flags)
3519922bccbSDmitry Chagin {
3529922bccbSDmitry Chagin 	int flags = LINUX_ST_VALID;
3539922bccbSDmitry Chagin 
3549922bccbSDmitry Chagin 	if (f_flags & MNT_RDONLY)
3559922bccbSDmitry Chagin 		flags |= LINUX_ST_RDONLY;
3569922bccbSDmitry Chagin 	if (f_flags & MNT_NOEXEC)
3579922bccbSDmitry Chagin 		flags |= LINUX_ST_NOEXEC;
3589922bccbSDmitry Chagin 	if (f_flags & MNT_NOSUID)
3599922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSUID;
3609922bccbSDmitry Chagin 	if (f_flags & MNT_NOATIME)
3619922bccbSDmitry Chagin 		flags |= LINUX_ST_NOATIME;
3629922bccbSDmitry Chagin 	if (f_flags & MNT_NOSYMFOLLOW)
3639922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSYMFOLLOW;
3649922bccbSDmitry Chagin 	if (f_flags & MNT_SYNCHRONOUS)
3659922bccbSDmitry Chagin 		flags |= LINUX_ST_SYNCHRONOUS;
3669922bccbSDmitry Chagin 
3679922bccbSDmitry Chagin 	return (flags);
3689922bccbSDmitry Chagin }
3699922bccbSDmitry Chagin 
3709922bccbSDmitry Chagin static int
371d0cad55dSPawel Jakub Dawidek bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
372f7a25872SJohn Baldwin {
373953688e8SDmitry Chagin 
374525c9796SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
375953688e8SDmitry Chagin 	statfs_scale_blocks(bsd_statfs, INT32_MAX);
376525c9796SDmitry Chagin #endif
377f7a25872SJohn Baldwin 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
378f7a25872SJohn Baldwin 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
379f7a25872SJohn Baldwin 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
380f7a25872SJohn Baldwin 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
381f7a25872SJohn Baldwin 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
382953688e8SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
383953688e8SDmitry Chagin 	linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
384953688e8SDmitry Chagin 	linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
385953688e8SDmitry Chagin #else
386f7a25872SJohn Baldwin 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
387f7a25872SJohn Baldwin 	linux_statfs->f_files = bsd_statfs->f_files;
388953688e8SDmitry Chagin #endif
389f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
390f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
391f7a25872SJohn Baldwin 	linux_statfs->f_namelen = MAXNAMLEN;
392e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
3939922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
394e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
395525c9796SDmitry Chagin 
396525c9796SDmitry Chagin 	return (0);
397f7a25872SJohn Baldwin }
398f7a25872SJohn Baldwin 
399c21dee17SSøren Schmidt int
400b40ce416SJulian Elischer linux_statfs(struct thread *td, struct linux_statfs_args *args)
401c21dee17SSøren Schmidt {
4025002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
4032f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
404206a5d3aSIan Dowse 	char *path;
4052166e4e0SDmitry Chagin 	int error;
406d66a5066SPeter Wemm 
407a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
408a125ed50SMateusz Guzik 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
409a125ed50SMateusz Guzik 		error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
410a125ed50SMateusz Guzik 	} else {
411af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
4122f304845SKonstantin Belousov 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4132f304845SKonstantin Belousov 		error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
414206a5d3aSIan Dowse 		LFREEPATH(path);
415a125ed50SMateusz Guzik 	}
4162f304845SKonstantin Belousov 	if (error == 0)
4172f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
4182f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4192f304845SKonstantin Belousov 	if (error != 0)
4202ad02313SDmitry Chagin 		return (error);
4217958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
422c21dee17SSøren Schmidt }
423c21dee17SSøren Schmidt 
4247f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
425835e5061SAlexander Leidinger static void
426835e5061SAlexander Leidinger bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
427835e5061SAlexander Leidinger {
428835e5061SAlexander Leidinger 
429835e5061SAlexander Leidinger 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
430835e5061SAlexander Leidinger 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
431835e5061SAlexander Leidinger 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
432835e5061SAlexander Leidinger 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
433835e5061SAlexander Leidinger 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
434835e5061SAlexander Leidinger 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
435835e5061SAlexander Leidinger 	linux_statfs->f_files = bsd_statfs->f_files;
436835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
437835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
438835e5061SAlexander Leidinger 	linux_statfs->f_namelen = MAXNAMLEN;
439e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
4409922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
441e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
442835e5061SAlexander Leidinger }
443835e5061SAlexander Leidinger 
444835e5061SAlexander Leidinger int
445835e5061SAlexander Leidinger linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
446835e5061SAlexander Leidinger {
447835e5061SAlexander Leidinger 	struct l_statfs64 linux_statfs;
4482f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
449835e5061SAlexander Leidinger 	char *path;
450835e5061SAlexander Leidinger 	int error;
451835e5061SAlexander Leidinger 
4523ab85269SDavid Malone 	if (args->bufsize != sizeof(struct l_statfs64))
453340f4a8dSEd Maste 		return (EINVAL);
4543ab85269SDavid Malone 
455a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
456a125ed50SMateusz Guzik 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
457a125ed50SMateusz Guzik 		error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
458a125ed50SMateusz Guzik 	} else {
459af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->path, &path);
4602f304845SKonstantin Belousov 		bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4612f304845SKonstantin Belousov 		error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
462835e5061SAlexander Leidinger 		LFREEPATH(path);
463a125ed50SMateusz Guzik 	}
4642f304845SKonstantin Belousov 	if (error == 0)
4652f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4662f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4672f304845SKonstantin Belousov 	if (error != 0)
468835e5061SAlexander Leidinger 		return (error);
4697958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
470835e5061SAlexander Leidinger }
47199546279SDmitry Chagin 
47299546279SDmitry Chagin int
47399546279SDmitry Chagin linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
47499546279SDmitry Chagin {
47599546279SDmitry Chagin 	struct l_statfs64 linux_statfs;
4762f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
47799546279SDmitry Chagin 	int error;
47899546279SDmitry Chagin 
47999546279SDmitry Chagin 	if (args->bufsize != sizeof(struct l_statfs64))
48099546279SDmitry Chagin 		return (EINVAL);
48199546279SDmitry Chagin 
4822f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4832f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
4842f304845SKonstantin Belousov 	if (error == 0)
4852f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4862f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4872f304845SKonstantin Belousov 	if (error != 0)
4882f304845SKonstantin Belousov 		return (error);
48999546279SDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
49099546279SDmitry Chagin }
4917f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
492835e5061SAlexander Leidinger 
493c21dee17SSøren Schmidt int
494b40ce416SJulian Elischer linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
495c21dee17SSøren Schmidt {
4965002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
4972f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
498c21dee17SSøren Schmidt 	int error;
499c21dee17SSøren Schmidt 
5002f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
5012f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
5022f304845SKonstantin Belousov 	if (error == 0)
5032f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
5042f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
5052f304845SKonstantin Belousov 	if (error != 0)
5062ad02313SDmitry Chagin 		return (error);
5077958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
508c21dee17SSøren Schmidt }
509408da119SMarcel Moolenaar 
5105002a60fSMarcel Moolenaar struct l_ustat
511408da119SMarcel Moolenaar {
5125002a60fSMarcel Moolenaar 	l_daddr_t	f_tfree;
5135002a60fSMarcel Moolenaar 	l_ino_t		f_tinode;
5145002a60fSMarcel Moolenaar 	char		f_fname[6];
5155002a60fSMarcel Moolenaar 	char		f_fpack[6];
5165002a60fSMarcel Moolenaar };
5175002a60fSMarcel Moolenaar 
518931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
5195002a60fSMarcel Moolenaar int
520b40ce416SJulian Elischer linux_ustat(struct thread *td, struct linux_ustat_args *args)
5215002a60fSMarcel Moolenaar {
5221e247cc2SPoul-Henning Kamp 
5231e247cc2SPoul-Henning Kamp 	return (EOPNOTSUPP);
524408da119SMarcel Moolenaar }
525931e2a1aSEd Maste #endif
5265002a60fSMarcel Moolenaar 
5271997c537SDavid E. O'Brien #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
5285002a60fSMarcel Moolenaar 
5295002a60fSMarcel Moolenaar static int
5305002a60fSMarcel Moolenaar stat64_copyout(struct stat *buf, void *ubuf)
5315002a60fSMarcel Moolenaar {
5325002a60fSMarcel Moolenaar 	struct l_stat64 lbuf;
5335002a60fSMarcel Moolenaar 
5345002a60fSMarcel Moolenaar 	bzero(&lbuf, sizeof(lbuf));
535ab35e1c7SBruce Evans 	lbuf.st_dev = dev_to_ldev(buf->st_dev);
5365002a60fSMarcel Moolenaar 	lbuf.st_ino = buf->st_ino;
5375002a60fSMarcel Moolenaar 	lbuf.st_mode = buf->st_mode;
5385002a60fSMarcel Moolenaar 	lbuf.st_nlink = buf->st_nlink;
5395002a60fSMarcel Moolenaar 	lbuf.st_uid = buf->st_uid;
5405002a60fSMarcel Moolenaar 	lbuf.st_gid = buf->st_gid;
5415002a60fSMarcel Moolenaar 	lbuf.st_rdev = buf->st_rdev;
5425002a60fSMarcel Moolenaar 	lbuf.st_size = buf->st_size;
543510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
544510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
545510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
546510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
547510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
548510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
5495002a60fSMarcel Moolenaar 	lbuf.st_blksize = buf->st_blksize;
5505002a60fSMarcel Moolenaar 	lbuf.st_blocks = buf->st_blocks;
5515002a60fSMarcel Moolenaar 
5525002a60fSMarcel Moolenaar 	/*
5535002a60fSMarcel Moolenaar 	 * The __st_ino field makes all the difference. In the Linux kernel
5545002a60fSMarcel Moolenaar 	 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
5555002a60fSMarcel Moolenaar 	 * but without the assignment to __st_ino the runtime linker refuses
5565002a60fSMarcel Moolenaar 	 * to mmap(2) any shared libraries. I guess it's broken alright :-)
5575002a60fSMarcel Moolenaar 	 */
5585002a60fSMarcel Moolenaar 	lbuf.__st_ino = buf->st_ino;
5595002a60fSMarcel Moolenaar 
5605002a60fSMarcel Moolenaar 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
5615002a60fSMarcel Moolenaar }
5625002a60fSMarcel Moolenaar 
5635002a60fSMarcel Moolenaar int
564b40ce416SJulian Elischer linux_stat64(struct thread *td, struct linux_stat64_args *args)
5655002a60fSMarcel Moolenaar {
5665002a60fSMarcel Moolenaar 	struct stat buf;
567206a5d3aSIan Dowse 	char *filename;
568f7a25872SJohn Baldwin 	int error;
5695002a60fSMarcel Moolenaar 
570a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
571a125ed50SMateusz Guzik 		error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
572a125ed50SMateusz Guzik 	} else {
573af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->filename, &filename);
5740eee862aSEd Schouten 		error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
575206a5d3aSIan Dowse 		LFREEPATH(filename);
576a125ed50SMateusz Guzik 	}
5775002a60fSMarcel Moolenaar 	if (error)
5785002a60fSMarcel Moolenaar 		return (error);
5795002a60fSMarcel Moolenaar 	return (stat64_copyout(&buf, args->statbuf));
5805002a60fSMarcel Moolenaar }
5815002a60fSMarcel Moolenaar 
5825002a60fSMarcel Moolenaar int
583b40ce416SJulian Elischer linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
5845002a60fSMarcel Moolenaar {
5855002a60fSMarcel Moolenaar 	struct stat sb;
586206a5d3aSIan Dowse 	char *filename;
587f7a25872SJohn Baldwin 	int error;
5885002a60fSMarcel Moolenaar 
589a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
590a125ed50SMateusz Guzik 		error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
591a125ed50SMateusz Guzik 	} else {
592af4051d2SMateusz Guzik 		LCONVPATHEXIST(args->filename, &filename);
5930eee862aSEd Schouten 		error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
594206a5d3aSIan Dowse 		LFREEPATH(filename);
595a125ed50SMateusz Guzik 	}
5965002a60fSMarcel Moolenaar 	if (error)
5975002a60fSMarcel Moolenaar 		return (error);
5985002a60fSMarcel Moolenaar 	return (stat64_copyout(&sb, args->statbuf));
5995002a60fSMarcel Moolenaar }
6005002a60fSMarcel Moolenaar 
6015002a60fSMarcel Moolenaar int
602b40ce416SJulian Elischer linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
6035002a60fSMarcel Moolenaar {
6045002a60fSMarcel Moolenaar 	struct stat buf;
6055002a60fSMarcel Moolenaar 	int error;
6065002a60fSMarcel Moolenaar 
607f7a25872SJohn Baldwin 	error = kern_fstat(td, args->fd, &buf);
608060e4882SDoug Ambrisko 	translate_fd_major_minor(td, args->fd, &buf);
6095002a60fSMarcel Moolenaar 	if (!error)
6105002a60fSMarcel Moolenaar 		error = stat64_copyout(&buf, args->statbuf);
6115002a60fSMarcel Moolenaar 
6125002a60fSMarcel Moolenaar 	return (error);
6135002a60fSMarcel Moolenaar }
6145002a60fSMarcel Moolenaar 
61548b05c3fSKonstantin Belousov int
61648b05c3fSKonstantin Belousov linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
61748b05c3fSKonstantin Belousov {
61848b05c3fSKonstantin Belousov 	char *path;
6199d167945SEdward Tomasz Napierala 	int error, dfd, flag, unsupported;
62048b05c3fSKonstantin Belousov 	struct stat buf;
62148b05c3fSKonstantin Belousov 
6229d167945SEdward Tomasz Napierala 	unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
6239d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
6249d167945SEdward Tomasz Napierala 		linux_msg(td, "fstatat64 unsupported flag 0x%x", unsupported);
62548b05c3fSKonstantin Belousov 		return (EINVAL);
6264b45c2bbSEdward Tomasz Napierala 	}
62748b05c3fSKonstantin Belousov 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
62848b05c3fSKonstantin Belousov 	    AT_SYMLINK_NOFOLLOW : 0;
6294b45c2bbSEdward Tomasz Napierala 	flag |= (args->flag & LINUX_AT_EMPTY_PATH) ?
6304b45c2bbSEdward Tomasz Napierala 	    AT_EMPTY_PATH : 0;
63148b05c3fSKonstantin Belousov 
63248b05c3fSKonstantin Belousov 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
633a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
634a125ed50SMateusz Guzik 		error = linux_kern_statat(td, flag, dfd, args->pathname,
635a125ed50SMateusz Guzik 		    UIO_USERSPACE, &buf);
636a125ed50SMateusz Guzik 	} else {
637af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dfd);
6380eee862aSEd Schouten 		error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
63948b05c3fSKonstantin Belousov 		LFREEPATH(path);
640a125ed50SMateusz Guzik 	}
641a125ed50SMateusz Guzik 	if (error == 0)
642a125ed50SMateusz Guzik 		error = stat64_copyout(&buf, args->statbuf);
64348b05c3fSKonstantin Belousov 
64448b05c3fSKonstantin Belousov 	return (error);
64548b05c3fSKonstantin Belousov }
64648b05c3fSKonstantin Belousov 
647606bcc17SDmitry Chagin #else /* __amd64__ && !COMPAT_LINUX32 */
648606bcc17SDmitry Chagin 
649606bcc17SDmitry Chagin int
650606bcc17SDmitry Chagin linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
651606bcc17SDmitry Chagin {
652606bcc17SDmitry Chagin 	char *path;
6539d167945SEdward Tomasz Napierala 	int error, dfd, flag, unsupported;
654606bcc17SDmitry Chagin 	struct stat buf;
655606bcc17SDmitry Chagin 
6569d167945SEdward Tomasz Napierala 	unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
6579d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
6589d167945SEdward Tomasz Napierala 		linux_msg(td, "fstatat unsupported flag 0x%x", unsupported);
659606bcc17SDmitry Chagin 		return (EINVAL);
6604b45c2bbSEdward Tomasz Napierala 	}
6614b45c2bbSEdward Tomasz Napierala 
662606bcc17SDmitry Chagin 	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
663606bcc17SDmitry Chagin 	    AT_SYMLINK_NOFOLLOW : 0;
6644b45c2bbSEdward Tomasz Napierala 	flag |= (args->flag & LINUX_AT_EMPTY_PATH) ?
6654b45c2bbSEdward Tomasz Napierala 	    AT_EMPTY_PATH : 0;
666606bcc17SDmitry Chagin 
667606bcc17SDmitry Chagin 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
668a125ed50SMateusz Guzik 	if (!LUSECONVPATH(td)) {
669a125ed50SMateusz Guzik 		error = linux_kern_statat(td, flag, dfd, args->pathname,
670a125ed50SMateusz Guzik 		    UIO_USERSPACE, &buf);
671a125ed50SMateusz Guzik 	} else {
672af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dfd);
673606bcc17SDmitry Chagin 		error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
674a125ed50SMateusz Guzik 		LFREEPATH(path);
675a125ed50SMateusz Guzik 	}
676606bcc17SDmitry Chagin 	if (error == 0)
677606bcc17SDmitry Chagin 		error = newstat_copyout(&buf, args->statbuf);
678606bcc17SDmitry Chagin 
679606bcc17SDmitry Chagin 	return (error);
680606bcc17SDmitry Chagin }
681606bcc17SDmitry Chagin 
6821997c537SDavid E. O'Brien #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
6839802eb9eSDmitry Chagin 
6849802eb9eSDmitry Chagin int
6859802eb9eSDmitry Chagin linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
6869802eb9eSDmitry Chagin {
6879802eb9eSDmitry Chagin 	struct mount *mp;
6889802eb9eSDmitry Chagin 	struct vnode *vp;
6899802eb9eSDmitry Chagin 	int error, save;
6909802eb9eSDmitry Chagin 
691cbd92ce6SMatt Macy 	error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
6929802eb9eSDmitry Chagin 	if (error != 0)
6939802eb9eSDmitry Chagin 		/*
6949802eb9eSDmitry Chagin 		 * Linux syncfs() returns only EBADF, however fgetvp()
6959802eb9eSDmitry Chagin 		 * can return EINVAL in case of file descriptor does
6969802eb9eSDmitry Chagin 		 * not represent a vnode. XXX.
6979802eb9eSDmitry Chagin 		 */
6989802eb9eSDmitry Chagin 		return (error);
6999802eb9eSDmitry Chagin 
7009802eb9eSDmitry Chagin 	mp = vp->v_mount;
7019802eb9eSDmitry Chagin 	mtx_lock(&mountlist_mtx);
7029802eb9eSDmitry Chagin 	error = vfs_busy(mp, MBF_MNTLSTLOCK);
7039802eb9eSDmitry Chagin 	if (error != 0) {
7049802eb9eSDmitry Chagin 		/* See comment above. */
7059802eb9eSDmitry Chagin 		mtx_unlock(&mountlist_mtx);
7069802eb9eSDmitry Chagin 		goto out;
7079802eb9eSDmitry Chagin 	}
7089802eb9eSDmitry Chagin 	if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7099802eb9eSDmitry Chagin 	    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
7109802eb9eSDmitry Chagin 		save = curthread_pflags_set(TDP_SYNCIO);
711c8b3463dSMateusz Guzik 		vfs_periodic(mp, MNT_NOWAIT);
7129802eb9eSDmitry Chagin 		VFS_SYNC(mp, MNT_NOWAIT);
7139802eb9eSDmitry Chagin 		curthread_pflags_restore(save);
7149802eb9eSDmitry Chagin 		vn_finished_write(mp);
7159802eb9eSDmitry Chagin 	}
7169802eb9eSDmitry Chagin 	vfs_unbusy(mp);
7179802eb9eSDmitry Chagin 
7189802eb9eSDmitry Chagin  out:
7199802eb9eSDmitry Chagin 	vrele(vp);
7209802eb9eSDmitry Chagin 	return (error);
7219802eb9eSDmitry Chagin }
7222362ad45SPhilippe Michaud-Boudreault 
723*e9204c5cSDmitry Chagin static int
724*e9204c5cSDmitry Chagin statx_copyout(struct stat *buf, void *ubuf)
725*e9204c5cSDmitry Chagin {
726*e9204c5cSDmitry Chagin 	struct l_statx tbuf;
727*e9204c5cSDmitry Chagin 
728*e9204c5cSDmitry Chagin 	bzero(&tbuf, sizeof(tbuf));
729*e9204c5cSDmitry Chagin 	tbuf.stx_mask = STATX_ALL;
730*e9204c5cSDmitry Chagin 	tbuf.stx_blksize = buf->st_blksize;
731*e9204c5cSDmitry Chagin 	tbuf.stx_attributes = 0;
732*e9204c5cSDmitry Chagin 	tbuf.stx_nlink = buf->st_nlink;
733*e9204c5cSDmitry Chagin 	tbuf.stx_uid = buf->st_uid;
734*e9204c5cSDmitry Chagin 	tbuf.stx_gid = buf->st_gid;
735*e9204c5cSDmitry Chagin 	tbuf.stx_mode = buf->st_mode;
736*e9204c5cSDmitry Chagin 	tbuf.stx_ino = buf->st_ino;
737*e9204c5cSDmitry Chagin 	tbuf.stx_size = buf->st_size;
738*e9204c5cSDmitry Chagin 	tbuf.stx_blocks = buf->st_blocks;
739*e9204c5cSDmitry Chagin 
740*e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
741*e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
742*e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
743*e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
744*e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
745*e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
746*e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
747*e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
748*e9204c5cSDmitry Chagin 
749*e9204c5cSDmitry Chagin 	tbuf.stx_rdev_major = buf->st_rdev >> 8;
750*e9204c5cSDmitry Chagin 	tbuf.stx_rdev_minor = buf->st_rdev & 0xff;
751*e9204c5cSDmitry Chagin 	tbuf.stx_dev_major = buf->st_dev >> 8;
752*e9204c5cSDmitry Chagin 	tbuf.stx_dev_minor = buf->st_dev & 0xff;
753*e9204c5cSDmitry Chagin 
754*e9204c5cSDmitry Chagin 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
755*e9204c5cSDmitry Chagin }
756*e9204c5cSDmitry Chagin 
7572362ad45SPhilippe Michaud-Boudreault int
7582362ad45SPhilippe Michaud-Boudreault linux_statx(struct thread *td, struct linux_statx_args *args)
7592362ad45SPhilippe Michaud-Boudreault {
7602362ad45SPhilippe Michaud-Boudreault 	char *path;
7619d167945SEdward Tomasz Napierala 	int error, dirfd, flags, unsupported;
7622362ad45SPhilippe Michaud-Boudreault 	struct stat buf;
7632362ad45SPhilippe Michaud-Boudreault 
764ff39d74aSDmitry Chagin 	unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW |
765ff39d74aSDmitry Chagin 	    LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT);
7669d167945SEdward Tomasz Napierala 	if (unsupported != 0) {
7679d167945SEdward Tomasz Napierala 		linux_msg(td, "statx unsupported flags 0x%x", unsupported);
7682362ad45SPhilippe Michaud-Boudreault 		return (EINVAL);
7692362ad45SPhilippe Michaud-Boudreault 	}
7702362ad45SPhilippe Michaud-Boudreault 
7712362ad45SPhilippe Michaud-Boudreault 	flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ?
7722362ad45SPhilippe Michaud-Boudreault 	    AT_SYMLINK_NOFOLLOW : 0;
7732362ad45SPhilippe Michaud-Boudreault 	flags |= (args->flags & LINUX_AT_EMPTY_PATH) ?
7742362ad45SPhilippe Michaud-Boudreault 	    AT_EMPTY_PATH : 0;
7752362ad45SPhilippe Michaud-Boudreault 
7762362ad45SPhilippe Michaud-Boudreault 	dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
7772362ad45SPhilippe Michaud-Boudreault 	if (!LUSECONVPATH(td)) {
7782362ad45SPhilippe Michaud-Boudreault 		error = linux_kern_statat(td, flags, dirfd, args->pathname,
7792362ad45SPhilippe Michaud-Boudreault 		    UIO_USERSPACE, &buf);
7802362ad45SPhilippe Michaud-Boudreault 	} else {
781af4051d2SMateusz Guzik 		LCONVPATHEXIST_AT(args->pathname, &path, dirfd);
7822362ad45SPhilippe Michaud-Boudreault 		error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf);
7832362ad45SPhilippe Michaud-Boudreault 		LFREEPATH(path);
7842362ad45SPhilippe Michaud-Boudreault 	}
7852362ad45SPhilippe Michaud-Boudreault 	if (error == 0)
7862362ad45SPhilippe Michaud-Boudreault 		error = statx_copyout(&buf, args->statxbuf);
7872362ad45SPhilippe Michaud-Boudreault 
7882362ad45SPhilippe Michaud-Boudreault 	return (error);
7892362ad45SPhilippe Michaud-Boudreault }
790