use crate::error::{VZError, VZResult};
use crate::shim_ffi;
use std::ffi::{CString, c_void};
use std::path::Path;
fn path_cstring(path: &Path) -> VZResult<CString> {
CString::new(path.to_string_lossy().as_bytes()).map_err(|_| {
VZError::InvalidConfiguration(format!("path contains NUL: {}", path.display()))
})
}
pub trait BootLoader {
fn as_ptr(&self) -> *mut c_void;
}
pub struct LinuxBootLoader {
inner: *mut c_void,
}
unsafe impl Send for LinuxBootLoader {}
impl LinuxBootLoader {
pub fn new(kernel_path: impl AsRef<Path>) -> VZResult<Self> {
let path = kernel_path.as_ref();
if !path.exists() {
return Err(VZError::NotFound(path.display().to_string()));
}
let c_path = path_cstring(path)?;
let obj = unsafe { shim_ffi::abx_bootloader_linux_new(c_path.as_ptr()) };
Ok(Self { inner: obj })
}
pub fn set_initial_ramdisk(&mut self, path: impl AsRef<Path>) -> &mut Self {
let path = path.as_ref();
if path.exists()
&& let Ok(c_path) = path_cstring(path)
{
unsafe {
shim_ffi::abx_bootloader_linux_set_initrd(self.inner.cast(), c_path.as_ptr());
}
}
self
}
pub fn set_command_line(&mut self, cmdline: &str) -> &mut Self {
if let Ok(c_cmdline) = CString::new(cmdline) {
unsafe {
shim_ffi::abx_bootloader_linux_set_cmdline(self.inner.cast(), c_cmdline.as_ptr());
}
}
self
}
}
impl BootLoader for LinuxBootLoader {
fn as_ptr(&self) -> *mut c_void {
self.inner
}
}
impl Drop for LinuxBootLoader {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}
pub struct MacOSBootLoader {
inner: *mut c_void,
}
unsafe impl Send for MacOSBootLoader {}
impl MacOSBootLoader {
pub fn new() -> VZResult<Self> {
let obj = unsafe { shim_ffi::abx_bootloader_macos_new() };
Ok(Self { inner: obj })
}
}
impl BootLoader for MacOSBootLoader {
fn as_ptr(&self) -> *mut c_void {
self.inner
}
}
impl Drop for MacOSBootLoader {
fn drop(&mut self) {
if !self.inner.is_null() {
unsafe { shim_ffi::abx_object_release(self.inner.cast()) };
}
}
}