11use std:: collections:: HashSet ;
22use std:: ffi:: CString ;
3- use std:: fs:: { read_dir, read_link, File } ;
3+ use std:: fs:: { read_dir, read_link, DirEntry , File } ;
44use std:: io:: Write ;
55use std:: os:: fd:: AsFd ;
66use std:: path:: { Path , PathBuf } ;
@@ -14,7 +14,10 @@ use rustix::mount::{
1414use rustix:: path:: Arg ;
1515use serde_json:: json;
1616
17- fn make_tmpfs ( dir : & str ) -> Result < ( ) > {
17+ fn make_tmpfs < P > ( dir : P ) -> Result < ( ) >
18+ where
19+ P : rustix:: path:: Arg ,
20+ {
1821 mount2 (
1922 Some ( "tmpfs" ) ,
2023 dir,
@@ -25,7 +28,10 @@ fn make_tmpfs(dir: &str) -> Result<()> {
2528 . context ( "Failed to mount tmpfs" )
2629}
2730
28- fn mkdir_fex ( dir : & str ) {
31+ fn mkdir_fex < P > ( dir : P )
32+ where
33+ P : rustix:: path:: Arg ,
34+ {
2935 // Must succeed since /run/ was just mounted and is now an empty tmpfs.
3036 mkdir (
3137 dir,
@@ -39,19 +45,19 @@ fn do_mount_recursive_bind(source: &str, target: PathBuf) -> Result<()> {
3945 // the /run/muvm-host thing.
4046 if source == "/run" {
4147 mount_bind ( source, & target)
42- . context ( format ! ( "Failed to mount {:?} on {:?}" , & source , & target ) ) ?;
48+ . with_context ( || format ! ( "Failed to mount {source :?} on {target :?}" ) ) ?;
4349 let host = target. join ( "muvm-host" ) ;
44- mount_bind ( "/" , & host) . context ( format ! ( "Failed to mount / on {:?}" , & host ) ) ?;
50+ mount_bind ( "/" , & host) . with_context ( || format ! ( "Failed to mount / on {host :?}" ) ) ?;
4551 } else {
4652 mount_recursive_bind ( source, & target)
47- . context ( format ! ( "Failed to mount {:?} on {:?}" , & source , & target ) ) ?;
53+ . with_context ( || format ! ( "Failed to mount {source :?} on {target :?}" ) ) ?;
4854 }
4955 Ok ( ( ) )
5056}
5157
5258fn mount_fex_rootfs ( merged_rootfs : bool ) -> Result < ( ) > {
53- let dir = "/run/fex-emu/" ;
54- let dir_rootfs = dir. to_string ( ) + "rootfs" ;
59+ let dir = Path :: new ( "/run/fex-emu/" ) ;
60+ let dir_rootfs = dir. join ( "rootfs" ) ;
5561
5662 // Make base directories
5763 mkdir_fex ( dir) ;
@@ -69,22 +75,31 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
6975 }
7076
7177 // Find /dev/vd*
72- for x in read_dir ( "/dev" ) . unwrap ( ) {
73- let file = x. unwrap ( ) ;
74- let name = file. file_name ( ) . into_string ( ) . unwrap ( ) ;
75- if !name. starts_with ( "vd" ) {
76- continue ;
77- }
78-
79- let path = file. path ( ) . into_os_string ( ) . into_string ( ) . unwrap ( ) ;
80- let dir = dir. to_string ( ) + & name;
81-
78+ let mut dev_vd_entries: Vec < DirEntry > = read_dir ( "/dev" )
79+ . context ( "Failed to read directory `/dev`" ) ?
80+ . collect :: < Result < Vec < _ > , _ > > ( )
81+ . context ( "Failed to read directory entry in `/dev`" ) ?
82+ . into_iter ( )
83+ . filter ( |entry| {
84+ entry
85+ . file_name ( )
86+ . into_string ( )
87+ . expect ( "file_name should not contain invalid UTF-8" )
88+ . starts_with ( "vd" )
89+ } )
90+ . collect ( ) ;
91+ // [readdir(3)](https://man7.org/linux/man-pages/man3/readdir.3.html#NOTES)
92+ //
93+ // > The order in which filenames are read by successive calls to readdir() depends on the
94+ // > filesystem implementation; it is unlikely that the names will be sorted in any fashion.
95+ dev_vd_entries. sort_unstable_by_key ( |entry| entry. file_name ( ) ) ;
96+ for entry in dev_vd_entries {
97+ let target_dir = dir. join ( entry. file_name ( ) ) ;
8298 // Mount the erofs images.
83- mkdir_fex ( & dir) ;
84- mount2 ( Some ( path) , dir. clone ( ) , Some ( "erofs" ) , flags, None )
85- . context ( "Failed to mount erofs" )
86- . unwrap ( ) ;
87- images. push ( dir) ;
99+ mkdir_fex ( & target_dir) ;
100+ mount2 ( Some ( entry. path ( ) ) , & target_dir, Some ( "erofs" ) , flags, None )
101+ . context ( "Failed to mount erofs" ) ?;
102+ images. push ( target_dir) ;
88103 }
89104
90105 if images. is_empty ( ) {
@@ -99,7 +114,7 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
99114 // For merged rootfs mode, we need to overlay subtrees separately
100115 // onto the real rootfs. First, insert the real rootfs as the
101116 // bottom-most "image".
102- images. insert ( 0 , "/" . to_owned ( ) ) ;
117+ images. insert ( 0 , PathBuf :: from ( "/" ) ) ;
103118
104119 let mut merge_dirs = HashSet :: new ( ) ;
105120 let mut non_dirs = HashSet :: new ( ) ;
@@ -115,25 +130,25 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
115130 continue ;
116131 } ;
117132 let source = entry. path ( ) ;
118- let file_name = entry. file_name ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) ;
119- let target = Path :: new ( & dir_rootfs) . join ( & file_name) ;
133+ let file_name = entry. file_name ( ) ;
134+ let target = dir_rootfs. join ( & file_name) ;
120135
121136 if file_type. is_file ( ) {
122137 // File in the root fs, bind mount it from the uppermost layer
123138 if non_dirs. insert ( file_name) {
124139 File :: create ( & target) ?;
125- mount_bind ( & source, & target) ?;
140+ mount_bind ( source, target) ?;
126141 }
127142 } else if file_type. is_symlink ( ) {
128143 // Symlink in the root fs, create it from the uppermost layer
129144 if non_dirs. insert ( file_name) {
130145 let symlink_target = read_link ( source) ?;
131- symlink ( & symlink_target, & target) ?;
146+ symlink ( symlink_target, target) ?;
132147 }
133148 } else {
134149 // Directory, so we potentially have to overlayfs it
135150 if merge_dirs. insert ( file_name) {
136- mkdir_fex ( target. as_str ( ) ? ) ;
151+ mkdir_fex ( target) ;
137152 }
138153 }
139154 }
@@ -142,11 +157,11 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
142157 // Now, go through each potential merged dir and figure out which
143158 // layers have it, then mount an overlayfs (or bind if one layer).
144159 for dir in merge_dirs {
145- let target = Path :: new ( & dir_rootfs) . join ( & dir) ;
160+ let target = dir_rootfs. join ( & dir) ;
146161 let mut layers = Vec :: new ( ) ;
147162
148163 for image in images. iter ( ) {
149- let source = Path :: new ( image) . join ( & dir) ;
164+ let source = image. join ( & dir) ;
150165 if source. is_dir ( ) {
151166 layers. push ( source. as_str ( ) . unwrap ( ) . to_owned ( ) ) ;
152167 }
@@ -161,8 +176,8 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
161176 layers[ 0 ] = "/run/muvm-host/etc" . to_owned ( ) ;
162177 }
163178 let opts = format ! (
164- "lowerdir={},metacopy=off,redirect_dir=nofollow,userxattr" ,
165- layers. into_iter( ) . rev( ) . collect:: <Vec <String >>( ) . join( ":" )
179+ "lowerdir={lowerdir },metacopy=off,redirect_dir=nofollow,userxattr" ,
180+ lowerdir = layers. into_iter( ) . rev( ) . collect:: <Vec <String >>( ) . join( ":" )
166181 ) ;
167182 let opts = CString :: new ( opts) . unwrap ( ) ;
168183 let overlay = "overlay" . to_string ( ) ;
@@ -176,14 +191,19 @@ fn mount_fex_rootfs(merged_rootfs: bool) -> Result<()> {
176191 // Special case: Put back the /etc/resolv.conf overlay on top
177192 overlay_file (
178193 "/etc/resolv.conf" ,
179- & ( dir_rootfs. clone ( ) + "/ etc/resolv.conf") ,
194+ dir_rootfs. join ( " etc/resolv.conf") . as_str ( ) . unwrap ( ) ,
180195 ) ?;
181196 } else {
182197 if images. len ( ) >= 2 {
183198 // Overlay the mounts together.
184199 let opts = format ! (
185- "lowerdir={}" ,
186- images. into_iter( ) . rev( ) . collect:: <Vec <String >>( ) . join( ":" )
200+ "lowerdir={lowerdir}" ,
201+ lowerdir = images
202+ . into_iter( )
203+ . rev( )
204+ . map( |path| path. as_str( ) . unwrap( ) . to_owned( ) )
205+ . collect:: <Vec <_>>( )
206+ . join( ":" )
187207 ) ;
188208 let opts = CString :: new ( opts) . unwrap ( ) ;
189209 let overlay = "overlay" . to_string ( ) ;
0 commit comments