mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
hypha: setup image as disk
This commit is contained in:
parent
80311db549
commit
649a0c303d
@ -1,6 +1,7 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use hypha::ctl::Controller;
|
use hypha::ctl::Controller;
|
||||||
use hypha::error::{HyphaError, Result};
|
use hypha::error::{HyphaError, Result};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about)]
|
#[command(version, about)]
|
||||||
@ -20,23 +21,28 @@ struct ControllerArgs {
|
|||||||
#[arg(short, long, default_value_t = 512)]
|
#[arg(short, long, default_value_t = 512)]
|
||||||
mem: u64,
|
mem: u64,
|
||||||
|
|
||||||
#[arg(short = 'C', long, default_value = "auto")]
|
#[arg(short, long, default_value = "auto")]
|
||||||
cache: String,
|
store: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let args = ControllerArgs::parse();
|
let args = ControllerArgs::parse();
|
||||||
let cache_path = if args.cache == "auto" {
|
let store_path = if args.store == "auto" {
|
||||||
default_cache_path()
|
default_store_path()
|
||||||
.ok_or_else(|| HyphaError::new("unable to determine default cache path"))
|
.ok_or_else(|| HyphaError::new("unable to determine default store path"))
|
||||||
} else {
|
} else {
|
||||||
Ok(args.cache)
|
Ok(PathBuf::from(args.store))
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
let store_path = store_path
|
||||||
|
.to_str()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.ok_or_else(|| HyphaError::new("unable to convert store path to string"))?;
|
||||||
|
|
||||||
let mut controller = Controller::new(
|
let mut controller = Controller::new(
|
||||||
cache_path,
|
store_path,
|
||||||
args.kernel,
|
args.kernel,
|
||||||
args.initrd,
|
args.initrd,
|
||||||
args.image,
|
args.image,
|
||||||
@ -48,9 +54,13 @@ fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_cache_path() -> Option<String> {
|
fn default_store_path() -> Option<PathBuf> {
|
||||||
let user_dirs = directories::UserDirs::new()?;
|
let user_dirs = directories::UserDirs::new()?;
|
||||||
let mut path = user_dirs.home_dir().to_path_buf();
|
let mut path = user_dirs.home_dir().to_path_buf();
|
||||||
path.push(".hypha/cache");
|
if path == PathBuf::from("/root") {
|
||||||
Some(path.to_str()?.to_string())
|
path.push("/var/lib/hypha")
|
||||||
|
} else {
|
||||||
|
path.push(".hypha");
|
||||||
|
}
|
||||||
|
Some(path)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::error::Result;
|
use crate::error::{HyphaError, Result};
|
||||||
use crate::image::cache::ImageCache;
|
use crate::image::cache::ImageCache;
|
||||||
use crate::image::{ImageCompiler, ImageInfo};
|
use crate::image::{ImageCompiler, ImageInfo};
|
||||||
use ocipkg::ImageName;
|
use ocipkg::ImageName;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use xenclient::{DomainConfig, XenClient};
|
use xenclient::{DomainConfig, DomainDisk, XenClient};
|
||||||
|
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
image_cache: ImageCache,
|
image_cache: ImageCache,
|
||||||
@ -19,17 +19,18 @@ pub struct Controller {
|
|||||||
|
|
||||||
impl Controller {
|
impl Controller {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cache_path: String,
|
store_path: String,
|
||||||
kernel_path: String,
|
kernel_path: String,
|
||||||
initrd_path: String,
|
initrd_path: String,
|
||||||
image: String,
|
image: String,
|
||||||
vcpus: u32,
|
vcpus: u32,
|
||||||
mem: u64,
|
mem: u64,
|
||||||
) -> Result<Controller> {
|
) -> Result<Controller> {
|
||||||
fs::create_dir_all(&cache_path)?;
|
let mut image_cache_path = PathBuf::from(store_path);
|
||||||
|
image_cache_path.push("cache");
|
||||||
|
fs::create_dir_all(&image_cache_path)?;
|
||||||
|
|
||||||
let client = XenClient::open()?;
|
let client = XenClient::open()?;
|
||||||
let mut image_cache_path = PathBuf::from(cache_path);
|
|
||||||
image_cache_path.push("image");
|
image_cache_path.push("image");
|
||||||
fs::create_dir_all(&image_cache_path)?;
|
fs::create_dir_all(&image_cache_path)?;
|
||||||
let image_cache = ImageCache::new(&image_cache_path)?;
|
let image_cache = ImageCache::new(&image_cache_path)?;
|
||||||
@ -53,14 +54,24 @@ impl Controller {
|
|||||||
pub fn launch(&mut self) -> Result<u32> {
|
pub fn launch(&mut self) -> Result<u32> {
|
||||||
let uuid = Uuid::new_v4();
|
let uuid = Uuid::new_v4();
|
||||||
let name = format!("hypha-{uuid}");
|
let name = format!("hypha-{uuid}");
|
||||||
let _image_info = self.compile()?;
|
let image_info = self.compile()?;
|
||||||
|
let squashfs_path = image_info
|
||||||
|
.squashfs
|
||||||
|
.to_str()
|
||||||
|
.ok_or_else(|| HyphaError::new("failed to convert squashfs path to string"))?;
|
||||||
let config = DomainConfig {
|
let config = DomainConfig {
|
||||||
|
backend_domid: 0,
|
||||||
name: &name,
|
name: &name,
|
||||||
max_vcpus: self.vcpus,
|
max_vcpus: self.vcpus,
|
||||||
mem_mb: self.mem,
|
mem_mb: self.mem,
|
||||||
kernel_path: self.kernel_path.as_str(),
|
kernel_path: self.kernel_path.as_str(),
|
||||||
initrd_path: self.initrd_path.as_str(),
|
initrd_path: self.initrd_path.as_str(),
|
||||||
cmdline: "debug elevator=noop",
|
cmdline: "elevator=noop",
|
||||||
|
disks: vec![DomainDisk {
|
||||||
|
vdev: "xvda",
|
||||||
|
pdev: squashfs_path,
|
||||||
|
writable: false,
|
||||||
|
}],
|
||||||
};
|
};
|
||||||
Ok(self.client.create(&config)?)
|
Ok(self.client.create(&config)?)
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,14 @@ fn main() -> Result<(), XenClientError> {
|
|||||||
let initrd_path = args.get(2).expect("argument not specified");
|
let initrd_path = args.get(2).expect("argument not specified");
|
||||||
let mut client = XenClient::open()?;
|
let mut client = XenClient::open()?;
|
||||||
let config = DomainConfig {
|
let config = DomainConfig {
|
||||||
|
backend_domid: 0,
|
||||||
name: "xenclient-test",
|
name: "xenclient-test",
|
||||||
max_vcpus: 1,
|
max_vcpus: 1,
|
||||||
mem_mb: 512,
|
mem_mb: 512,
|
||||||
kernel_path: kernel_image_path.as_str(),
|
kernel_path: kernel_image_path.as_str(),
|
||||||
initrd_path: initrd_path.as_str(),
|
initrd_path: initrd_path.as_str(),
|
||||||
cmdline: "debug elevator=noop",
|
cmdline: "debug elevator=noop",
|
||||||
|
disks: vec![],
|
||||||
};
|
};
|
||||||
let domid = client.create(&config)?;
|
let domid = client.create(&config)?;
|
||||||
println!("created domain {}", domid);
|
println!("created domain {}", domid);
|
||||||
|
@ -16,7 +16,9 @@ use xencall::sys::CreateDomain;
|
|||||||
use xencall::{XenCall, XenCallError};
|
use xencall::{XenCall, XenCallError};
|
||||||
use xenevtchn::EventChannelError;
|
use xenevtchn::EventChannelError;
|
||||||
use xenstore::bus::XsdBusError;
|
use xenstore::bus::XsdBusError;
|
||||||
use xenstore::client::{XsPermissions, XsdClient, XsdInterface};
|
use xenstore::client::{
|
||||||
|
XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct XenClient {
|
pub struct XenClient {
|
||||||
store: XsdClient,
|
store: XsdClient,
|
||||||
@ -78,13 +80,21 @@ impl From<EventChannelError> for XenClientError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DomainDisk<'a> {
|
||||||
|
pub vdev: &'a str,
|
||||||
|
pub pdev: &'a str,
|
||||||
|
pub writable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DomainConfig<'a> {
|
pub struct DomainConfig<'a> {
|
||||||
|
pub backend_domid: u32,
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub max_vcpus: u32,
|
pub max_vcpus: u32,
|
||||||
pub mem_mb: u64,
|
pub mem_mb: u64,
|
||||||
pub kernel_path: &'a str,
|
pub kernel_path: &'a str,
|
||||||
pub initrd_path: &'a str,
|
pub initrd_path: &'a str,
|
||||||
pub cmdline: &'a str,
|
pub cmdline: &'a str,
|
||||||
|
pub disks: Vec<DomainDisk<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XenClient {
|
impl XenClient {
|
||||||
@ -100,55 +110,71 @@ impl XenClient {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let domid = self.call.create_domain(domain)?;
|
let domid = self.call.create_domain(domain)?;
|
||||||
|
let backend_dom_path = self.store.get_domain_path(0)?;
|
||||||
let dom_path = self.store.get_domain_path(domid)?;
|
let dom_path = self.store.get_domain_path(domid)?;
|
||||||
let uuid_string = Uuid::from_bytes(domain.handle).to_string();
|
let uuid_string = Uuid::from_bytes(domain.handle).to_string();
|
||||||
let vm_path = format!("/vm/{}", uuid_string);
|
let vm_path = format!("/vm/{}", uuid_string);
|
||||||
let libxl_path = format!("/libxl/{}", domid);
|
|
||||||
|
|
||||||
let ro_perm = XsPermissions { id: 0, perms: 0 };
|
let ro_perm = &[
|
||||||
let rw_perm = XsPermissions { id: 0, perms: 0 };
|
XsPermission {
|
||||||
let no_perm = XsPermissions { id: 0, perms: 0 };
|
id: 0,
|
||||||
|
perms: XS_PERM_NONE,
|
||||||
|
},
|
||||||
|
XsPermission {
|
||||||
|
id: domid,
|
||||||
|
perms: XS_PERM_READ,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let rw_perm = &[XsPermission {
|
||||||
|
id: domid,
|
||||||
|
perms: XS_PERM_READ_WRITE,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let no_perm = &[XsPermission {
|
||||||
|
id: 0,
|
||||||
|
perms: XS_PERM_NONE,
|
||||||
|
}];
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut tx = self.store.transaction()?;
|
let mut tx = self.store.transaction()?;
|
||||||
|
|
||||||
tx.rm(dom_path.as_str())?;
|
tx.rm(dom_path.as_str())?;
|
||||||
tx.mknod(dom_path.as_str(), &ro_perm)?;
|
tx.mknod(dom_path.as_str(), ro_perm)?;
|
||||||
|
|
||||||
tx.rm(vm_path.as_str())?;
|
tx.rm(vm_path.as_str())?;
|
||||||
tx.mknod(vm_path.as_str(), &ro_perm)?;
|
tx.mknod(vm_path.as_str(), ro_perm)?;
|
||||||
|
|
||||||
tx.rm(libxl_path.as_str())?;
|
tx.mknod(vm_path.as_str(), no_perm)?;
|
||||||
tx.mknod(vm_path.as_str(), &no_perm)?;
|
tx.mknod(format!("{}/device", vm_path).as_str(), no_perm)?;
|
||||||
tx.mknod(format!("{}/device", vm_path).as_str(), &no_perm)?;
|
|
||||||
|
|
||||||
tx.write_string(format!("{}/vm", dom_path).as_str(), &vm_path)?;
|
tx.write_string(format!("{}/vm", dom_path).as_str(), &vm_path)?;
|
||||||
|
|
||||||
tx.mknod(format!("{}/cpu", dom_path).as_str(), &ro_perm)?;
|
tx.mknod(format!("{}/cpu", dom_path).as_str(), ro_perm)?;
|
||||||
tx.mknod(format!("{}/memory", dom_path).as_str(), &ro_perm)?;
|
tx.mknod(format!("{}/memory", dom_path).as_str(), ro_perm)?;
|
||||||
|
|
||||||
tx.mknod(format!("{}/control", dom_path).as_str(), &ro_perm)?;
|
tx.mknod(format!("{}/control", dom_path).as_str(), ro_perm)?;
|
||||||
|
|
||||||
tx.mknod(format!("{}/control/shutdown", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/control/shutdown", dom_path).as_str(), rw_perm)?;
|
||||||
tx.mknod(
|
tx.mknod(
|
||||||
format!("{}/control/feature-poweroff", dom_path).as_str(),
|
format!("{}/control/feature-poweroff", dom_path).as_str(),
|
||||||
&rw_perm,
|
rw_perm,
|
||||||
)?;
|
)?;
|
||||||
tx.mknod(
|
tx.mknod(
|
||||||
format!("{}/control/feature-reboot", dom_path).as_str(),
|
format!("{}/control/feature-reboot", dom_path).as_str(),
|
||||||
&rw_perm,
|
rw_perm,
|
||||||
)?;
|
)?;
|
||||||
tx.mknod(
|
tx.mknod(
|
||||||
format!("{}/control/feature-suspend", dom_path).as_str(),
|
format!("{}/control/feature-suspend", dom_path).as_str(),
|
||||||
&rw_perm,
|
rw_perm,
|
||||||
)?;
|
)?;
|
||||||
tx.mknod(format!("{}/control/sysrq", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/control/sysrq", dom_path).as_str(), rw_perm)?;
|
||||||
|
|
||||||
tx.mknod(format!("{}/data", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/data", dom_path).as_str(), rw_perm)?;
|
||||||
tx.mknod(format!("{}/drivers", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/drivers", dom_path).as_str(), rw_perm)?;
|
||||||
tx.mknod(format!("{}/feature", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/feature", dom_path).as_str(), rw_perm)?;
|
||||||
tx.mknod(format!("{}/attr", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/attr", dom_path).as_str(), rw_perm)?;
|
||||||
tx.mknod(format!("{}/error", dom_path).as_str(), &rw_perm)?;
|
tx.mknod(format!("{}/error", dom_path).as_str(), rw_perm)?;
|
||||||
|
|
||||||
tx.write_string(
|
tx.write_string(
|
||||||
format!("{}/uuid", vm_path).as_str(),
|
format!("{}/uuid", vm_path).as_str(),
|
||||||
@ -156,7 +182,6 @@ impl XenClient {
|
|||||||
)?;
|
)?;
|
||||||
tx.write_string(format!("{}/name", dom_path).as_str(), config.name)?;
|
tx.write_string(format!("{}/name", dom_path).as_str(), config.name)?;
|
||||||
tx.write_string(format!("{}/name", vm_path).as_str(), config.name)?;
|
tx.write_string(format!("{}/name", vm_path).as_str(), config.name)?;
|
||||||
tx.write_string(format!("{}/type", libxl_path).as_str(), "pv")?;
|
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,53 +247,192 @@ impl XenClient {
|
|||||||
&xenstore_mfn.to_string(),
|
&xenstore_mfn.to_string(),
|
||||||
)?;
|
)?;
|
||||||
for i in 0..config.max_vcpus {
|
for i in 0..config.max_vcpus {
|
||||||
tx.write_string(
|
let path = format!("{}/cpu/{}", dom_path, i);
|
||||||
format!("{}/cpu/{}/availability", dom_path, i).as_str(),
|
tx.mkdir(&path)?;
|
||||||
"online",
|
tx.set_perms(&path, ro_perm)?;
|
||||||
)?;
|
let path = format!("{}/cpu/{}/availability", dom_path, i);
|
||||||
|
tx.write_string(&path, "online")?;
|
||||||
|
tx.set_perms(&path, ro_perm)?;
|
||||||
}
|
}
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
}
|
}
|
||||||
|
if !self
|
||||||
self.console_device_add(&dom_path.to_string(), domid, console_evtchn, console_mfn)?;
|
.store
|
||||||
self.store
|
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?
|
||||||
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?;
|
{
|
||||||
|
return Err(XenClientError::new("failed to introduce domain"));
|
||||||
|
}
|
||||||
|
self.console_device_add(
|
||||||
|
&dom_path,
|
||||||
|
&backend_dom_path,
|
||||||
|
config.backend_domid,
|
||||||
|
domid,
|
||||||
|
console_evtchn,
|
||||||
|
console_mfn,
|
||||||
|
)?;
|
||||||
|
for (index, disk) in config.disks.iter().enumerate() {
|
||||||
|
self.disk_device_add(
|
||||||
|
&dom_path,
|
||||||
|
&backend_dom_path,
|
||||||
|
config.backend_domid,
|
||||||
|
domid,
|
||||||
|
index,
|
||||||
|
disk,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
self.call.unpause_domain(domid)?;
|
self.call.unpause_domain(domid)?;
|
||||||
|
|
||||||
Ok(domid)
|
Ok(domid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn disk_device_add(
|
||||||
|
&mut self,
|
||||||
|
dom_path: &str,
|
||||||
|
backend_dom_path: &str,
|
||||||
|
backend_domid: u32,
|
||||||
|
domid: u32,
|
||||||
|
index: usize,
|
||||||
|
disk: &DomainDisk,
|
||||||
|
) -> Result<(), XenClientError> {
|
||||||
|
let id = (202 << 8) | (index << 4) as u64;
|
||||||
|
let backend_items: Vec<(&str, String)> = vec![
|
||||||
|
("frontend-id", domid.to_string()),
|
||||||
|
("params", disk.pdev.to_string()),
|
||||||
|
("script", "/etc/xen/scripts/block".to_string()),
|
||||||
|
("online", "1".to_string()),
|
||||||
|
("removable", "0".to_string()),
|
||||||
|
("bootable", "1".to_string()),
|
||||||
|
("state", "1".to_string()),
|
||||||
|
("dev", disk.vdev.to_string()),
|
||||||
|
("type", "phy".to_string()),
|
||||||
|
("mode", if disk.writable { "w" } else { "r" }.to_string()),
|
||||||
|
("device-type", "disk".to_string()),
|
||||||
|
("discard-enable", "0".to_string()),
|
||||||
|
("specification", "xen".to_string()),
|
||||||
|
];
|
||||||
|
|
||||||
|
let frontend_items: Vec<(&str, String)> = vec![
|
||||||
|
("backend-id", backend_domid.to_string()),
|
||||||
|
("state", "1".to_string()),
|
||||||
|
("virtual-device", id.to_string()),
|
||||||
|
("device-type", "disk".to_string()),
|
||||||
|
("trusted", "1".to_string()),
|
||||||
|
("protocol", "x86_64-abi".to_string()),
|
||||||
|
];
|
||||||
|
|
||||||
|
self.device_add(
|
||||||
|
"vbd",
|
||||||
|
id,
|
||||||
|
dom_path,
|
||||||
|
backend_dom_path,
|
||||||
|
backend_domid,
|
||||||
|
domid,
|
||||||
|
frontend_items,
|
||||||
|
backend_items,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn console_device_add(
|
fn console_device_add(
|
||||||
&mut self,
|
&mut self,
|
||||||
dom_path: &String,
|
dom_path: &str,
|
||||||
|
backend_dom_path: &str,
|
||||||
|
backend_domid: u32,
|
||||||
domid: u32,
|
domid: u32,
|
||||||
port: u32,
|
port: u32,
|
||||||
mfn: u64,
|
mfn: u64,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<(), XenClientError> {
|
||||||
let frontend_path = format!("{}/console", dom_path);
|
let backend_entries = vec![
|
||||||
let backend_path = format!("{}/backend/console/{}/{}", dom_path, domid, 0);
|
("frontend-id", domid.to_string()),
|
||||||
let mut tx = self.store.transaction()?;
|
("online", "1".to_string()),
|
||||||
tx.write_string(
|
("state", "1".to_string()),
|
||||||
format!("{}/frontend-id", backend_path).as_str(),
|
("protocol", "vt100".to_string()),
|
||||||
&domid.to_string(),
|
];
|
||||||
)?;
|
|
||||||
tx.write_string(format!("{}/online", backend_path).as_str(), "1")?;
|
|
||||||
tx.write_string(format!("{}/state", backend_path).as_str(), "1")?;
|
|
||||||
tx.write_string(format!("{}/protocol", backend_path).as_str(), "vt100")?;
|
|
||||||
|
|
||||||
tx.write_string(format!("{}/backend-id", frontend_path).as_str(), "0")?;
|
let frontend_entries = vec![
|
||||||
tx.write_string(format!("{}/limit", frontend_path).as_str(), "1048576")?;
|
("backend-id", backend_domid.to_string()),
|
||||||
tx.write_string(format!("{}/type", frontend_path).as_str(), "xenconsoled")?;
|
("limit", "1048576".to_string()),
|
||||||
tx.write_string(format!("{}/output", frontend_path).as_str(), "pty")?;
|
("type", "xenconsoled".to_string()),
|
||||||
tx.write_string(format!("{}/tty", frontend_path).as_str(), "")?;
|
("output", "pty".to_string()),
|
||||||
tx.write_string(
|
("tty", "".to_string()),
|
||||||
format!("{}/port", frontend_path).as_str(),
|
("port", port.to_string()),
|
||||||
&port.to_string(),
|
("ring-ref", mfn.to_string()),
|
||||||
)?;
|
];
|
||||||
tx.write_string(
|
|
||||||
format!("{}/ring-ref", frontend_path).as_str(),
|
self.device_add(
|
||||||
&mfn.to_string(),
|
"console",
|
||||||
|
0,
|
||||||
|
dom_path,
|
||||||
|
backend_dom_path,
|
||||||
|
backend_domid,
|
||||||
|
domid,
|
||||||
|
frontend_entries,
|
||||||
|
backend_entries,
|
||||||
)?;
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn device_add(
|
||||||
|
&mut self,
|
||||||
|
typ: &str,
|
||||||
|
id: u64,
|
||||||
|
dom_path: &str,
|
||||||
|
backend_dom_path: &str,
|
||||||
|
backend_domid: u32,
|
||||||
|
domid: u32,
|
||||||
|
frontend_items: Vec<(&str, String)>,
|
||||||
|
backend_items: Vec<(&str, String)>,
|
||||||
|
) -> Result<(), XenClientError> {
|
||||||
|
let console_zero = typ == "console" && id == 0;
|
||||||
|
|
||||||
|
let frontend_path = if console_zero {
|
||||||
|
format!("{}/console", dom_path)
|
||||||
|
} else {
|
||||||
|
format!("{}/device/{}/{}", dom_path, typ, id)
|
||||||
|
};
|
||||||
|
let backend_path = format!("{}/backend/{}/{}/{}", backend_dom_path, typ, domid, id);
|
||||||
|
|
||||||
|
let mut backend_items: Vec<(&str, String)> = backend_items.clone();
|
||||||
|
let mut frontend_items: Vec<(&str, String)> = frontend_items.clone();
|
||||||
|
backend_items.push(("frontend", frontend_path.clone()));
|
||||||
|
frontend_items.push(("backend", backend_path.clone()));
|
||||||
|
let frontend_perms = &[
|
||||||
|
XsPermission {
|
||||||
|
id: domid,
|
||||||
|
perms: XS_PERM_NONE,
|
||||||
|
},
|
||||||
|
XsPermission {
|
||||||
|
id: backend_domid,
|
||||||
|
perms: XS_PERM_READ,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let backend_perms = &[
|
||||||
|
XsPermission {
|
||||||
|
id: backend_domid,
|
||||||
|
perms: XS_PERM_NONE,
|
||||||
|
},
|
||||||
|
XsPermission {
|
||||||
|
id: domid,
|
||||||
|
perms: XS_PERM_READ,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut tx = self.store.transaction()?;
|
||||||
|
tx.mknod(&frontend_path, frontend_perms)?;
|
||||||
|
for (p, value) in &frontend_items {
|
||||||
|
let path = format!("{}/{}", frontend_path, *p);
|
||||||
|
tx.write_string(&path, value)?;
|
||||||
|
if !console_zero {
|
||||||
|
tx.set_perms(&path, frontend_perms)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.mknod(&backend_path, backend_perms)?;
|
||||||
|
for (p, value) in &backend_items {
|
||||||
|
let path = format!("{}/{}", backend_path, *p);
|
||||||
|
tx.write_string(&path, value)?;
|
||||||
|
}
|
||||||
tx.commit()?;
|
tx.commit()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -120,13 +120,7 @@ impl XsdResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
|
pub fn parse_bool(&self) -> Result<bool, XsdBusError> {
|
||||||
if self.payload.is_empty() {
|
Ok(true)
|
||||||
Err(XsdBusError::new(
|
|
||||||
"Expected bool payload to be at least one byte.",
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok(self.payload[0] == 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,39 @@
|
|||||||
use crate::bus::{XsdBusError, XsdSocket};
|
use crate::bus::{XsdBusError, XsdSocket};
|
||||||
use crate::sys::{
|
use crate::sys::{
|
||||||
XSD_DIRECTORY, XSD_GET_DOMAIN_PATH, XSD_INTRODUCE, XSD_MKDIR, XSD_READ, XSD_RM,
|
XSD_DIRECTORY, XSD_GET_DOMAIN_PATH, XSD_INTRODUCE, XSD_MKDIR, XSD_READ, XSD_RM, XSD_SET_PERMS,
|
||||||
XSD_TRANSACTION_END, XSD_TRANSACTION_START, XSD_WRITE,
|
XSD_TRANSACTION_END, XSD_TRANSACTION_START, XSD_WRITE,
|
||||||
};
|
};
|
||||||
|
use log::trace;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
pub const XS_PERM_NONE: u32 = 0x00;
|
||||||
|
pub const XS_PERM_READ: u32 = 0x01;
|
||||||
|
pub const XS_PERM_WRITE: u32 = 0x02;
|
||||||
|
pub const XS_PERM_READ_WRITE: u32 = XS_PERM_READ | XS_PERM_WRITE;
|
||||||
|
|
||||||
pub struct XsdClient {
|
pub struct XsdClient {
|
||||||
pub socket: XsdSocket,
|
pub socket: XsdSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct XsPermissions {
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct XsPermission {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub perms: u32,
|
pub perms: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl XsPermission {
|
||||||
|
pub fn encode(&self) -> Result<String, XsdBusError> {
|
||||||
|
let c = match self.perms {
|
||||||
|
XS_PERM_READ_WRITE => 'b',
|
||||||
|
XS_PERM_WRITE => 'w',
|
||||||
|
XS_PERM_READ => 'r',
|
||||||
|
XS_PERM_NONE => 'n',
|
||||||
|
_ => return Err(XsdBusError::new("invalid permissions")),
|
||||||
|
};
|
||||||
|
Ok(format!("{}{}", c, self.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait XsdInterface {
|
pub trait XsdInterface {
|
||||||
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
|
fn list(&mut self, path: &str) -> Result<Vec<String>, XsdBusError>;
|
||||||
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
|
fn read(&mut self, path: &str) -> Result<Vec<u8>, XsdBusError>;
|
||||||
@ -22,9 +42,12 @@ pub trait XsdInterface {
|
|||||||
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError>;
|
fn write_string(&mut self, path: &str, data: &str) -> Result<bool, XsdBusError>;
|
||||||
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
fn mkdir(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
||||||
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError>;
|
||||||
|
fn set_perms(&mut self, path: &str, perms: &[XsPermission]) -> Result<bool, XsdBusError>;
|
||||||
|
|
||||||
fn mknod(&mut self, path: &str, _perm: &XsPermissions) -> Result<bool, XsdBusError> {
|
fn mknod(&mut self, path: &str, perms: &[XsPermission]) -> Result<bool, XsdBusError> {
|
||||||
self.write_string(path, "")
|
let result1 = self.write_string(path, "")?;
|
||||||
|
let result2 = self.set_perms(path, perms)?;
|
||||||
|
Ok(result1 && result2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,16 +58,19 @@ impl XsdClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn list(&mut self, tx: u32, path: &str) -> Result<Vec<String>, XsdBusError> {
|
fn list(&mut self, tx: u32, path: &str) -> Result<Vec<String>, XsdBusError> {
|
||||||
|
trace!("list tx={tx} path={path}");
|
||||||
let response = self.socket.send_single(tx, XSD_DIRECTORY, path)?;
|
let response = self.socket.send_single(tx, XSD_DIRECTORY, path)?;
|
||||||
response.parse_string_vec()
|
response.parse_string_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, tx: u32, path: &str) -> Result<Vec<u8>, XsdBusError> {
|
fn read(&mut self, tx: u32, path: &str) -> Result<Vec<u8>, XsdBusError> {
|
||||||
|
trace!("read tx={tx} path={path}");
|
||||||
let response = self.socket.send_single(tx, XSD_READ, path)?;
|
let response = self.socket.send_single(tx, XSD_READ, path)?;
|
||||||
Ok(response.payload)
|
Ok(response.payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, tx: u32, path: &str, data: Vec<u8>) -> Result<bool, XsdBusError> {
|
fn write(&mut self, tx: u32, path: &str, data: Vec<u8>) -> Result<bool, XsdBusError> {
|
||||||
|
trace!("write tx={tx} path={path} data={:?}", data);
|
||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
let path = CString::new(path)?;
|
let path = CString::new(path)?;
|
||||||
buffer.extend_from_slice(path.as_bytes_with_nul());
|
buffer.extend_from_slice(path.as_bytes_with_nul());
|
||||||
@ -54,14 +80,34 @@ impl XsdClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mkdir(&mut self, tx: u32, path: &str) -> Result<bool, XsdBusError> {
|
fn mkdir(&mut self, tx: u32, path: &str) -> Result<bool, XsdBusError> {
|
||||||
|
trace!("mkdir tx={tx} path={path}");
|
||||||
self.socket.send_single(tx, XSD_MKDIR, path)?.parse_bool()
|
self.socket.send_single(tx, XSD_MKDIR, path)?.parse_bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rm(&mut self, tx: u32, path: &str) -> Result<bool, XsdBusError> {
|
fn rm(&mut self, tx: u32, path: &str) -> Result<bool, XsdBusError> {
|
||||||
|
trace!("rm tx={tx} path={path}");
|
||||||
self.socket.send_single(tx, XSD_RM, path)?.parse_bool()
|
self.socket.send_single(tx, XSD_RM, path)?.parse_bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_perms(
|
||||||
|
&mut self,
|
||||||
|
tx: u32,
|
||||||
|
path: &str,
|
||||||
|
perms: &[XsPermission],
|
||||||
|
) -> Result<bool, XsdBusError> {
|
||||||
|
trace!("set_perms tx={tx} path={path} perms={:?}", perms);
|
||||||
|
let mut items: Vec<String> = Vec::new();
|
||||||
|
items.push(path.to_string());
|
||||||
|
for perm in perms {
|
||||||
|
items.push(perm.encode()?);
|
||||||
|
}
|
||||||
|
let items_str: Vec<&str> = items.iter().map(|x| x.as_str()).collect();
|
||||||
|
let response = self.socket.send_multiple(tx, XSD_SET_PERMS, &items_str)?;
|
||||||
|
response.parse_bool()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
|
pub fn transaction(&mut self) -> Result<XsdTransaction, XsdBusError> {
|
||||||
|
trace!("transaction start");
|
||||||
let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?;
|
let response = self.socket.send_single(0, XSD_TRANSACTION_START, "")?;
|
||||||
let str = response.parse_string()?;
|
let str = response.parse_string()?;
|
||||||
let tx = str.parse::<u32>()?;
|
let tx = str.parse::<u32>()?;
|
||||||
@ -79,18 +125,19 @@ impl XsdClient {
|
|||||||
&mut self,
|
&mut self,
|
||||||
domid: u32,
|
domid: u32,
|
||||||
mfn: u64,
|
mfn: u64,
|
||||||
eventchn: u32,
|
evtchn: u32,
|
||||||
) -> Result<String, XsdBusError> {
|
) -> Result<bool, XsdBusError> {
|
||||||
|
trace!("introduce domain domid={domid} mfn={mfn} evtchn={evtchn}");
|
||||||
let response = self.socket.send_multiple(
|
let response = self.socket.send_multiple(
|
||||||
0,
|
0,
|
||||||
XSD_INTRODUCE,
|
XSD_INTRODUCE,
|
||||||
&[
|
&[
|
||||||
domid.to_string().as_str(),
|
domid.to_string().as_str(),
|
||||||
mfn.to_string().as_str(),
|
mfn.to_string().as_str(),
|
||||||
eventchn.to_string().as_str(),
|
evtchn.to_string().as_str(),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
response.parse_string()
|
response.parse_bool()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +174,10 @@ impl XsdInterface for XsdClient {
|
|||||||
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||||
self.rm(0, path)
|
self.rm(0, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_perms(&mut self, path: &str, perms: &[XsPermission]) -> Result<bool, XsdBusError> {
|
||||||
|
self.set_perms(0, path, perms)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XsdInterface for XsdTransaction<'_> {
|
impl XsdInterface for XsdTransaction<'_> {
|
||||||
@ -157,12 +208,17 @@ impl XsdInterface for XsdTransaction<'_> {
|
|||||||
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
fn rm(&mut self, path: &str) -> Result<bool, XsdBusError> {
|
||||||
self.client.rm(self.tx, path)
|
self.client.rm(self.tx, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_perms(&mut self, path: &str, perms: &[XsPermission]) -> Result<bool, XsdBusError> {
|
||||||
|
self.client.set_perms(self.tx, path, perms)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XsdTransaction<'_> {
|
impl XsdTransaction<'_> {
|
||||||
pub fn end(&mut self, abort: bool) -> Result<bool, XsdBusError> {
|
pub fn end(&mut self, abort: bool) -> Result<bool, XsdBusError> {
|
||||||
let abort_str = if abort { "F" } else { "T" };
|
let abort_str = if abort { "F" } else { "T" };
|
||||||
|
|
||||||
|
trace!("transaction end abort={abort_str}");
|
||||||
self.client
|
self.client
|
||||||
.socket
|
.socket
|
||||||
.send_single(self.tx, XSD_TRANSACTION_END, abort_str)?
|
.send_single(self.tx, XSD_TRANSACTION_END, abort_str)?
|
||||||
|
Loading…
Reference in New Issue
Block a user