diff --git a/Cargo.lock b/Cargo.lock
index 21ee53f..f31bb9a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1028,10 +1028,10 @@ dependencies = [
name = "libsession-sys"
version = "0.1.0"
dependencies = [
- "hyprwire",
- "hyprwire-protocols-sessiond",
"libc",
"libsystemd-sys",
+ "sessiond-state",
+ "toml",
"zbus",
]
@@ -1547,6 +1547,7 @@ dependencies = [
"owo-colors",
"serde_json",
"termtree",
+ "uzers",
]
[[package]]
@@ -1564,6 +1565,7 @@ dependencies = [
"log",
"rustix",
"serde",
+ "sessiond-state",
"syslog",
"toml",
"uzers",
@@ -1659,6 +1661,15 @@ dependencies = [
"sessiond-power-client",
]
+[[package]]
+name = "sessiond-state"
+version = "0.1.0"
+dependencies = [
+ "serde",
+ "thiserror",
+ "toml",
+]
+
[[package]]
name = "sessiond-suspendctl"
version = "0.1.0"
@@ -1798,18 +1809,18 @@ checksum = "d4d1330fe7f7f872cd05165130b10602d667b205fd85be09be2814b115d4ced9"
[[package]]
name = "thiserror"
-version = "2.0.20"
+version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
+checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "2.0.20"
+version = "2.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
+checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
dependencies = [
"proc-macro2",
"quote",
diff --git a/Cargo.toml b/Cargo.toml
index 0b03da4..0473219 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
members = [
"sessionctl",
"sessiond",
+ "sessiond-state",
"libsession-sys",
"libsession-rs",
"pam",
diff --git a/hyprwire-protocols-sessiond/protocols/session_core_v1.xml b/hyprwire-protocols-sessiond/protocols/session_core_v1.xml
index c2b6ea3..00244d3 100644
--- a/hyprwire-protocols-sessiond/protocols/session_core_v1.xml
+++ b/hyprwire-protocols-sessiond/protocols/session_core_v1.xml
@@ -116,9 +116,6 @@
-
-
-
@@ -196,9 +193,6 @@
-
-
-
@@ -234,9 +228,6 @@
-
-
-
diff --git a/libsession-sys/Cargo.toml b/libsession-sys/Cargo.toml
index 8d902e8..dfe5d4d 100644
--- a/libsession-sys/Cargo.toml
+++ b/libsession-sys/Cargo.toml
@@ -14,17 +14,15 @@ name = "session"
crate-type = ["rlib", "cdylib", "staticlib"]
[dependencies]
-hyprwire = { version = "0.5.1", optional = true }
zbus = { version = "5.16.0", optional = true }
libsystemd-sys = { version = "0.9.4", optional = true }
-hyprwire-protocols-sessiond = { path = "../hyprwire-protocols-sessiond", version = "0.2.0", optional = true }
libc = "0.2.189"
-
-[build-dependencies]
+toml = { version = "1.1.2", optional = true }
+sessiond-state = { path = "../sessiond-state", version = "0.1.0", optional = true }
[features]
default = ["sessiond", "logind", "consolekit"]
-sessiond = ["dep:hyprwire", "dep:hyprwire-protocols-sessiond"]
+sessiond = ["dep:sessiond-state"]
consolekit = ["dep:zbus"]
logind = ["dep:libsystemd-sys"]
diff --git a/libsession-sys/src/backend/sessiond.rs b/libsession-sys/src/backend/sessiond.rs
index de1e381..eef34f4 100644
--- a/libsession-sys/src/backend/sessiond.rs
+++ b/libsession-sys/src/backend/sessiond.rs
@@ -1,350 +1,95 @@
-use hyprwire::client;
-use hyprwire_protocols_sessiond::client::session_core::v1::session_core_v1;
-use hyprwire_protocols_sessiond::client::session_core::v1::session_core_v1::{
- session_core_manager, session_core_session, session_core_user,
-};
-use std::ffi;
-
-pub struct Session {
- id: u32,
- pid: u32,
- uid: u32,
- class: session_core_v1::SessionClass,
- state: session_core_v1::ActiveState,
- timestamp: u32,
- done: bool,
- is_local: bool,
- object: session_core_session::SessionCoreSession,
-}
-
-impl Session {
- pub const fn new(
- object: session_core_session::SessionCoreSession,
- id: u32,
- pid: u32,
- uid: u32,
- ) -> Self {
- Self {
- id,
- pid,
- uid,
- class: session_core_v1::SessionClass::User,
- state: session_core_v1::ActiveState::Online,
- timestamp: 0,
- done: false,
- is_local: false,
- object,
- }
- }
-}
-
-pub struct User {
- uid: u32,
- state: session_core_v1::UserState,
- object: session_core_user::SessionCoreUser,
- done: bool,
-}
+use super::inotify;
+use std::os::unix::ffi::OsStrExt;
+use std::{env, ffi, fs, path};
pub struct Sessiond {
- eq: hyprwire::EventQueue,
- session_manager: Option,
- sessions: Vec,
- users: Vec,
-}
-
-impl hyprwire::Dispatch for Sessiond {
- fn event(
- &mut self,
- object: &session_core_session::SessionCoreSession,
- event: ::Event<'_>,
- ) {
- let Some(index) = self
- .sessions
- .iter()
- .position(|session| session.object == *object)
- else {
- return;
- };
-
- match event {
- session_core_session::Event::SessionId { session_id } => {
- self.sessions[index].id = session_id;
- }
- session_core_session::Event::Uid { uid } => {
- self.sessions[index].uid = uid;
- }
- session_core_session::Event::Class { class } => {
- self.sessions[index].class = class;
- }
- session_core_session::Event::Active { state } => {
- self.sessions[index].state = state;
- }
- session_core_session::Event::Timestamp { timestamp } => {
- self.sessions[index].timestamp = timestamp;
- }
- session_core_session::Event::Done => {
- self.sessions[index].done = true;
- }
- session_core_session::Event::IsLocal { is_local } => {
- self.sessions[index].is_local = is_local != 0;
- }
- session_core_session::Event::Destroyed => {
- self.sessions.remove(index);
- }
- _ => {}
- }
- }
-}
-
-impl hyprwire::Dispatch for Sessiond {
- fn event(
- &mut self,
- object: &session_core_user::SessionCoreUser,
- event: ::Event<'_>,
- ) {
- let Some(index) = self.users.iter().position(|user| user.object == *object) else {
- return;
- };
-
- match event {
- session_core_user::Event::Uid { uid } => self.users[index].uid = uid,
- session_core_user::Event::State { state } => self.users[index].state = state,
- session_core_user::Event::Done => self.users[index].done = true,
- session_core_user::Event::NotFound => {
- self.users.retain(|candidate| candidate.object != *object);
- }
- _ => {}
- }
- }
+ state_path: path::PathBuf,
}
impl Sessiond {
- fn wait_user(&mut self, object: &session_core_user::SessionCoreUser) -> Option {
- let eq = self.eq.clone();
- eq.dispatch_events(self, false).ok()?;
- loop {
- let index = self.users.iter().position(|user| user.object == *object)?;
- if self.users[index].done {
- return Some(index);
- }
- eq.dispatch_events(self, true).ok()?;
- }
- }
-
- fn wait_session(&mut self, object: &session_core_session::SessionCoreSession) -> Option {
- let eq = self.eq.clone();
- eq.dispatch_events(self, false).ok()?;
- loop {
- let index = self.sessions.iter().position(|s| s.object == *object)?;
- if self.sessions[index].done {
- return Some(index);
- }
- eq.dispatch_events(self, true).ok()?;
- }
- }
-
pub fn try_connect() -> Option {
- let Ok(mut socket) = client::Client::connect("/run/sessiond/sessiond.sock") else {
- return None;
+ let runtime_dir = env::var_os("SESSIOND_RUNTIME_DIR")
+ .map_or_else(|| path::PathBuf::from("/run/sessiond"), path::PathBuf::from);
+ let backend = Self {
+ state_path: runtime_dir.join("state.toml"),
};
- let eq = socket.new_event_queue();
-
- socket.add_implementation::();
-
- let mut sessiond = Self {
- eq: eq.clone(),
- sessions: Vec::new(),
- session_manager: None,
- users: Vec::new(),
- };
-
- eq.wait_for_handshake(&mut sessiond).ok()?;
-
- // if we fail to bind manager the connectionn is useless, try another backend
- sessiond.session_manager = Some(socket.bind(&eq, &mut sessiond, 3).ok()?);
+ sessiond_state::try_read(&backend.state_path).ok()?;
- eq.roundtrip(&mut sessiond).ok()?;
-
- Some(sessiond)
+ Some(backend)
}
}
impl super::Backend for Sessiond {
fn get_session_id(&mut self, pid: u32) -> Option {
- if let Some(object) = self
- .sessions
- .iter()
- .find(|session| session.pid == pid)
- .map(|session| session.object.clone())
- {
- let index = self.wait_session(&object)?;
- return Some(self.sessions[index].id.to_string());
- }
- let object = self
- .session_manager
- .as_ref()?
- .send_get_session_by_pid::(pid)?;
- self.sessions.push(Session::new(object.clone(), 0, pid, 0));
- self.wait_session(&object)
- .map(|index| self.sessions[index].id.to_string())
+ let cgroup = fs::read_to_string(format!("/proc/{pid}/cgroup")).ok()?;
+ cgroup.lines().find_map(|line| {
+ let path = line.splitn(3, ':').nth(2)?;
+ path.split('/')
+ .find_map(|part| part.strip_prefix("session-")?.parse().ok())
+ })
}
fn get_owner_uid(&mut self, pid: u32) -> Option {
- if let Some(object) = self
- .sessions
- .iter()
- .find(|session| session.pid == pid)
- .map(|session| session.object.clone())
- {
- let index = self.wait_session(&object)?;
- return Some(self.sessions[index].uid);
- }
- let object = self
- .session_manager
- .as_ref()?
- .send_get_session_by_pid::(pid)?;
- self.sessions.push(Session::new(object.clone(), 0, pid, 0));
- self.wait_session(&object)
- .map(|index| self.sessions[index].uid)
+ let owner_uid = fs::read_to_string(format!("/proc/{pid}/loginuid")).ok()?;
+ owner_uid.trim().parse().ok()
}
fn get_uid(&mut self, session_id: &ffi::CStr) -> Option {
- let Ok(session_id) = session_id.to_string_lossy().parse::() else {
- return None;
- };
-
- if let Some(object) = self
+ let state = sessiond_state::try_read(&self.state_path).ok()?;
+ let session = state
.sessions
- .iter()
- .find(|session| session.id == session_id)
- .map(|session| session.object.clone())
- {
- let index = self.wait_session(&object)?;
- return Some(self.sessions[index].uid);
- }
- let object = self
- .session_manager
- .as_ref()?
- .send_get_session::(session_id)?;
- self.sessions
- .push(Session::new(object.clone(), session_id, 0, 0));
- self.wait_session(&object)
- .map(|index| self.sessions[index].uid)
+ .get(&session_id.to_string_lossy().to_string())?;
+
+ Some(session.uid)
}
fn get_state(&mut self, uid: u32) -> Option {
- let object = if let Some(object) = self
- .users
- .iter()
- .find(|user| user.uid == uid)
- .map(|user| user.object.clone())
- {
- object
- } else {
- let object = self.session_manager.as_ref()?.send_get_user::(uid)?;
- self.users.push(User {
- uid,
- state: session_core_v1::UserState::Offline,
- object: object.clone(),
- done: false,
- });
- object
- };
- let index = self.wait_user(&object)?;
- Some(match self.users[index].state {
- session_core_v1::UserState::Offline => crate::LibsessionUserState::Offline,
- session_core_v1::UserState::Lingering => crate::LibsessionUserState::Lingering,
- session_core_v1::UserState::Online => crate::LibsessionUserState::Online,
- session_core_v1::UserState::Active => crate::LibsessionUserState::Active,
- session_core_v1::UserState::Closing => crate::LibsessionUserState::Closing,
- _ => return None,
- })
+ let state = sessiond_state::try_read(&self.state_path).ok()?;
+ let user = state.users.get(&uid)?;
+
+ match user.state {
+ sessiond_state::UserState::Offline => Some(crate::LibsessionUserState::Offline),
+ sessiond_state::UserState::Lingering => Some(crate::LibsessionUserState::Lingering),
+ sessiond_state::UserState::Online => Some(crate::LibsessionUserState::Online),
+ sessiond_state::UserState::Active => Some(crate::LibsessionUserState::Active),
+ sessiond_state::UserState::Closing => Some(crate::LibsessionUserState::Closing),
+ sessiond_state::UserState::Unknown => Some(crate::LibsessionUserState::Unknown),
+ }
}
fn get_display(&mut self, uid: u32) -> Option {
- // Only the daemon has the complete session list needed to find the display session
- let object = self
- .session_manager
- .as_ref()?
- .send_get_display_session_by_uid::(uid)?;
- self.sessions.push(Session::new(object.clone(), 0, 0, uid));
- let result = self
- .wait_session(&object)
- .map(|index| self.sessions[index].id.to_string());
- self.sessions.retain(|session| session.object != object);
- drop(object);
- result
+ todo!()
}
fn get_session_state(
&mut self,
session_id: &ffi::CStr,
) -> Option {
- let Ok(session_id) = session_id.to_string_lossy().parse::() else {
- return None;
- };
-
- if let Some(object) = self
- .sessions
- .iter()
- .find(|session| session.id == session_id)
- .map(|session| session.object.clone())
- {
- let index = self.wait_session(&object)?;
- return Some(match self.sessions[index].state {
- session_core_v1::ActiveState::Online => crate::LibsessionSessionState::Online,
- session_core_v1::ActiveState::Active => crate::LibsessionSessionState::Active,
- session_core_v1::ActiveState::Closing => crate::LibsessionSessionState::Closing,
- session_core_v1::ActiveState::Opening => crate::LibsessionSessionState::Opening,
- _ => crate::LibsessionSessionState::Unkown,
- });
+ let state = sessiond_state::try_read(&self.state_path).ok()?;
+ let session = state.sessions.get(session_id.to_str().ok()?)?;
+
+ match session.active {
+ sessiond_state::ActiveState::Online => Some(crate::LibsessionSessionState::Online),
+ sessiond_state::ActiveState::Closing => Some(crate::LibsessionSessionState::Closing),
+ sessiond_state::ActiveState::Opening => Some(crate::LibsessionSessionState::Opening),
+ sessiond_state::ActiveState::Active => Some(crate::LibsessionSessionState::Active),
+ sessiond_state::ActiveState::Unknown => Some(crate::LibsessionSessionState::Unkown),
}
- let object = self
- .session_manager
- .as_ref()?
- .send_get_session::(session_id)?;
- self.sessions
- .push(Session::new(object.clone(), session_id, 0, 0));
- self.wait_session(&object)
- .map(|index| match self.sessions[index].state {
- session_core_v1::ActiveState::Online => crate::LibsessionSessionState::Online,
- session_core_v1::ActiveState::Active => crate::LibsessionSessionState::Active,
- session_core_v1::ActiveState::Closing => crate::LibsessionSessionState::Closing,
- session_core_v1::ActiveState::Opening => crate::LibsessionSessionState::Opening,
- _ => crate::LibsessionSessionState::Unkown,
- })
}
fn is_local_session(&mut self, session_id: &ffi::CStr) -> Option {
- let Ok(session_id) = session_id.to_string_lossy().parse::() else {
- return None;
- };
+ let state = sessiond_state::try_read(&self.state_path).ok()?;
+ let session = state.sessions.get(session_id.to_str().ok()?)?;
- if let Some(object) = self
- .sessions
- .iter()
- .find(|session| session.id == session_id)
- .map(|session| session.object.clone())
- {
- let index = self.wait_session(&object)?;
- return Some(self.sessions[index].is_local);
- }
- let object = self
- .session_manager
- .as_ref()?
- .send_get_session::(session_id)?;
- self.sessions
- .push(Session::new(object.clone(), session_id, 0, 0));
- self.wait_session(&object)
- .map(|index| self.sessions[index].is_local)
+ Some(session.remote_host.is_some())
}
fn get_monitor(&mut self) -> Option> {
- Some(Box::new(super::inotify::InotifyMonitor::new(
- c"/run/sessiond",
+ Some(Box::new(inotify::InotifyMonitor::new(
+ ffi::CString::new(self.state_path.as_os_str().as_bytes())
+ .ok()?
+ .as_c_str(),
)?))
}
}
-
-hyprwire::delegate_noop!(Sessiond: ignore session_core_manager::SessionCoreManager);
diff --git a/libsession-sys/src/lib.rs b/libsession-sys/src/lib.rs
index cc44d7b..55fde63 100644
--- a/libsession-sys/src/lib.rs
+++ b/libsession-sys/src/lib.rs
@@ -37,6 +37,7 @@ pub enum LibsessionUserState {
Online = 2,
Active = 3,
Closing = 4,
+ Unknown = 5,
}
#[repr(C)]
diff --git a/sessionctl/Cargo.toml b/sessionctl/Cargo.toml
index 57ecf31..44d61e7 100644
--- a/sessionctl/Cargo.toml
+++ b/sessionctl/Cargo.toml
@@ -22,6 +22,7 @@ comfy-table = "7.2.2"
owo-colors = "4.3.0"
serde_json = "1.0.145"
termtree = "1.0.0"
+uzers = "0.12.2"
hyprwire = "0.5.1"
hyprwire-protocols-sessiond = { path = "../hyprwire-protocols-sessiond", version = "0.2.0" }
diff --git a/sessionctl/src/main.rs b/sessionctl/src/main.rs
index a171192..9c9f45d 100644
--- a/sessionctl/src/main.rs
+++ b/sessionctl/src/main.rs
@@ -21,6 +21,12 @@ use seat_core_v1::{seat_core_client, seat_core_device, seat_core_manager, seat_c
use serde_json::json;
use std::{collections::BTreeSet, env, ffi::OsString, fs, io, path, process, time};
+fn username(uid: u32) -> String {
+ uzers::get_user_by_uid(uid)
+ .map(|user| user.name().to_string_lossy().into_owned())
+ .unwrap_or_else(|| uid.to_string())
+}
+
struct Session {
object: Option,
id: u32,
@@ -516,8 +522,10 @@ impl hyprwire::Dispatch for State {
};
match event {
session_core_session::Event::SessionId { session_id } => s.id = session_id,
- session_core_session::Event::Uid { uid } => s.uid = uid,
- session_core_session::Event::Username { username } => s.username = username,
+ session_core_session::Event::Uid { uid } => {
+ s.uid = uid;
+ s.username = username(uid);
+ }
session_core_session::Event::Class { class } => s.class = class,
session_core_session::Event::Vt { vt } => s.vt = vt,
session_core_session::Event::Leader { leader } => s.leader = leader,
@@ -545,8 +553,10 @@ impl hyprwire::Dispatch for State {
return;
};
match event {
- session_core_user::Event::Uid { uid } => u.uid = uid,
- session_core_user::Event::Username { username } => u.username = username,
+ session_core_user::Event::Uid { uid } => {
+ u.uid = uid;
+ u.username = username(uid);
+ }
session_core_user::Event::Lingering { lingering } => u.lingering = lingering != 0,
session_core_user::Event::State { state } => u.state = state,
session_core_user::Event::CanModify { can_modify } => u.can_modify = can_modify != 0,
@@ -575,9 +585,9 @@ impl hyprwire::Dispatch for State
self.inhibitors[index].id = inhibitor_id;
}
session_core_inhibitor::Event::Who { who } => self.inhibitors[index].who = who,
- session_core_inhibitor::Event::Uid { uid } => self.inhibitors[index].uid = uid,
- session_core_inhibitor::Event::Username { username } => {
- self.inhibitors[index].username = username;
+ session_core_inhibitor::Event::Uid { uid } => {
+ self.inhibitors[index].uid = uid;
+ self.inhibitors[index].username = username(uid);
}
session_core_inhibitor::Event::Pid { pid } => self.inhibitors[index].pid = pid,
session_core_inhibitor::Event::Comm { comm } => self.inhibitors[index].comm = comm,
diff --git a/sessiond-state/Cargo.toml b/sessiond-state/Cargo.toml
new file mode 100644
index 0000000..9bd28c1
--- /dev/null
+++ b/sessiond-state/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "sessiond-state"
+version = "0.1.0"
+edition.workspace = true
+license = "MIT"
+repository.workspace = true
+description = "Shared sessiond state file types"
+
+[dependencies]
+serde = { version = "1.0.228", features = ["derive", "rc"] }
+thiserror = "2.0.21"
+toml = "1.1.2"
+
+[lints]
+workspace = true
diff --git a/sessiond-state/src/lib.rs b/sessiond-state/src/lib.rs
new file mode 100644
index 0000000..629d082
--- /dev/null
+++ b/sessiond-state/src/lib.rs
@@ -0,0 +1,105 @@
+use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
+use std::{fs, io, path, result, sync};
+use toml::{de, ser};
+
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum SessionClass {
+ #[default]
+ User,
+ Greeter,
+ LockScreen,
+ Background,
+ BackgroundLight,
+ Manager,
+ ManagerEarly,
+ #[serde(other)]
+ Unknown,
+}
+
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum ActiveState {
+ #[default]
+ Online,
+ Active,
+ Closing,
+ Opening,
+ #[serde(other)]
+ Unknown,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum UserState {
+ Offline,
+ Lingering,
+ Online,
+ Active,
+ Closing,
+ #[serde(other)]
+ Unknown,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct User {
+ pub state: UserState,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct State {
+ pub next_session_id: u32,
+ #[serde(default)]
+ pub users: BTreeMap,
+ #[serde(default)]
+ pub sessions: BTreeMap,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct Session {
+ pub uid: u32,
+ #[serde(default)]
+ pub class: SessionClass,
+ #[serde(default)]
+ pub vt: Option,
+ pub leader: i32,
+ #[serde(default)]
+ pub remote_host: Option>,
+ pub timestamp: u128,
+ #[serde(default)]
+ pub env: BTreeMap, sync::Arc>,
+ #[serde(default)]
+ pub active: ActiveState,
+ pub recoverable: bool,
+}
+
+pub type Result = result::Result;
+
+#[derive(Debug, thiserror::Error)]
+#[non_exhaustive]
+pub enum Error {
+ #[error("state file I/O failed: {0}")]
+ Io(#[from] io::Error),
+
+ #[error("invalid state file: {0}")]
+ Decode(#[from] de::Error),
+
+ #[error("failed to serialize state: {0}")]
+ Encode(#[from] ser::Error),
+}
+
+/// Reads session state from a TOML file.
+///
+/// # Errors
+///
+/// Returns an error if the file cannot be read as UTF-8 or its contents
+/// cannot be deserialized into [`State`].
+pub fn try_read(path: &path::Path) -> Result {
+ let state = fs::read_to_string(path)?;
+
+ Ok(toml::from_str::(&state)?)
+}
diff --git a/sessiond/Cargo.toml b/sessiond/Cargo.toml
index 84944a9..04be756 100644
--- a/sessiond/Cargo.toml
+++ b/sessiond/Cargo.toml
@@ -14,6 +14,7 @@ readme.workspace = true
workspace = true
[dependencies]
+sessiond-state = { path = "../sessiond-state", version = "0.1.0" }
anyhow = "1.0.102"
clap = { version = "4.6.1", features = ["derive"] }
env_logger = { version = "0.11.10", features = ["kv"] }
diff --git a/sessiond/src/cgroup.rs b/sessiond/src/cgroup.rs
index b40caa8..0ba2aa8 100644
--- a/sessiond/src/cgroup.rs
+++ b/sessiond/src/cgroup.rs
@@ -269,8 +269,6 @@ pub fn handle_cgroup_empty(
Entity,
&session::SessionId,
&session::Uid,
- &session::Gid,
- &session::Username,
&session::Objects,
),
With,
@@ -292,14 +290,13 @@ pub fn handle_cgroup_empty(
.get(&empty.uid.0)
.is_some_and(|&entity| lingering_users.contains(entity));
- if let Some((entity, session_id, uid, gid, username, objects)) = sessions
+ if let Some((entity, session_id, uid, objects)) = sessions
.iter()
- .find(|(_, id, _, _, _, _)| **id == empty.session_id)
+ .find(|(_, id, _, _)| **id == empty.session_id)
{
log::info!(
session_id = session_id.as_raw(),
- uid = uid.0,
- username = username.0;
+ uid = uid.0;
"session destroyed"
);
@@ -325,7 +322,7 @@ pub fn handle_cgroup_empty(
.users
.get(&sync::Arc::from(user.name().to_string_lossy()))
.unwrap_or(&default_config)
- .runtime_dir(uid.0, gid.0),
+ .runtime_dir(uid.0),
)
{
log::error!(uid = uid.0, error = e.to_string().as_str(); "failed to remove runtime dir");
diff --git a/sessiond/src/config.rs b/sessiond/src/config.rs
index 7489c21..9ba39fe 100644
--- a/sessiond/src/config.rs
+++ b/sessiond/src/config.rs
@@ -23,24 +23,22 @@ impl Default for UserConfig {
}
impl UserConfig {
- pub fn runtime_dir(&self, uid: u32, gid: u32) -> sync::Arc {
+ pub fn runtime_dir(&self, uid: u32) -> sync::Arc {
self.runtime_dir
.replace(concat!("{", "uid", "}"), &uid.to_string())
- .replace(concat!("{", "gid", "}"), &gid.to_string())
.into()
}
pub fn environment(
&self,
uid: u32,
- gid: u32,
session_id: u32,
term: Option>,
sessiond_runtime_dir: sync::Arc,
) -> BTreeMap, sync::Arc> {
#[cfg(feature = "consolekit")]
let _ = session_id;
- let runtime_dir = self.runtime_dir(uid, gid);
+ let runtime_dir = self.runtime_dir(uid);
let mut env: BTreeMap, sync::Arc> = BTreeMap::from([
(sync::Arc::from("XDG_RUNTIME_DIR"), runtime_dir),
#[cfg(not(feature = "consolekit"))]
diff --git a/sessiond/src/inhibit.rs b/sessiond/src/inhibit.rs
index 73a28f2..6a7a045 100644
--- a/sessiond/src/inhibit.rs
+++ b/sessiond/src/inhibit.rs
@@ -79,9 +79,6 @@ pub struct What(pub(crate) u32);
#[derive(Component, Debug, Clone, Copy)]
pub struct Uid(pub(crate) u32);
-#[derive(Component, Debug)]
-pub struct Username(pub(crate) String);
-
#[derive(Component, Debug, Clone, Copy)]
pub struct Pid(pub(crate) u32);
@@ -99,7 +96,6 @@ pub struct InhibitorBundle {
pub who: Who,
pub why: Why,
pub uid: Uid,
- pub username: Username,
pub pid: Pid,
pub comm: Comm,
pub mode: Mode,
@@ -177,9 +173,6 @@ impl hyprwire::Dispatch for crat
let creds = *object.client().creds();
let uid = creds.uid.as_raw();
let pid = creds.pid.as_raw_pid().cast_unsigned();
- let username = uzers::get_user_by_uid(uid)
- .map(|user| user.name().to_string_lossy().into_owned())
- .unwrap_or_default();
let comm = fs::read_to_string(format!("/proc/{pid}/comm"))
.map(|comm| comm.trim().to_owned())
.unwrap_or_default();
@@ -192,7 +185,6 @@ impl hyprwire::Dispatch for crat
who: Who(who),
why: Why(why),
uid: Uid(uid),
- username: Username(username),
pid: Pid(pid),
comm: Comm(comm),
mode: Mode(mode),
@@ -292,7 +284,6 @@ pub fn handle_add_object(
&Who,
&Why,
&Uid,
- &Username,
&Pid,
&Comm,
&Mode,
@@ -302,9 +293,9 @@ pub fn handle_add_object(
>,
) {
for request in requests.read() {
- let Some((id, what, who, why, uid, username, pid, comm, mode, mut objects)) = inhibitors
+ let Some((id, what, who, why, uid, pid, comm, mode, mut objects)) = inhibitors
.iter_mut()
- .find(|(id, _, _, _, _, _, _, _, _, _)| **id == request.inhibitor_id)
+ .find(|(id, _, _, _, _, _, _, _, _)| **id == request.inhibitor_id)
else {
request.object.send_active(0);
request.object.send_destroyed();
@@ -314,7 +305,6 @@ pub fn handle_add_object(
request.object.send_inhibitor_id(id.as_raw());
request.object.send_who(&who.0);
request.object.send_uid(uid.0);
- request.object.send_username(&username.0);
request.object.send_pid(pid.0);
request.object.send_comm(&comm.0);
request.object.send_what(what.0);
diff --git a/sessiond/src/session.rs b/sessiond/src/session.rs
index d427db4..e9d1627 100644
--- a/sessiond/src/session.rs
+++ b/sessiond/src/session.rs
@@ -92,7 +92,6 @@ impl SessionManagementTarget {
pub struct PendingSession {
pub manager: Option,
pub uid: u32,
- pub gid: u32,
pub class: Option,
pub vt: Option,
pub remote_host: Option>,
@@ -153,8 +152,6 @@ pub struct SessionBundle {
pub id: SessionId,
pub class: SessionClass,
pub uid: Uid,
- pub gid: Gid,
- pub username: Username,
pub timestamp: Timestamp,
pub leader_id: LeaderId,
pub env: SessionEnv,
@@ -177,12 +174,6 @@ pub struct IsLocal;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)]
pub struct Uid(pub u32);
-#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Gid(pub u32);
-
-#[derive(Component, Debug, Clone, PartialEq, Eq)]
-pub struct Username(pub sync::Arc);
-
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)]
pub struct Vt(pub num::NonZeroU32);
@@ -271,8 +262,6 @@ pub fn spawn(
session_id: SessionId,
class: SessionClass,
uid: u32,
- gid: u32,
- username: sync::Arc,
vt: Option,
leader_id: i32,
remote_host: Option>,
@@ -288,8 +277,6 @@ pub fn spawn(
id: session_id,
class,
uid: Uid(uid),
- gid: Gid(gid),
- username: Username(username),
timestamp: Timestamp(time::SystemTime::now()),
leader_id: LeaderId(leader_id),
env: SessionEnv(env),
@@ -535,7 +522,6 @@ pub fn handle_add_object(
Entity,
&SessionId,
&Uid,
- &Username,
Option<&Vt>,
&SessionClass,
&ActiveState,
@@ -554,7 +540,6 @@ pub fn handle_add_object(
entity,
session_id,
uid,
- username,
vt,
class,
state,
@@ -565,9 +550,7 @@ pub fn handle_add_object(
mut objects,
)) = sessions
.iter_mut()
- .find(|(_, session_id, _, _, _, _, _, _, _, _, _, _)| {
- **session_id == request.session_id
- })
+ .find(|(_, session_id, _, _, _, _, _, _, _, _, _)| **session_id == request.session_id)
else {
log::warn!(session_id = request.session_id.as_raw(); "get_session_by_pid requested for unknown session");
request.object.send_destroyed();
@@ -577,7 +560,6 @@ pub fn handle_add_object(
log::debug!(session_id = request.session_id.as_raw(), uid = request.object.client().creds().uid.as_raw(); "session info requested");
request.object.send_session_id(session_id.as_raw());
request.object.send_uid(uid.0);
- request.object.send_username(&username.0);
request.object.send_class((*class).into());
request.object.send_vt(vt.map_or(0, |vt| vt.0.get()));
request.object.send_active(state.0);
@@ -801,21 +783,18 @@ pub fn handle_session_management_action(
uid,
leader_id,
} => {
- if let Some(user) = uzers::get_user_by_uid(*uid) {
- pending_sessions.by_management_object.insert(
- object.clone(),
- PendingSession {
- manager: management_object.clone(),
- uid: *uid,
- gid: user.primary_group_id(),
- class: None,
- vt: None,
- remote_host: None,
- env: BTreeMap::new(),
- leader_id: *leader_id,
- },
- );
- }
+ pending_sessions.by_management_object.insert(
+ object.clone(),
+ PendingSession {
+ manager: management_object.clone(),
+ uid: *uid,
+ class: None,
+ vt: None,
+ remote_host: None,
+ env: BTreeMap::new(),
+ leader_id: *leader_id,
+ },
+ );
continue;
}
SessionManagementAction::Env { key, value } => {
@@ -858,7 +837,7 @@ pub fn handle_session_management_action(
);
return;
};
- let username = user.name().to_string_lossy().into();
+ let username: sync::Arc = user.name().to_string_lossy().into();
let session_id = next_id.take();
@@ -894,7 +873,7 @@ pub fn handle_session_management_action(
let user_config = config.users.get(&username).cloned().unwrap_or_default();
user::create_runtime_dir(
pending_session.uid,
- &user_config.runtime_dir(pending_session.uid, pending_session.gid),
+ &user_config.runtime_dir(pending_session.uid),
);
let is_local = pending_session.remote_host.is_none();
@@ -910,7 +889,6 @@ pub fn handle_session_management_action(
let term = pending_session.env.get("TERM").cloned();
let mut env = user_config.environment(
pending_session.uid,
- pending_session.gid,
session_id.as_raw(),
term,
sync::Arc::clone(&sessiond_runtime_dir.0),
@@ -929,8 +907,6 @@ pub fn handle_session_management_action(
session_id,
pending_session.class.unwrap_or_default(),
pending_session.uid,
- pending_session.gid,
- username,
pending_session.vt.map(num::NonZeroU32::get),
pending_session.leader_id,
pending_session.remote_host,
diff --git a/sessiond/src/state.rs b/sessiond/src/state.rs
index 9074d4a..385b47d 100644
--- a/sessiond/src/state.rs
+++ b/sessiond/src/state.rs
@@ -1,66 +1,41 @@
use crate::{cgroup, config, session, user};
-use anyhow::Context;
use bevy_ecs::prelude::*;
use hyprwire_protocols_sessiond::server::session_core::v1::session_core_v1;
-use serde::{Deserialize, Serialize};
-use std::collections::BTreeMap;
+use sessiond_state::{ActiveState, Session, SessionClass, State, UserState};
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
use std::{fs, path, sync, time};
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-pub struct State {
- pub next_session_id: u32,
- #[serde(default)]
- pub sessions: BTreeMap,
+trait SessionExt {
+ fn class(&self) -> session::SessionClass;
+ fn timestamp(&self) -> time::SystemTime;
+ fn active_state(&self) -> session_core_v1::ActiveState;
}
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-pub struct Session {
- pub uid: u32,
- pub gid: u32,
- pub username: sync::Arc,
- #[serde(default)]
- pub class: String,
- #[serde(default)]
- pub vt: Option,
- pub leader: i32,
- #[serde(default)]
- pub remote_host: Option>,
- pub timestamp: u128,
- #[serde(default)]
- pub env: BTreeMap, sync::Arc>,
- #[serde(default)]
- pub active: String,
- pub recoverable: bool,
-}
-
-impl Session {
- pub fn class(&self) -> session::SessionClass {
- match self.class.as_str() {
- "greeter" => session::SessionClass::Greeter,
- "lock-screen" => session::SessionClass::LockScreen,
- "background" => session::SessionClass::Background,
- "background-light" => session::SessionClass::BackgroundLight,
- "manager" => session::SessionClass::Manager,
- "manager-early" => session::SessionClass::ManagerEarly,
- _ => session::SessionClass::User,
+impl SessionExt for Session {
+ fn class(&self) -> session::SessionClass {
+ match self.class {
+ SessionClass::Greeter => session::SessionClass::Greeter,
+ SessionClass::LockScreen => session::SessionClass::LockScreen,
+ SessionClass::Background => session::SessionClass::Background,
+ SessionClass::BackgroundLight => session::SessionClass::BackgroundLight,
+ SessionClass::Manager => session::SessionClass::Manager,
+ SessionClass::ManagerEarly => session::SessionClass::ManagerEarly,
+ SessionClass::User | SessionClass::Unknown => session::SessionClass::User,
}
}
- pub fn timestamp(&self) -> time::SystemTime {
+ fn timestamp(&self) -> time::SystemTime {
time::UNIX_EPOCH
+ time::Duration::from_micros(u64::try_from(self.timestamp).unwrap_or(u64::MAX))
}
- pub fn active_state(&self) -> session_core_v1::ActiveState {
- match self.active.as_str() {
- "active" => session_core_v1::ActiveState::Active,
- "closing" => session_core_v1::ActiveState::Closing,
- "opening" => session_core_v1::ActiveState::Opening,
- _ => session_core_v1::ActiveState::Online,
+ fn active_state(&self) -> session_core_v1::ActiveState {
+ match self.active {
+ ActiveState::Active => session_core_v1::ActiveState::Active,
+ ActiveState::Closing => session_core_v1::ActiveState::Closing,
+ ActiveState::Opening => session_core_v1::ActiveState::Opening,
+ ActiveState::Online | ActiveState::Unknown => session_core_v1::ActiveState::Online,
}
}
}
@@ -74,8 +49,6 @@ pub fn write_state(
(
&session::SessionId,
&session::Uid,
- &session::Gid,
- &session::Username,
&session::SessionClass,
Option<&session::Vt>,
&session::LeaderId,
@@ -94,8 +67,6 @@ pub fn write_state(
Or<(
Added,
Changed,
- Changed,
- Changed,
Changed,
Changed,
Changed,
@@ -108,8 +79,26 @@ pub fn write_state(
>,
removed: RemovedComponents,
next_session_id: Res,
+ users: Query<(&session::Uid, &user::UserState), With>,
+ changed_users: Query<
+ Entity,
+ (
+ With,
+ Or<(
+ Added,
+ Changed,
+ Changed,
+ )>,
+ ),
+ >,
+ removed_users: RemovedComponents,
) {
- if changed.is_empty() && removed.is_empty() && !next_session_id.is_changed() {
+ if changed.is_empty()
+ && removed.is_empty()
+ && !next_session_id.is_changed()
+ && changed_users.is_empty()
+ && removed_users.is_empty()
+ {
return;
}
@@ -119,8 +108,6 @@ pub fn write_state(
|(
id,
uid,
- gid,
- username,
class,
vt,
leader,
@@ -136,28 +123,26 @@ pub fn write_state(
.unwrap_or_default()
.as_micros();
let class = match class {
- session::SessionClass::User => "user",
- session::SessionClass::Greeter => "greeter",
- session::SessionClass::LockScreen => "lock-screen",
- session::SessionClass::Background => "background",
- session::SessionClass::BackgroundLight => "background-light",
- session::SessionClass::Manager => "manager",
- session::SessionClass::ManagerEarly => "manager-early",
+ session::SessionClass::User => SessionClass::User,
+ session::SessionClass::Greeter => SessionClass::Greeter,
+ session::SessionClass::LockScreen => SessionClass::LockScreen,
+ session::SessionClass::Background => SessionClass::Background,
+ session::SessionClass::BackgroundLight => SessionClass::BackgroundLight,
+ session::SessionClass::Manager => SessionClass::Manager,
+ session::SessionClass::ManagerEarly => SessionClass::ManagerEarly,
};
let active = match active_state.0 {
- session_core_v1::ActiveState::Active => "active",
- session_core_v1::ActiveState::Closing => "closing",
- session_core_v1::ActiveState::Opening => "opening",
- _ => "online",
+ session_core_v1::ActiveState::Active => ActiveState::Active,
+ session_core_v1::ActiveState::Closing => ActiveState::Closing,
+ session_core_v1::ActiveState::Opening => ActiveState::Opening,
+ _ => ActiveState::Online,
};
(
id.as_raw().to_string(),
Session {
uid: uid.0,
- gid: gid.0,
- username: sync::Arc::clone(&username.0),
- class: class.to_owned(),
+ class,
vt: vt.map(|vt| vt.0.get()),
leader: leader.0,
remote_host: remote_host.map(|host| sync::Arc::clone(&host.0)),
@@ -167,7 +152,7 @@ pub fn write_state(
.iter()
.map(|(name, value)| (sync::Arc::clone(name), sync::Arc::clone(value)))
.collect(),
- active: active.to_owned(),
+ active,
recoverable: recoverable.is_some(),
},
)
@@ -177,6 +162,20 @@ pub fn write_state(
let state = State {
next_session_id: next_session_id.0.as_raw(),
+ users: users
+ .iter()
+ .map(|(uid, state)| {
+ let state = match state.0 {
+ session_core_v1::UserState::Active => UserState::Active,
+ session_core_v1::UserState::Closing => UserState::Closing,
+ session_core_v1::UserState::Lingering => UserState::Lingering,
+ session_core_v1::UserState::Online => UserState::Online,
+ session_core_v1::UserState::Offline => UserState::Offline,
+ _ => UserState::Unknown,
+ };
+ (uid.0, sessiond_state::User { state })
+ })
+ .collect(),
sessions,
};
@@ -185,23 +184,12 @@ pub fn write_state(
}
}
-impl State {
- pub fn load(path: &path::Path) -> anyhow::Result {
- let state = fs::read_to_string(path)
- .with_context(|| format!("failed to read state file: {}", path.display()))?;
-
- toml::from_str::(&state)
- .inspect_err(|err| {
- log::error!(
- path = path.to_string_lossy().as_ref(),
- error = err.to_string().as_str();
- "failed to parse config file"
- );
- })
- .with_context(|| format!("failed to parse staet file {}", path.display()))
- }
+trait StateExt: Sized {
+ fn write(&self, path: &path::Path) -> anyhow::Result<()>;
+}
- pub fn write(&self, path: &path::Path) -> anyhow::Result<()> {
+impl StateExt for State {
+ fn write(&self, path: &path::Path) -> anyhow::Result<()> {
let mut temp_path = path.as_os_str().to_os_string();
temp_path.push("~");
@@ -228,7 +216,7 @@ pub fn load_state(
loop_handle: NonSend<'_, calloop::LoopHandle<'static, crate::Sessiond>>,
) {
if state_writer.0.exists() {
- match State::load(&state_writer.0) {
+ match sessiond_state::try_read(&state_writer.0) {
Ok(saved_state) => {
next_session_id.0 = session::SessionId::from_raw(saved_state.next_session_id);
@@ -243,6 +231,13 @@ pub fn load_state(
};
let session_id = session::SessionId::from_raw(raw_id);
+ let Some(user) = uzers::get_user_by_uid(saved_session.uid) else {
+ log::warn!(session_id = raw_id, uid = saved_session.uid; "ignoring session whose user no longer exists");
+ continue;
+ };
+ let username: sync::Arc =
+ user.name().to_string_lossy().into_owned().into();
+
let cgroup = match cgroup_manager
.restore_session_cgroup(saved_session.uid, session_id)
{
@@ -264,10 +259,10 @@ pub fn load_state(
let runtime_dir = config
.users
- .get(&saved_session.username)
+ .get(&username)
.cloned()
.unwrap_or_default()
- .runtime_dir(saved_session.uid, saved_session.gid);
+ .runtime_dir(saved_session.uid);
user::create_runtime_dir(saved_session.uid, &runtime_dir);
let active_state = saved_session.active_state();
@@ -277,8 +272,6 @@ pub fn load_state(
session_id,
saved_session.class(),
saved_session.uid,
- saved_session.gid,
- sync::Arc::clone(&saved_session.username),
saved_session.vt,
saved_session.leader,
saved_session.remote_host.as_ref().map(sync::Arc::clone),
diff --git a/sessiond/src/user.rs b/sessiond/src/user.rs
index 7992b8e..d56168d 100644
--- a/sessiond/src/user.rs
+++ b/sessiond/src/user.rs
@@ -3,7 +3,7 @@ use bevy_ecs::prelude::*;
use hyprwire_protocols_sessiond::server::session_core::v1::session_core_v1;
use hyprwire_protocols_sessiond::server::session_core::v1::session_core_v1::session_core_user;
use std::collections::HashMap;
-use std::{fs, io, sync};
+use std::{fs, io};
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq)]
pub struct UserState(pub session_core_v1::UserState);
@@ -32,7 +32,6 @@ pub struct UserRegistry {
pub struct UserBundle {
pub marker: User,
pub uid: session::Uid,
- pub username: session::Username,
pub state: UserState,
pub objects: Objects,
}
@@ -49,7 +48,6 @@ pub struct Objects(pub Vec);
pub fn spawn(
commands: &mut Commands,
uid: u32,
- username: sync::Arc,
lingering: bool,
state: UserState,
user_registry: &mut ResMut,
@@ -58,7 +56,6 @@ pub fn spawn(
let mut cmd = commands.spawn(UserBundle {
marker: User,
uid: session::Uid(uid),
- username: session::Username(username),
state,
objects: Objects::default(),
});
@@ -98,13 +95,13 @@ pub fn remove_runtime_dir(path: &str) -> io::Result<()> {
pub fn ensure_session_users(
mut commands: Commands,
sessions: Query<
- (&session::Uid, &session::Username, &session::ActiveState),
+ (&session::Uid, &session::ActiveState),
(With, Added),
>,
mut user_registry: ResMut,
info_managers: Res,
) {
- for (uid, username, session_state) in sessions {
+ for (uid, session_state) in sessions {
if user_registry.by_uid.contains_key(&uid.0) {
continue;
}
@@ -118,7 +115,6 @@ pub fn ensure_session_users(
spawn(
&mut commands,
uid.0,
- sync::Arc::clone(&username.0),
false,
state,
&mut user_registry,
@@ -182,7 +178,6 @@ pub fn handle_add_object(
(
Entity,
&session::Uid,
- &session::Username,
Option<&Lingering>,
&UserState,
&mut Objects,
@@ -192,9 +187,9 @@ pub fn handle_add_object(
mut user_registry: ResMut,
) {
for request in requests.read() {
- let Some((entity, uid, username, lingering, state, mut objects)) = users
+ let Some((entity, uid, lingering, state, mut objects)) = users
.iter_mut()
- .find(|(_, uid, _, _, _, _)| uid.0 == request.uid)
+ .find(|(_, uid, _, _, _)| uid.0 == request.uid)
else {
log::warn!(uid = request.uid; "get_user requested for unknown user");
request.object.send_not_found();
@@ -202,7 +197,6 @@ pub fn handle_add_object(
};
request.object.send_uid(uid.0);
- request.object.send_username(&username.0);
if lingering.is_some() {
request.object.send_lingering(1);
} else {
@@ -364,34 +358,26 @@ pub fn initialize_lingering_users(
.filter(|(_, config)| config.linger)
.filter_map(|(name, config)| {
let user = uzers::get_user_by_name(name.as_ref())?;
- Some((
- user.uid(),
- config.runtime_dir(user.uid(), user.primary_group_id()),
- ))
+ Some((user.uid(), config.runtime_dir(user.uid())))
})
.collect::>();
for (uid, runtime_dir) in lingering_users {
- if let Some(user) = uzers::get_user_by_uid(uid) {
- spawn(
- &mut commands,
+ spawn(
+ &mut commands,
+ uid,
+ true,
+ UserState::LINGERING,
+ &mut user_registry,
+ &info_managers,
+ );
+
+ create_runtime_dir(uid, &runtime_dir);
+ if let Err(e) = cgroup_manager.ensure_user_cgroup(uid) {
+ log::error!(
uid,
- user.name().to_string_lossy().into(),
- true,
- UserState::LINGERING,
- &mut user_registry,
- &info_managers,
+ error = e.to_string().as_str();
+ "failed to create user cgroup"
);
-
- create_runtime_dir(uid, &runtime_dir);
- if let Err(e) = cgroup_manager.ensure_user_cgroup(uid) {
- log::error!(
- uid,
- error = e.to_string().as_str();
- "failed to create user cgroup"
- );
- }
- } else {
- log::warn!(uid; "configured lingering user no longer exists");
}
}
}