libsession-sys 0.1.1

session management daemon
Documentation
use crate::logging;
use libsystemd_sys::login;
use std::os::fd;
use std::{ffi, ptr, rc};

fn sd_string(value: *mut ffi::c_char) -> Option<String> {
    let value = ptr::NonNull::new(value)?;
    let result = unsafe { ffi::CStr::from_ptr(value.as_ptr()) }
        .to_string_lossy()
        .into_owned();
    unsafe { libc::free(value.as_ptr().cast()) };
    Some(result)
}
pub struct Logind {
    logger: rc::Rc<logging::Logger>,
}

impl Logind {
    pub fn try_connect(logger: rc::Rc<logging::Logger>) -> Option<Self> {
        let mut sessions = ptr::null_mut::<*mut ffi::c_char>();
        let result = unsafe { login::sd_get_sessions(&raw mut sessions) };
        if result < 0 {
            return None;
        }
        if !sessions.is_null() {
            for index in 0..usize::try_from(result).ok()? {
                unsafe {
                    libc::free((*sessions.add(index)).cast());
                }
            }
            unsafe { libc::free(sessions.cast()) };
        }
        Some(Self { logger })
    }
}

impl super::Backend for Logind {
    fn is_local_session(&self, session_id: &ffi::CStr) -> Option<bool> {
        let result = unsafe { login::sd_session_is_remote(session_id.as_ptr()) };
        (result >= 0).then_some(result == 0)
    }

    fn get_owner_uid(&mut self, pid: u32) -> Option<u32> {
        let mut uid = 0;
        let result = unsafe { login::sd_pid_get_owner_uid(pid.cast_signed(), &raw mut uid) };
        (result >= 0).then_some(uid)
    }

    fn get_state(&mut self, uid: u32) -> Option<crate::LibsessionUserState> {
        let mut state = ptr::null_mut();
        let result = unsafe { login::sd_uid_get_state(uid, &raw mut state) };
        let state = (result >= 0).then(|| sd_string(state))??;
        Some(match state.as_str() {
            "offline" => crate::LibsessionUserState::Offline,
            "lingering" => crate::LibsessionUserState::Lingering,
            "online" => crate::LibsessionUserState::Online,
            "active" => crate::LibsessionUserState::Active,
            "closing" => crate::LibsessionUserState::Closing,
            _ => return None,
        })
    }

    fn get_session_id(&mut self, pid: u32) -> Option<String> {
        self.logger.log(crate::LibsessionLogLevel::Debug, || {
            format!("logind: looking up session for process {pid}")
        });
        let mut session = ptr::null_mut();
        let result = unsafe { login::sd_pid_get_session(pid.cast_signed(), &raw mut session) };
        (result >= 0).then(|| sd_string(session))?
    }

    fn get_display(&mut self, uid: u32) -> Option<String> {
        let mut display = ptr::null_mut();
        let result = unsafe { login::sd_uid_get_display(uid, &raw mut display) };
        (result >= 0).then(|| sd_string(display))?
    }

    fn get_uid(&mut self, session_id: &ffi::CStr) -> Option<u32> {
        let mut uid = 0;
        let result = unsafe { login::sd_session_get_uid(session_id.as_ptr(), &raw mut uid) };
        (result >= 0).then_some(uid)
    }

    fn get_session_state(
        &mut self,
        session_id: &ffi::CStr,
    ) -> Option<crate::LibsessionSessionState> {
        let mut state = ptr::null_mut();
        let result = unsafe { login::sd_session_get_state(session_id.as_ptr(), &raw mut state) };
        let state = (result >= 0).then(|| sd_string(state))??;
        Some(match state.as_str() {
            "online" => crate::LibsessionSessionState::Online,
            "active" => crate::LibsessionSessionState::Active,
            "closing" => crate::LibsessionSessionState::Closing,
            "opening" => crate::LibsessionSessionState::Opening,
            _ => crate::LibsessionSessionState::Unkown,
        })
    }

    fn get_monitor(&self) -> Option<Box<dyn super::BackendMonitor>> {
        let mut monitor = ptr::null_mut();
        let result = unsafe { login::sd_login_monitor_new(c"session".as_ptr(), &raw mut monitor) };

        if result < 0 {
            return None;
        }

        Some(Box::new(LogindMonitor(monitor)))
    }
}

pub struct LogindMonitor(*mut login::sd_login_monitor);

impl Drop for LogindMonitor {
    fn drop(&mut self) {
        unsafe { login::sd_login_monitor_unref(self.0) };
    }
}

impl super::BackendMonitor for LogindMonitor {
    fn fd(&self) -> fd::RawFd {
        unsafe { login::sd_login_monitor_get_fd(self.0) }
    }

    fn flush(&mut self) {
        if !self.0.is_null() {
            unsafe { login::sd_login_monitor_flush(self.0) };
        }
    }
}