Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linux/linux_file.c
101772 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 <sys/param.h>
30
#include <sys/systm.h>
31
#include <sys/dirent.h>
32
#include <sys/fcntl.h>
33
#include <sys/file.h>
34
#include <sys/filedesc.h>
35
#include <sys/inotify.h>
36
#include <sys/lock.h>
37
#include <sys/mman.h>
38
#include <sys/selinfo.h>
39
#include <sys/pipe.h>
40
#include <sys/proc.h>
41
#include <sys/specialfd.h>
42
#include <sys/stat.h>
43
#include <sys/sx.h>
44
#include <sys/syscallsubr.h>
45
#include <sys/sysproto.h>
46
#include <sys/tty.h>
47
#include <sys/unistd.h>
48
#include <sys/vnode.h>
49
50
#ifdef COMPAT_LINUX32
51
#include <compat/freebsd32/freebsd32_misc.h>
52
#include <compat/freebsd32/freebsd32_util.h>
53
#include <machine/../linux32/linux.h>
54
#include <machine/../linux32/linux32_proto.h>
55
#else
56
#include <machine/../linux/linux.h>
57
#include <machine/../linux/linux_proto.h>
58
#endif
59
#include <compat/linux/linux_misc.h>
60
#include <compat/linux/linux_util.h>
61
#include <compat/linux/linux_file.h>
62
63
static int linux_common_open(struct thread *, int, const char *, int, int,
64
enum uio_seg);
65
static int linux_do_accessat(struct thread *t, int, const char *, int, int);
66
static int linux_getdents_error(struct thread *, int, int);
67
68
static struct bsd_to_linux_bitmap seal_bitmap[] = {
69
BITMAP_1t1_LINUX(F_SEAL_SEAL),
70
BITMAP_1t1_LINUX(F_SEAL_SHRINK),
71
BITMAP_1t1_LINUX(F_SEAL_GROW),
72
BITMAP_1t1_LINUX(F_SEAL_WRITE),
73
};
74
75
#define MFD_HUGETLB_ENTRY(_size) \
76
{ \
77
.bsd_value = MFD_HUGE_##_size, \
78
.linux_value = LINUX_HUGETLB_FLAG_ENCODE_##_size \
79
}
80
static struct bsd_to_linux_bitmap mfd_bitmap[] = {
81
BITMAP_1t1_LINUX(MFD_CLOEXEC),
82
BITMAP_1t1_LINUX(MFD_ALLOW_SEALING),
83
BITMAP_1t1_LINUX(MFD_HUGETLB),
84
MFD_HUGETLB_ENTRY(64KB),
85
MFD_HUGETLB_ENTRY(512KB),
86
MFD_HUGETLB_ENTRY(1MB),
87
MFD_HUGETLB_ENTRY(2MB),
88
MFD_HUGETLB_ENTRY(8MB),
89
MFD_HUGETLB_ENTRY(16MB),
90
MFD_HUGETLB_ENTRY(32MB),
91
MFD_HUGETLB_ENTRY(256MB),
92
MFD_HUGETLB_ENTRY(512MB),
93
MFD_HUGETLB_ENTRY(1GB),
94
MFD_HUGETLB_ENTRY(2GB),
95
MFD_HUGETLB_ENTRY(16GB),
96
};
97
#undef MFD_HUGETLB_ENTRY
98
99
#ifdef LINUX_LEGACY_SYSCALLS
100
int
101
linux_creat(struct thread *td, struct linux_creat_args *args)
102
{
103
104
return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
105
O_WRONLY | O_CREAT | O_TRUNC, args->mode));
106
}
107
#endif
108
109
int
110
linux_common_openflags(int l_flags)
111
{
112
int bsd_flags;
113
114
bsd_flags = 0;
115
switch (l_flags & LINUX_O_ACCMODE) {
116
case LINUX_O_WRONLY:
117
bsd_flags |= O_WRONLY;
118
break;
119
case LINUX_O_RDWR:
120
bsd_flags |= O_RDWR;
121
break;
122
default:
123
bsd_flags |= O_RDONLY;
124
}
125
if (l_flags & LINUX_O_NDELAY)
126
bsd_flags |= O_NONBLOCK;
127
if (l_flags & LINUX_O_APPEND)
128
bsd_flags |= O_APPEND;
129
if (l_flags & LINUX_O_SYNC)
130
bsd_flags |= O_FSYNC;
131
if (l_flags & LINUX_O_CLOEXEC)
132
bsd_flags |= O_CLOEXEC;
133
if (l_flags & LINUX_O_NONBLOCK)
134
bsd_flags |= O_NONBLOCK;
135
if (l_flags & LINUX_O_ASYNC)
136
bsd_flags |= O_ASYNC;
137
if (l_flags & LINUX_O_CREAT)
138
bsd_flags |= O_CREAT;
139
if (l_flags & LINUX_O_TRUNC)
140
bsd_flags |= O_TRUNC;
141
if (l_flags & LINUX_O_EXCL)
142
bsd_flags |= O_EXCL;
143
if (l_flags & LINUX_O_NOCTTY)
144
bsd_flags |= O_NOCTTY;
145
if (l_flags & LINUX_O_DIRECT)
146
bsd_flags |= O_DIRECT;
147
if (l_flags & LINUX_O_NOFOLLOW)
148
bsd_flags |= O_NOFOLLOW;
149
if (l_flags & LINUX_O_DIRECTORY)
150
bsd_flags |= O_DIRECTORY;
151
if (l_flags & LINUX_O_PATH)
152
bsd_flags |= O_PATH;
153
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
154
return (bsd_flags);
155
}
156
157
static int
158
linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
159
int mode, enum uio_seg seg)
160
{
161
struct proc *p = td->td_proc;
162
struct file *fp;
163
int fd;
164
int bsd_flags, error;
165
166
bsd_flags = linux_common_openflags(l_flags);
167
error = kern_openat(td, dirfd, path, seg, bsd_flags, mode);
168
if (error != 0) {
169
if (error == EMLINK)
170
error = ELOOP;
171
goto done;
172
}
173
if (p->p_flag & P_CONTROLT)
174
goto done;
175
if (bsd_flags & O_NOCTTY)
176
goto done;
177
178
/*
179
* XXX In between kern_openat() and fget(), another process
180
* having the same filedesc could use that fd without
181
* checking below.
182
*/
183
fd = td->td_retval[0];
184
if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) {
185
if (fp->f_type != DTYPE_VNODE) {
186
fdrop(fp, td);
187
goto done;
188
}
189
sx_slock(&proctree_lock);
190
PROC_LOCK(p);
191
if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
192
PROC_UNLOCK(p);
193
sx_sunlock(&proctree_lock);
194
/* XXXPJD: Verify if TIOCSCTTY is allowed. */
195
(void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
196
td->td_ucred, td);
197
} else {
198
PROC_UNLOCK(p);
199
sx_sunlock(&proctree_lock);
200
}
201
fdrop(fp, td);
202
}
203
204
done:
205
return (error);
206
}
207
208
int
209
linux_openat(struct thread *td, struct linux_openat_args *args)
210
{
211
int dfd;
212
213
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
214
return (linux_common_open(td, dfd, args->filename, args->flags,
215
args->mode, UIO_USERSPACE));
216
}
217
218
#ifdef LINUX_LEGACY_SYSCALLS
219
int
220
linux_open(struct thread *td, struct linux_open_args *args)
221
{
222
223
return (linux_common_open(td, AT_FDCWD, args->path, args->flags,
224
args->mode, UIO_USERSPACE));
225
}
226
#endif
227
228
int
229
linux_name_to_handle_at(struct thread *td,
230
struct linux_name_to_handle_at_args *args)
231
{
232
static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW |
233
LINUX_AT_EMPTY_PATH);
234
static const l_uint fh_size = sizeof(fhandle_t);
235
236
fhandle_t fh;
237
l_uint fh_bytes;
238
l_int mount_id;
239
int error, fd, bsd_flags;
240
241
if (args->flags & ~valid_flags)
242
return (EINVAL);
243
244
fd = args->dirfd;
245
if (fd == LINUX_AT_FDCWD)
246
fd = AT_FDCWD;
247
248
bsd_flags = 0;
249
if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW))
250
bsd_flags |= AT_SYMLINK_NOFOLLOW;
251
if ((args->flags & LINUX_AT_EMPTY_PATH) != 0)
252
bsd_flags |= AT_EMPTY_PATH;
253
254
error = kern_getfhat(td, bsd_flags, fd, args->name,
255
UIO_USERSPACE, &fh, UIO_SYSSPACE);
256
if (error != 0)
257
return (error);
258
259
/* Emit mount_id -- required before EOVERFLOW case. */
260
mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]);
261
error = copyout(&mount_id, args->mnt_id, sizeof(mount_id));
262
if (error != 0)
263
return (error);
264
265
/* Check if there is room for handle. */
266
error = copyin(&args->handle->handle_bytes, &fh_bytes,
267
sizeof(fh_bytes));
268
if (error != 0)
269
return (error);
270
271
if (fh_bytes < fh_size) {
272
error = copyout(&fh_size, &args->handle->handle_bytes,
273
sizeof(fh_size));
274
if (error == 0)
275
error = EOVERFLOW;
276
return (error);
277
}
278
279
/* Emit handle. */
280
mount_id = 0;
281
/*
282
* We don't use handle_type for anything yet, but initialize a known
283
* value.
284
*/
285
error = copyout(&mount_id, &args->handle->handle_type,
286
sizeof(mount_id));
287
if (error != 0)
288
return (error);
289
290
error = copyout(&fh, &args->handle->f_handle,
291
sizeof(fh));
292
return (error);
293
}
294
295
int
296
linux_open_by_handle_at(struct thread *td,
297
struct linux_open_by_handle_at_args *args)
298
{
299
l_uint fh_bytes;
300
int bsd_flags, error;
301
302
error = copyin(&args->handle->handle_bytes, &fh_bytes,
303
sizeof(fh_bytes));
304
if (error != 0)
305
return (error);
306
307
if (fh_bytes < sizeof(fhandle_t))
308
return (EINVAL);
309
310
bsd_flags = linux_common_openflags(args->flags);
311
return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags));
312
}
313
314
int
315
linux_lseek(struct thread *td, struct linux_lseek_args *args)
316
{
317
318
return (kern_lseek(td, args->fdes, args->off, args->whence));
319
}
320
321
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
322
int
323
linux_llseek(struct thread *td, struct linux_llseek_args *args)
324
{
325
int error;
326
off_t off;
327
328
off = (args->olow) | (((off_t) args->ohigh) << 32);
329
330
error = kern_lseek(td, args->fd, off, args->whence);
331
if (error != 0)
332
return (error);
333
334
error = copyout(td->td_retval, args->res, sizeof(off_t));
335
if (error != 0)
336
return (error);
337
338
td->td_retval[0] = 0;
339
return (0);
340
}
341
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
342
343
/*
344
* Note that linux_getdents(2) and linux_getdents64(2) have the same
345
* arguments. They only differ in the definition of struct dirent they
346
* operate on.
347
* Note that linux_readdir(2) is a special case of linux_getdents(2)
348
* where count is always equals 1, meaning that the buffer is one
349
* dirent-structure in size and that the code can't handle more anyway.
350
* Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
351
* as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
352
* trash user stack.
353
*/
354
355
static int
356
linux_getdents_error(struct thread *td, int fd, int err)
357
{
358
struct vnode *vp;
359
struct file *fp;
360
int error;
361
362
/* Linux return ENOTDIR in case when fd is not a directory. */
363
error = getvnode(td, fd, &cap_read_rights, &fp);
364
if (error != 0)
365
return (error);
366
vp = fp->f_vnode;
367
if (vp->v_type != VDIR) {
368
fdrop(fp, td);
369
return (ENOTDIR);
370
}
371
fdrop(fp, td);
372
return (err);
373
}
374
375
struct l_dirent {
376
l_ulong d_ino;
377
l_off_t d_off;
378
l_ushort d_reclen;
379
char d_name[LINUX_NAME_MAX + 1];
380
};
381
382
struct l_dirent64 {
383
uint64_t d_ino;
384
int64_t d_off;
385
l_ushort d_reclen;
386
u_char d_type;
387
char d_name[LINUX_NAME_MAX + 1];
388
};
389
390
/*
391
* Linux uses the last byte in the dirent buffer to store d_type,
392
* at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
393
*/
394
#define LINUX_RECLEN(namlen) \
395
roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
396
397
#define LINUX_RECLEN64(namlen) \
398
roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \
399
sizeof(uint64_t))
400
401
/*
402
* Do kern_getdirentries() and then skip over any invalid entries.
403
* (Repeat, if there are no valid entries.)
404
* Adjust bufp and lenp.
405
*/
406
static int
407
linux_getdirentries(struct thread *td, int fd, caddr_t *bufp, int buflen,
408
off_t *basep, int *lenp)
409
{
410
struct dirent *bdp;
411
caddr_t buf;
412
int error, len;
413
414
/* Loop around until a valid entry is found or at EOF. */
415
for (;;) {
416
error = kern_getdirentries(td, fd, *bufp, buflen,
417
basep, NULL, UIO_SYSSPACE);
418
if (error != 0)
419
return (error);
420
len = td->td_retval[0];
421
if (len == 0) {
422
*lenp = 0;
423
return (0);
424
}
425
buf = *bufp;
426
while (len > 0) {
427
bdp = (struct dirent *)buf;
428
if (bdp->d_fileno != 0) {
429
*bufp = buf;
430
*lenp = len;
431
return (0);
432
}
433
buf += bdp->d_reclen;
434
len -= bdp->d_reclen;
435
}
436
}
437
}
438
439
#ifdef LINUX_LEGACY_SYSCALLS
440
int
441
linux_getdents(struct thread *td, struct linux_getdents_args *args)
442
{
443
struct dirent *bdp;
444
caddr_t inp, buf, bufsav; /* BSD-format */
445
int len, reclen; /* BSD-format */
446
caddr_t outp; /* Linux-format */
447
int resid, linuxreclen; /* Linux-format */
448
caddr_t lbuf; /* Linux-format */
449
off_t base;
450
struct l_dirent *linux_dirent;
451
int buflen, error;
452
size_t retval;
453
454
buflen = min(roundup2(args->count, DEV_BSIZE), MAXBSIZE);
455
bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
456
457
error = linux_getdirentries(td, args->fd, &buf, buflen,
458
&base, &len);
459
if (error != 0) {
460
error = linux_getdents_error(td, args->fd, error);
461
goto out1;
462
}
463
464
lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX, M_WAITOK | M_ZERO);
465
466
inp = buf;
467
outp = (caddr_t)args->dent;
468
resid = args->count;
469
retval = 0;
470
471
while (len > 0) {
472
bdp = (struct dirent *) inp;
473
reclen = bdp->d_reclen;
474
/* Copy a valid entry out. */
475
if (bdp->d_fileno != 0) {
476
linuxreclen = LINUX_RECLEN(bdp->d_namlen);
477
/*
478
* No more space in the user supplied dirent buffer.
479
* Return EINVAL.
480
*/
481
if (resid < linuxreclen) {
482
error = EINVAL;
483
goto out;
484
}
485
486
linux_dirent = (struct l_dirent*)lbuf;
487
linux_dirent->d_ino = bdp->d_fileno;
488
linux_dirent->d_off = bdp->d_off;
489
linux_dirent->d_reclen = linuxreclen;
490
/*
491
* Copy d_type to last byte of l_dirent buffer
492
*/
493
lbuf[linuxreclen - 1] = bdp->d_type;
494
strlcpy(linux_dirent->d_name, bdp->d_name,
495
linuxreclen - offsetof(struct l_dirent, d_name)-1);
496
error = copyout(linux_dirent, outp, linuxreclen);
497
if (error != 0)
498
goto out;
499
retval += linuxreclen;
500
outp += linuxreclen;
501
resid -= linuxreclen;
502
}
503
504
inp += reclen;
505
base += reclen;
506
len -= reclen;
507
508
}
509
td->td_retval[0] = retval;
510
511
out:
512
free(lbuf, M_LINUX);
513
out1:
514
free(bufsav, M_LINUX);
515
return (error);
516
}
517
#endif
518
519
int
520
linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
521
{
522
struct dirent *bdp;
523
caddr_t inp, buf, bufsav; /* BSD-format */
524
int len, reclen; /* BSD-format */
525
caddr_t outp; /* Linux-format */
526
int resid, linuxreclen; /* Linux-format */
527
off_t base;
528
struct l_dirent64 *linux_dirent64;
529
int buflen, error;
530
size_t retval;
531
532
buflen = min(roundup2(args->count, DEV_BSIZE), MAXBSIZE);
533
bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
534
535
error = linux_getdirentries(td, args->fd, &buf, buflen,
536
&base, &len);
537
if (error != 0) {
538
error = linux_getdents_error(td, args->fd, error);
539
goto out1;
540
}
541
542
linux_dirent64 = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_LINUX,
543
M_WAITOK | M_ZERO);
544
545
inp = buf;
546
outp = (caddr_t)args->dirent;
547
resid = args->count;
548
retval = 0;
549
550
while (len > 0) {
551
bdp = (struct dirent *) inp;
552
reclen = bdp->d_reclen;
553
/* Copy a valid entry out. */
554
if (bdp->d_fileno != 0) {
555
linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
556
/*
557
* No more space in the user supplied dirent buffer.
558
* Return EINVAL.
559
*/
560
if (resid < linuxreclen) {
561
error = EINVAL;
562
goto out;
563
}
564
565
linux_dirent64->d_ino = bdp->d_fileno;
566
linux_dirent64->d_off = bdp->d_off;
567
linux_dirent64->d_reclen = linuxreclen;
568
linux_dirent64->d_type = bdp->d_type;
569
strlcpy(linux_dirent64->d_name, bdp->d_name,
570
linuxreclen - offsetof(struct l_dirent64, d_name));
571
error = copyout(linux_dirent64, outp, linuxreclen);
572
if (error != 0)
573
goto out;
574
retval += linuxreclen;
575
outp += linuxreclen;
576
resid -= linuxreclen;
577
}
578
579
inp += reclen;
580
base += reclen;
581
len -= reclen;
582
583
}
584
td->td_retval[0] = retval;
585
586
out:
587
free(linux_dirent64, M_LINUX);
588
out1:
589
free(bufsav, M_LINUX);
590
return (error);
591
}
592
593
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
594
int
595
linux_readdir(struct thread *td, struct linux_readdir_args *args)
596
{
597
struct dirent *bdp;
598
caddr_t buf, bufsav; /* BSD-format */
599
int linuxreclen; /* Linux-format */
600
off_t base;
601
struct l_dirent *linux_dirent; /* Linux-format */
602
int buflen, error, len;
603
604
buflen = DEV_BSIZE;
605
bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
606
607
error = linux_getdirentries(td, args->fd, &buf, buflen,
608
&base, &len);
609
if (error != 0) {
610
error = linux_getdents_error(td, args->fd, error);
611
goto out;
612
}
613
if (len == 0)
614
goto out;
615
616
linux_dirent = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX,
617
M_WAITOK | M_ZERO);
618
619
bdp = (struct dirent *) buf;
620
linuxreclen = LINUX_RECLEN(bdp->d_namlen);
621
622
linux_dirent->d_ino = bdp->d_fileno;
623
linux_dirent->d_off = bdp->d_off;
624
linux_dirent->d_reclen = bdp->d_namlen;
625
strlcpy(linux_dirent->d_name, bdp->d_name,
626
linuxreclen - offsetof(struct l_dirent, d_name));
627
error = copyout(linux_dirent, args->dent, linuxreclen);
628
if (error == 0)
629
td->td_retval[0] = linuxreclen;
630
631
free(linux_dirent, M_LINUX);
632
out:
633
free(bufsav, M_LINUX);
634
return (error);
635
}
636
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
637
638
/*
639
* These exist mainly for hooks for doing /compat/linux translation.
640
*/
641
642
#ifdef LINUX_LEGACY_SYSCALLS
643
int
644
linux_access(struct thread *td, struct linux_access_args *args)
645
{
646
647
/* Linux convention. */
648
if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
649
return (EINVAL);
650
651
return (kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0,
652
args->amode));
653
}
654
#endif
655
656
static int
657
linux_do_accessat(struct thread *td, int ldfd, const char *filename,
658
int amode, int flags)
659
{
660
int dfd;
661
662
/* Linux convention. */
663
if (amode & ~(F_OK | X_OK | W_OK | R_OK))
664
return (EINVAL);
665
666
dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
667
return (kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode));
668
}
669
670
int
671
linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
672
{
673
674
return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
675
0));
676
}
677
678
int
679
linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args)
680
{
681
int flags, unsupported;
682
683
unsupported = args->flags & ~(LINUX_AT_EACCESS | LINUX_AT_EMPTY_PATH |
684
LINUX_AT_SYMLINK_NOFOLLOW);
685
if (unsupported != 0) {
686
linux_msg(td, "faccessat2 unsupported flag 0x%x", unsupported);
687
return (EINVAL);
688
}
689
690
flags = (args->flags & LINUX_AT_EACCESS) == 0 ? 0 :
691
AT_EACCESS;
692
flags |= (args->flags & LINUX_AT_EMPTY_PATH) == 0 ? 0 :
693
AT_EMPTY_PATH;
694
flags |= (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
695
AT_SYMLINK_NOFOLLOW;
696
return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
697
flags));
698
}
699
700
701
#ifdef LINUX_LEGACY_SYSCALLS
702
int
703
linux_unlink(struct thread *td, struct linux_unlink_args *args)
704
{
705
int error;
706
struct stat st;
707
708
error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE,
709
UIO_USERSPACE, 0, 0);
710
if (error == EPERM) {
711
/* Introduce POSIX noncompliant behaviour of Linux */
712
if (kern_statat(td, 0, AT_FDCWD, args->path,
713
UIO_USERSPACE, &st) == 0) {
714
if (S_ISDIR(st.st_mode))
715
error = EISDIR;
716
}
717
}
718
719
return (error);
720
}
721
#endif
722
723
static int
724
linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
725
int dfd, struct linux_unlinkat_args *args)
726
{
727
struct stat st;
728
int error;
729
730
if (args->flag & LINUX_AT_REMOVEDIR)
731
error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0);
732
else
733
error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 0, 0);
734
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
735
/* Introduce POSIX noncompliant behaviour of Linux */
736
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
737
pathseg, &st) == 0 && S_ISDIR(st.st_mode))
738
error = EISDIR;
739
}
740
return (error);
741
}
742
743
int
744
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
745
{
746
int dfd;
747
748
if (args->flag & ~LINUX_AT_REMOVEDIR)
749
return (EINVAL);
750
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
751
return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
752
dfd, args));
753
}
754
755
int
756
linux_chdir(struct thread *td, struct linux_chdir_args *args)
757
{
758
759
return (kern_chdir(td, args->path, UIO_USERSPACE));
760
}
761
762
#ifdef LINUX_LEGACY_SYSCALLS
763
int
764
linux_chmod(struct thread *td, struct linux_chmod_args *args)
765
{
766
767
return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
768
args->mode, 0));
769
}
770
#endif
771
772
int
773
linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
774
{
775
int dfd;
776
777
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
778
return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
779
args->mode, 0));
780
}
781
782
#ifdef LINUX_LEGACY_SYSCALLS
783
int
784
linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
785
{
786
787
return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
788
}
789
#endif
790
791
int
792
linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
793
{
794
int dfd;
795
796
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
797
return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
798
}
799
800
#ifdef LINUX_LEGACY_SYSCALLS
801
int
802
linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
803
{
804
805
return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
806
UIO_USERSPACE, 0));
807
}
808
809
int
810
linux_rename(struct thread *td, struct linux_rename_args *args)
811
{
812
813
return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
814
args->to, UIO_USERSPACE));
815
}
816
#endif
817
818
int
819
linux_renameat(struct thread *td, struct linux_renameat_args *args)
820
{
821
struct linux_renameat2_args renameat2_args = {
822
.olddfd = args->olddfd,
823
.oldname = args->oldname,
824
.newdfd = args->newdfd,
825
.newname = args->newname,
826
.flags = 0
827
};
828
829
return (linux_renameat2(td, &renameat2_args));
830
}
831
832
int
833
linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
834
{
835
int olddfd, newdfd;
836
837
if (args->flags != 0) {
838
if (args->flags & ~(LINUX_RENAME_EXCHANGE |
839
LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT))
840
return (EINVAL);
841
if (args->flags & LINUX_RENAME_EXCHANGE &&
842
args->flags & (LINUX_RENAME_NOREPLACE |
843
LINUX_RENAME_WHITEOUT))
844
return (EINVAL);
845
#if 0
846
/*
847
* This spams the console on Ubuntu Focal.
848
*
849
* What's needed here is a general mechanism to let users know
850
* about missing features without hogging the system.
851
*/
852
linux_msg(td, "renameat2 unsupported flags 0x%x",
853
args->flags);
854
#endif
855
return (EINVAL);
856
}
857
858
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
859
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
860
return (kern_renameat(td, olddfd, args->oldname, newdfd,
861
args->newname, UIO_USERSPACE));
862
}
863
864
#ifdef LINUX_LEGACY_SYSCALLS
865
int
866
linux_symlink(struct thread *td, struct linux_symlink_args *args)
867
{
868
869
return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
870
UIO_USERSPACE));
871
}
872
#endif
873
874
int
875
linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
876
{
877
int dfd;
878
879
dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
880
return (kern_symlinkat(td, args->oldname, dfd, args->newname,
881
UIO_USERSPACE));
882
}
883
884
#ifdef LINUX_LEGACY_SYSCALLS
885
int
886
linux_readlink(struct thread *td, struct linux_readlink_args *args)
887
{
888
889
if (args->count <= 0)
890
return (EINVAL);
891
892
return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
893
args->buf, UIO_USERSPACE, args->count));
894
}
895
#endif
896
897
int
898
linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
899
{
900
int dfd;
901
902
if (args->bufsiz <= 0)
903
return (EINVAL);
904
905
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
906
return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
907
args->buf, UIO_USERSPACE, args->bufsiz));
908
}
909
910
int
911
linux_truncate(struct thread *td, struct linux_truncate_args *args)
912
{
913
914
return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
915
}
916
917
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
918
int
919
linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
920
{
921
off_t length;
922
923
#if defined(__amd64__) && defined(COMPAT_LINUX32)
924
length = PAIR32TO64(off_t, args->length);
925
#else
926
length = args->length;
927
#endif
928
929
return (kern_truncate(td, args->path, UIO_USERSPACE, length));
930
}
931
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
932
933
int
934
linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
935
{
936
937
return (kern_ftruncate(td, args->fd, args->length));
938
}
939
940
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
941
int
942
linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
943
{
944
off_t length;
945
946
#if defined(__amd64__) && defined(COMPAT_LINUX32)
947
length = PAIR32TO64(off_t, args->length);
948
#else
949
length = args->length;
950
#endif
951
952
return (kern_ftruncate(td, args->fd, length));
953
}
954
#endif
955
956
#ifdef LINUX_LEGACY_SYSCALLS
957
int
958
linux_link(struct thread *td, struct linux_link_args *args)
959
{
960
961
return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
962
UIO_USERSPACE, AT_SYMLINK_FOLLOW));
963
}
964
#endif
965
966
int
967
linux_linkat(struct thread *td, struct linux_linkat_args *args)
968
{
969
int olddfd, newdfd, flag;
970
971
if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH))
972
return (EINVAL);
973
974
flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW :
975
0;
976
flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0;
977
978
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
979
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
980
return (kern_linkat(td, olddfd, newdfd, args->oldname,
981
args->newname, UIO_USERSPACE, flag));
982
}
983
984
int
985
linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap)
986
{
987
988
return (kern_fsync(td, uap->fd, false));
989
}
990
991
int
992
linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap)
993
{
994
off_t nbytes, offset;
995
996
#if defined(__amd64__) && defined(COMPAT_LINUX32)
997
nbytes = PAIR32TO64(off_t, uap->nbytes);
998
offset = PAIR32TO64(off_t, uap->offset);
999
#else
1000
nbytes = uap->nbytes;
1001
offset = uap->offset;
1002
#endif
1003
1004
if (offset < 0 || nbytes < 0 ||
1005
(uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE |
1006
LINUX_SYNC_FILE_RANGE_WRITE |
1007
LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) {
1008
return (EINVAL);
1009
}
1010
1011
return (kern_fsync(td, uap->fd, false));
1012
}
1013
1014
int
1015
linux_pread(struct thread *td, struct linux_pread_args *uap)
1016
{
1017
struct vnode *vp;
1018
off_t offset;
1019
int error;
1020
1021
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1022
offset = PAIR32TO64(off_t, uap->offset);
1023
#else
1024
offset = uap->offset;
1025
#endif
1026
1027
error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset);
1028
if (error == 0) {
1029
/* This seems to violate POSIX but Linux does it. */
1030
error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
1031
if (error != 0)
1032
return (error);
1033
if (vp->v_type == VDIR)
1034
error = EISDIR;
1035
vrele(vp);
1036
}
1037
return (error);
1038
}
1039
1040
int
1041
linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
1042
{
1043
off_t offset;
1044
1045
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1046
offset = PAIR32TO64(off_t, uap->offset);
1047
#else
1048
offset = uap->offset;
1049
#endif
1050
1051
return (linux_enobufs2eagain(td, uap->fd,
1052
kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset)));
1053
}
1054
1055
#define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2))
1056
1057
static inline off_t
1058
pos_from_hilo(unsigned long high, unsigned long low)
1059
{
1060
1061
return (((off_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
1062
}
1063
1064
int
1065
linux_preadv(struct thread *td, struct linux_preadv_args *uap)
1066
{
1067
struct uio *auio;
1068
int error;
1069
off_t offset;
1070
1071
/*
1072
* According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
1073
* pos_l and pos_h, respectively, contain the
1074
* low order and high order 32 bits of offset.
1075
*/
1076
offset = pos_from_hilo(uap->pos_h, uap->pos_l);
1077
if (offset < 0)
1078
return (EINVAL);
1079
#ifdef COMPAT_LINUX32
1080
error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1081
#else
1082
error = copyinuio(uap->vec, uap->vlen, &auio);
1083
#endif
1084
if (error != 0)
1085
return (error);
1086
error = kern_preadv(td, uap->fd, auio, offset);
1087
freeuio(auio);
1088
return (error);
1089
}
1090
1091
int
1092
linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
1093
{
1094
struct uio *auio;
1095
int error;
1096
off_t offset;
1097
1098
/*
1099
* According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
1100
* pos_l and pos_h, respectively, contain the
1101
* low order and high order 32 bits of offset.
1102
*/
1103
offset = pos_from_hilo(uap->pos_h, uap->pos_l);
1104
if (offset < 0)
1105
return (EINVAL);
1106
#ifdef COMPAT_LINUX32
1107
error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
1108
#else
1109
error = copyinuio(uap->vec, uap->vlen, &auio);
1110
#endif
1111
if (error != 0)
1112
return (error);
1113
error = kern_pwritev(td, uap->fd, auio, offset);
1114
freeuio(auio);
1115
return (linux_enobufs2eagain(td, uap->fd, error));
1116
}
1117
1118
int
1119
linux_mount(struct thread *td, struct linux_mount_args *args)
1120
{
1121
struct mntarg *ma = NULL;
1122
char *fstypename, *mntonname, *mntfromname, *data;
1123
int error, fsflags;
1124
1125
fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK);
1126
mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
1127
mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
1128
data = NULL;
1129
error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1,
1130
NULL);
1131
if (error != 0)
1132
goto out;
1133
if (args->specialfile != NULL) {
1134
error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
1135
if (error != 0)
1136
goto out;
1137
} else {
1138
mntfromname[0] = '\0';
1139
}
1140
error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
1141
if (error != 0)
1142
goto out;
1143
1144
if (strcmp(fstypename, "ext2") == 0) {
1145
strcpy(fstypename, "ext2fs");
1146
} else if (strcmp(fstypename, "proc") == 0) {
1147
strcpy(fstypename, "linprocfs");
1148
} else if (strcmp(fstypename, "vfat") == 0) {
1149
strcpy(fstypename, "msdosfs");
1150
} else if (strcmp(fstypename, "fuse") == 0 ||
1151
strncmp(fstypename, "fuse.", 5) == 0) {
1152
char *fuse_options, *fuse_option, *fuse_name;
1153
1154
strcpy(mntfromname, "/dev/fuse");
1155
strcpy(fstypename, "fusefs");
1156
data = malloc(MNAMELEN, M_TEMP, M_WAITOK);
1157
error = copyinstr(args->data, data, MNAMELEN - 1, NULL);
1158
if (error != 0)
1159
goto out;
1160
1161
fuse_options = data;
1162
while ((fuse_option = strsep(&fuse_options, ",")) != NULL) {
1163
fuse_name = strsep(&fuse_option, "=");
1164
if (fuse_name == NULL || fuse_option == NULL)
1165
goto out;
1166
ma = mount_arg(ma, fuse_name, fuse_option, -1);
1167
}
1168
1169
/*
1170
* The FUSE server uses Linux errno values instead of FreeBSD
1171
* ones; add a flag to tell fuse(4) to do errno translation.
1172
*/
1173
ma = mount_arg(ma, "linux_errnos", "1", -1);
1174
}
1175
1176
fsflags = 0;
1177
1178
/*
1179
* Linux SYNC flag is not included; the closest equivalent
1180
* FreeBSD has is !ASYNC, which is our default.
1181
*/
1182
if (args->rwflag & LINUX_MS_RDONLY)
1183
fsflags |= MNT_RDONLY;
1184
if (args->rwflag & LINUX_MS_NOSUID)
1185
fsflags |= MNT_NOSUID;
1186
if (args->rwflag & LINUX_MS_NOEXEC)
1187
fsflags |= MNT_NOEXEC;
1188
if (args->rwflag & LINUX_MS_REMOUNT)
1189
fsflags |= MNT_UPDATE;
1190
1191
ma = mount_arg(ma, "fstype", fstypename, -1);
1192
ma = mount_arg(ma, "fspath", mntonname, -1);
1193
ma = mount_arg(ma, "from", mntfromname, -1);
1194
error = kernel_mount(ma, fsflags);
1195
out:
1196
free(fstypename, M_TEMP);
1197
free(mntonname, M_TEMP);
1198
free(mntfromname, M_TEMP);
1199
free(data, M_TEMP);
1200
return (error);
1201
}
1202
1203
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1204
int
1205
linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1206
{
1207
1208
return (kern_unmount(td, args->path, 0));
1209
}
1210
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1211
1212
#ifdef LINUX_LEGACY_SYSCALLS
1213
int
1214
linux_umount(struct thread *td, struct linux_umount_args *args)
1215
{
1216
int flags;
1217
1218
flags = 0;
1219
if ((args->flags & LINUX_MNT_FORCE) != 0) {
1220
args->flags &= ~LINUX_MNT_FORCE;
1221
flags |= MNT_FORCE;
1222
}
1223
if (args->flags != 0) {
1224
linux_msg(td, "unsupported umount2 flags %#x", args->flags);
1225
return (EINVAL);
1226
}
1227
1228
return (kern_unmount(td, args->path, flags));
1229
}
1230
#endif
1231
1232
/*
1233
* fcntl family of syscalls
1234
*/
1235
1236
struct l_flock {
1237
l_short l_type;
1238
l_short l_whence;
1239
l_off_t l_start;
1240
l_off_t l_len;
1241
l_pid_t l_pid;
1242
}
1243
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1244
__packed
1245
#endif
1246
;
1247
1248
static void
1249
linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1250
{
1251
switch (linux_flock->l_type) {
1252
case LINUX_F_RDLCK:
1253
bsd_flock->l_type = F_RDLCK;
1254
break;
1255
case LINUX_F_WRLCK:
1256
bsd_flock->l_type = F_WRLCK;
1257
break;
1258
case LINUX_F_UNLCK:
1259
bsd_flock->l_type = F_UNLCK;
1260
break;
1261
default:
1262
bsd_flock->l_type = -1;
1263
break;
1264
}
1265
bsd_flock->l_whence = linux_flock->l_whence;
1266
bsd_flock->l_start = (off_t)linux_flock->l_start;
1267
bsd_flock->l_len = (off_t)linux_flock->l_len;
1268
bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1269
bsd_flock->l_sysid = 0;
1270
}
1271
1272
static void
1273
bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1274
{
1275
switch (bsd_flock->l_type) {
1276
case F_RDLCK:
1277
linux_flock->l_type = LINUX_F_RDLCK;
1278
break;
1279
case F_WRLCK:
1280
linux_flock->l_type = LINUX_F_WRLCK;
1281
break;
1282
case F_UNLCK:
1283
linux_flock->l_type = LINUX_F_UNLCK;
1284
break;
1285
}
1286
linux_flock->l_whence = bsd_flock->l_whence;
1287
linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1288
linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1289
linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1290
}
1291
1292
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1293
struct l_flock64 {
1294
l_short l_type;
1295
l_short l_whence;
1296
l_loff_t l_start;
1297
l_loff_t l_len;
1298
l_pid_t l_pid;
1299
}
1300
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1301
__packed
1302
#endif
1303
;
1304
1305
static void
1306
linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1307
{
1308
switch (linux_flock->l_type) {
1309
case LINUX_F_RDLCK:
1310
bsd_flock->l_type = F_RDLCK;
1311
break;
1312
case LINUX_F_WRLCK:
1313
bsd_flock->l_type = F_WRLCK;
1314
break;
1315
case LINUX_F_UNLCK:
1316
bsd_flock->l_type = F_UNLCK;
1317
break;
1318
default:
1319
bsd_flock->l_type = -1;
1320
break;
1321
}
1322
bsd_flock->l_whence = linux_flock->l_whence;
1323
bsd_flock->l_start = (off_t)linux_flock->l_start;
1324
bsd_flock->l_len = (off_t)linux_flock->l_len;
1325
bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1326
bsd_flock->l_sysid = 0;
1327
}
1328
1329
static void
1330
bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1331
{
1332
switch (bsd_flock->l_type) {
1333
case F_RDLCK:
1334
linux_flock->l_type = LINUX_F_RDLCK;
1335
break;
1336
case F_WRLCK:
1337
linux_flock->l_type = LINUX_F_WRLCK;
1338
break;
1339
case F_UNLCK:
1340
linux_flock->l_type = LINUX_F_UNLCK;
1341
break;
1342
}
1343
linux_flock->l_whence = bsd_flock->l_whence;
1344
linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1345
linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1346
linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1347
}
1348
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1349
1350
static int
1351
fcntl_common(struct thread *td, struct linux_fcntl_args *args)
1352
{
1353
struct l_flock linux_flock;
1354
struct flock bsd_flock;
1355
struct pipe *fpipe;
1356
struct file *fp;
1357
long arg;
1358
int error, result;
1359
1360
switch (args->cmd) {
1361
case LINUX_F_DUPFD:
1362
return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1363
1364
case LINUX_F_GETFD:
1365
return (kern_fcntl(td, args->fd, F_GETFD, 0));
1366
1367
case LINUX_F_SETFD:
1368
return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1369
1370
case LINUX_F_GETFL:
1371
error = kern_fcntl(td, args->fd, F_GETFL, 0);
1372
result = td->td_retval[0];
1373
td->td_retval[0] = 0;
1374
if (result & O_RDONLY)
1375
td->td_retval[0] |= LINUX_O_RDONLY;
1376
if (result & O_WRONLY)
1377
td->td_retval[0] |= LINUX_O_WRONLY;
1378
if (result & O_RDWR)
1379
td->td_retval[0] |= LINUX_O_RDWR;
1380
if (result & O_NDELAY)
1381
td->td_retval[0] |= LINUX_O_NONBLOCK;
1382
if (result & O_APPEND)
1383
td->td_retval[0] |= LINUX_O_APPEND;
1384
if (result & O_FSYNC)
1385
td->td_retval[0] |= LINUX_O_SYNC;
1386
if (result & O_ASYNC)
1387
td->td_retval[0] |= LINUX_O_ASYNC;
1388
#ifdef LINUX_O_NOFOLLOW
1389
if (result & O_NOFOLLOW)
1390
td->td_retval[0] |= LINUX_O_NOFOLLOW;
1391
#endif
1392
#ifdef LINUX_O_DIRECT
1393
if (result & O_DIRECT)
1394
td->td_retval[0] |= LINUX_O_DIRECT;
1395
#endif
1396
return (error);
1397
1398
case LINUX_F_SETFL:
1399
arg = 0;
1400
if (args->arg & LINUX_O_NDELAY)
1401
arg |= O_NONBLOCK;
1402
if (args->arg & LINUX_O_APPEND)
1403
arg |= O_APPEND;
1404
if (args->arg & LINUX_O_SYNC)
1405
arg |= O_FSYNC;
1406
if (args->arg & LINUX_O_ASYNC)
1407
arg |= O_ASYNC;
1408
#ifdef LINUX_O_NOFOLLOW
1409
if (args->arg & LINUX_O_NOFOLLOW)
1410
arg |= O_NOFOLLOW;
1411
#endif
1412
#ifdef LINUX_O_DIRECT
1413
if (args->arg & LINUX_O_DIRECT)
1414
arg |= O_DIRECT;
1415
#endif
1416
return (kern_fcntl(td, args->fd, F_SETFL, arg));
1417
1418
case LINUX_F_GETLK:
1419
error = copyin((void *)args->arg, &linux_flock,
1420
sizeof(linux_flock));
1421
if (error)
1422
return (error);
1423
linux_to_bsd_flock(&linux_flock, &bsd_flock);
1424
error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1425
if (error)
1426
return (error);
1427
bsd_to_linux_flock(&bsd_flock, &linux_flock);
1428
return (copyout(&linux_flock, (void *)args->arg,
1429
sizeof(linux_flock)));
1430
1431
case LINUX_F_SETLK:
1432
error = copyin((void *)args->arg, &linux_flock,
1433
sizeof(linux_flock));
1434
if (error)
1435
return (error);
1436
linux_to_bsd_flock(&linux_flock, &bsd_flock);
1437
return (kern_fcntl(td, args->fd, F_SETLK,
1438
(intptr_t)&bsd_flock));
1439
1440
case LINUX_F_SETLKW:
1441
error = copyin((void *)args->arg, &linux_flock,
1442
sizeof(linux_flock));
1443
if (error)
1444
return (error);
1445
linux_to_bsd_flock(&linux_flock, &bsd_flock);
1446
return (kern_fcntl(td, args->fd, F_SETLKW,
1447
(intptr_t)&bsd_flock));
1448
1449
case LINUX_F_GETOWN:
1450
return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1451
1452
case LINUX_F_SETOWN:
1453
/*
1454
* XXX some Linux applications depend on F_SETOWN having no
1455
* significant effect for pipes (SIGIO is not delivered for
1456
* pipes under Linux-2.2.35 at least).
1457
*/
1458
error = fget(td, args->fd,
1459
&cap_fcntl_rights, &fp);
1460
if (error)
1461
return (error);
1462
if (fp->f_type == DTYPE_PIPE) {
1463
fdrop(fp, td);
1464
return (EINVAL);
1465
}
1466
fdrop(fp, td);
1467
1468
return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1469
1470
case LINUX_F_DUPFD_CLOEXEC:
1471
return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
1472
/*
1473
* Our F_SEAL_* values match Linux one for maximum compatibility. So we
1474
* only needed to account for different values for fcntl(2) commands.
1475
*/
1476
case LINUX_F_GET_SEALS:
1477
error = kern_fcntl(td, args->fd, F_GET_SEALS, 0);
1478
if (error != 0)
1479
return (error);
1480
td->td_retval[0] = bsd_to_linux_bits(td->td_retval[0],
1481
seal_bitmap, 0);
1482
return (0);
1483
1484
case LINUX_F_ADD_SEALS:
1485
return (kern_fcntl(td, args->fd, F_ADD_SEALS,
1486
linux_to_bsd_bits(args->arg, seal_bitmap, 0)));
1487
1488
case LINUX_F_GETPIPE_SZ:
1489
error = fget(td, args->fd,
1490
&cap_fcntl_rights, &fp);
1491
if (error != 0)
1492
return (error);
1493
if (fp->f_type != DTYPE_PIPE) {
1494
fdrop(fp, td);
1495
return (EINVAL);
1496
}
1497
fpipe = fp->f_data;
1498
td->td_retval[0] = fpipe->pipe_buffer.size;
1499
fdrop(fp, td);
1500
return (0);
1501
1502
case LINUX_F_DUPFD_QUERY:
1503
error = kern_kcmp(td, td->td_proc->p_pid, td->td_proc->p_pid,
1504
KCMP_FILE, args->fd, args->arg);
1505
if (error != 0)
1506
return (error);
1507
td->td_retval[0] = (td->td_retval[0] == 0) ? 1 : 0;
1508
return (0);
1509
1510
default:
1511
linux_msg(td, "unsupported fcntl cmd %d", args->cmd);
1512
return (EINVAL);
1513
}
1514
}
1515
1516
int
1517
linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1518
{
1519
1520
return (fcntl_common(td, args));
1521
}
1522
1523
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1524
int
1525
linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1526
{
1527
struct l_flock64 linux_flock;
1528
struct flock bsd_flock;
1529
struct linux_fcntl_args fcntl_args;
1530
int error;
1531
1532
switch (args->cmd) {
1533
case LINUX_F_GETLK64:
1534
error = copyin((void *)args->arg, &linux_flock,
1535
sizeof(linux_flock));
1536
if (error)
1537
return (error);
1538
linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1539
error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1540
if (error)
1541
return (error);
1542
bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1543
return (copyout(&linux_flock, (void *)args->arg,
1544
sizeof(linux_flock)));
1545
1546
case LINUX_F_SETLK64:
1547
error = copyin((void *)args->arg, &linux_flock,
1548
sizeof(linux_flock));
1549
if (error)
1550
return (error);
1551
linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1552
return (kern_fcntl(td, args->fd, F_SETLK,
1553
(intptr_t)&bsd_flock));
1554
1555
case LINUX_F_SETLKW64:
1556
error = copyin((void *)args->arg, &linux_flock,
1557
sizeof(linux_flock));
1558
if (error)
1559
return (error);
1560
linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1561
return (kern_fcntl(td, args->fd, F_SETLKW,
1562
(intptr_t)&bsd_flock));
1563
}
1564
1565
fcntl_args.fd = args->fd;
1566
fcntl_args.cmd = args->cmd;
1567
fcntl_args.arg = args->arg;
1568
return (fcntl_common(td, &fcntl_args));
1569
}
1570
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1571
1572
#ifdef LINUX_LEGACY_SYSCALLS
1573
int
1574
linux_chown(struct thread *td, struct linux_chown_args *args)
1575
{
1576
1577
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
1578
args->uid, args->gid, 0));
1579
}
1580
#endif
1581
1582
int
1583
linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1584
{
1585
int dfd, flag, unsupported;
1586
1587
unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
1588
if (unsupported != 0) {
1589
linux_msg(td, "fchownat unsupported flag 0x%x", unsupported);
1590
return (EINVAL);
1591
}
1592
1593
flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1594
AT_SYMLINK_NOFOLLOW;
1595
flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 :
1596
AT_EMPTY_PATH;
1597
1598
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1599
return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
1600
args->uid, args->gid, flag));
1601
}
1602
1603
#ifdef LINUX_LEGACY_SYSCALLS
1604
int
1605
linux_lchown(struct thread *td, struct linux_lchown_args *args)
1606
{
1607
1608
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
1609
args->gid, AT_SYMLINK_NOFOLLOW));
1610
}
1611
#endif
1612
1613
static int
1614
convert_fadvice(int advice)
1615
{
1616
switch (advice) {
1617
case LINUX_POSIX_FADV_NORMAL:
1618
return (POSIX_FADV_NORMAL);
1619
case LINUX_POSIX_FADV_RANDOM:
1620
return (POSIX_FADV_RANDOM);
1621
case LINUX_POSIX_FADV_SEQUENTIAL:
1622
return (POSIX_FADV_SEQUENTIAL);
1623
case LINUX_POSIX_FADV_WILLNEED:
1624
return (POSIX_FADV_WILLNEED);
1625
case LINUX_POSIX_FADV_DONTNEED:
1626
return (POSIX_FADV_DONTNEED);
1627
case LINUX_POSIX_FADV_NOREUSE:
1628
return (POSIX_FADV_NOREUSE);
1629
default:
1630
return (-1);
1631
}
1632
}
1633
1634
int
1635
linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1636
{
1637
off_t offset;
1638
int advice;
1639
1640
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1641
offset = PAIR32TO64(off_t, args->offset);
1642
#else
1643
offset = args->offset;
1644
#endif
1645
1646
advice = convert_fadvice(args->advice);
1647
if (advice == -1)
1648
return (EINVAL);
1649
return (kern_posix_fadvise(td, args->fd, offset, args->len, advice));
1650
}
1651
1652
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1653
int
1654
linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1655
{
1656
off_t len, offset;
1657
int advice;
1658
1659
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1660
len = PAIR32TO64(off_t, args->len);
1661
offset = PAIR32TO64(off_t, args->offset);
1662
#else
1663
len = args->len;
1664
offset = args->offset;
1665
#endif
1666
1667
advice = convert_fadvice(args->advice);
1668
if (advice == -1)
1669
return (EINVAL);
1670
return (kern_posix_fadvise(td, args->fd, offset, len, advice));
1671
}
1672
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1673
1674
#ifdef LINUX_LEGACY_SYSCALLS
1675
int
1676
linux_pipe(struct thread *td, struct linux_pipe_args *args)
1677
{
1678
int fildes[2];
1679
int error;
1680
1681
error = kern_pipe(td, fildes, 0, NULL, NULL);
1682
if (error != 0)
1683
return (error);
1684
1685
error = copyout(fildes, args->pipefds, sizeof(fildes));
1686
if (error != 0) {
1687
(void)kern_close(td, fildes[0]);
1688
(void)kern_close(td, fildes[1]);
1689
}
1690
1691
return (error);
1692
}
1693
#endif
1694
1695
int
1696
linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1697
{
1698
int fildes[2];
1699
int error, flags;
1700
1701
if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1702
return (EINVAL);
1703
1704
flags = 0;
1705
if ((args->flags & LINUX_O_NONBLOCK) != 0)
1706
flags |= O_NONBLOCK;
1707
if ((args->flags & LINUX_O_CLOEXEC) != 0)
1708
flags |= O_CLOEXEC;
1709
error = kern_pipe(td, fildes, flags, NULL, NULL);
1710
if (error != 0)
1711
return (error);
1712
1713
error = copyout(fildes, args->pipefds, sizeof(fildes));
1714
if (error != 0) {
1715
(void)kern_close(td, fildes[0]);
1716
(void)kern_close(td, fildes[1]);
1717
}
1718
1719
return (error);
1720
}
1721
1722
int
1723
linux_dup3(struct thread *td, struct linux_dup3_args *args)
1724
{
1725
int cmd;
1726
intptr_t newfd;
1727
1728
if (args->oldfd == args->newfd)
1729
return (EINVAL);
1730
if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1731
return (EINVAL);
1732
if (args->flags & LINUX_O_CLOEXEC)
1733
cmd = F_DUP2FD_CLOEXEC;
1734
else
1735
cmd = F_DUP2FD;
1736
1737
newfd = args->newfd;
1738
return (kern_fcntl(td, args->oldfd, cmd, newfd));
1739
}
1740
1741
int
1742
linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1743
{
1744
off_t len, offset;
1745
1746
/*
1747
* We emulate only posix_fallocate system call for which
1748
* mode should be 0.
1749
*/
1750
if (args->mode != 0)
1751
return (EOPNOTSUPP);
1752
1753
#if defined(__amd64__) && defined(COMPAT_LINUX32)
1754
len = PAIR32TO64(off_t, args->len);
1755
offset = PAIR32TO64(off_t, args->offset);
1756
#else
1757
len = args->len;
1758
offset = args->offset;
1759
#endif
1760
1761
return (kern_posix_fallocate(td, args->fd, offset, len));
1762
}
1763
1764
int
1765
linux_copy_file_range(struct thread *td, struct linux_copy_file_range_args
1766
*args)
1767
{
1768
l_loff_t inoff, outoff, *inoffp, *outoffp;
1769
int error, flags;
1770
1771
/*
1772
* copy_file_range(2) on Linux doesn't define any flags (yet), so is
1773
* the native implementation. Enforce it.
1774
*/
1775
if (args->flags != 0) {
1776
linux_msg(td, "copy_file_range unsupported flags 0x%x",
1777
args->flags);
1778
return (EINVAL);
1779
}
1780
flags = 0;
1781
inoffp = outoffp = NULL;
1782
if (args->off_in != NULL) {
1783
error = copyin(args->off_in, &inoff, sizeof(l_loff_t));
1784
if (error != 0)
1785
return (error);
1786
inoffp = &inoff;
1787
}
1788
if (args->off_out != NULL) {
1789
error = copyin(args->off_out, &outoff, sizeof(l_loff_t));
1790
if (error != 0)
1791
return (error);
1792
outoffp = &outoff;
1793
}
1794
1795
error = kern_copy_file_range(td, args->fd_in, inoffp, args->fd_out,
1796
outoffp, args->len, flags);
1797
if (error == 0 && args->off_in != NULL)
1798
error = copyout(inoffp, args->off_in, sizeof(l_loff_t));
1799
if (error == 0 && args->off_out != NULL)
1800
error = copyout(outoffp, args->off_out, sizeof(l_loff_t));
1801
return (error);
1802
}
1803
1804
#define LINUX_MEMFD_PREFIX "memfd:"
1805
1806
int
1807
linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args)
1808
{
1809
char memfd_name[LINUX_NAME_MAX + 1];
1810
int error, flags, shmflags, oflags;
1811
1812
/*
1813
* This is our clever trick to avoid the heap allocation to copy in the
1814
* uname. We don't really need to go this far out of our way, but it
1815
* does keep the rest of this function fairly clean as they don't have
1816
* to worry about cleanup on the way out.
1817
*/
1818
error = copyinstr(args->uname_ptr,
1819
memfd_name + sizeof(LINUX_MEMFD_PREFIX) - 1,
1820
LINUX_NAME_MAX - sizeof(LINUX_MEMFD_PREFIX) - 1, NULL);
1821
if (error != 0) {
1822
if (error == ENAMETOOLONG)
1823
error = EINVAL;
1824
return (error);
1825
}
1826
1827
memcpy(memfd_name, LINUX_MEMFD_PREFIX, sizeof(LINUX_MEMFD_PREFIX) - 1);
1828
flags = linux_to_bsd_bits(args->flags, mfd_bitmap, 0);
1829
if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB |
1830
MFD_HUGE_MASK)) != 0)
1831
return (EINVAL);
1832
/* Size specified but no HUGETLB. */
1833
if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0)
1834
return (EINVAL);
1835
/* We don't actually support HUGETLB. */
1836
if ((flags & MFD_HUGETLB) != 0)
1837
return (ENOSYS);
1838
oflags = O_RDWR;
1839
shmflags = SHM_GROW_ON_WRITE;
1840
if ((flags & MFD_CLOEXEC) != 0)
1841
oflags |= O_CLOEXEC;
1842
if ((flags & MFD_ALLOW_SEALING) != 0)
1843
shmflags |= SHM_ALLOW_SEALING;
1844
return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL,
1845
memfd_name, NULL));
1846
}
1847
1848
int
1849
linux_splice(struct thread *td, struct linux_splice_args *args)
1850
{
1851
1852
linux_msg(td, "syscall splice not really implemented");
1853
1854
/*
1855
* splice(2) is documented to return EINVAL in various circumstances;
1856
* returning it instead of ENOSYS should hint the caller to use fallback
1857
* instead.
1858
*/
1859
return (EINVAL);
1860
}
1861
1862
int
1863
linux_close_range(struct thread *td, struct linux_close_range_args *args)
1864
{
1865
u_int flags = 0;
1866
1867
/*
1868
* Implementing close_range(CLOSE_RANGE_UNSHARE) allows Linux to
1869
* unshare filedesc table of the calling thread from others threads
1870
* in a thread group (i.e., process in the FreeBSD) or others processes,
1871
* which shares the same table, before closing the files. FreeBSD does
1872
* not have compatible unsharing mechanism due to the fact that sharing
1873
* process resources, including filedesc table, is at thread level in the
1874
* Linux, while in the FreeBSD it is at the process level.
1875
* Return EINVAL for now if the CLOSE_RANGE_UNSHARE flag is specified
1876
* until this new Linux API stabilizes.
1877
*/
1878
1879
if ((args->flags & ~(LINUX_CLOSE_RANGE_CLOEXEC)) != 0)
1880
return (EINVAL);
1881
if (args->first > args->last)
1882
return (EINVAL);
1883
if ((args->flags & LINUX_CLOSE_RANGE_CLOEXEC) != 0)
1884
flags |= CLOSE_RANGE_CLOEXEC;
1885
return (kern_close_range(td, flags, args->first, args->last));
1886
}
1887
1888
int
1889
linux_enobufs2eagain(struct thread *td, int fd, int error)
1890
{
1891
struct file *fp;
1892
1893
if (error != ENOBUFS)
1894
return (error);
1895
if (fget(td, fd, &cap_no_rights, &fp) != 0)
1896
return (error);
1897
if (fp->f_type == DTYPE_SOCKET && (fp->f_flag & FNONBLOCK) != 0)
1898
error = EAGAIN;
1899
fdrop(fp, td);
1900
return (error);
1901
}
1902
1903
int
1904
linux_write(struct thread *td, struct linux_write_args *args)
1905
{
1906
struct write_args bargs = {
1907
.fd = args->fd,
1908
.buf = args->buf,
1909
.nbyte = args->nbyte,
1910
};
1911
1912
return (linux_enobufs2eagain(td, args->fd, sys_write(td, &bargs)));
1913
}
1914
1915
int
1916
linux_writev(struct thread *td, struct linux_writev_args *args)
1917
{
1918
struct uio *auio;
1919
int error;
1920
1921
#ifdef COMPAT_LINUX32
1922
error = freebsd32_copyinuio(PTRIN(args->iovp), args->iovcnt, &auio);
1923
#else
1924
error = copyinuio(args->iovp, args->iovcnt, &auio);
1925
#endif
1926
if (error != 0)
1927
return (error);
1928
error = kern_writev(td, args->fd, auio);
1929
freeuio(auio);
1930
return (linux_enobufs2eagain(td, args->fd, error));
1931
}
1932
1933
static int
1934
linux_inotify_init_flags(int l_flags)
1935
{
1936
int bsd_flags;
1937
1938
if ((l_flags & ~(LINUX_IN_CLOEXEC | LINUX_IN_NONBLOCK)) != 0)
1939
linux_msg(NULL, "inotify_init1 unsupported flags 0x%x",
1940
l_flags);
1941
1942
bsd_flags = 0;
1943
if ((l_flags & LINUX_IN_CLOEXEC) != 0)
1944
bsd_flags |= O_CLOEXEC;
1945
if ((l_flags & LINUX_IN_NONBLOCK) != 0)
1946
bsd_flags |= O_NONBLOCK;
1947
return (bsd_flags);
1948
}
1949
1950
static int
1951
inotify_init_common(struct thread *td, int flags)
1952
{
1953
struct specialfd_inotify si;
1954
1955
si.flags = linux_inotify_init_flags(flags);
1956
return (kern_specialfd(td, SPECIALFD_INOTIFY, &si));
1957
}
1958
1959
#if defined(__i386__) || defined(__amd64__)
1960
int
1961
linux_inotify_init(struct thread *td, struct linux_inotify_init_args *args)
1962
{
1963
return (inotify_init_common(td, 0));
1964
}
1965
#endif
1966
1967
int
1968
linux_inotify_init1(struct thread *td, struct linux_inotify_init1_args *args)
1969
{
1970
return (inotify_init_common(td, args->flags));
1971
}
1972
1973
/*
1974
* The native implementation uses the same values for inotify events as
1975
* libinotify, which gives us binary compatibility with Linux. This simplifies
1976
* the shim implementation a lot, as otherwise we would have to handle read(2)
1977
* calls on inotify descriptors and translate events to Linux's ABI.
1978
*/
1979
_Static_assert(LINUX_IN_ACCESS == IN_ACCESS,
1980
"IN_ACCESS mismatch");
1981
_Static_assert(LINUX_IN_MODIFY == IN_MODIFY,
1982
"IN_MODIFY mismatch");
1983
_Static_assert(LINUX_IN_ATTRIB == IN_ATTRIB,
1984
"IN_ATTRIB mismatch");
1985
_Static_assert(LINUX_IN_CLOSE_WRITE == IN_CLOSE_WRITE,
1986
"IN_CLOSE_WRITE mismatch");
1987
_Static_assert(LINUX_IN_CLOSE_NOWRITE == IN_CLOSE_NOWRITE,
1988
"IN_CLOSE_NOWRITE mismatch");
1989
_Static_assert(LINUX_IN_OPEN == IN_OPEN,
1990
"IN_OPEN mismatch");
1991
_Static_assert(LINUX_IN_MOVED_FROM == IN_MOVED_FROM,
1992
"IN_MOVED_FROM mismatch");
1993
_Static_assert(LINUX_IN_MOVED_TO == IN_MOVED_TO,
1994
"IN_MOVED_TO mismatch");
1995
_Static_assert(LINUX_IN_CREATE == IN_CREATE,
1996
"IN_CREATE mismatch");
1997
_Static_assert(LINUX_IN_DELETE == IN_DELETE,
1998
"IN_DELETE mismatch");
1999
_Static_assert(LINUX_IN_DELETE_SELF == IN_DELETE_SELF,
2000
"IN_DELETE_SELF mismatch");
2001
_Static_assert(LINUX_IN_MOVE_SELF == IN_MOVE_SELF,
2002
"IN_MOVE_SELF mismatch");
2003
2004
_Static_assert(LINUX_IN_UNMOUNT == IN_UNMOUNT,
2005
"IN_UNMOUNT mismatch");
2006
_Static_assert(LINUX_IN_Q_OVERFLOW == IN_Q_OVERFLOW,
2007
"IN_Q_OVERFLOW mismatch");
2008
_Static_assert(LINUX_IN_IGNORED == IN_IGNORED,
2009
"IN_IGNORED mismatch");
2010
2011
_Static_assert(LINUX_IN_ISDIR == IN_ISDIR,
2012
"IN_ISDIR mismatch");
2013
_Static_assert(LINUX_IN_ONLYDIR == IN_ONLYDIR,
2014
"IN_ONLYDIR mismatch");
2015
_Static_assert(LINUX_IN_DONT_FOLLOW == IN_DONT_FOLLOW,
2016
"IN_DONT_FOLLOW mismatch");
2017
_Static_assert(LINUX_IN_MASK_CREATE == IN_MASK_CREATE,
2018
"IN_MASK_CREATE mismatch");
2019
_Static_assert(LINUX_IN_MASK_ADD == IN_MASK_ADD,
2020
"IN_MASK_ADD mismatch");
2021
_Static_assert(LINUX_IN_ONESHOT == IN_ONESHOT,
2022
"IN_ONESHOT mismatch");
2023
_Static_assert(LINUX_IN_EXCL_UNLINK == IN_EXCL_UNLINK,
2024
"IN_EXCL_UNLINK mismatch");
2025
2026
static int
2027
linux_inotify_watch_flags(int l_flags)
2028
{
2029
if ((l_flags & ~(LINUX_IN_ALL_EVENTS | LINUX_IN_ALL_FLAGS)) != 0) {
2030
linux_msg(NULL, "inotify_add_watch unsupported flags 0x%x",
2031
l_flags);
2032
}
2033
2034
return (l_flags);
2035
}
2036
2037
int
2038
linux_inotify_add_watch(struct thread *td,
2039
struct linux_inotify_add_watch_args *args)
2040
{
2041
return (kern_inotify_add_watch(args->fd, AT_FDCWD, args->pathname,
2042
linux_inotify_watch_flags(args->mask), td));
2043
}
2044
2045
int
2046
linux_inotify_rm_watch(struct thread *td,
2047
struct linux_inotify_rm_watch_args *args)
2048
{
2049
return (kern_inotify_rm_watch(args->fd, args->wd, td));
2050
}
2051
2052