@@ -152,7 +152,7 @@ pub struct Container {
152
152
153
153
// Note: we don't use Command::env or Command::env_clear, because those
154
154
// cause Command::exec to allocate, which we don't want to do after forking.
155
- envs : Vec < ( OsString , OsString ) > ,
155
+ envs : Vec < CString > ,
156
156
157
157
tmp_stderr : Option < OwnedFd > ,
158
158
@@ -180,21 +180,26 @@ impl Container {
180
180
let exe_path =
181
181
find_executable_in_path ( & exe) . ok_or ( anyhow ! ( "command {:?} not in PATH" , & exe) ) ?;
182
182
183
- let mut envs: Vec < ( OsString , OsString ) > = app_config. env . clone ( ) . into_iter ( ) . collect ( ) ;
183
+ let mut envs: Vec < CString > = app_config
184
+ . env
185
+ . clone ( )
186
+ . into_iter ( )
187
+ . map ( |( k, v) | make_putenv ( k, v) )
188
+ . collect ( ) ;
184
189
185
190
let mut child_cmd = Command :: new ( exe_path) ;
186
191
child_cmd. current_dir ( "/" ) ;
187
192
child_cmd. args ( args) ;
188
193
189
194
if let Some ( path) = std:: env:: var_os ( "PATH" ) {
190
- envs. push ( ( "PATH" . into ( ) , path) ) ;
195
+ envs. push ( make_putenv ( "PATH" , path) ) ;
191
196
}
192
197
193
198
let uid = getuid ( ) ;
194
199
let gid = getgid ( ) ;
195
200
196
201
let intern_run_path: OsString = format ! ( "/run/user/{}" , uid. as_raw( ) ) . try_into ( ) . unwrap ( ) ;
197
- envs. push ( ( "XDG_RUNTIME_DIR" . into ( ) , intern_run_path. clone ( ) ) ) ;
202
+ envs. push ( make_putenv ( "XDG_RUNTIME_DIR" , intern_run_path. clone ( ) ) ) ;
198
203
199
204
let extern_run_path = std:: env:: temp_dir ( ) . join ( format ! (
200
205
"mm.{}" ,
@@ -203,7 +208,7 @@ impl Container {
203
208
std:: fs:: create_dir_all ( & extern_run_path) ?;
204
209
205
210
let intern_home_path: OsString = std:: env:: var_os ( "HOME" ) . unwrap_or ( "/home/mm" . into ( ) ) ;
206
- envs. push ( ( "HOME" . into ( ) , intern_home_path. clone ( ) ) ) ;
211
+ envs. push ( make_putenv ( "HOME" , intern_home_path. clone ( ) ) ) ;
207
212
208
213
debug ! ( home_mode = ?app_config. home_isolation_mode, "using home mode" ) ;
209
214
let ( extern_home_path, clear_home) = match app_config. home_isolation_mode {
@@ -270,8 +275,7 @@ impl Container {
270
275
K : AsRef < OsStr > ,
271
276
V : AsRef < OsStr > ,
272
277
{
273
- self . envs
274
- . push ( ( key. as_ref ( ) . to_owned ( ) , val. as_ref ( ) . to_owned ( ) ) )
278
+ self . envs . push ( make_putenv ( key, val) )
275
279
}
276
280
277
281
pub fn set_stdout < T : AsFd > ( & mut self , stdio : T ) -> anyhow:: Result < ( ) > {
@@ -321,8 +325,6 @@ impl Container {
321
325
. flag_newns ( )
322
326
. flag_newpid ( ) ;
323
327
324
- // TODO
325
- self . child_cmd . env_clear ( ) . envs ( self . envs . clone ( ) ) ;
326
328
debug ! ( cmd = ?self . child_cmd, "spawning child process" ) ;
327
329
328
330
let ( barrier, child_barrier) = ipc:: EventfdBarrier :: new ( ) ?;
@@ -584,10 +586,10 @@ impl Container {
584
586
585
587
// We don't trust std::os::Command's env handling, because sometimes
586
588
// it allocates.
587
- // libc::clearenv();
588
- // for (k, v) in &self.envs {
589
- // libc::setenv
590
- // }
589
+ libc:: clearenv ( ) ;
590
+ for v in & mut self . envs {
591
+ libc:: putenv ( v . as_ptr ( ) as * mut _ ) ;
592
+ }
591
593
592
594
// If successful, this never returns.
593
595
let _e = self . child_cmd . exec ( ) ;
@@ -823,6 +825,16 @@ fn sync_barrier(barrier: &ipc::EventfdBarrier) -> rustix::io::Result<()> {
823
825
barrier. sync ( time:: Duration :: from_secs ( 1 ) )
824
826
}
825
827
828
+ /// Generates a CString in the format key=value, for putenv(3).
829
+ fn make_putenv ( k : impl AsRef < OsStr > , v : impl AsRef < OsStr > ) -> CString {
830
+ CString :: new ( format ! (
831
+ "{}={}" ,
832
+ k. as_ref( ) . to_str( ) . unwrap( ) ,
833
+ v. as_ref( ) . to_str( ) . unwrap( )
834
+ ) )
835
+ . unwrap ( )
836
+ }
837
+
826
838
#[ cfg( test) ]
827
839
mod test {
828
840
use std:: { fs:: File , io:: Read as _} ;
0 commit comments