1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! efivar is a crate for manipulating EFI variables using the OS interface. This crate is mainly
//! used by `efivarcli` to implement its functionality.
//!
//! On Linux, it is assumed that efivarfs is mounted and available at /sys/firmware/efi/efivars,
//! which should be the default nowadays on all major distros.
//!
//! On Windows, it uses the Get/SetFirmwareEnvironmentVariable family of functions, which require
//! administrative rights. This also requires adjusting the security token for the current thread
//! to include SeSystemEnvironmentPrivilege. This is done during the initialization of
//! SystemManager (see  SystemManager::new() ).
//!
//! In-memory and filesystem storage are also provided for testing purposes, or as a way to dump
//! system variables to an external file.

#![doc(html_root_url = "https://docs.rs/efivar/2.0.0")]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "store")]
#[macro_use]
extern crate serde_derive;

#[cfg(windows)]
extern crate winapi;

/// EFI constants based on the [UEFI specification](http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf)
pub mod efi;
#[cfg(feature = "store")]
pub mod store;

pub mod boot;
mod enumerator;
mod error;
pub mod push;
mod reader;
mod sys;
pub mod test_utils;
pub mod utils;
mod writer;

use boot::{BootVarReader, BootVarWriter};

pub use crate::enumerator::VarEnumerator;
pub use crate::reader::*;
pub use crate::writer::VarWriter;

pub use crate::error::Error;

/// Result type for this crate's API functions
pub type Result<T> = std::result::Result<T, Error>;

/// Represents an EFI variable manager that can read, write and list variables
pub trait VarManager:
    VarEnumerator + VarReader + VarWriter + BootVarReader + BootVarWriter
{
}

use crate::sys::SystemManager;
/// Returns a `VarManager` that represents the firmware variables of the running system
///
/// Reading variables should not require extra permissions, but writing variables will.
///
/// ***The returned object will change the values stored in the system's NVRAM. Please be cautious
/// when using its methods.***
pub fn system() -> Box<dyn VarManager> {
    Box::new(SystemManager::new())
}

/// Returns a `VarManager` which loads and stores variables to a TOML file. The variable file will
/// be read when calling this method, and written to when the returned object is dropped.
///
/// # Arguments
///
/// * `filename`: Path to the TOML file for this variable storage. If the file doesn't exist, it
/// will be created.
///
/// # Examples
///
/// ```
/// # use efivar::file_store;
/// use efivar::efi::{VariableFlags, Variable};
/// # {
/// // Name of the BootOrder variable
/// let boot_order = Variable::new("BootOrder");
///
/// // Create a store from the file doc-test.toml
/// let mut store = file_store("doc-test.toml");
/// let value = vec![1, 2, 3, 4];
/// // Write the value of a variable
/// store.write(&boot_order, VariableFlags::NON_VOLATILE, &value);
///
/// // Check the value of the written variable
/// let (data, attributes) = store.read(&boot_order).unwrap();
/// assert_eq!(data, value);
/// assert_eq!(attributes, VariableFlags::NON_VOLATILE);
/// // At this point, store is dropped and doc-test.toml will be updated
/// # }
/// # std::fs::remove_file("doc-test.toml");
/// ```
#[cfg(feature = "store")]
pub fn file_store<P: Into<std::path::PathBuf>>(filename: P) -> Box<dyn VarManager> {
    Box::new(store::FileStore::new(filename.into()))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    #[cfg(feature = "store")]
    fn file_store_roundtrip() {
        use crate::efi::{Variable, VariableFlags};

        {
            // Create a store from the file doc-test.toml
            let mut store = file_store("doc-test.toml");
            let value = vec![1, 2, 3, 4];
            // Write the value of a variable
            store
                .write(
                    &Variable::new("BootOrder"),
                    VariableFlags::NON_VOLATILE,
                    &value,
                )
                .expect("Failed to write value in store");

            // Check the value of the written variable
            let (data, attributes) = store.read(&Variable::new("BootOrder")).unwrap();
            assert_eq!(attributes, VariableFlags::NON_VOLATILE);
            assert_eq!(data, value);
            // At this point, store is dropped and doc-test.toml will be updated
        }
        std::fs::remove_file("doc-test.toml")
            .expect("Failed to remove temporary file doc-test.toml");
    }

    #[test]
    fn system_instantiate() {
        system();
    }
}