@@ -125,7 +125,7 @@ pub fn error_string(errno: RawOsError) -> String {
125
125
}
126
126
127
127
pub fn getcwd ( ) -> io:: Result < PathBuf > {
128
- match uefi_shell :: open_shell ( ) {
128
+ match helpers :: open_shell ( ) {
129
129
Some ( shell) => {
130
130
// SAFETY: path_ptr is managed by UEFI shell and should not be deallocated
131
131
let path_ptr = unsafe { ( ( * shell. as_ptr ( ) ) . get_cur_dir ) ( crate :: ptr:: null_mut ( ) ) } ;
@@ -144,7 +144,7 @@ pub fn getcwd() -> io::Result<PathBuf> {
144
144
}
145
145
146
146
pub fn chdir ( p : & path:: Path ) -> io:: Result < ( ) > {
147
- let shell = uefi_shell :: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
147
+ let shell = helpers :: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
148
148
149
149
let mut p = helpers:: os_string_to_raw ( p. as_os_str ( ) )
150
150
. ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidData , "Invalid path" ) ) ?;
@@ -192,44 +192,58 @@ pub fn current_exe() -> io::Result<PathBuf> {
192
192
helpers:: device_path_to_text ( protocol) . map ( PathBuf :: from)
193
193
}
194
194
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 ) > ) ;
196
210
197
211
impl Env {
198
212
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
199
213
pub fn str_debug ( & self ) -> impl fmt:: Debug + ' _ {
200
- let Self ( inner) = self ;
201
- match * inner { }
214
+ EnvStrDebug { iter : self . 0 . as_slice ( ) }
202
215
}
203
216
}
204
217
205
218
impl Iterator for Env {
206
219
type Item = ( OsString , OsString ) ;
220
+
207
221
fn next ( & mut self ) -> Option < ( OsString , OsString ) > {
208
- self . 0
222
+ self . 0 . next ( )
209
223
}
210
224
}
211
225
212
226
impl 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)
216
229
}
217
230
}
218
231
219
232
pub 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 ( ) )
221
235
}
222
236
223
- pub fn getenv ( _ : & OsStr ) -> Option < OsString > {
224
- None
237
+ pub fn getenv ( key : & OsStr ) -> Option < OsString > {
238
+ uefi_env :: get ( key )
225
239
}
226
240
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 )
229
243
}
230
244
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 )
233
247
}
234
248
235
249
pub fn temp_dir ( ) -> PathBuf {
@@ -261,36 +275,84 @@ pub fn getpid() -> u32 {
261
275
panic ! ( "no pids on this platform" )
262
276
}
263
277
264
- mod uefi_shell {
265
- use r_efi :: protocols :: shell ;
266
-
267
- use super :: super :: helpers ;
278
+ mod uefi_env {
279
+ use crate :: ffi :: { OsStr , OsString } ;
280
+ use crate :: io ;
281
+ use crate :: os :: uefi :: ffi :: OsStringExt ;
268
282
use crate :: ptr:: NonNull ;
269
- use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
270
-
271
- pub fn open_shell ( ) -> Option < NonNull < shell:: Protocol > > {
272
- static LAST_VALID_HANDLE : AtomicPtr < crate :: ffi:: c_void > =
273
- AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ;
274
-
275
- if let Some ( handle) = NonNull :: new ( LAST_VALID_HANDLE . load ( Ordering :: Acquire ) ) {
276
- if let Ok ( protocol) = helpers:: open_protocol :: < shell:: Protocol > (
277
- handle,
278
- r_efi:: protocols:: shell:: PROTOCOL_GUID ,
279
- ) {
280
- return Some ( protocol) ;
281
- }
283
+ use crate :: sys:: { helpers, unsupported_err} ;
284
+
285
+ pub ( crate ) fn get ( key : & OsStr ) -> Option < OsString > {
286
+ let shell = helpers:: open_shell ( ) ?;
287
+ let mut key_ptr = helpers:: os_string_to_raw ( key) ?;
288
+ unsafe { get_raw ( shell, key_ptr. as_mut_ptr ( ) ) }
289
+ }
290
+
291
+ pub ( crate ) fn set ( key : & OsStr , val : & OsStr ) -> io:: Result < ( ) > {
292
+ let mut key_ptr = helpers:: os_string_to_raw ( key)
293
+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Key" ) ) ?;
294
+ let mut val_ptr = helpers:: os_string_to_raw ( val)
295
+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Value" ) ) ?;
296
+ unsafe { set_raw ( key_ptr. as_mut_ptr ( ) , val_ptr. as_mut_ptr ( ) ) }
297
+ }
298
+
299
+ pub ( crate ) fn unset ( key : & OsStr ) -> io:: Result < ( ) > {
300
+ let mut key_ptr = helpers:: os_string_to_raw ( key)
301
+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Key" ) ) ?;
302
+ unsafe { set_raw ( key_ptr. as_mut_ptr ( ) , crate :: ptr:: null_mut ( ) ) }
303
+ }
304
+
305
+ pub ( crate ) fn get_all ( ) -> io:: Result < Vec < ( OsString , OsString ) > > {
306
+ let shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
307
+
308
+ let mut vars = Vec :: new ( ) ;
309
+ let val = unsafe { ( ( * shell. as_ptr ( ) ) . get_env ) ( crate :: ptr:: null_mut ( ) ) } ;
310
+
311
+ if val. is_null ( ) {
312
+ return Ok ( vars) ;
282
313
}
283
314
284
- let handles = helpers:: locate_handles ( shell:: PROTOCOL_GUID ) . ok ( ) ?;
285
- for handle in handles {
286
- if let Ok ( protocol) =
287
- helpers:: open_protocol :: < shell:: Protocol > ( handle, shell:: PROTOCOL_GUID )
288
- {
289
- LAST_VALID_HANDLE . store ( handle. as_ptr ( ) , Ordering :: Release ) ;
290
- return Some ( protocol) ;
315
+ let mut start = 0 ;
316
+
317
+ // UEFI Shell returns all keys seperated by NULL.
318
+ // End of string is denoted by two NULLs
319
+ for i in 0 .. {
320
+ if unsafe { * val. add ( i) } == 0 {
321
+ // Two NULL signal end of string
322
+ if i == start {
323
+ break ;
324
+ }
325
+
326
+ let key = OsString :: from_wide ( unsafe {
327
+ crate :: slice:: from_raw_parts ( val. add ( start) , i - start)
328
+ } ) ;
329
+ // SAFETY: val.add(start) is always NULL terminated
330
+ let val = unsafe { get_raw ( shell, val. add ( start) ) }
331
+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Value" ) ) ?;
332
+
333
+ vars. push ( ( key, val) ) ;
334
+ start = i + 1 ;
291
335
}
292
336
}
293
337
294
- None
338
+ Ok ( vars)
339
+ }
340
+
341
+ unsafe fn get_raw (
342
+ shell : NonNull < r_efi:: efi:: protocols:: shell:: Protocol > ,
343
+ key_ptr : * mut r_efi:: efi:: Char16 ,
344
+ ) -> Option < OsString > {
345
+ let val = unsafe { ( ( * shell. as_ptr ( ) ) . get_env ) ( key_ptr) } ;
346
+ helpers:: os_string_from_raw ( val)
347
+ }
348
+
349
+ unsafe fn set_raw (
350
+ key_ptr : * mut r_efi:: efi:: Char16 ,
351
+ val_ptr : * mut r_efi:: efi:: Char16 ,
352
+ ) -> io:: Result < ( ) > {
353
+ let shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?;
354
+ let r =
355
+ unsafe { ( ( * shell. as_ptr ( ) ) . set_env ) ( key_ptr, val_ptr, r_efi:: efi:: Boolean :: FALSE ) } ;
356
+ if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( ( ) ) }
295
357
}
296
358
}
0 commit comments