Files
s390-tools/rust/pvapconfig/src/uv.rs
Steffen Eiden fb65b53b9b rust/pvapconfig: use pv_base instead of pv crate
Replace the pv crate with the pv_core crate.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 16:11:21 +01:00

106 lines
3.5 KiB
Rust

// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp. 2023
//
//! UV related functions for pvapconfig
//
use pv_core::uv::{ListCmd, SecretList, UvDevice, UvcSuccess};
use regex::Regex;
use std::path::Path;
/// The byte size of association secret of type 2 in struct SecretEntry
pub const AP_ASSOC_SECRET_ID_SIZE: usize = 32;
const PATH_SYS_FW_UV_FACILITIES: &str = "/sys/firmware/uv/query/facilities";
const RE_UV_FACILITIES: &str = r"^(0x)?([[:xdigit:]]+)";
const RE_UV_FAC_BIT_LIST_SECRETS: u32 = 30;
/// Check UV facilities to offer the 'list secrets' call.
/// Returns a Result with Ok(()) if the 'list secrets' feature
/// is available, otherwise an Err(reasonstring) is returned where
/// the string denotes a hint which can be displayed.
/// # Panics
/// Panics if the compilation of a static regular expression fails.
/// Panics if RE_UV_FACILITIES does not match.
pub fn has_list_secrets_facility() -> Result<(), String> {
if !Path::new(PATH_SYS_FW_UV_FACILITIES).is_file() {
return Err(format!(
"UV facilities sysfs attribute not found (file {} does not exist).",
PATH_SYS_FW_UV_FACILITIES
));
}
let facstr = match crate::helper::sysfs_read_string(PATH_SYS_FW_UV_FACILITIES) {
Ok(s) => s,
Err(err) => {
return Err(format!(
"Failure reading UV facilities from {PATH_SYS_FW_UV_FACILITIES} ({:?}).",
err
))
}
};
let re_uv_facilities = Regex::new(RE_UV_FACILITIES).unwrap();
if !re_uv_facilities.is_match(&facstr) {
Err(format!("Failure parsing UV facilities entry '{facstr}'."))
} else {
let caps = re_uv_facilities.captures(&facstr).unwrap();
let fachex = caps.get(2).unwrap().as_str();
let i: usize = RE_UV_FAC_BIT_LIST_SECRETS as usize / 4;
if i >= fachex.len() {
return Err(format!("Failure parsing UV facilities entry '{fachex}'."));
}
let nibble = u32::from_str_radix(&fachex[i..i + 1], 16).unwrap();
const THEBIT: u32 = 1 << (3 - (RE_UV_FAC_BIT_LIST_SECRETS % 4));
if nibble & THEBIT == 0 {
return Err("The 'list secret' feature is missing on this UV.".to_string());
}
Ok(())
}
}
/// Fetch the list of secrets from the UV.
/// Returns Err(errorstring) on error or
/// Ok(SecretList) on success.
/// The list may be empty if the UV doesn't have any secrets stored.
pub fn gather_secrets() -> Result<SecretList, String> {
let uv = match UvDevice::open() {
Err(e) => return Err(format!("Failed to open UV device: {:?}.", e)),
Ok(u) => u,
};
let mut cmd = ListCmd::default();
match uv.send_cmd(&mut cmd).map_err(|e| format!("{e:?}"))? {
UvcSuccess::RC_SUCCESS => (),
UvcSuccess::RC_MORE_DATA => println!("Warning: There is more data available than expected"),
};
cmd.try_into().map_err(|e| format!("{e:?}"))
}
#[cfg(test)]
mod tests {
use super::*;
// As the name says: check for list secrets feature bit in UV facilities.
#[test]
fn test_has_list_secrets_facility() {
let r = has_list_secrets_facility();
if pv_core::misc::pv_guest_bit_set() {
assert!(r.is_ok());
} else {
assert!(r.is_err());
}
}
// Simple invocation of the list_secrets function. Should not fail
#[test]
fn test_list_secrets() {
let r = gather_secrets();
if pv_core::misc::pv_guest_bit_set() {
assert!(r.is_ok());
} else {
assert!(r.is_err());
}
}
}