xenstore_rs/unix/
mod.rs

1//! Unix blocking implementation.
2//!
3//! Uses either xenstored socket or xenbus/xenstore device.
4
5mod interface;
6
7use std::{cell::RefCell, io, ops::DerefMut};
8
9use crate::{
10    wire::{XsMessage, XsMessageType},
11    Xs,
12};
13
14/// Unix Xenstore implementation.
15pub struct XsUnix(RefCell<interface::XsUnixInterface>);
16
17impl XsUnix {
18    /// Try to open Xenstore interface.
19    /// Attempt in order :
20    ///  - `/run/xenstored/socket` (unix domain socket)
21    ///  - [crate::wire::XENBUS_DEVICE_PATH] (xenstore device)
22    pub fn new() -> io::Result<Self> {
23        Ok(Self(RefCell::new(interface::XsUnixInterface::new()?)))
24    }
25
26    fn transmit_request(&self, request: XsMessage) -> io::Result<XsMessage> {
27        let mut writer = self.0.borrow_mut();
28        request.write_to(writer.deref_mut())?;
29
30        let response = XsMessage::read_from(writer.deref_mut())?;
31
32        match response.msg_type {
33            // Response type must match request.
34            msg_type if msg_type == request.msg_type => Ok(response),
35            XsMessageType::Error => Err(response.parse_error()),
36            msg_type => Err(io::Error::new(
37                io::ErrorKind::InvalidData,
38                format!("Got unrelated response ({msg_type:?})"),
39            )),
40        }
41    }
42}
43
44impl Xs for XsUnix {
45    fn directory(&self, path: &str) -> io::Result<Vec<Box<str>>> {
46        // TODO: If we receive E2BIG, it means that the directory listing is too long,
47        //       and that we should use DIRECTORY_PART.
48        let response =
49            self.transmit_request(XsMessage::from_string(XsMessageType::Directory, 0, path))?;
50
51        Ok(response
52            .parse_payload_list()
53            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
54            // convert &str to Box<str>
55            .iter()
56            .map(|s| s.to_string().into_boxed_str())
57            .collect())
58    }
59
60    fn read(&self, path: &str) -> io::Result<Box<str>> {
61        let response =
62            self.transmit_request(XsMessage::from_string(XsMessageType::Read, 0, path))?;
63
64        Ok(response
65            .parse_payload_str()
66            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
67            .unwrap_or_default()
68            // convert &str to Box<str>
69            .to_string()
70            .into_boxed_str())
71    }
72
73    fn write(&self, path: &str, data: &str) -> io::Result<()> {
74        self.transmit_request(XsMessage::from_string_slice(
75            XsMessageType::Write,
76            0,
77            &[path, data],
78            false,
79        ))?;
80
81        Ok(())
82    }
83
84    fn rm(&self, path: &str) -> io::Result<()> {
85        self.transmit_request(XsMessage::from_string(XsMessageType::Rm, 0, path))?;
86
87        Ok(())
88    }
89}