1mod handle;
2use std::{
3 ffi::{CStr, CString, c_char, c_void},
4 rc::Rc,
5};
6
7use xen_sys::{XBT_NULL, xs_directory, xs_read};
8
9pub use self::handle::XenStoreHandle;
10use crate::{XenDomainId, XenError};
11
12#[derive(Debug, Clone)]
13pub struct XenStore {
14 pub(crate) handle: Rc<XenStoreHandle>,
15}
16
17impl XenStore {
18 pub fn new() -> Result<Self, XenError> {
19 Ok(Self {
20 handle: Rc::new(XenStoreHandle::new()?),
21 })
22 }
23
24 pub fn domain_id_from_name(&self, name: &str) -> Result<Option<XenDomainId>, XenError> {
25 for domain in self.directory("/local/domain")? {
26 let domain_name = self.read(&format!("/local/domain/{domain}/name"))?;
27 if domain_name == name {
28 match domain.parse() {
29 Ok(domain) => return Ok(Some(XenDomainId(domain))),
30 Err(_) => return Err(XenError::Other("Failed to parse domain id")),
31 }
32 }
33 }
34
35 Ok(None)
36 }
37
38 pub fn directory(&self, path: &str) -> Result<Vec<String>, XenError> {
39 let path = CString::new(path).unwrap();
40 let mut num = 0;
41 let result = unsafe { xs_directory(self.handle.0, XBT_NULL, path.as_ptr(), &mut num) };
42
43 if result.is_null() {
44 return Err(XenError::Other("Failed to read xen store directory"));
45 }
46
47 let mut entries = Vec::with_capacity(num as usize);
48 for i in 0..num {
49 let entry = unsafe { CStr::from_ptr(*result.offset(i as isize)) };
50 entries.push(entry.to_string_lossy().into());
51 }
52
53 unsafe {
54 libc::free(result as *mut c_void);
55 }
56
57 Ok(entries)
58 }
59
60 pub fn read(&self, path: &str) -> Result<String, XenError> {
61 let mut len = 0;
62 let path = CString::new(path).unwrap();
63 let result = unsafe { xs_read(self.handle.0, XBT_NULL, path.as_ptr(), &mut len) };
64 if result.is_null() {
65 return Err(XenError::Other("Failed to read xen store"));
66 }
67
68 let value = unsafe { CStr::from_ptr(result as *const c_char) };
69 let value = value.to_string_lossy().into_owned();
70
71 unsafe {
72 libc::free(result);
73 }
74
75 Ok(value)
76 }
77}