@@ -192,44 +192,58 @@ pub fn current_exe() -> io::Result<PathBuf> {
192192 helpers:: device_path_to_text ( protocol) . map ( PathBuf :: from)
193193}
194194
195- pub struct Env ( !) ;
195+ pub struct EnvStrDebug < ' a > {
196+ iter : & ' a [ ( OsString , OsString ) ] ,
197+ }
198+
199+ impl fmt:: Debug for EnvStrDebug < ' _ > {
200+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
201+ let mut list = f. debug_list ( ) ;
202+ for ( a, b) in self . iter {
203+ list. entry ( & ( a. to_str ( ) . unwrap ( ) , b. to_str ( ) . unwrap ( ) ) ) ;
204+ }
205+ list. finish ( )
206+ }
207+ }
208+
209+ pub struct Env ( crate :: vec:: IntoIter < ( OsString , OsString ) > ) ;
196210
197211impl Env {
198212 // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
199213 pub fn str_debug ( & self ) -> impl fmt:: Debug + ' _ {
200- let Self ( inner) = self ;
201- match * inner { }
214+ EnvStrDebug { iter : self . 0 . as_slice ( ) }
202215 }
203216}
204217
205218impl Iterator for Env {
206219 type Item = ( OsString , OsString ) ;
220+
207221 fn next ( & mut self ) -> Option < ( OsString , OsString ) > {
208- self . 0
222+ self . 0 . next ( )
209223 }
210224}
211225
212226impl fmt:: Debug for Env {
213- fn fmt ( & self , _: & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
214- let Self ( inner) = self ;
215- match * inner { }
227+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
228+ self . 0 . fmt ( f)
216229 }
217230}
218231
219232pub fn env ( ) -> Env {
220- panic ! ( "not supported on this platform" )
233+ let env = uefi_env:: get_all ( ) . expect ( "not supported on this platform" ) ;
234+ Env ( env. into_iter ( ) )
221235}
222236
223- pub fn getenv ( _ : & OsStr ) -> Option < OsString > {
224- None
237+ pub fn getenv ( key : & OsStr ) -> Option < OsString > {
238+ uefi_env :: get ( key )
225239}
226240
227- pub unsafe fn setenv ( _ : & OsStr , _ : & OsStr ) -> io:: Result < ( ) > {
228- Err ( io :: const_io_error! ( io :: ErrorKind :: Unsupported , "cannot set env vars on this platform" ) )
241+ pub unsafe fn setenv ( key : & OsStr , val : & OsStr ) -> io:: Result < ( ) > {
242+ uefi_env :: set ( key , val )
229243}
230244
231- pub unsafe fn unsetenv ( _ : & OsStr ) -> io:: Result < ( ) > {
232- Err ( io :: const_io_error! ( io :: ErrorKind :: Unsupported , "cannot unset env vars on this platform" ) )
245+ pub unsafe fn unsetenv ( key : & OsStr ) -> io:: Result < ( ) > {
246+ uefi_env :: unset ( key )
233247}
234248
235249pub fn temp_dir ( ) -> PathBuf {
@@ -294,3 +308,87 @@ mod uefi_shell {
294308 None
295309 }
296310}
311+
312+ mod uefi_env {
313+ use crate :: ffi:: { OsStr , OsString } ;
314+ use crate :: io;
315+ use crate :: os:: uefi:: ffi:: OsStringExt ;
316+ use crate :: ptr:: NonNull ;
317+ use crate :: sys:: { helpers, unsupported_err} ;
318+
319+ pub ( crate ) fn get ( key : & OsStr ) -> Option < OsString > {
320+ let shell = helpers:: open_shell ( ) ?;
321+ let mut key_ptr = helpers:: os_string_to_raw ( key) ?;
322+ unsafe { get_raw ( shell, key_ptr. as_mut_ptr ( ) ) }
323+ }
324+
325+ pub ( crate ) fn set ( key : & OsStr , val : & OsStr ) -> io:: Result < ( ) > {
326+ let mut key_ptr = helpers:: os_string_to_raw ( key)
327+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Key" ) ) ?;
328+ let mut val_ptr = helpers:: os_string_to_raw ( val)
329+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Value" ) ) ?;
330+ unsafe { set_raw ( key_ptr. as_mut_ptr ( ) , val_ptr. as_mut_ptr ( ) ) }
331+ }
332+
333+ pub ( crate ) fn unset ( key : & OsStr ) -> io:: Result < ( ) > {
334+ let mut key_ptr = helpers:: os_string_to_raw ( key)
335+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Key" ) ) ?;
336+ unsafe { set_raw ( key_ptr. as_mut_ptr ( ) , crate :: ptr:: null_mut ( ) ) }
337+ }
338+
339+ pub ( crate ) fn get_all ( ) -> io:: Result < Vec < ( OsString , OsString ) > > {
340+ let shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
341+
342+ let mut vars = Vec :: new ( ) ;
343+ let val = unsafe { ( ( * shell. as_ptr ( ) ) . get_env ) ( crate :: ptr:: null_mut ( ) ) } ;
344+
345+ if val. is_null ( ) {
346+ return Ok ( vars) ;
347+ }
348+
349+ let mut start = 0 ;
350+
351+ // UEFI Shell returns all keys seperated by NULL.
352+ // End of string is denoted by two NULLs
353+ for i in 0 .. {
354+ let temp = unsafe { val. add ( i) } ;
355+ // ptr.is_null() does not seem to check if *ptr == 0.
356+ if temp. is_null ( ) || unsafe { * temp } == 0 {
357+ // Two NULL signal end of string
358+ if i == start {
359+ break ;
360+ }
361+
362+ let key = OsString :: from_wide ( unsafe {
363+ crate :: slice:: from_raw_parts ( val. add ( start) , i - start)
364+ } ) ;
365+ // SAFETY: val.add(start) is always NULL terminated
366+ let val = unsafe { get_raw ( shell, val. add ( start) ) }
367+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Value" ) ) ?;
368+
369+ vars. push ( ( key, val) ) ;
370+ start = i + 1 ;
371+ }
372+ }
373+
374+ Ok ( vars)
375+ }
376+
377+ unsafe fn get_raw (
378+ shell : NonNull < r_efi:: efi:: protocols:: shell:: Protocol > ,
379+ key_ptr : * mut r_efi:: efi:: Char16 ,
380+ ) -> Option < OsString > {
381+ let val = unsafe { ( ( * shell. as_ptr ( ) ) . get_env ) ( key_ptr) } ;
382+ helpers:: os_string_from_raw ( val)
383+ }
384+
385+ unsafe fn set_raw (
386+ key_ptr : * mut r_efi:: efi:: Char16 ,
387+ val_ptr : * mut r_efi:: efi:: Char16 ,
388+ ) -> io:: Result < ( ) > {
389+ let shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
390+ let r =
391+ unsafe { ( ( * shell. as_ptr ( ) ) . set_env ) ( key_ptr, val_ptr, r_efi:: efi:: Boolean :: FALSE ) } ;
392+ if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( ( ) ) }
393+ }
394+ }
0 commit comments