11use crate :: ffi_util:: ToCString ;
22use crate :: { Command , Namespace } ;
3- use libc:: { MNT_DETACH , MS_BIND , MS_PRIVATE , MS_RDONLY , MS_REC , MS_REMOUNT } ;
3+ use libc:: {
4+ MNT_DETACH , MS_BIND , MS_PRIVATE , MS_RDONLY , MS_REC , MS_REMOUNT , O_CLOEXEC , O_CREAT , O_RDONLY ,
5+ } ;
46use std:: ffi:: { c_char, c_void, CString } ;
57use std:: path:: Path ;
68
@@ -29,6 +31,16 @@ impl Command {
2931self . config . fake_root_base =Some ( base. to_cstring ( ) ) ;
3032}
3133
34+ fn fakeroot_mkdir ( & mut self , base : & str , dir : & Path ) {
35+ dir. parent ( ) . map ( |parent_dir|{
36+ if dir != parent_dir{
37+ self . fakeroot_mkdir ( base, parent_dir) ;
38+ let outer_dir =format ! ( "{}/{}" , base, dir. to_str( ) . unwrap( ) ) ;
39+ self . config . fake_root_mkdirs . push ( outer_dir. to_cstring ( ) ) ;
40+ }
41+ } ) ;
42+ }
43+
3244/// Add an existing directory to the fakeroot.
3345///
3446/// fakeroot_enable() must be called first, otherwise this function will panic.
@@ -46,7 +58,39 @@ impl Command {
4658. as_ref ( )
4759. expect ( "call fakeroot_enable() first!" )
4860. to_str ( )
49- . unwrap ( ) ;
61+ . unwrap ( )
62+ . to_owned ( ) ;
63+ self . fakeroot_mkdir ( base. as_ref ( ) , Path :: new ( dst) ) ;
64+ self . config . fake_root_mounts . push ( FakeRootMount {
65+ mountpoint : dst. to_cstring ( ) ,
66+ mountpoint_outer : format ! ( "{}/{}" , base, dst) . to_cstring ( ) ,
67+ src : src. as_ref ( ) . to_cstring ( ) ,
68+ readonly,
69+ is_special_fs : false ,
70+ } ) ;
71+ }
72+
73+ /// Add an existing file or device to the fakeroot.
74+ ///
75+ /// fakeroot_enable() must be called first, otherwise this function will panic.
76+ ///
77+ /// Example usage:
78+ /// cmd.fakeroot_mount_file("/dev/urandom", "/dev/urandom", false);
79+ pub fn fakeroot_mount_file < P : AsRef < Path > > ( & mut self , src : P , dst : & str , readonly : bool ) {
80+ let base =self
81+ . config
82+ . fake_root_base
83+ . as_ref ( )
84+ . expect ( "call fakeroot_enable() first!" )
85+ . to_str ( )
86+ . unwrap ( )
87+ . to_owned ( ) ;
88+ Path :: new ( dst) . parent ( ) . map ( |parent_dir|{
89+ self . fakeroot_mkdir ( base. as_ref ( ) , parent_dir) ;
90+ } ) ;
91+ self . config
92+ . fake_root_touchs
93+ . push ( format ! ( "{}/{}" , base, dst) . to_cstring ( ) ) ;
5094self . config . fake_root_mounts . push ( FakeRootMount {
5195mountpoint : dst. to_cstring ( ) ,
5296mountpoint_outer : format ! ( "{}/{}" , base, dst) . to_cstring ( ) ,
@@ -69,7 +113,9 @@ impl Command {
69113. as_ref ( )
70114. expect ( "call fakeroot_enable() first!" )
71115. to_str ( )
72- . unwrap ( ) ;
116+ . unwrap ( )
117+ . to_owned ( ) ;
118+ self . fakeroot_mkdir ( base. as_ref ( ) , Path :: new ( dst) ) ;
73119self . config . fake_root_mounts . push ( FakeRootMount {
74120mountpoint : dst. to_cstring ( ) ,
75121mountpoint_outer : format ! ( "{}/{}" , base, dst) . to_cstring ( ) ,
@@ -81,7 +127,12 @@ impl Command {
81127}
82128
83129/// This syscall sequence is more or less taken from nsjail (https://github.com/google/nsjail).
84- pub ( crate ) unsafe fn build_fakeroot ( base : & CString , mountpoints : & [ FakeRootMount ] ) ->bool {
130+ pub ( crate ) unsafe fn build_fakeroot (
131+ base : & CString ,
132+ mkdirs : & [ CString ] ,
133+ touchs : & [ CString ] ,
134+ mountpoints : & [ FakeRootMount ] ,
135+ ) ->bool {
85136// define some libc constants
86137let null_char =0 as * const c_char ;
87138let null_void =0 as * const c_void ;
@@ -100,9 +151,19 @@ pub(crate) unsafe fn build_fakeroot(base: &CString, mountpoints: &[FakeRootMount
100151return false ;
101152}
102153
154+ // create mount points
155+ for dirin mkdirs{
156+ libc:: mkdir ( dir. as_ptr ( ) , 0o777 ) ;
157+ }
158+ for filein touchs{
159+ let fd = libc:: open ( file. as_ptr ( ) , O_RDONLY |O_CREAT |O_CLOEXEC ) ;
160+ if fd >=0 {
161+ libc:: close ( fd) ;
162+ }
163+ }
164+
103165// mount directories - still read-write (because MS_BIND + MS_RDONLY are not supported)
104166for mountin mountpoints{
105- libc:: mkdir ( mount. mountpoint_outer . as_ptr ( ) , 0o777 ) ;
106167let ( src, fstype, flags) =if mount. is_special_fs {
107168( null_char, mount. src . as_ptr ( ) , 0 )
108169} else {