@@ -6,6 +6,7 @@ use crate::error::Error as StdError;
6
6
use crate :: ffi:: { OsStr , OsString } ;
7
7
use crate :: marker:: PhantomData ;
8
8
use crate :: os:: uefi;
9
+ use crate :: os:: uefi:: ffi:: OsStringExt ;
9
10
use crate :: path:: { self , PathBuf } ;
10
11
use crate :: ptr:: NonNull ;
11
12
use crate :: { fmt, io} ;
@@ -171,44 +172,70 @@ pub fn current_exe() -> io::Result<PathBuf> {
171
172
helpers:: device_path_to_text ( protocol) . map ( PathBuf :: from)
172
173
}
173
174
174
- pub struct Env ( !) ;
175
+ #[ derive( Clone ) ]
176
+ pub struct Env {
177
+ last_var_name : Vec < u16 > ,
178
+ last_var_guid : r_efi:: efi:: Guid ,
179
+ }
175
180
176
181
impl Env {
177
182
// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
178
183
pub fn str_debug ( & self ) -> impl fmt:: Debug + ' _ {
179
- let Self ( inner) = self ;
180
- match * inner { }
184
+ self
181
185
}
182
186
}
183
187
184
188
impl Iterator for Env {
185
189
type Item = ( OsString , OsString ) ;
190
+
186
191
fn next ( & mut self ) -> Option < ( OsString , OsString ) > {
187
- self . 0
192
+ let ( key, guid) =
193
+ uefi_vars:: get_next_variable_name ( & self . last_var_name , self . last_var_guid ) . ok ( ) ?;
194
+
195
+ self . last_var_name = key;
196
+ self . last_var_guid = guid;
197
+
198
+ if self . last_var_guid == uefi_vars:: SHELL_VARIABLE_GUID {
199
+ let k = OsString :: from_wide ( & self . last_var_name [ ..( self . last_var_name . len ( ) - 1 ) ] ) ;
200
+ let v = uefi_vars:: get ( self . last_var_name . as_mut_slice ( ) ) ?;
201
+
202
+ Some ( ( k, v) )
203
+ } else {
204
+ self . next ( )
205
+ }
188
206
}
189
207
}
190
208
191
209
impl fmt:: Debug for Env {
192
- fn fmt ( & self , _: & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
193
- let Self ( inner) = self ;
194
- match * inner { }
210
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
211
+ let iter: Env = self . clone ( ) ;
212
+ let mut list = f. debug_list ( ) ;
213
+ for ( a, b) in iter {
214
+ list. entry ( & ( a. to_str ( ) . unwrap ( ) , b. to_str ( ) . unwrap ( ) ) ) ;
215
+ }
216
+ list. finish ( )
195
217
}
196
218
}
197
219
198
220
pub fn env ( ) -> Env {
199
- panic ! ( "not supported on this platform" )
221
+ Env { last_var_name : Vec :: from ( [ 0 ] ) , last_var_guid : uefi_vars :: SHELL_VARIABLE_GUID }
200
222
}
201
223
202
- pub fn getenv ( _: & OsStr ) -> Option < OsString > {
203
- None
224
+ pub fn getenv ( key : & OsStr ) -> Option < OsString > {
225
+ let mut key = uefi_vars:: key ( key) ?;
226
+ uefi_vars:: get ( key. as_mut_slice ( ) )
204
227
}
205
228
206
- pub unsafe fn setenv ( _: & OsStr , _: & OsStr ) -> io:: Result < ( ) > {
207
- Err ( io:: const_io_error!( io:: ErrorKind :: Unsupported , "cannot set env vars on this platform" ) )
229
+ pub unsafe fn setenv ( k : & OsStr , v : & OsStr ) -> io:: Result < ( ) > {
230
+ let mut k =
231
+ uefi_vars:: key ( k) . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid key" ) ) ?;
232
+ uefi_vars:: set ( k. as_mut_slice ( ) , v)
208
233
}
209
234
210
- pub unsafe fn unsetenv ( _: & OsStr ) -> io:: Result < ( ) > {
211
- Err ( io:: const_io_error!( io:: ErrorKind :: Unsupported , "cannot unset env vars on this platform" ) )
235
+ pub unsafe fn unsetenv ( k : & OsStr ) -> io:: Result < ( ) > {
236
+ let mut k =
237
+ uefi_vars:: key ( k) . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid key" ) ) ?;
238
+ uefi_vars:: unset ( k. as_mut_slice ( ) )
212
239
}
213
240
214
241
pub fn temp_dir ( ) -> PathBuf {
@@ -239,3 +266,148 @@ pub fn exit(code: i32) -> ! {
239
266
pub fn getpid ( ) -> u32 {
240
267
panic ! ( "no pids on this platform" )
241
268
}
269
+
270
+ mod uefi_vars {
271
+ use super :: helpers;
272
+ use crate :: ffi:: { OsStr , OsString } ;
273
+ use crate :: io;
274
+ use crate :: mem:: size_of;
275
+ use crate :: os:: uefi:: ffi:: { OsStrExt , OsStringExt } ;
276
+ use crate :: ptr:: NonNull ;
277
+
278
+ // Using Shell Variable Guid from edk2/ShellPkg
279
+ // https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Guid/ShellVariableGuid.h
280
+ pub ( crate ) const SHELL_VARIABLE_GUID : r_efi:: efi:: Guid = r_efi:: efi:: Guid :: from_fields (
281
+ 0x158def5a ,
282
+ 0xf656 ,
283
+ 0x419c ,
284
+ 0xb0 ,
285
+ 0x27 ,
286
+ & [ 0x7a , 0x31 , 0x92 , 0xc0 , 0x79 , 0xd2 ] ,
287
+ ) ;
288
+
289
+ pub ( crate ) fn key ( k : & OsStr ) -> Option < Vec < u16 > > {
290
+ let key = k. encode_wide ( ) . chain ( Some ( 0 ) ) . collect :: < Vec < u16 > > ( ) ;
291
+ if key[ ..key. len ( ) - 1 ] . contains ( & 0 ) {
292
+ return None ;
293
+ } else {
294
+ Some ( key)
295
+ }
296
+ }
297
+
298
+ pub ( crate ) fn get ( key : & mut [ u16 ] ) -> Option < OsString > {
299
+ let rt: NonNull < r_efi:: efi:: RuntimeServices > =
300
+ helpers:: runtime_services ( ) . expect ( "UEFI Runtime Services Missing" ) . cast ( ) ;
301
+
302
+ let mut len = 0usize ;
303
+ let mut guid = SHELL_VARIABLE_GUID ;
304
+
305
+ let ret = unsafe {
306
+ ( ( * rt. as_ptr ( ) ) . get_variable ) (
307
+ key. as_mut_ptr ( ) ,
308
+ & mut guid,
309
+ crate :: ptr:: null_mut ( ) ,
310
+ & mut len,
311
+ crate :: ptr:: null_mut ( ) ,
312
+ )
313
+ } ;
314
+
315
+ if ret != r_efi:: efi:: Status :: BUFFER_TOO_SMALL {
316
+ return None ;
317
+ }
318
+
319
+ let mut val = Vec :: < u16 > :: with_capacity ( len / size_of :: < u16 > ( ) ) ;
320
+ let ret = unsafe {
321
+ ( ( * rt. as_ptr ( ) ) . get_variable ) (
322
+ key. as_mut_ptr ( ) ,
323
+ & mut guid,
324
+ crate :: ptr:: null_mut ( ) ,
325
+ & mut len,
326
+ val. as_mut_ptr ( ) . cast ( ) ,
327
+ )
328
+ } ;
329
+
330
+ if ret. is_error ( ) {
331
+ None
332
+ } else {
333
+ unsafe { val. set_len ( len / size_of :: < u16 > ( ) ) } ;
334
+ Some ( OsString :: from_wide ( & val) )
335
+ }
336
+ }
337
+
338
+ pub ( crate ) fn set ( key : & mut [ u16 ] , val : & OsStr ) -> io:: Result < ( ) > {
339
+ // UEFI variable value does not need to be NULL terminated.
340
+ let mut val = val. encode_wide ( ) . collect :: < Vec < u16 > > ( ) ;
341
+ let rt: NonNull < r_efi:: efi:: RuntimeServices > =
342
+ helpers:: runtime_services ( ) . expect ( "UEFI Runtime Services Missing" ) . cast ( ) ;
343
+ let mut guid = SHELL_VARIABLE_GUID ;
344
+
345
+ let r = unsafe {
346
+ ( ( * rt. as_ptr ( ) ) . set_variable ) (
347
+ key. as_mut_ptr ( ) ,
348
+ & mut guid,
349
+ r_efi:: efi:: VARIABLE_BOOTSERVICE_ACCESS ,
350
+ val. len ( ) * size_of :: < u16 > ( ) ,
351
+ val. as_mut_ptr ( ) . cast ( ) ,
352
+ )
353
+ } ;
354
+
355
+ if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( ( ) ) }
356
+ }
357
+
358
+ pub ( crate ) fn unset ( key : & mut [ u16 ] ) -> io:: Result < ( ) > {
359
+ let rt: NonNull < r_efi:: efi:: RuntimeServices > =
360
+ helpers:: runtime_services ( ) . expect ( "UEFI Runtime Services Missing" ) . cast ( ) ;
361
+ let mut guid = SHELL_VARIABLE_GUID ;
362
+
363
+ let r = unsafe {
364
+ ( ( * rt. as_ptr ( ) ) . set_variable ) (
365
+ key. as_mut_ptr ( ) ,
366
+ & mut guid,
367
+ r_efi:: efi:: VARIABLE_BOOTSERVICE_ACCESS ,
368
+ 0 ,
369
+ crate :: ptr:: null_mut ( ) ,
370
+ )
371
+ } ;
372
+
373
+ if r. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) } else { Ok ( ( ) ) }
374
+ }
375
+
376
+ pub ( crate ) fn get_next_variable_name (
377
+ last_var_name : & [ u16 ] ,
378
+ last_guid : r_efi:: efi:: Guid ,
379
+ ) -> io:: Result < ( Vec < u16 > , r_efi:: efi:: Guid ) > {
380
+ let mut var_name = Vec :: from ( last_var_name) ;
381
+ let mut var_size = var_name. capacity ( ) * size_of :: < u16 > ( ) ;
382
+ let mut guid: r_efi:: efi:: Guid = last_guid;
383
+ let rt: NonNull < r_efi:: efi:: RuntimeServices > =
384
+ helpers:: runtime_services ( ) . expect ( "UEFI Runtime Services Missing" ) . cast ( ) ;
385
+
386
+ let r = unsafe {
387
+ ( ( * rt. as_ptr ( ) ) . get_next_variable_name ) ( & mut var_size, var_name. as_mut_ptr ( ) , & mut guid)
388
+ } ;
389
+
390
+ if !r. is_error ( ) {
391
+ unsafe { var_name. set_len ( var_size / size_of :: < u16 > ( ) ) } ;
392
+ return Ok ( ( var_name, guid) ) ;
393
+ }
394
+
395
+ if r != r_efi:: efi:: Status :: BUFFER_TOO_SMALL {
396
+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
397
+ }
398
+
399
+ var_name. reserve ( ( var_size / size_of :: < u16 > ( ) ) - var_name. capacity ( ) + 1 ) ;
400
+ var_size = var_name. capacity ( ) * size_of :: < u16 > ( ) ;
401
+
402
+ let r = unsafe {
403
+ ( ( * rt. as_ptr ( ) ) . get_next_variable_name ) ( & mut var_size, var_name. as_mut_ptr ( ) , & mut guid)
404
+ } ;
405
+
406
+ if r. is_error ( ) {
407
+ Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) )
408
+ } else {
409
+ unsafe { var_name. set_len ( var_size / size_of :: < u16 > ( ) ) } ;
410
+ Ok ( ( var_name, guid) )
411
+ }
412
+ }
413
+ }
0 commit comments