starnix_container_structured_config/
starnix_container_structured_config_rust_config_lib_source.rs
1use fidl::unpersist;
2use fidl_cf_sc_internal_starnixcontainerstructuredconfig::Config as FidlConfig;
3use fuchsia_inspect::{ArrayProperty, Node};
4use fuchsia_runtime::{take_startup_handle, HandleInfo, HandleType};
5use std::convert::TryInto;
6const EXPECTED_CHECKSUM: &[u8] = &[
7 0x4b, 0xf3, 0x71, 0xe5, 0x3b, 0xbc, 0x37, 0xbd, 0xb2, 0x65, 0xcf, 0x3b, 0xe3, 0xbe, 0x68, 0xd9,
8 0x9f, 0xfb, 0x03, 0x20, 0x1e, 0x53, 0x87, 0xd4, 0x2c, 0xa5, 0xe3, 0xe1, 0x29, 0x9e, 0xe6, 0x36,
9];
10#[derive(Debug)]
11pub struct Config {
12 pub enable_utc_time_adjustment: bool,
13 pub extra_features: Vec<String>,
14 pub mlock_always_onfault: bool,
15 pub mlock_pin_flavor: String,
16 pub ui_visual_debugging_level: u8,
17}
18impl Config {
19 #[doc = r" Take the config startup handle and parse its contents."]
20 #[doc = r""]
21 #[doc = r" # Panics"]
22 #[doc = r""]
23 #[doc = r" If the config startup handle was already taken or if it is not valid."]
24 pub fn take_from_startup_handle() -> Self {
25 let handle_info = HandleInfo::new(HandleType::ComponentConfigVmo, 0);
26 let config_vmo: zx::Vmo =
27 take_startup_handle(handle_info).expect("Config VMO handle must be present.").into();
28 Self::from_vmo(&config_vmo).expect("Config VMO handle must be valid.")
29 }
30 #[doc = r" Parse `Self` from `vmo`."]
31 pub fn from_vmo(vmo: &zx::Vmo) -> Result<Self, Error> {
32 let config_size = vmo.get_content_size().map_err(Error::GettingContentSize)?;
33 let config_bytes = vmo.read_to_vec(0, config_size).map_err(Error::ReadingConfigBytes)?;
34 Self::from_bytes(&config_bytes)
35 }
36 #[doc = r" Parse `Self` from `bytes`."]
37 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
38 let (checksum_len_bytes, bytes) = bytes.split_at_checked(2).ok_or(Error::TooFewBytes)?;
39 let checksum_len_bytes: [u8; 2] =
40 checksum_len_bytes.try_into().expect("previous call guaranteed 2 element slice");
41 let checksum_length = u16::from_le_bytes(checksum_len_bytes) as usize;
42 let (observed_checksum, bytes) =
43 bytes.split_at_checked(checksum_length).ok_or(Error::TooFewBytes)?;
44 if observed_checksum != EXPECTED_CHECKSUM {
45 return Err(Error::ChecksumMismatch { observed_checksum: observed_checksum.to_vec() });
46 }
47 let fidl_config: FidlConfig = unpersist(bytes).map_err(Error::Unpersist)?;
48 Ok(Self {
49 enable_utc_time_adjustment: fidl_config.enable_utc_time_adjustment,
50 extra_features: fidl_config.extra_features,
51 mlock_always_onfault: fidl_config.mlock_always_onfault,
52 mlock_pin_flavor: fidl_config.mlock_pin_flavor,
53 ui_visual_debugging_level: fidl_config.ui_visual_debugging_level,
54 })
55 }
56 pub fn record_inspect(&self, inspector_node: &Node) {
57 inspector_node.record_bool("enable_utc_time_adjustment", self.enable_utc_time_adjustment);
58 let arr = inspector_node.create_string_array("extra_features", self.extra_features.len());
59 for i in 0..self.extra_features.len() {
60 arr.set(i, &self.extra_features[i]);
61 }
62 inspector_node.record(arr);
63 inspector_node.record_bool("mlock_always_onfault", self.mlock_always_onfault);
64 inspector_node.record_string("mlock_pin_flavor", &self.mlock_pin_flavor);
65 inspector_node
66 .record_uint("ui_visual_debugging_level", self.ui_visual_debugging_level as u64);
67 }
68}
69#[derive(Debug)]
70pub enum Error {
71 #[doc = r" Failed to read the content size of the VMO."]
72 GettingContentSize(zx::Status),
73 #[doc = r" Failed to read the content of the VMO."]
74 ReadingConfigBytes(zx::Status),
75 #[doc = r" The VMO was too small for this config library."]
76 TooFewBytes,
77 #[doc = r" The VMO's config ABI checksum did not match this library's."]
78 ChecksumMismatch { observed_checksum: Vec<u8> },
79 #[doc = r" Failed to parse the non-checksum bytes of the VMO as this library's FIDL type."]
80 Unpersist(fidl::Error),
81}
82impl std::fmt::Display for Error {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match self {
85 Self::GettingContentSize(status) => {
86 write!(f, "Failed to get content size: {status}")
87 }
88 Self::ReadingConfigBytes(status) => {
89 write!(f, "Failed to read VMO content: {status}")
90 }
91 Self::TooFewBytes => {
92 write!(f, "VMO content is not large enough for this config library.")
93 }
94 Self::ChecksumMismatch { observed_checksum } => {
95 write!(
96 f,
97 "ABI checksum mismatch, expected {:?}, got {:?}",
98 EXPECTED_CHECKSUM, observed_checksum,
99 )
100 }
101 Self::Unpersist(fidl_error) => {
102 write!(f, "Failed to parse contents of config VMO: {fidl_error}")
103 }
104 }
105 }
106}
107impl std::error::Error for Error {
108 #[allow(unused_parens, reason = "rustfmt errors without parens here")]
109 fn source(&self) -> Option<(&'_ (dyn std::error::Error + 'static))> {
110 match self {
111 Self::GettingContentSize(ref status) | Self::ReadingConfigBytes(ref status) => {
112 Some(status)
113 }
114 Self::TooFewBytes => None,
115 Self::ChecksumMismatch { .. } => None,
116 Self::Unpersist(ref fidl_error) => Some(fidl_error),
117 }
118 }
119 fn description(&self) -> &str {
120 match self {
121 Self::GettingContentSize(_) => "getting content size",
122 Self::ReadingConfigBytes(_) => "reading VMO contents",
123 Self::TooFewBytes => "VMO contents too small",
124 Self::ChecksumMismatch { .. } => "ABI checksum mismatch",
125 Self::Unpersist(_) => "FIDL parsing error",
126 }
127 }
128}