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