sysd_manager_proxy_lib/
interface.rs

1use base::{RunMode, consts::*, enums::UnitDBusLevel, proxy::DisEnAbleUnitFiles};
2
3use log::{debug, info, warn};
4use std::{borrow::Cow, env, error::Error, sync::OnceLock};
5use tokio::sync::OnceCell;
6use zbus::{
7    Connection, ObjectServer, connection, interface, message::Header, object_server::SignalEmitter,
8};
9
10use crate::{SysDManagerProxy, file, sysdcom};
11
12#[interface(name = "io.github.plrigaux.SysDManager", introspection_docs = true)]
13impl SysDManagerProxy {
14    pub async fn create_drop_in(
15        &mut self,
16        #[zbus(header)] header: Header<'_>,
17        runtime: bool,
18        unit_name: &str,
19        file_name: &str,
20        content: &str,
21    ) -> zbus::fdo::Result<()> {
22        //self.
23        self.check_autorisation(header).await?;
24
25        //   self.get_all(object_server, connection, header, emitter)
26        file::create_drop_in(runtime, unit_name, file_name, content).await
27    }
28
29    pub async fn save_file(
30        &mut self,
31        #[zbus(header)] header: Header<'_>,
32
33        file_path: &str,
34        content: &str,
35    ) -> zbus::fdo::Result<u64> {
36        self.check_autorisation(header).await?;
37        file::save(file_path, content).await
38    }
39
40    pub async fn my_user_id(
41        &mut self,
42        #[zbus(header)] header: Header<'_>,
43    ) -> zbus::fdo::Result<u32> {
44        self.check_autorisation(header).await?;
45
46        let id = unsafe { libc::getegid() };
47        info!("ids {}", id);
48
49        Ok(id)
50    }
51    // "Bye" signal (note: no implementation body).
52    #[zbus(signal)]
53    async fn bye(signal_emitter: &SignalEmitter<'_>, message: &str) -> zbus::Result<()>;
54
55    // "Quit" method. A method may throw errors.
56    async fn quit(
57        &self,
58        #[zbus(header)] hdr: Header<'_>,
59        #[zbus(signal_emitter)] emitter: SignalEmitter<'_>,
60        #[zbus(object_server)] _server: &ObjectServer,
61    ) -> zbus::fdo::Result<()> {
62        let path = hdr.path().unwrap();
63        let msg = format!("You are leaving me on the {} path?", path);
64        emitter.bye(&msg).await?;
65
66        // Do some asynchronous tasks before quitting..
67
68        Ok(())
69    }
70
71    async fn even_ping(
72        &mut self,
73        #[zbus(header)] header: Header<'_>,
74        val: u32,
75    ) -> zbus::fdo::Result<u32> {
76        info!("even_ping {val}");
77        self.check_autorisation(header).await?;
78        if val.is_multiple_of(2) {
79            Ok(val)
80        } else {
81            Err(zbus::fdo::Error::Failed(format!("{val} not even!")))
82        }
83    }
84
85    async fn clean_unit(
86        &self,
87        #[zbus(header)] header: Header<'_>,
88
89        unit_name: &str,
90        what: Vec<&str>,
91    ) -> zbus::fdo::Result<()> {
92        self.check_autorisation(header).await?;
93        let proxy = get_proxy(UnitDBusLevel::System).await?;
94
95        info!("clean_unit {} {:?}", unit_name, what);
96        proxy
97            .clean_unit(unit_name, &what)
98            .await
99            .inspect_err(|e| warn!("Error while calling clean_unit on sysdbus proxy: {:?}", e))
100    }
101
102    async fn freeze_unit(
103        &self,
104        #[zbus(header)] header: Header<'_>,
105        unit_name: &str,
106    ) -> zbus::fdo::Result<()> {
107        let proxy = get_proxy(UnitDBusLevel::System).await?;
108        self.check_autorisation(header).await?;
109        info!("freeze_unit {}", unit_name);
110        proxy
111            .freeze_unit(unit_name)
112            .await
113            .inspect_err(|e| warn!("Error while calling freeze_unit on sysdbus proxy: {:?}", e))
114    }
115
116    async fn thaw_unit(
117        &self,
118        #[zbus(header)] header: Header<'_>,
119        unit_name: &str,
120    ) -> zbus::fdo::Result<()> {
121        let proxy = get_proxy(UnitDBusLevel::System).await?;
122        self.check_autorisation(header).await?;
123        info!("thaw_unit {}", unit_name);
124        proxy
125            .thaw_unit(unit_name)
126            .await
127            .inspect_err(|e| warn!("Error while calling thaw_unit on sysdbus proxy: {:?}", e))
128    }
129
130    async fn revert_unit_files(
131        &self,
132        #[zbus(header)] header: Header<'_>,
133        file_names: Vec<String>,
134    ) -> zbus::fdo::Result<Vec<DisEnAbleUnitFiles>> {
135        info!("Revert_unit_files  {:?}", file_names);
136
137        let proxy: &sysdcom::SysDManagerComLinkProxy<'_> = get_proxy(UnitDBusLevel::System).await?;
138
139        debug!("Proxy {:?}", proxy);
140        self.check_autorisation(header).await?;
141        debug!("Polkit autorized");
142        match proxy.revert_unit_files(&file_names).await {
143            Ok(vec) => {
144                info!("revert_unit_files {:?} --> {:?}", file_names, vec);
145                Ok(vec)
146            }
147            Err(err) => {
148                warn!(
149                    "Error while calling revert_unit_files on sysdbus proxy: {:?}",
150                    err
151                );
152                Err(err)
153            }
154        }
155    }
156
157    async fn reload(&self, #[zbus(header)] header: Header<'_>) -> zbus::fdo::Result<()> {
158        info!("Reload");
159        let proxy: &sysdcom::SysDManagerComLinkProxy<'_> = get_proxy(UnitDBusLevel::System).await?;
160        self.check_autorisation(header).await?;
161        debug!("Polkit autorized");
162        proxy
163            .reload()
164            .await
165            .inspect_err(|e| warn!("Error while calling reload on sysdbus proxy: {:?}", e))
166    }
167}
168
169static CONNECTION: OnceLock<Connection> = OnceLock::new();
170
171pub async fn init_serve_connection(run_mode: RunMode) -> Result<(), Box<dyn Error>> {
172    info!("Init Proxy");
173
174    let proxy = SysDManagerProxy::new()?;
175
176    let id = unsafe { libc::getegid() };
177    info!("User id {id}");
178
179    let default_name = if run_mode == RunMode::Development {
180        DBUS_NAME_DEV
181    } else {
182        DBUS_NAME
183    };
184
185    let dbus_name = get_env("DBUS_NAME", default_name);
186    let dbus_path = get_env("DBUS_PATH", DBUS_PATH);
187
188    info!("DBus name {dbus_name}");
189    info!("DBus path {dbus_path}");
190
191    let connection = connection::Builder::system()?
192        .name(dbus_name)?
193        .serve_at(dbus_path, proxy)?
194        .build()
195        .await?;
196
197    CONNECTION.get_or_init(|| connection);
198    Ok(())
199}
200
201fn get_env<'a>(key: &str, default: &'a str) -> Cow<'a, str> {
202    match env::var(key) {
203        Ok(val) => {
204            info!("Key {key}, Value {val}");
205            Cow::Owned(val)
206        }
207        Err(e) => {
208            debug!("Env error {e:?}");
209            info!("Key {key}, Use default value {default}");
210            Cow::Borrowed(default)
211        }
212    }
213}
214
215async fn get_proxy(
216    _dbus_level: UnitDBusLevel,
217) -> Result<&'static sysdcom::SysDManagerComLinkProxy<'static>, zbus::Error> {
218    system_proxy().await //Only system cause the proxy runs at root so no session
219}
220
221static SYS_PROXY: OnceCell<sysdcom::SysDManagerComLinkProxy> = OnceCell::const_new();
222
223async fn system_proxy() -> Result<&'static sysdcom::SysDManagerComLinkProxy<'static>, zbus::Error> {
224    SYS_PROXY
225        .get_or_try_init(
226            async || -> Result<sysdcom::SysDManagerComLinkProxy, zbus::Error> {
227                let connection = Connection::system().await?;
228                let proxy = sysdcom::SysDManagerComLinkProxy::builder(&connection)
229                    .build()
230                    .await?;
231                Ok(proxy)
232            },
233        )
234        .await
235}