1
+ // SPDX-License-Identifier: GPL-2.0-only
2
+ #define _GNU_SOURCE
3
+ #include <fcntl.h>
1
4
#include <stdbool.h>
2
5
#include <stddef.h>
3
6
#include <stdio.h>
@@ -50,6 +53,8 @@ static struct fuse_opt lklfuse_opts[] = {
50
53
FUSE_OPT_END
51
54
};
52
55
56
+ #define ARRAY_SIZE (arr ) (sizeof(arr) / sizeof(arr[0]))
57
+
53
58
static void usage (void )
54
59
{
55
60
printf (
@@ -255,8 +260,39 @@ static int lklfuse_open3(const char *path, bool create, mode_t mode,
255
260
else
256
261
return - EINVAL ;
257
262
263
+ /*
264
+ * XXX see rules in fuse3/fuse.h:
265
+ * Creation (O_CREAT, O_EXCL, O_NOCTTY) flags will be filtered out /
266
+ * handled by FUSE kernel...
267
+ */
258
268
if (create )
259
269
flags |= LKL_O_CREAT ;
270
+ if (fi -> flags & O_TRUNC )
271
+ flags |= LKL_O_TRUNC ;
272
+ if (fi -> flags & O_APPEND )
273
+ flags |= LKL_O_APPEND ;
274
+ if (fi -> flags & O_NONBLOCK )
275
+ flags |= LKL_O_NONBLOCK ;
276
+ if (fi -> flags & O_DSYNC )
277
+ flags |= LKL_O_DSYNC ;
278
+ if (fi -> flags & O_DIRECT )
279
+ flags |= LKL_O_DIRECT ;
280
+ if (fi -> flags & O_LARGEFILE )
281
+ flags |= LKL_O_LARGEFILE ;
282
+ if (fi -> flags & O_DIRECTORY )
283
+ flags |= LKL_O_DIRECTORY ;
284
+ if (fi -> flags & O_NOFOLLOW )
285
+ flags |= LKL_O_NOFOLLOW ;
286
+ if (fi -> flags & O_NOATIME )
287
+ flags |= LKL_O_NOATIME ;
288
+ if (fi -> flags & O_CLOEXEC )
289
+ flags |= LKL_O_CLOEXEC ;
290
+ if (fi -> flags & O_SYNC )
291
+ flags |= LKL_O_SYNC ;
292
+ if (fi -> flags & O_PATH )
293
+ flags |= LKL_O_PATH ;
294
+ if (fi -> flags & O_TMPFILE )
295
+ flags |= LKL_O_TMPFILE ;
260
296
261
297
ret = lkl_sys_open (path , flags , mode );
262
298
if (ret < 0 )
@@ -545,12 +581,122 @@ const struct fuse_operations lklfuse_ops = {
545
581
.fallocate = lklfuse_fallocate ,
546
582
};
547
583
584
+ static int lklfuse_parse_vfs_flags (bool ro , const char * opts , int * flags ,
585
+ char * remain , size_t remlen )
586
+ {
587
+ size_t optslen ;
588
+ char tokbuf [4096 ];
589
+ char * tb = tokbuf ;
590
+ char * tok ;
591
+ char * saveptr = NULL ;
592
+ /* we could consider using libmount for this mapping */
593
+ struct flagmap {
594
+ const char * opt ;
595
+ int flag ;
596
+ bool invert ;
597
+ } map [] = {
598
+ { "ro" , LKL_MS_RDONLY },
599
+ { "nosuid" , LKL_MS_NOSUID },
600
+ { "nodev" , LKL_MS_NODEV },
601
+ { "noexec" , LKL_MS_NOEXEC },
602
+ { "sync" , LKL_MS_SYNCHRONOUS },
603
+ { "remount" , LKL_MS_REMOUNT },
604
+ { "dirsync" , LKL_MS_DIRSYNC },
605
+ { "nosymfollow" , LKL_MS_NOSYMFOLLOW },
606
+ { "noatime" , LKL_MS_NOATIME },
607
+ { "nodiratime" , LKL_MS_NODIRATIME },
608
+ { "bind" , LKL_MS_BIND },
609
+ { "rbind" , LKL_MS_BIND | LKL_MS_REC },
610
+ { "move" , LKL_MS_MOVE },
611
+ { "silent" , LKL_MS_SILENT },
612
+
613
+ { "relatime" , LKL_MS_RELATIME },
614
+ { "iversion" , LKL_MS_I_VERSION },
615
+ { "strictatime" , LKL_MS_STRICTATIME },
616
+ { "lazytime" , LKL_MS_LAZYTIME },
617
+
618
+ /* opts below aren't passed to external mount.type helpers */
619
+ { "unbindable" , LKL_MS_UNBINDABLE },
620
+ { "runbindable" , LKL_MS_UNBINDABLE | LKL_MS_REC },
621
+ { "private" , LKL_MS_PRIVATE },
622
+ { "rprivate" , LKL_MS_PRIVATE | LKL_MS_REC },
623
+ { "slave" , LKL_MS_SLAVE },
624
+ { "rslave" , LKL_MS_SLAVE | LKL_MS_REC },
625
+ { "shared" , LKL_MS_SHARED },
626
+ { "rshared" , LKL_MS_SHARED | LKL_MS_REC },
627
+
628
+ /* opts below invert flags */
629
+ { "rw" , LKL_MS_RDONLY , true },
630
+ { "suid" , LKL_MS_NOSUID , true },
631
+ { "dev" , LKL_MS_NODEV , true },
632
+ { "exec" , LKL_MS_NOEXEC , true },
633
+ { "async" , LKL_MS_SYNCHRONOUS , true },
634
+ { "symfollow" , LKL_MS_NOSYMFOLLOW , true },
635
+ { "atime" , LKL_MS_NOATIME , true },
636
+ { "diratime" , LKL_MS_NODIRATIME , true },
637
+ { "loud" , LKL_MS_SILENT , true },
638
+ { "norelatime" , LKL_MS_RELATIME , true },
639
+ { "noiversion" , LKL_MS_I_VERSION , true },
640
+ { "nostrictatime" , LKL_MS_STRICTATIME , true },
641
+ { "nolazytime" , LKL_MS_LAZYTIME , true },
642
+ };
643
+ * flags = ro ? LKL_MS_RDONLY : 0 ;
644
+
645
+ optslen = opts ? strlen (opts ) : 0 ;
646
+ /* need enough space in @remain to at most pass through all options */
647
+ if (optslen >= remlen || optslen >= sizeof (tokbuf ))
648
+ return - EINVAL ;
649
+
650
+ * remain = '\0' ;
651
+ if (optslen == 0 )
652
+ return 0 ;
653
+
654
+ strncpy (tokbuf , opts , sizeof (tokbuf ));
655
+ /*
656
+ * '\,' and '\=' escapes for mount options provided via -o opts=... are
657
+ * removed by libfuse, so we just need to map and remove any VFS flags.
658
+ */
659
+ while ((tok = strtok_r (tb , "," , & saveptr )) != NULL ) {
660
+ size_t i ;
661
+
662
+ tb = NULL ;
663
+ for (i = 0 ; i < ARRAY_SIZE (map ); i ++ ) {
664
+ if (strcmp (tok , map [i ].opt ))
665
+ continue ;
666
+ if (map [i ].invert )
667
+ * flags &= ~map [i ].flag ;
668
+ else
669
+ * flags |= map [i ].flag ;
670
+ break ;
671
+ }
672
+ /* opts mapped to a flag shouldn't be retained */
673
+ if (i < ARRAY_SIZE (map ))
674
+ continue ;
675
+
676
+ if (* remain != '\0' )
677
+ strcat (remain , "," );
678
+ strcat (remain , tok );
679
+ }
680
+
681
+ return 0 ;
682
+ }
683
+
548
684
static int start_lkl (void )
549
685
{
550
686
long ret ;
551
687
char mpoint [32 ];
552
688
struct timespec walltime ;
553
689
struct lkl_timespec ts ;
690
+ int mount_flags = 0 ;
691
+ char remaining_mopts [4096 ] = { 0 };
692
+
693
+ ret = lklfuse_parse_vfs_flags (lklfuse .ro , lklfuse .opts , & mount_flags ,
694
+ remaining_mopts , sizeof (remaining_mopts ));
695
+ if (ret < 0 ) {
696
+ fprintf (stderr , "failed to parse mount flags: %s\n" ,
697
+ lklfuse .opts );
698
+ goto out ;
699
+ }
554
700
555
701
ret = lkl_start_kernel ("mem=%dM" , lklfuse .mb );
556
702
if (ret ) {
@@ -574,9 +720,8 @@ static int start_lkl(void)
574
720
}
575
721
576
722
ret = lkl_mount_dev (lklfuse .disk_id , lklfuse .part , lklfuse .type ,
577
- lklfuse . ro ? LKL_MS_RDONLY : 0 , lklfuse . opts ,
723
+ mount_flags , remaining_mopts ,
578
724
mpoint , sizeof (mpoint ));
579
-
580
725
if (ret ) {
581
726
fprintf (stderr , "can't mount disk: %s\n" , lkl_strerror (ret ));
582
727
goto out_halt ;
0 commit comments