19313Ssos/*-
2230132Suqs * Copyright (c) 1994-1995 S��ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
9111798Sdes *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
1597748Sschweikh *    derived from this software without specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos */
289313Ssos
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD$");
31116173Sobrien
32156874Sru#include "opt_compat.h"
33101189Srwatson
349313Ssos#include <sys/param.h>
359313Ssos#include <sys/dirent.h>
369313Ssos#include <sys/file.h>
379313Ssos#include <sys/filedesc.h>
389313Ssos#include <sys/proc.h>
39102954Sbde#include <sys/malloc.h>
409313Ssos#include <sys/mount.h>
419313Ssos#include <sys/namei.h>
429313Ssos#include <sys/stat.h>
43141473Sjhb#include <sys/syscallsubr.h>
4453758Smarcel#include <sys/systm.h>
45181905Sed#include <sys/tty.h>
469313Ssos#include <sys/vnode.h>
47158311Sambrisko#include <sys/conf.h>
48158311Sambrisko#include <sys/fcntl.h>
499313Ssos
50140214Sobrien#ifdef COMPAT_LINUX32
51140214Sobrien#include <machine/../linux32/linux.h>
52140214Sobrien#include <machine/../linux32/linux32_proto.h>
53140214Sobrien#else
5464913Smarcel#include <machine/../linux/linux.h>
5568583Smarcel#include <machine/../linux/linux_proto.h>
56133816Stjr#endif
57102954Sbde
5864913Smarcel#include <compat/linux/linux_util.h>
59177997Skib#include <compat/linux/linux_file.h>
609313Ssos
61218497Snetchild#define	LINUX_SHMFS_MAGIC 0x01021994
62218497Snetchild
63188849Sedstatic void
64188849Sedtranslate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
65188849Sed{
66188849Sed	int major, minor;
67188849Sed
68188849Sed	if (vp->v_type == VCHR && vp->v_rdev != NULL &&
69231378Sed	    linux_driver_get_major_minor(devtoname(vp->v_rdev),
70188849Sed	    &major, &minor) == 0) {
71188849Sed		sb->st_rdev = (major << 8 | minor);
72188849Sed	}
73188849Sed}
74188849Sed
75188849Sedstatic int
76188849Sedlinux_kern_statat(struct thread *td, int flag, int fd, char *path,
77188849Sed    enum uio_seg pathseg, struct stat *sbp)
78188849Sed{
79188849Sed
80188849Sed	return (kern_statat_vnhook(td, flag, fd, path, pathseg, sbp,
81188849Sed	    translate_vnhook_major_minor));
82188849Sed}
83188849Sed
84188849Sedstatic int
85188849Sedlinux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
86188849Sed    struct stat *sbp)
87188849Sed{
88188849Sed
89188849Sed	return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
90188849Sed}
91188849Sed
92188849Sedstatic int
93188849Sedlinux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
94188849Sed    struct stat *sbp)
95188849Sed{
96188849Sed
97188849Sed	return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
98188849Sed	    pathseg, sbp));
99188849Sed}
100188849Sed
101143635Sphk/*
102143635Sphk * XXX: This was removed from newstat_copyout(), and almost identical
103143635Sphk * XXX: code was in stat64_copyout().  findcdev() needs to be replaced
104143635Sphk * XXX: with something that does lookup and locking properly.
105143635Sphk * XXX: When somebody fixes this: please try to avoid duplicating it.
106143635Sphk */
107143635Sphk#if 0
108143635Sphkstatic void
109143635Sphkdisk_foo(struct somestat *tbuf)
1109313Ssos{
11171048Sjoe	struct cdevsw *cdevsw;
112130585Sphk	struct cdev *dev;
1139313Ssos
11471048Sjoe	/* Lie about disk drives which are character devices
11571048Sjoe	 * in FreeBSD but block devices under Linux.
11671048Sjoe	 */
11783221Smarcel	if (S_ISCHR(tbuf.st_mode) &&
118130640Sphk	    (dev = findcdev(buf->st_rdev)) != NULL) {
119135715Sphk		cdevsw = dev_refthread(dev);
120135715Sphk		if (cdevsw != NULL) {
121135715Sphk			if (cdevsw->d_flags & D_DISK) {
122135715Sphk				tbuf.st_mode &= ~S_IFMT;
123135715Sphk				tbuf.st_mode |= S_IFBLK;
12450356Smarcel
125135715Sphk				/* XXX this may not be quite right */
126135715Sphk				/* Map major number to 0 */
127187830Sed				tbuf.st_dev = minor(buf->st_dev) & 0xf;
128135715Sphk				tbuf.st_rdev = buf->st_rdev & 0xff;
129135715Sphk			}
130135715Sphk			dev_relthread(dev);
13171048Sjoe		}
13270458Spaul	}
13370458Spaul
134143635Sphk}
135143635Sphk#endif
136143635Sphk
137158311Sambriskostatic void
138158311Sambriskotranslate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
139158311Sambrisko{
140158311Sambrisko	struct file *fp;
141188849Sed	struct vnode *vp;
142158311Sambrisko	int major, minor;
143158311Sambrisko
144224778Srwatson	/*
145224778Srwatson	 * No capability rights required here.
146224778Srwatson	 */
147164890Sjkim	if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
148224778Srwatson	    fget(td, fd, 0, &fp) != 0)
149158311Sambrisko		return;
150188849Sed	vp = fp->f_vnode;
151188849Sed	if (vp != NULL && vp->v_rdev != NULL &&
152231378Sed	    linux_driver_get_major_minor(devtoname(vp->v_rdev),
153181905Sed					 &major, &minor) == 0) {
154164890Sjkim		buf->st_rdev = (major << 8 | minor);
155181905Sed	} else if (fp->f_type == DTYPE_PTS) {
156181905Sed		struct tty *tp = fp->f_data;
157181905Sed
158181905Sed		/* Convert the numbers for the slave device. */
159231378Sed		if (linux_driver_get_major_minor(devtoname(tp->t_dev),
160181905Sed					 &major, &minor) == 0) {
161181905Sed			buf->st_rdev = (major << 8 | minor);
162181905Sed		}
163181905Sed	}
164158311Sambrisko	fdrop(fp, td);
165158311Sambrisko}
166158311Sambrisko
167143635Sphkstatic int
168143635Sphknewstat_copyout(struct stat *buf, void *ubuf)
169143635Sphk{
170143635Sphk	struct l_newstat tbuf;
171143635Sphk
172143635Sphk	bzero(&tbuf, sizeof(tbuf));
173187830Sed	tbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8);
174143635Sphk	tbuf.st_ino = buf->st_ino;
175143635Sphk	tbuf.st_mode = buf->st_mode;
176143635Sphk	tbuf.st_nlink = buf->st_nlink;
177143635Sphk	tbuf.st_uid = buf->st_uid;
178143635Sphk	tbuf.st_gid = buf->st_gid;
179143635Sphk	tbuf.st_rdev = buf->st_rdev;
180143635Sphk	tbuf.st_size = buf->st_size;
181205792Sed	tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
182205792Sed	tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
183205792Sed	tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
184205792Sed	tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
185205792Sed	tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
186205792Sed	tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
187143635Sphk	tbuf.st_blksize = buf->st_blksize;
188143635Sphk	tbuf.st_blocks = buf->st_blocks;
189143635Sphk
19050356Smarcel	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
1919313Ssos}
1929313Ssos
1939313Ssosint
19483366Sjulianlinux_newstat(struct thread *td, struct linux_newstat_args *args)
1959313Ssos{
19650356Smarcel	struct stat buf;
197102814Siedowse	char *path;
19850356Smarcel	int error;
19914331Speter
200102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
20150356Smarcel
2029313Ssos#ifdef DEBUG
20372543Sjlemon	if (ldebug(newstat))
204102814Siedowse		printf(ARGS(newstat, "%s, *"), path);
2059313Ssos#endif
20650356Smarcel
207188849Sed	error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
208102814Siedowse	LFREEPATH(path);
20950356Smarcel	if (error)
21050356Smarcel		return (error);
21150356Smarcel	return (newstat_copyout(&buf, args->buf));
2129313Ssos}
2139313Ssos
2149313Ssosint
21583366Sjulianlinux_newlstat(struct thread *td, struct linux_newlstat_args *args)
2169313Ssos{
21750356Smarcel	struct stat sb;
218102814Siedowse	char *path;
219141473Sjhb	int error;
22014331Speter
221102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
22250356Smarcel
2239313Ssos#ifdef DEBUG
22472543Sjlemon	if (ldebug(newlstat))
225102814Siedowse		printf(ARGS(newlstat, "%s, *"), path);
2269313Ssos#endif
22750356Smarcel
228188849Sed	error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
229102814Siedowse	LFREEPATH(path);
23014331Speter	if (error)
23114331Speter		return (error);
23283221Smarcel	return (newstat_copyout(&sb, args->buf));
2339313Ssos}
2349313Ssos
2359313Ssosint
23683366Sjulianlinux_newfstat(struct thread *td, struct linux_newfstat_args *args)
2379313Ssos{
23850356Smarcel	struct stat buf;
23950356Smarcel	int error;
24050356Smarcel
2419313Ssos#ifdef DEBUG
24272543Sjlemon	if (ldebug(newfstat))
24372543Sjlemon		printf(ARGS(newfstat, "%d, *"), args->fd);
2449313Ssos#endif
24550356Smarcel
246141473Sjhb	error = kern_fstat(td, args->fd, &buf);
247158311Sambrisko	translate_fd_major_minor(td, args->fd, &buf);
24850356Smarcel	if (!error)
24950356Smarcel		error = newstat_copyout(&buf, args->buf);
25050356Smarcel
25150356Smarcel	return (error);
2529313Ssos}
2539313Ssos
254156842Snetchildstatic int
255156842Snetchildstat_copyout(struct stat *buf, void *ubuf)
256156842Snetchild{
257156842Snetchild	struct l_stat lbuf;
258156842Snetchild
259156842Snetchild	bzero(&lbuf, sizeof(lbuf));
260156842Snetchild	lbuf.st_dev = buf->st_dev;
261156842Snetchild	lbuf.st_ino = buf->st_ino;
262156842Snetchild	lbuf.st_mode = buf->st_mode;
263156842Snetchild	lbuf.st_nlink = buf->st_nlink;
264156842Snetchild	lbuf.st_uid = buf->st_uid;
265156842Snetchild	lbuf.st_gid = buf->st_gid;
266156842Snetchild	lbuf.st_rdev = buf->st_rdev;
267156842Snetchild	if (buf->st_size < (quad_t)1 << 32)
268156842Snetchild		lbuf.st_size = buf->st_size;
269156842Snetchild	else
270156842Snetchild		lbuf.st_size = -2;
271205792Sed	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
272205792Sed	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
273205792Sed	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
274205792Sed	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
275205792Sed	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
276205792Sed	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
277156842Snetchild	lbuf.st_blksize = buf->st_blksize;
278156842Snetchild	lbuf.st_blocks = buf->st_blocks;
279156842Snetchild	lbuf.st_flags = buf->st_flags;
280156842Snetchild	lbuf.st_gen = buf->st_gen;
281156842Snetchild
282156842Snetchild	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
283156842Snetchild}
284156842Snetchild
285156842Snetchildint
286156842Snetchildlinux_stat(struct thread *td, struct linux_stat_args *args)
287156842Snetchild{
288156842Snetchild	struct stat buf;
289174974Skib	char *path;
290156842Snetchild	int error;
291174974Skib
292174974Skib	LCONVPATHEXIST(td, args->path, &path);
293174974Skib
294156842Snetchild#ifdef DEBUG
295156842Snetchild	if (ldebug(stat))
296175107Skib		printf(ARGS(stat, "%s, *"), path);
297156842Snetchild#endif
298188849Sed	error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
299175107Skib	if (error) {
300175107Skib		LFREEPATH(path);
301175107Skib		return (error);
302175107Skib	}
303174974Skib	LFREEPATH(path);
304156842Snetchild	return(stat_copyout(&buf, args->up));
305156842Snetchild}
306156842Snetchild
307156842Snetchildint
308156842Snetchildlinux_lstat(struct thread *td, struct linux_lstat_args *args)
309156842Snetchild{
310156842Snetchild	struct stat buf;
311174974Skib	char *path;
312156842Snetchild	int error;
313156842Snetchild
314174974Skib	LCONVPATHEXIST(td, args->path, &path);
315174974Skib
316156842Snetchild#ifdef DEBUG
317156842Snetchild	if (ldebug(lstat))
318175107Skib		printf(ARGS(lstat, "%s, *"), path);
319156842Snetchild#endif
320188849Sed	error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
321175107Skib	if (error) {
322175107Skib		LFREEPATH(path);
323175107Skib		return (error);
324175107Skib	}
325174974Skib	LFREEPATH(path);
326156842Snetchild	return(stat_copyout(&buf, args->up));
327156842Snetchild}
328156842Snetchild
32983221Smarcel/* XXX - All fields of type l_int are defined as l_long on i386 */
33083221Smarcelstruct l_statfs {
33183221Smarcel	l_int		f_type;
33283221Smarcel	l_int		f_bsize;
33383221Smarcel	l_int		f_blocks;
33483221Smarcel	l_int		f_bfree;
33583221Smarcel	l_int		f_bavail;
33683221Smarcel	l_int		f_files;
33783221Smarcel	l_int		f_ffree;
33883221Smarcel	l_fsid_t	f_fsid;
33983221Smarcel	l_int		f_namelen;
34083221Smarcel	l_int		f_spare[6];
3419313Ssos};
3429313Ssos
34355629Smarcel#define	LINUX_CODA_SUPER_MAGIC	0x73757245L
34455629Smarcel#define	LINUX_EXT2_SUPER_MAGIC	0xEF53L
34555629Smarcel#define	LINUX_HPFS_SUPER_MAGIC	0xf995e849L
34655629Smarcel#define	LINUX_ISOFS_SUPER_MAGIC	0x9660L
34755629Smarcel#define	LINUX_MSDOS_SUPER_MAGIC	0x4d44L
34855629Smarcel#define	LINUX_NCP_SUPER_MAGIC	0x564cL
34955629Smarcel#define	LINUX_NFS_SUPER_MAGIC	0x6969L
35055629Smarcel#define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
35155629Smarcel#define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
35255629Smarcel#define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
353154834Scognet#define LINUX_DEVFS_SUPER_MAGIC	0x1373L
35455629Smarcel
35555629Smarcelstatic long
35683667Ssobomaxbsd_to_linux_ftype(const char *fstypename)
35755629Smarcel{
35883667Ssobomax	int i;
35983667Ssobomax	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
36083667Ssobomax		{"ufs",     LINUX_UFS_SUPER_MAGIC},
36183667Ssobomax		{"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
36283667Ssobomax		{"nfs",     LINUX_NFS_SUPER_MAGIC},
36383667Ssobomax		{"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
36483667Ssobomax		{"procfs",  LINUX_PROC_SUPER_MAGIC},
36583667Ssobomax		{"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
36683667Ssobomax		{"ntfs",    LINUX_NTFS_SUPER_MAGIC},
36783667Ssobomax		{"nwfs",    LINUX_NCP_SUPER_MAGIC},
36883667Ssobomax		{"hpfs",    LINUX_HPFS_SUPER_MAGIC},
36983667Ssobomax		{"coda",    LINUX_CODA_SUPER_MAGIC},
370154834Scognet		{"devfs",   LINUX_DEVFS_SUPER_MAGIC},
37183667Ssobomax		{NULL,      0L}};
37255629Smarcel
37383667Ssobomax	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
37483667Ssobomax		if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
37583667Ssobomax			return (b2l_tbl[i].linux_type);
37655629Smarcel
37755629Smarcel	return (0L);
37855629Smarcel}
37955629Smarcel
380141473Sjhbstatic void
381146695Spjdbsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
382141473Sjhb{
383141473Sjhb
384141473Sjhb	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
385141473Sjhb	linux_statfs->f_bsize = bsd_statfs->f_bsize;
386141473Sjhb	linux_statfs->f_blocks = bsd_statfs->f_blocks;
387141473Sjhb	linux_statfs->f_bfree = bsd_statfs->f_bfree;
388141473Sjhb	linux_statfs->f_bavail = bsd_statfs->f_bavail;
389141473Sjhb	linux_statfs->f_ffree = bsd_statfs->f_ffree;
390141473Sjhb	linux_statfs->f_files = bsd_statfs->f_files;
391146502Spjd	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
392146502Spjd	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
393141473Sjhb	linux_statfs->f_namelen = MAXNAMLEN;
394141473Sjhb}
395141473Sjhb
3969313Ssosint
39783366Sjulianlinux_statfs(struct thread *td, struct linux_statfs_args *args)
3989313Ssos{
39983221Smarcel	struct l_statfs linux_statfs;
400141473Sjhb	struct statfs bsd_statfs;
401102814Siedowse	char *path;
402218497Snetchild	int error, dev_shm;
4039313Ssos
404102814Siedowse	LCONVPATHEXIST(td, args->path, &path);
40514331Speter
4069313Ssos#ifdef DEBUG
40772543Sjlemon	if (ldebug(statfs))
408102814Siedowse		printf(ARGS(statfs, "%s, *"), path);
4099313Ssos#endif
410218497Snetchild	dev_shm = 0;
411141473Sjhb	error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs);
412218497Snetchild	if (strncmp(path, "/dev/shm", sizeof("/dev/shm") - 1) == 0)
413218497Snetchild		dev_shm = (path[8] == '\0'
414218497Snetchild		    || (path[8] == '/' && path[9] == '\0'));
415102814Siedowse	LFREEPATH(path);
41646571Speter	if (error)
417101189Srwatson		return (error);
418146695Spjd	bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
419218497Snetchild	if (dev_shm)
420218497Snetchild		linux_statfs.f_type = LINUX_SHMFS_MAGIC;
421111797Sdes	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
4229313Ssos}
4239313Ssos
424161665Snetchildstatic void
425161665Snetchildbsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
426161665Snetchild{
427161665Snetchild
428161665Snetchild	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
429161665Snetchild	linux_statfs->f_bsize = bsd_statfs->f_bsize;
430161665Snetchild	linux_statfs->f_blocks = bsd_statfs->f_blocks;
431161665Snetchild	linux_statfs->f_bfree = bsd_statfs->f_bfree;
432161665Snetchild	linux_statfs->f_bavail = bsd_statfs->f_bavail;
433161665Snetchild	linux_statfs->f_ffree = bsd_statfs->f_ffree;
434161665Snetchild	linux_statfs->f_files = bsd_statfs->f_files;
435161665Snetchild	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
436161665Snetchild	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
437161665Snetchild	linux_statfs->f_namelen = MAXNAMLEN;
438161665Snetchild}
439161665Snetchild
4409313Ssosint
441161665Snetchildlinux_statfs64(struct thread *td, struct linux_statfs64_args *args)
442161665Snetchild{
443161665Snetchild	struct l_statfs64 linux_statfs;
444161665Snetchild	struct statfs bsd_statfs;
445161665Snetchild	char *path;
446161665Snetchild	int error;
447161665Snetchild
448172220Sdwmalone	if (args->bufsize != sizeof(struct l_statfs64))
449172220Sdwmalone		return EINVAL;
450172220Sdwmalone
451161665Snetchild	LCONVPATHEXIST(td, args->path, &path);
452161665Snetchild
453161665Snetchild#ifdef DEBUG
454161665Snetchild	if (ldebug(statfs64))
455161665Snetchild		printf(ARGS(statfs64, "%s, *"), path);
456161665Snetchild#endif
457161665Snetchild	error = kern_statfs(td, path, UIO_SYSSPACE, &bsd_statfs);
458161665Snetchild	LFREEPATH(path);
459161665Snetchild	if (error)
460161665Snetchild		return (error);
461161665Snetchild	bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs);
462161665Snetchild	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
463161665Snetchild}
464161665Snetchild
465161665Snetchildint
46683366Sjulianlinux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
4679313Ssos{
46883221Smarcel	struct l_statfs linux_statfs;
469141473Sjhb	struct statfs bsd_statfs;
4709313Ssos	int error;
4719313Ssos
4729313Ssos#ifdef DEBUG
47372543Sjlemon	if (ldebug(fstatfs))
47472543Sjlemon		printf(ARGS(fstatfs, "%d, *"), args->fd);
4759313Ssos#endif
476141473Sjhb	error = kern_fstatfs(td, args->fd, &bsd_statfs);
47746571Speter	if (error)
4789313Ssos		return error;
479146695Spjd	bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
480141473Sjhb	return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
4819313Ssos}
48253758Smarcel
483111798Sdesstruct l_ustat
48483221Smarcel{
48583221Smarcel	l_daddr_t	f_tfree;
48683221Smarcel	l_ino_t		f_tinode;
48783221Smarcel	char		f_fname[6];
48883221Smarcel	char		f_fpack[6];
48983221Smarcel};
49083221Smarcel
49153758Smarcelint
49283366Sjulianlinux_ustat(struct thread *td, struct linux_ustat_args *args)
49353758Smarcel{
494142220Sphk#ifdef DEBUG
495142220Sphk	if (ldebug(ustat))
496142220Sphk		printf(ARGS(ustat, "%d, *"), args->dev);
497142220Sphk#endif
498142220Sphk
499142220Sphk	return (EOPNOTSUPP);
50053758Smarcel}
50183221Smarcel
502140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
50383221Smarcel
50483221Smarcelstatic int
50583221Smarcelstat64_copyout(struct stat *buf, void *ubuf)
50683221Smarcel{
50783221Smarcel	struct l_stat64 lbuf;
50883221Smarcel
50983221Smarcel	bzero(&lbuf, sizeof(lbuf));
510187830Sed	lbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8);
51183221Smarcel	lbuf.st_ino = buf->st_ino;
51283221Smarcel	lbuf.st_mode = buf->st_mode;
51383221Smarcel	lbuf.st_nlink = buf->st_nlink;
51483221Smarcel	lbuf.st_uid = buf->st_uid;
51583221Smarcel	lbuf.st_gid = buf->st_gid;
51683221Smarcel	lbuf.st_rdev = buf->st_rdev;
51783221Smarcel	lbuf.st_size = buf->st_size;
518205792Sed	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
519205792Sed	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
520205792Sed	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
521205792Sed	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
522205792Sed	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
523205792Sed	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
52483221Smarcel	lbuf.st_blksize = buf->st_blksize;
52583221Smarcel	lbuf.st_blocks = buf->st_blocks;
52683221Smarcel
52783221Smarcel	/*
52883221Smarcel	 * The __st_ino field makes all the difference. In the Linux kernel
52983221Smarcel	 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
53083221Smarcel	 * but without the assignment to __st_ino the runtime linker refuses
53183221Smarcel	 * to mmap(2) any shared libraries. I guess it's broken alright :-)
53283221Smarcel	 */
53383221Smarcel	lbuf.__st_ino = buf->st_ino;
53483221Smarcel
53583221Smarcel	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
53683221Smarcel}
53783221Smarcel
53883221Smarcelint
53983366Sjulianlinux_stat64(struct thread *td, struct linux_stat64_args *args)
54083221Smarcel{
54183221Smarcel	struct stat buf;
542141473Sjhb	char *filename;
54383221Smarcel	int error;
54483221Smarcel
545102814Siedowse	LCONVPATHEXIST(td, args->filename, &filename);
54683221Smarcel
54783221Smarcel#ifdef DEBUG
54883221Smarcel	if (ldebug(stat64))
549102814Siedowse		printf(ARGS(stat64, "%s, *"), filename);
55083221Smarcel#endif
55183221Smarcel
552188849Sed	error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
553102814Siedowse	LFREEPATH(filename);
55483221Smarcel	if (error)
55583221Smarcel		return (error);
55683221Smarcel	return (stat64_copyout(&buf, args->statbuf));
55783221Smarcel}
55883221Smarcel
55983221Smarcelint
56083366Sjulianlinux_lstat64(struct thread *td, struct linux_lstat64_args *args)
56183221Smarcel{
56283221Smarcel	struct stat sb;
563102814Siedowse	char *filename;
564141473Sjhb	int error;
56583221Smarcel
566102814Siedowse	LCONVPATHEXIST(td, args->filename, &filename);
56783221Smarcel
56883221Smarcel#ifdef DEBUG
56983221Smarcel	if (ldebug(lstat64))
57083221Smarcel		printf(ARGS(lstat64, "%s, *"), args->filename);
57183221Smarcel#endif
57283221Smarcel
573188849Sed	error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
574102814Siedowse	LFREEPATH(filename);
57583221Smarcel	if (error)
57683221Smarcel		return (error);
57783221Smarcel	return (stat64_copyout(&sb, args->statbuf));
57883221Smarcel}
57983221Smarcel
58083221Smarcelint
58183366Sjulianlinux_fstat64(struct thread *td, struct linux_fstat64_args *args)
58283221Smarcel{
58383221Smarcel	struct stat buf;
58483221Smarcel	int error;
58583221Smarcel
58683221Smarcel#ifdef DEBUG
58783221Smarcel	if (ldebug(fstat64))
58883221Smarcel		printf(ARGS(fstat64, "%d, *"), args->fd);
58983221Smarcel#endif
59083221Smarcel
591141473Sjhb	error = kern_fstat(td, args->fd, &buf);
592158311Sambrisko	translate_fd_major_minor(td, args->fd, &buf);
59383221Smarcel	if (!error)
59483221Smarcel		error = stat64_copyout(&buf, args->statbuf);
59583221Smarcel
59683221Smarcel	return (error);
59783221Smarcel}
59883221Smarcel
599177997Skibint
600177997Skiblinux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
601177997Skib{
602177997Skib	char *path;
603177997Skib	int error, dfd, flag;
604177997Skib	struct stat buf;
605177997Skib
606177997Skib	if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
607177997Skib		return (EINVAL);
608177997Skib	flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
609177997Skib	    AT_SYMLINK_NOFOLLOW : 0;
610177997Skib
611177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
612177997Skib	LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
613177997Skib
614177997Skib#ifdef DEBUG
615177997Skib	if (ldebug(fstatat64))
616177997Skib		printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
617177997Skib#endif
618177997Skib
619188849Sed	error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
620177997Skib	if (!error)
621177997Skib		error = stat64_copyout(&buf, args->statbuf);
622177997Skib	LFREEPATH(path);
623177997Skib
624177997Skib	return (error);
625177997Skib}
626177997Skib
627140214Sobrien#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
628