diff --git a/systemd-ipc/build.rs b/systemd-ipc/build.rs index 89bc35a..fcec0de 100644 --- a/systemd-ipc/build.rs +++ b/systemd-ipc/build.rs @@ -3,7 +3,7 @@ extern crate varlink_generator; use walkdir::WalkDir; fn main() { - // walk dir to find varlink files + println!("cargo:rerun-if-changed=src/*.varlink"); for entry in WalkDir::new("src").into_iter().filter_map(|e| e.ok()) { if entry.file_name().to_str().unwrap().ends_with(".varlink") { varlink_generator::cargo_build_tosource(&entry.path().display().to_string(), true); diff --git a/systemd-ipc/src/addrs.rs b/systemd-ipc/src/addrs.rs index a05aca2..1e6f888 100644 --- a/systemd-ipc/src/addrs.rs +++ b/systemd-ipc/src/addrs.rs @@ -1,2 +1,3 @@ #[allow(dead_code)] pub const SYSTEMD_HOSTNAME: &str = "unix:/run/systemd/io.systemd.Hostname"; +pub const SYSTEMD_BOOTCONTROL: &str = "unix:/run/systemd/io.systemd.BootControl"; diff --git a/systemd-ipc/src/io.systemd.bootcontrol.varlink b/systemd-ipc/src/io.systemd.bootcontrol.varlink new file mode 100644 index 0000000..871e560 --- /dev/null +++ b/systemd-ipc/src/io.systemd.bootcontrol.varlink @@ -0,0 +1,70 @@ +# Boot Loader control APIs +interface io.systemd.BootControl + +# The type of a boot entry +type BootEntryType( + # Boot Loader Specification Type #1 entries (.conf files) + type1, + # Boot Loader Specification Type #2 entries (UKIs) + type2, + # Additional entries reported by boot loader + loader, + # Automatically generated entries + auto +) + +# A structure encapsulating a boot entry +type BootEntry( + type: BootEntryType, + # The string identifier of the entry + id: ?string, + path: ?string, + root: ?string, + title: ?string, + showTitle: ?string, + sortKey: ?string, + version: ?string, + machineId: ?string, + architecture: ?string, + options: ?string, + linux: ?string, + efi: ?string, + initrd: ?[]string, + devicetree: ?string, + devicetreeOverlay: ?[]string, + # Indicates whether the boot loader reported this entry on the current boot + isReported: bool, + # Indicates the number of tries left for this boot entry before it is assumed to be not working. + triesLeft: ?int, + # Indicates the number of unsuccessful tries already made for this boot entry. + triesDone: ?int, + # Indicates whether this entry is the default entry. + isDefault: ?bool, + # Indicates whether this entry has been booted. + isSelected: ?bool +) + +# Enumerates boot entries. Method call must be called with 'more' flag set. Each response returns one entry. If no entries are defined returns the NoSuchBootEntry error. +# [Requires 'more' flag] +method ListBootEntries() -> ( + # A boot menu entry structure + entry: ?BootEntry +) + +# Sets the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not. +method SetRebootToFirmware( + # The new value of the reboot-to-firmware-UI flag + state: bool +) -> () + +# Gets the current state of the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not. +method GetRebootToFirmware() -> ( + # The current state of the reboot-to-firmware-UI flag + state: bool +) + +# SetRebootToFirmware() and GetRebootToFirmware() return this if the firmware does not actually support the reboot-to-firmware-UI concept. +error RebootToFirmwareNotSupported() + +# No boot entry defined. +error NoSuchBootEntry() diff --git a/systemd-ipc/src/io_systemd_bootcontrol.rs b/systemd-ipc/src/io_systemd_bootcontrol.rs new file mode 100644 index 0000000..e36709d --- /dev/null +++ b/systemd-ipc/src/io_systemd_bootcontrol.rs @@ -0,0 +1,356 @@ +#![doc = "This file was automatically generated by the varlink rust generator"] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +use serde_derive::{Deserialize, Serialize}; +use std::io::BufRead; +use std::sync::{Arc, RwLock}; +use varlink::{self, CallTrait}; +#[allow(dead_code)] +#[derive(Clone, PartialEq, Debug)] +#[allow(clippy::enum_variant_names)] +pub enum ErrorKind { + Varlink_Error, + VarlinkReply_Error, + NoSuchBootEntry(Option<NoSuchBootEntry_Args>), + RebootToFirmwareNotSupported(Option<RebootToFirmwareNotSupported_Args>), +} +impl ::std::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + ErrorKind::Varlink_Error => write!(f, "Varlink Error"), + ErrorKind::VarlinkReply_Error => write!(f, "Varlink error reply"), + ErrorKind::NoSuchBootEntry(v) => { + write!(f, "io.systemd.BootControl.NoSuchBootEntry: {:#?}", v) + } + ErrorKind::RebootToFirmwareNotSupported(v) => write!( + f, + "io.systemd.BootControl.RebootToFirmwareNotSupported: {:#?}", + v + ), + } + } +} +pub struct Error( + pub ErrorKind, + pub Option<Box<dyn std::error::Error + 'static + Send + Sync>>, + pub Option<&'static str>, +); +impl Error { + #[allow(dead_code)] + pub fn kind(&self) -> &ErrorKind { + &self.0 + } +} +impl From<ErrorKind> for Error { + fn from(e: ErrorKind) -> Self { + Error(e, None, None) + } +} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.1 + .as_ref() + .map(|e| e.as_ref() as &(dyn std::error::Error + 'static)) + } +} +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} +impl std::fmt::Debug for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + use std::error::Error as StdError; + if let Some(ref o) = self.2 { + std::fmt::Display::fmt(o, f)?; + } + std::fmt::Debug::fmt(&self.0, f)?; + if let Some(e) = self.source() { + std::fmt::Display::fmt("\nCaused by:\n", f)?; + std::fmt::Debug::fmt(&e, f)?; + } + Ok(()) + } +} +#[allow(dead_code)] +pub type Result<T> = std::result::Result<T, Error>; +impl From<varlink::Error> for Error { + fn from(e: varlink::Error) -> Self { + match e.kind() { + varlink::ErrorKind::VarlinkErrorReply(r) => Error( + ErrorKind::from(r), + Some(Box::from(e)), + Some(concat!(file!(), ":", line!(), ": ")), + ), + _ => Error( + ErrorKind::Varlink_Error, + Some(Box::from(e)), + Some(concat!(file!(), ":", line!(), ": ")), + ), + } + } +} +#[allow(dead_code)] +impl Error { + pub fn source_varlink_kind(&self) -> Option<&varlink::ErrorKind> { + use std::error::Error as StdError; + let mut s: &dyn StdError = self; + while let Some(c) = s.source() { + let k = self + .source() + .and_then(|e| e.downcast_ref::<varlink::Error>()) + .map(|e| e.kind()); + if k.is_some() { + return k; + } + s = c; + } + None + } +} +impl From<&varlink::Reply> for ErrorKind { + #[allow(unused_variables)] + fn from(e: &varlink::Reply) -> Self { + match e { + varlink::Reply { + error: Some(ref t), .. + } if t == "io.systemd.BootControl.NoSuchBootEntry" => match e { + varlink::Reply { + parameters: Some(p), + .. + } => match serde_json::from_value(p.clone()) { + Ok(v) => ErrorKind::NoSuchBootEntry(v), + Err(_) => ErrorKind::NoSuchBootEntry(None), + }, + _ => ErrorKind::NoSuchBootEntry(None), + }, + varlink::Reply { + error: Some(ref t), .. + } if t == "io.systemd.BootControl.RebootToFirmwareNotSupported" => match e { + varlink::Reply { + parameters: Some(p), + .. + } => match serde_json::from_value(p.clone()) { + Ok(v) => ErrorKind::RebootToFirmwareNotSupported(v), + Err(_) => ErrorKind::RebootToFirmwareNotSupported(None), + }, + _ => ErrorKind::RebootToFirmwareNotSupported(None), + }, + _ => ErrorKind::VarlinkReply_Error, + } + } +} +pub trait VarlinkCallError: varlink::CallTrait { + fn reply_no_such_boot_entry(&mut self) -> varlink::Result<()> { + self.reply_struct(varlink::Reply::error( + "io.systemd.BootControl.NoSuchBootEntry", + None, + )) + } + fn reply_reboot_to_firmware_not_supported(&mut self) -> varlink::Result<()> { + self.reply_struct(varlink::Reply::error( + "io.systemd.BootControl.RebootToFirmwareNotSupported", + None, + )) + } +} +impl<'a> VarlinkCallError for varlink::Call<'a> {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct r#BootEntry { + pub r#type: BootEntryType, + pub r#id: Option<String>, + pub r#path: Option<String>, + pub r#root: Option<String>, + pub r#title: Option<String>, + pub r#showTitle: Option<String>, + pub r#sortKey: Option<String>, + pub r#version: Option<String>, + pub r#machineId: Option<String>, + pub r#architecture: Option<String>, + pub r#options: Option<String>, + pub r#linux: Option<String>, + pub r#efi: Option<String>, + pub r#initrd: Option<Vec<String>>, + pub r#devicetree: Option<String>, + pub r#devicetreeOverlay: Option<Vec<String>>, + pub r#isReported: bool, + pub r#triesLeft: Option<i64>, + pub r#triesDone: Option<i64>, + pub r#isDefault: Option<bool>, + pub r#isSelected: Option<bool>, +} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub enum r#BootEntryType { + r#type1, + r#type2, + r#loader, + r#auto, +} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct NoSuchBootEntry_Args {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct RebootToFirmwareNotSupported_Args {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct GetRebootToFirmware_Reply { + pub r#state: bool, +} +impl varlink::VarlinkReply for GetRebootToFirmware_Reply {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct GetRebootToFirmware_Args {} +pub trait Call_GetRebootToFirmware: VarlinkCallError { + fn reply(&mut self, r#state: bool) -> varlink::Result<()> { + self.reply_struct(GetRebootToFirmware_Reply { r#state }.into()) + } +} +impl<'a> Call_GetRebootToFirmware for varlink::Call<'a> {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ListBootEntries_Reply { + #[serde(skip_serializing_if = "Option::is_none")] + pub r#entry: Option<BootEntry>, +} +impl varlink::VarlinkReply for ListBootEntries_Reply {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ListBootEntries_Args {} +pub trait Call_ListBootEntries: VarlinkCallError { + fn reply(&mut self, r#entry: Option<BootEntry>) -> varlink::Result<()> { + self.reply_struct(ListBootEntries_Reply { r#entry }.into()) + } +} +impl<'a> Call_ListBootEntries for varlink::Call<'a> {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct SetRebootToFirmware_Reply {} +impl varlink::VarlinkReply for SetRebootToFirmware_Reply {} +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct SetRebootToFirmware_Args { + pub r#state: bool, +} +pub trait Call_SetRebootToFirmware: VarlinkCallError { + fn reply(&mut self) -> varlink::Result<()> { + self.reply_struct(varlink::Reply::parameters(None)) + } +} +impl<'a> Call_SetRebootToFirmware for varlink::Call<'a> {} +pub trait VarlinkInterface { + fn get_reboot_to_firmware( + &self, + call: &mut dyn Call_GetRebootToFirmware, + ) -> varlink::Result<()>; + fn list_boot_entries(&self, call: &mut dyn Call_ListBootEntries) -> varlink::Result<()>; + fn set_reboot_to_firmware( + &self, + call: &mut dyn Call_SetRebootToFirmware, + r#state: bool, + ) -> varlink::Result<()>; + fn call_upgraded( + &self, + _call: &mut varlink::Call, + _bufreader: &mut dyn BufRead, + ) -> varlink::Result<Vec<u8>> { + Ok(Vec::new()) + } +} +pub trait VarlinkClientInterface { + fn get_reboot_to_firmware( + &mut self, + ) -> varlink::MethodCall<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error>; + fn list_boot_entries( + &mut self, + ) -> varlink::MethodCall<ListBootEntries_Args, ListBootEntries_Reply, Error>; + fn set_reboot_to_firmware( + &mut self, + r#state: bool, + ) -> varlink::MethodCall<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error>; +} +#[allow(dead_code)] +pub struct VarlinkClient { + connection: Arc<RwLock<varlink::Connection>>, +} +impl VarlinkClient { + #[allow(dead_code)] + pub fn new(connection: Arc<RwLock<varlink::Connection>>) -> Self { + VarlinkClient { connection } + } +} +impl VarlinkClientInterface for VarlinkClient { + fn get_reboot_to_firmware( + &mut self, + ) -> varlink::MethodCall<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error> { + varlink::MethodCall::<GetRebootToFirmware_Args, GetRebootToFirmware_Reply, Error>::new( + self.connection.clone(), + "io.systemd.BootControl.GetRebootToFirmware", + GetRebootToFirmware_Args {}, + ) + } + fn list_boot_entries( + &mut self, + ) -> varlink::MethodCall<ListBootEntries_Args, ListBootEntries_Reply, Error> { + varlink::MethodCall::<ListBootEntries_Args, ListBootEntries_Reply, Error>::new( + self.connection.clone(), + "io.systemd.BootControl.ListBootEntries", + ListBootEntries_Args {}, + ) + } + fn set_reboot_to_firmware( + &mut self, + r#state: bool, + ) -> varlink::MethodCall<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error> { + varlink::MethodCall::<SetRebootToFirmware_Args, SetRebootToFirmware_Reply, Error>::new( + self.connection.clone(), + "io.systemd.BootControl.SetRebootToFirmware", + SetRebootToFirmware_Args { r#state }, + ) + } +} +#[allow(dead_code)] +pub struct VarlinkInterfaceProxy { + inner: Box<dyn VarlinkInterface + Send + Sync>, +} +#[allow(dead_code)] +pub fn new(inner: Box<dyn VarlinkInterface + Send + Sync>) -> VarlinkInterfaceProxy { + VarlinkInterfaceProxy { inner } +} +impl varlink::Interface for VarlinkInterfaceProxy { + fn get_description(&self) -> &'static str { + "# Boot Loader control APIs\ninterface io.systemd.BootControl\n\n# The type of a boot entry\ntype BootEntryType(\n\t# Boot Loader Specification Type #1 entries (.conf files)\n\ttype1,\n\t# Boot Loader Specification Type #2 entries (UKIs)\n\ttype2,\n\t# Additional entries reported by boot loader\n\tloader,\n\t# Automatically generated entries\n\tauto\n)\n\n# A structure encapsulating a boot entry\ntype BootEntry(\n\ttype: BootEntryType,\n\t# The string identifier of the entry\n\tid: ?string,\n\tpath: ?string,\n\troot: ?string,\n\ttitle: ?string,\n\tshowTitle: ?string,\n\tsortKey: ?string,\n\tversion: ?string,\n\tmachineId: ?string,\n\tarchitecture: ?string,\n\toptions: ?string,\n\tlinux: ?string,\n\tefi: ?string,\n\tinitrd: ?[]string,\n\tdevicetree: ?string,\n\tdevicetreeOverlay: ?[]string,\n\t# Indicates whether the boot loader reported this entry on the current boot\n\tisReported: bool,\n\t# Indicates the number of tries left for this boot entry before it is assumed to be not working.\n\ttriesLeft: ?int,\n\t# Indicates the number of unsuccessful tries already made for this boot entry.\n\ttriesDone: ?int,\n\t# Indicates whether this entry is the default entry.\n\tisDefault: ?bool,\n\t# Indicates whether this entry has been booted.\n\tisSelected: ?bool\n)\n\n# Enumerates boot entries. Method call must be called with 'more' flag set. Each response returns one entry. If no entries are defined returns the NoSuchBootEntry error.\n# [Requires 'more' flag]\nmethod ListBootEntries() -> (\n\t# A boot menu entry structure\n\tentry: ?BootEntry\n)\n\n# Sets the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.\nmethod SetRebootToFirmware(\n\t# The new value of the reboot-to-firmware-UI flag\n\tstate: bool\n) -> ()\n\n# Gets the current state of the reboot-to-firmware-UI flag of the firmware, if this concept exists. Returns the RebootToFirmwareNotSupported error if not.\nmethod GetRebootToFirmware() -> (\n\t# The current state of the reboot-to-firmware-UI flag\n\tstate: bool\n)\n\n# SetRebootToFirmware() and GetRebootToFirmware() return this if the firmware does not actually support the reboot-to-firmware-UI concept.\nerror RebootToFirmwareNotSupported()\n\n# No boot entry defined.\nerror NoSuchBootEntry()\n" + } + fn get_name(&self) -> &'static str { + "io.systemd.BootControl" + } + fn call_upgraded( + &self, + call: &mut varlink::Call, + bufreader: &mut dyn BufRead, + ) -> varlink::Result<Vec<u8>> { + self.inner.call_upgraded(call, bufreader) + } + fn call(&self, call: &mut varlink::Call) -> varlink::Result<()> { + let req = call.request.unwrap(); + match req.method.as_ref() { + "io.systemd.BootControl.GetRebootToFirmware" => self + .inner + .get_reboot_to_firmware(call as &mut dyn Call_GetRebootToFirmware), + "io.systemd.BootControl.ListBootEntries" => self + .inner + .list_boot_entries(call as &mut dyn Call_ListBootEntries), + "io.systemd.BootControl.SetRebootToFirmware" => { + if let Some(args) = req.parameters.clone() { + let args: SetRebootToFirmware_Args = match serde_json::from_value(args) { + Ok(v) => v, + Err(e) => { + let es = format!("{}", e); + let _ = call.reply_invalid_parameter(es.clone()); + return Err(varlink::context!(varlink::ErrorKind::SerdeJsonDe(es))); + } + }; + self.inner.set_reboot_to_firmware( + call as &mut dyn Call_SetRebootToFirmware, + args.r#state, + ) + } else { + call.reply_invalid_parameter("parameters".into()) + } + } + m => call.reply_method_not_found(String::from(m)), + } + } +}