libxen 0.5.0

Safe bindings for Xen libraries
Documentation
mod handle;
use std::{
    ffi::{CStr, CString, c_char, c_void},
    rc::Rc,
};

use xen_sys::{XBT_NULL, xs_directory, xs_read};

pub use self::handle::XenStoreHandle;
use crate::{XenDomainId, XenError};

#[derive(Debug, Clone)]
pub struct XenStore {
    pub(crate) handle: Rc<XenStoreHandle>,
}

impl XenStore {
    pub fn new() -> Result<Self, XenError> {
        Ok(Self {
            handle: Rc::new(XenStoreHandle::new()?),
        })
    }

    pub fn domain_id_from_name(&self, name: &str) -> Result<Option<XenDomainId>, XenError> {
        for domain in self.directory("/local/domain")? {
            let domain_name = self.read(&format!("/local/domain/{domain}/name"))?;
            if domain_name == name {
                match domain.parse() {
                    Ok(domain) => return Ok(Some(XenDomainId(domain))),
                    Err(_) => return Err(XenError::Other("Failed to parse domain id")),
                }
            }
        }

        Ok(None)
    }

    pub fn directory(&self, path: &str) -> Result<Vec<String>, XenError> {
        let path = CString::new(path).unwrap();
        let mut num = 0;
        let result = unsafe { xs_directory(self.handle.0, XBT_NULL, path.as_ptr(), &mut num) };

        if result.is_null() {
            return Err(XenError::Other("Failed to read xen store directory"));
        }

        let mut entries = Vec::with_capacity(num as usize);
        for i in 0..num {
            let entry = unsafe { CStr::from_ptr(*result.offset(i as isize)) };
            entries.push(entry.to_string_lossy().into());
        }

        unsafe {
            libc::free(result as *mut c_void);
        }

        Ok(entries)
    }

    pub fn read(&self, path: &str) -> Result<String, XenError> {
        let mut len = 0;
        let path = CString::new(path).unwrap();
        let result = unsafe { xs_read(self.handle.0, XBT_NULL, path.as_ptr(), &mut len) };
        if result.is_null() {
            return Err(XenError::Other("Failed to read xen store"));
        }

        let value = unsafe { CStr::from_ptr(result as *const c_char) };
        let value = value.to_string_lossy().into_owned();

        unsafe {
            libc::free(result);
        }

        Ok(value)
    }
}