diff --git a/xsd/examples/list.rs b/xsd/examples/list.rs index 155618c..1810992 100644 --- a/xsd/examples/list.rs +++ b/xsd/examples/list.rs @@ -4,21 +4,24 @@ use xsd::client::XsdClient; fn list_recursive(client: &mut XsdClient, level: usize, path: &str) -> Result<(), XsdBusError> { let children = match client.list(path) { Ok(children) => children, - Err(error) => return if error.to_string() == "EINVAL" { - Ok(()) - } else { - Err(error) + Err(error) => { + return if error.to_string() == "EINVAL" { + Ok(()) + } else { + Err(error) + } } }; for child in children { - let full = format!("{}/{}", if path == "/" { - "" - } else { - path - }, child); + let full = format!("{}/{}", if path == "/" { "" } else { path }, child); let value = client.read(full.as_str())?; - println!("{}{} = {:?}", " ".repeat(level), child, String::from_utf8(value)?); + println!( + "{}{} = {:?}", + " ".repeat(level), + child, + String::from_utf8(value)? + ); list_recursive(client, level + 1, full.as_str())?; } Ok(()) diff --git a/xsd/src/bus.rs b/xsd/src/bus.rs index 3374e11..866a6f1 100644 --- a/xsd/src/bus.rs +++ b/xsd/src/bus.rs @@ -1,3 +1,4 @@ +use crate::sys::{XsdMessageHeader, XSD_ERROR}; use std::error::Error; use std::ffi::{CString, FromVecWithNulError, NulError}; use std::fs::metadata; @@ -7,17 +8,14 @@ use std::net::Shutdown; use std::os::unix::net::UnixStream; use std::str::Utf8Error; use std::string::FromUtf8Error; -use crate::sys::{XSD_ERROR, XsdMessageHeader}; -const XEN_BUS_PATHS: &'static [&'static str] = &[ - "/var/run/xenstored/socket" -]; +const XEN_BUS_PATHS: &[&str] = &["/var/run/xenstored/socket"]; fn find_bus_path() -> Option { for path in XEN_BUS_PATHS { match metadata(path) { Ok(_) => return Some(String::from(*path)), - Err(_) => continue + Err(_) => continue, } } None @@ -25,18 +23,20 @@ fn find_bus_path() -> Option { #[derive(Debug)] pub struct XsdBusError { - message: String + message: String, } impl XsdBusError { pub fn new(msg: &str) -> XsdBusError { - return XsdBusError {message: msg.to_string()}; + XsdBusError { + message: msg.to_string(), + } } } impl std::fmt::Display for XsdBusError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f,"{}", self.message) + write!(f, "{}", self.message) } } @@ -77,13 +77,13 @@ impl From for XsdBusError { } pub struct XsdSocket { - handle: UnixStream + handle: UnixStream, } #[derive(Debug)] pub struct XsdResponse { pub header: XsdMessageHeader, - pub payload: Vec + pub payload: Vec, } impl XsdResponse { @@ -97,17 +97,25 @@ impl XsdResponse { buffer.clear(); continue; } - buffer.push(b.clone()); + buffer.push(*b); } Ok(strings) } + + pub fn parse_bool(&self) -> Result { + if self.payload.len() != 1 { + Err(XsdBusError::new("Expected payload to be a single byte.")) + } else { + Ok(self.payload[0] == 0) + } + } } impl XsdSocket { pub fn dial() -> Result { let path = match find_bus_path() { Some(path) => path, - None => return Err(XsdBusError::new("Failed to find valid bus path.")) + None => return Err(XsdBusError::new("Failed to find valid bus path.")), }; let stream = UnixStream::connect(path)?; Ok(XsdSocket { handle: stream }) @@ -118,12 +126,12 @@ impl XsdSocket { typ, req: 0, tx, - len: buf.len() as u32 + len: buf.len() as u32, }; self.handle.write_all(bytemuck::bytes_of(&header))?; self.handle.write_all(buf)?; let mut result_buf = vec![0u8; size_of::()]; - self.handle.read(result_buf.as_mut_slice())?; + self.handle.read_exact(result_buf.as_mut_slice())?; let result_header = bytemuck::from_bytes::(&result_buf); let mut payload = vec![0u8; result_header.len as usize]; self.handle.read_exact(payload.as_mut_slice())?; @@ -131,14 +139,22 @@ impl XsdSocket { let error = CString::from_vec_with_nul(payload)?; return Err(XsdBusError::new(error.to_str()?)); } - let response = XsdResponse { header: header.clone(), payload }; + let response = XsdResponse { + header, + payload, + }; Ok(response) } - pub fn send_single(&mut self, tx: u32, typ: u32, string: &str) -> Result { + pub fn send_single( + &mut self, + tx: u32, + typ: u32, + string: &str, + ) -> Result { let path = CString::new(string)?; let buf = path.as_bytes_with_nul(); - Ok(self.send(tx, typ, buf)?) + self.send(tx, typ, buf) } } diff --git a/xsd/src/client.rs b/xsd/src/client.rs index f289f38..b728e89 100644 --- a/xsd/src/client.rs +++ b/xsd/src/client.rs @@ -1,5 +1,6 @@ use crate::bus::{XsdBusError, XsdSocket}; -use crate::sys::{XSD_DIRECTORY, XSD_READ}; +use crate::sys::{XSD_DIRECTORY, XSD_MKDIR, XSD_READ, XSD_RM, XSD_WRITE}; +use std::ffi::CString; pub struct XsdClient { socket: XsdSocket, @@ -13,11 +14,28 @@ impl XsdClient { pub fn list(&mut self, path: &str) -> Result, XsdBusError> { let response = self.socket.send_single(0, XSD_DIRECTORY, path)?; - Ok(response.parse_string_vec()?) + response.parse_string_vec() } pub fn read(&mut self, path: &str) -> Result, XsdBusError> { let response = self.socket.send_single(0, XSD_READ, path)?; Ok(response.payload) } + + pub fn write(&mut self, path: &str, data: Vec) -> Result { + let mut buffer = Vec::new(); + let path = CString::new(path)?; + buffer.extend_from_slice(path.as_bytes_with_nul()); + buffer.extend_from_slice(data.as_slice()); + let response = self.socket.send(0, XSD_WRITE, buffer.as_slice())?; + response.parse_bool() + } + + pub fn mkdir(&mut self, path: &str) -> Result { + self.socket.send_single(0, XSD_MKDIR, path)?.parse_bool() + } + + pub fn rm(&mut self, path: &str) -> Result { + self.socket.send_single(0, XSD_RM, path)?.parse_bool() + } } diff --git a/xsd/src/lib.rs b/xsd/src/lib.rs index 4c7a6de..594ae47 100644 --- a/xsd/src/lib.rs +++ b/xsd/src/lib.rs @@ -1,3 +1,3 @@ -pub mod sys; pub mod bus; pub mod client; +pub mod sys; diff --git a/xsd/src/sys.rs b/xsd/src/sys.rs index 4db5c8d..1959de9 100644 --- a/xsd/src/sys.rs +++ b/xsd/src/sys.rs @@ -1,7 +1,7 @@ +use bytemuck::{Pod, Zeroable}; /// Handwritten protocol definitions for XenStore. /// Used xen/include/public/io/xs_wire.h as a reference. use libc; -use bytemuck::{Pod, Zeroable}; #[derive(Copy, Clone, Pod, Zeroable, Debug)] #[repr(C)] @@ -9,7 +9,7 @@ pub struct XsdMessageHeader { pub typ: u32, pub req: u32, pub tx: u32, - pub len: u32 + pub len: u32, } pub const XSD_CONTROL: u32 = 0; @@ -44,25 +44,73 @@ pub const XSD_WRITE_CREATE_EXCL: &str = "CREATE|EXCL"; #[repr(C)] pub struct XsError<'a> { num: i32, - error: &'a str + error: &'a str, } -pub const XSD_ERROR_EINVAL: XsError = XsError { num: libc::EINVAL, error: "EINVAL" }; -pub const XSD_ERROR_EACCES: XsError = XsError { num: libc::EACCES, error: "EACCES" }; -pub const XSD_ERROR_EEXIST: XsError = XsError { num: libc::EEXIST, error: "EEXIST" }; -pub const XSD_ERROR_EISDIR: XsError = XsError { num: libc::EISDIR, error: "EISDIR" }; -pub const XSD_ERROR_ENOENT: XsError = XsError { num: libc::ENOENT, error: "ENOENT" }; -pub const XSD_ERROR_ENOMEM: XsError = XsError { num: libc::ENOMEM, error: "ENOMEM" }; -pub const XSD_ERROR_ENOSPC: XsError = XsError { num: libc::ENOSPC, error: "ENOSPC" }; -pub const XSD_ERROR_EIO: XsError = XsError { num: libc::EIO, error: "EIO" }; -pub const XSD_ERROR_ENOTEMPTY: XsError = XsError { num: libc::ENOTEMPTY, error: "ENOTEMPTY" }; -pub const XSD_ERROR_ENOSYS: XsError = XsError { num: libc::ENOSYS, error: "ENOSYS" }; -pub const XSD_ERROR_EROFS: XsError = XsError { num: libc::EROFS, error: "EROFS" }; -pub const XSD_ERROR_EBUSY: XsError = XsError { num: libc::EBUSY, error: "EBUSY" }; -pub const XSD_ERROR_EAGAIN: XsError = XsError { num: libc::EAGAIN, error: "EAGAIN" }; -pub const XSD_ERROR_EISCONN: XsError = XsError { num: libc::EISCONN, error: "EISCONN" }; -pub const XSD_ERROR_E2BIG: XsError = XsError { num: libc::E2BIG, error: "E2BIG" }; -pub const XSD_ERROR_EPERM: XsError = XsError { num: libc::EPERM, error: "EPERM" }; +pub const XSD_ERROR_EINVAL: XsError = XsError { + num: libc::EINVAL, + error: "EINVAL", +}; +pub const XSD_ERROR_EACCES: XsError = XsError { + num: libc::EACCES, + error: "EACCES", +}; +pub const XSD_ERROR_EEXIST: XsError = XsError { + num: libc::EEXIST, + error: "EEXIST", +}; +pub const XSD_ERROR_EISDIR: XsError = XsError { + num: libc::EISDIR, + error: "EISDIR", +}; +pub const XSD_ERROR_ENOENT: XsError = XsError { + num: libc::ENOENT, + error: "ENOENT", +}; +pub const XSD_ERROR_ENOMEM: XsError = XsError { + num: libc::ENOMEM, + error: "ENOMEM", +}; +pub const XSD_ERROR_ENOSPC: XsError = XsError { + num: libc::ENOSPC, + error: "ENOSPC", +}; +pub const XSD_ERROR_EIO: XsError = XsError { + num: libc::EIO, + error: "EIO", +}; +pub const XSD_ERROR_ENOTEMPTY: XsError = XsError { + num: libc::ENOTEMPTY, + error: "ENOTEMPTY", +}; +pub const XSD_ERROR_ENOSYS: XsError = XsError { + num: libc::ENOSYS, + error: "ENOSYS", +}; +pub const XSD_ERROR_EROFS: XsError = XsError { + num: libc::EROFS, + error: "EROFS", +}; +pub const XSD_ERROR_EBUSY: XsError = XsError { + num: libc::EBUSY, + error: "EBUSY", +}; +pub const XSD_ERROR_EAGAIN: XsError = XsError { + num: libc::EAGAIN, + error: "EAGAIN", +}; +pub const XSD_ERROR_EISCONN: XsError = XsError { + num: libc::EISCONN, + error: "EISCONN", +}; +pub const XSD_ERROR_E2BIG: XsError = XsError { + num: libc::E2BIG, + error: "E2BIG", +}; +pub const XSD_ERROR_EPERM: XsError = XsError { + num: libc::EPERM, + error: "EPERM", +}; pub const XSD_WATCH_PATH: u32 = 0; pub const XSD_WATCH_TOKEN: u32 = 1; @@ -77,7 +125,7 @@ pub struct XenDomainInterface { rsp_prod: u32, server_features: u32, connection: u32, - error: u32 + error: u32, } pub const XS_PAYLOAD_MAX: u32 = 4096;