Advance redbear-full Wayland, greeter, and Qt integration
Consolidate the active desktop path around redbear-full while landing the greeter/session stack and the runtime fixes needed to keep Wayland and KWin bring-up moving forward.
This commit is contained in:
@@ -11,5 +11,6 @@ path = "src/main.rs"
|
||||
zbus = { version = "5", default-features = false, features = ["tokio"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
libredox = "0.1"
|
||||
redox-syscall = { package = "redox_syscall", version = "0.7" }
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
use std::{
|
||||
fs,
|
||||
io::{BufRead, BufReader},
|
||||
os::unix::{fs::PermissionsExt, net::UnixListener},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::runtime_state::SharedRuntime;
|
||||
|
||||
pub const CONTROL_SOCKET_PATH: &str = "/run/redbear-sessiond-control.sock";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
enum ControlMessage {
|
||||
SetSession {
|
||||
username: String,
|
||||
uid: u32,
|
||||
vt: u32,
|
||||
leader: u32,
|
||||
state: String,
|
||||
},
|
||||
ResetSession {
|
||||
vt: u32,
|
||||
},
|
||||
}
|
||||
|
||||
fn apply_message(runtime: &SharedRuntime, message: ControlMessage) {
|
||||
let Ok(mut runtime) = runtime.write() else {
|
||||
eprintln!("redbear-sessiond: runtime state is poisoned");
|
||||
return;
|
||||
};
|
||||
|
||||
match message {
|
||||
ControlMessage::SetSession {
|
||||
username,
|
||||
uid,
|
||||
vt,
|
||||
leader,
|
||||
state,
|
||||
} => {
|
||||
runtime.username = username;
|
||||
runtime.uid = uid;
|
||||
runtime.vt = vt;
|
||||
runtime.leader = leader;
|
||||
runtime.state = state;
|
||||
runtime.active = true;
|
||||
}
|
||||
ControlMessage::ResetSession { vt } => {
|
||||
runtime.username = String::from("root");
|
||||
runtime.uid = 0;
|
||||
runtime.vt = vt;
|
||||
runtime.leader = std::process::id();
|
||||
runtime.state = String::from("closing");
|
||||
runtime.active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_control_socket(runtime: SharedRuntime) {
|
||||
std::thread::spawn(move || {
|
||||
if Path::new(CONTROL_SOCKET_PATH).exists() {
|
||||
if let Err(err) = fs::remove_file(CONTROL_SOCKET_PATH) {
|
||||
eprintln!("redbear-sessiond: failed to remove stale control socket: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let listener = match UnixListener::bind(CONTROL_SOCKET_PATH) {
|
||||
Ok(listener) => listener,
|
||||
Err(err) => {
|
||||
eprintln!("redbear-sessiond: failed to bind control socket: {err}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = fs::set_permissions(CONTROL_SOCKET_PATH, fs::Permissions::from_mode(0o600)) {
|
||||
eprintln!("redbear-sessiond: failed to chmod control socket: {err}");
|
||||
}
|
||||
|
||||
for stream in listener.incoming() {
|
||||
let Ok(stream) = stream else {
|
||||
continue;
|
||||
};
|
||||
let mut reader = BufReader::new(stream);
|
||||
let mut line = String::new();
|
||||
if reader.read_line(&mut line).is_err() {
|
||||
continue;
|
||||
}
|
||||
match serde_json::from_str::<ControlMessage>(line.trim()) {
|
||||
Ok(message) => apply_message(&runtime, message),
|
||||
Err(err) => eprintln!("redbear-sessiond: invalid control message: {err}"),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::runtime_state::shared_runtime;
|
||||
|
||||
#[test]
|
||||
fn set_session_message_updates_runtime_state() {
|
||||
let runtime = shared_runtime();
|
||||
|
||||
apply_message(
|
||||
&runtime,
|
||||
ControlMessage::SetSession {
|
||||
username: String::from("user"),
|
||||
uid: 1000,
|
||||
vt: 7,
|
||||
leader: 4242,
|
||||
state: String::from("active"),
|
||||
},
|
||||
);
|
||||
|
||||
let runtime = runtime.read().expect("runtime lock should remain healthy");
|
||||
assert_eq!(runtime.username, "user");
|
||||
assert_eq!(runtime.uid, 1000);
|
||||
assert_eq!(runtime.vt, 7);
|
||||
assert_eq!(runtime.leader, 4242);
|
||||
assert_eq!(runtime.state, "active");
|
||||
assert!(runtime.active);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_session_message_restores_root_scaffold() {
|
||||
let runtime = shared_runtime();
|
||||
|
||||
apply_message(
|
||||
&runtime,
|
||||
ControlMessage::SetSession {
|
||||
username: String::from("user"),
|
||||
uid: 1000,
|
||||
vt: 7,
|
||||
leader: 4242,
|
||||
state: String::from("active"),
|
||||
},
|
||||
);
|
||||
apply_message(&runtime, ControlMessage::ResetSession { vt: 3 });
|
||||
|
||||
let runtime = runtime.read().expect("runtime lock should remain healthy");
|
||||
assert_eq!(runtime.username, "root");
|
||||
assert_eq!(runtime.uid, 0);
|
||||
assert_eq!(runtime.vt, 3);
|
||||
assert_eq!(runtime.state, "closing");
|
||||
assert!(runtime.active);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn control_message_json_matches_expected_shape() {
|
||||
let message = serde_json::from_str::<ControlMessage>(
|
||||
r#"{"type":"set_session","username":"user","uid":1000,"vt":3,"leader":99,"state":"online"}"#,
|
||||
)
|
||||
.expect("control message json should parse");
|
||||
|
||||
match message {
|
||||
ControlMessage::SetSession {
|
||||
username,
|
||||
uid,
|
||||
vt,
|
||||
leader,
|
||||
state,
|
||||
} => {
|
||||
assert_eq!(username, "user");
|
||||
assert_eq!(uid, 1000);
|
||||
assert_eq!(vt, 3);
|
||||
assert_eq!(leader, 99);
|
||||
assert_eq!(state, "online");
|
||||
}
|
||||
ControlMessage::ResetSession { .. } => panic!("expected set_session message"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
use std::{collections::HashMap, fs::File, io};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{self, File, OpenOptions},
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeviceMap {
|
||||
@@ -28,13 +36,11 @@ impl DeviceMap {
|
||||
return Some(path.clone());
|
||||
}
|
||||
|
||||
match (major, minor) {
|
||||
(13, minor) if minor >= 68 => Some(format!("/dev/input/event{}", minor - 64)),
|
||||
_ => None,
|
||||
}
|
||||
self.find_dynamic_path(major, minor)
|
||||
.or_else(|| self.fallback_path(major, minor))
|
||||
}
|
||||
|
||||
pub fn open_device(&self, major: u32, minor: u32) -> io::Result<File> {
|
||||
pub fn open_device(&self, major: u32, minor: u32) -> io::Result<(String, File)> {
|
||||
let Some(path) = self.resolve(major, minor) else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
@@ -42,6 +48,118 @@ impl DeviceMap {
|
||||
));
|
||||
};
|
||||
|
||||
File::open(path)
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(&path)
|
||||
.or_else(|_| OpenOptions::new().read(true).open(&path))
|
||||
.or_else(|_| OpenOptions::new().write(true).open(&path))?;
|
||||
|
||||
Ok((path, file))
|
||||
}
|
||||
|
||||
fn fallback_path(&self, major: u32, minor: u32) -> Option<String> {
|
||||
match (major, minor) {
|
||||
(13, minor) if minor >= 64 => {
|
||||
let path = format!("/dev/input/event{}", minor - 64);
|
||||
Path::new(&path).exists().then_some(path)
|
||||
}
|
||||
(226, minor) => {
|
||||
let path = format!("/scheme/drm/card{minor}");
|
||||
Path::new(&path).exists().then_some(path)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_dynamic_path(&self, major: u32, minor: u32) -> Option<String> {
|
||||
for path in candidate_paths() {
|
||||
if path_matches_device(&path, major, minor) {
|
||||
return Some(path.to_string_lossy().into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn candidate_paths() -> Vec<PathBuf> {
|
||||
let mut paths = Vec::new();
|
||||
|
||||
paths.extend(read_dir_paths("/dev/input", |name| name.starts_with("event")));
|
||||
paths.extend(read_dir_paths("/scheme/drm", |name| name.starts_with("card")));
|
||||
|
||||
for direct in ["/dev/fb0", "/scheme/null", "/scheme/zero", "/scheme/rand"] {
|
||||
let path = PathBuf::from(direct);
|
||||
if path.exists() {
|
||||
paths.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
paths
|
||||
}
|
||||
|
||||
fn read_dir_paths(dir: &str, include: impl Fn(&str) -> bool) -> Vec<PathBuf> {
|
||||
let mut paths = Vec::new();
|
||||
let Ok(entries) = fs::read_dir(dir) else {
|
||||
return paths;
|
||||
};
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
let Some(name) = path.file_name().and_then(|name| name.to_str()) else {
|
||||
continue;
|
||||
};
|
||||
if include(name) {
|
||||
paths.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
paths.sort();
|
||||
paths
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn path_matches_device(path: &Path, major: u32, minor: u32) -> bool {
|
||||
let Ok(metadata) = fs::metadata(path) else {
|
||||
return false;
|
||||
};
|
||||
let rdev = metadata.rdev();
|
||||
dev_major(rdev) == major && dev_minor(rdev) == minor
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn path_matches_device(_path: &Path, _major: u32, _minor: u32) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn dev_major(device: u64) -> u32 {
|
||||
(((device >> 31 >> 1) & 0xfffff000) | ((device >> 8) & 0x00000fff)) as u32
|
||||
}
|
||||
|
||||
fn dev_minor(device: u64) -> u32 {
|
||||
(((device >> 12) & 0xffffff00) | (device & 0x000000ff)) as u32
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{dev_major, dev_minor};
|
||||
|
||||
fn make_dev(major: u64, minor: u64) -> u64 {
|
||||
((major & 0xfffff000) << 32)
|
||||
| ((major & 0x00000fff) << 8)
|
||||
| ((minor & 0xffffff00) << 12)
|
||||
| (minor & 0x000000ff)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn splits_compound_dev_numbers() {
|
||||
let device = make_dev(226, 3);
|
||||
assert_eq!(dev_major(device), 226);
|
||||
assert_eq!(dev_minor(device), 3);
|
||||
|
||||
let event = make_dev(13, 67);
|
||||
assert_eq!(dev_major(event), 13);
|
||||
assert_eq!(dev_minor(event), 67);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
mod acpi_watcher;
|
||||
mod control;
|
||||
mod device_map;
|
||||
mod manager;
|
||||
mod runtime_state;
|
||||
mod seat;
|
||||
mod session;
|
||||
|
||||
@@ -15,6 +17,7 @@ use device_map::DeviceMap;
|
||||
use manager::LoginManager;
|
||||
use seat::LoginSeat;
|
||||
use session::LoginSession;
|
||||
use runtime_state::shared_runtime;
|
||||
use tokio::runtime::Builder as RuntimeBuilder;
|
||||
use zbus::{
|
||||
Address,
|
||||
@@ -26,7 +29,7 @@ const BUS_NAME: &str = "org.freedesktop.login1";
|
||||
const MANAGER_PATH: &str = "/org/freedesktop/login1";
|
||||
const SESSION_PATH: &str = "/org/freedesktop/login1/session/c1";
|
||||
const SEAT_PATH: &str = "/org/freedesktop/login1/seat/seat0";
|
||||
const USER_PATH: &str = "/org/freedesktop/login1/user/0";
|
||||
const USER_PATH: &str = "/org/freedesktop/login1/user/current";
|
||||
|
||||
enum Command {
|
||||
Run,
|
||||
@@ -113,10 +116,11 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||
let session_path = parse_object_path(SESSION_PATH)?;
|
||||
let seat_path = parse_object_path(SEAT_PATH)?;
|
||||
let user_path = parse_object_path(USER_PATH)?;
|
||||
let runtime = shared_runtime();
|
||||
|
||||
let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new());
|
||||
let seat = LoginSeat::new(session_path.clone());
|
||||
let manager = LoginManager::new(session_path, seat_path);
|
||||
let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new(), runtime.clone());
|
||||
let seat = LoginSeat::new(session_path.clone(), runtime.clone());
|
||||
let manager = LoginManager::new(session_path, seat_path, runtime.clone());
|
||||
|
||||
match system_connection_builder()?
|
||||
.name(BUS_NAME)?
|
||||
@@ -128,6 +132,7 @@ async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||
{
|
||||
Ok(connection) => {
|
||||
eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus");
|
||||
control::start_control_socket(runtime.clone());
|
||||
tokio::spawn(acpi_watcher::watch_and_emit(connection.clone()));
|
||||
wait_for_shutdown().await?;
|
||||
drop(connection);
|
||||
|
||||
@@ -5,20 +5,20 @@ use zbus::{
|
||||
zvariant::OwnedObjectPath,
|
||||
};
|
||||
|
||||
use crate::runtime_state::SharedRuntime;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LoginManager {
|
||||
session_id: String,
|
||||
runtime: SharedRuntime,
|
||||
session_path: OwnedObjectPath,
|
||||
seat_id: String,
|
||||
seat_path: OwnedObjectPath,
|
||||
}
|
||||
|
||||
impl LoginManager {
|
||||
pub fn new(session_path: OwnedObjectPath, seat_path: OwnedObjectPath) -> Self {
|
||||
pub fn new(session_path: OwnedObjectPath, seat_path: OwnedObjectPath, runtime: SharedRuntime) -> Self {
|
||||
Self {
|
||||
session_id: String::from("c1"),
|
||||
runtime,
|
||||
session_path,
|
||||
seat_id: String::from("seat0"),
|
||||
seat_path,
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,11 @@ impl LoginManager {
|
||||
#[interface(name = "org.freedesktop.login1.Manager")]
|
||||
impl LoginManager {
|
||||
fn get_session(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||
if id == self.session_id {
|
||||
let runtime = self
|
||||
.runtime
|
||||
.read()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
||||
if id == runtime.session_id {
|
||||
return Ok(self.session_path.clone());
|
||||
}
|
||||
|
||||
@@ -35,17 +39,25 @@ impl LoginManager {
|
||||
}
|
||||
|
||||
fn list_sessions(&self) -> fdo::Result<Vec<(String, u32, String, String, OwnedObjectPath)>> {
|
||||
let runtime = self
|
||||
.runtime
|
||||
.read()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
||||
Ok(vec![(
|
||||
self.session_id.clone(),
|
||||
0,
|
||||
String::from("root"),
|
||||
self.seat_id.clone(),
|
||||
runtime.session_id.clone(),
|
||||
runtime.uid,
|
||||
runtime.username.clone(),
|
||||
runtime.seat_id.clone(),
|
||||
self.session_path.clone(),
|
||||
)])
|
||||
}
|
||||
|
||||
fn get_seat(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||
if id == self.seat_id {
|
||||
let runtime = self
|
||||
.runtime
|
||||
.read()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))?;
|
||||
if id == runtime.seat_id {
|
||||
return Ok(self.seat_path.clone());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SessionRuntime {
|
||||
pub session_id: String,
|
||||
pub seat_id: String,
|
||||
pub username: String,
|
||||
pub uid: u32,
|
||||
pub vt: u32,
|
||||
pub leader: u32,
|
||||
pub state: String,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl Default for SessionRuntime {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
session_id: String::from("c1"),
|
||||
seat_id: String::from("seat0"),
|
||||
username: String::from("root"),
|
||||
uid: 0,
|
||||
vt: 3,
|
||||
leader: std::process::id(),
|
||||
state: String::from("online"),
|
||||
active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SharedRuntime = Arc<RwLock<SessionRuntime>>;
|
||||
|
||||
pub fn shared_runtime() -> SharedRuntime {
|
||||
Arc::new(RwLock::new(SessionRuntime::default()))
|
||||
}
|
||||
@@ -2,20 +2,22 @@ use std::sync::Mutex;
|
||||
|
||||
use zbus::{fdo, interface, zvariant::OwnedObjectPath};
|
||||
|
||||
use crate::runtime_state::SharedRuntime;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginSeat {
|
||||
id: String,
|
||||
session_id: String,
|
||||
session_path: OwnedObjectPath,
|
||||
runtime: SharedRuntime,
|
||||
last_requested_vt: Mutex<u32>,
|
||||
}
|
||||
|
||||
impl LoginSeat {
|
||||
pub fn new(session_path: OwnedObjectPath) -> Self {
|
||||
pub fn new(session_path: OwnedObjectPath, runtime: SharedRuntime) -> Self {
|
||||
Self {
|
||||
id: String::from("seat0"),
|
||||
session_id: String::from("c1"),
|
||||
session_path,
|
||||
runtime,
|
||||
last_requested_vt: Mutex::new(1),
|
||||
}
|
||||
}
|
||||
@@ -46,12 +48,24 @@ impl LoginSeat {
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "ActiveSession")]
|
||||
fn active_session(&self) -> (String, OwnedObjectPath) {
|
||||
(self.session_id.clone(), self.session_path.clone())
|
||||
(
|
||||
self.runtime
|
||||
.read()
|
||||
.map(|runtime| runtime.session_id.clone())
|
||||
.unwrap_or_else(|_| String::from("c1")),
|
||||
self.session_path.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Sessions")]
|
||||
fn sessions(&self) -> Vec<(String, OwnedObjectPath)> {
|
||||
vec![(self.session_id.clone(), self.session_path.clone())]
|
||||
vec![(
|
||||
self.runtime
|
||||
.read()
|
||||
.map(|runtime| runtime.session_id.clone())
|
||||
.unwrap_or_else(|_| String::from("c1")),
|
||||
self.session_path.clone(),
|
||||
)]
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "CanGraphical")]
|
||||
|
||||
@@ -13,16 +13,14 @@ use zbus::{
|
||||
};
|
||||
|
||||
use crate::device_map::DeviceMap;
|
||||
use crate::runtime_state::SharedRuntime;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginSession {
|
||||
id: String,
|
||||
seat_id: String,
|
||||
seat_path: OwnedObjectPath,
|
||||
user_uid: u32,
|
||||
user_path: OwnedObjectPath,
|
||||
leader: u32,
|
||||
device_map: DeviceMap,
|
||||
runtime: SharedRuntime,
|
||||
controlled: Mutex<bool>,
|
||||
taken_devices: Mutex<HashSet<(u32, u32)>>,
|
||||
}
|
||||
@@ -32,15 +30,13 @@ impl LoginSession {
|
||||
seat_path: OwnedObjectPath,
|
||||
user_path: OwnedObjectPath,
|
||||
device_map: DeviceMap,
|
||||
runtime: SharedRuntime,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: String::from("c1"),
|
||||
seat_id: String::from("seat0"),
|
||||
seat_path,
|
||||
user_uid: 0,
|
||||
user_path,
|
||||
leader: process::id(),
|
||||
device_map,
|
||||
runtime,
|
||||
controlled: Mutex::new(false),
|
||||
taken_devices: Mutex::new(HashSet::new()),
|
||||
}
|
||||
@@ -57,21 +53,35 @@ impl LoginSession {
|
||||
.lock()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 device state is poisoned")))
|
||||
}
|
||||
|
||||
fn runtime(&self) -> fdo::Result<crate::runtime_state::SessionRuntime> {
|
||||
self.runtime
|
||||
.read()
|
||||
.map(|runtime| runtime.clone())
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 runtime state is poisoned")))
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "org.freedesktop.login1.Session")]
|
||||
impl LoginSession {
|
||||
fn activate(&self) -> fdo::Result<()> {
|
||||
eprintln!("redbear-sessiond: Activate requested for session {}", self.id);
|
||||
eprintln!("redbear-sessiond: Activate requested for session {}", self.runtime()?.session_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn take_control(&self, force: bool) -> fdo::Result<()> {
|
||||
let mut controlled = self.control_state()?;
|
||||
let runtime = self.runtime()?;
|
||||
if *controlled && !force {
|
||||
return Err(fdo::Error::Failed(format!(
|
||||
"session {} is already under control",
|
||||
runtime.session_id
|
||||
)));
|
||||
}
|
||||
*controlled = true;
|
||||
eprintln!(
|
||||
"redbear-sessiond: TakeControl requested for session {} (force={force})",
|
||||
self.id
|
||||
runtime.session_id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -79,34 +89,56 @@ impl LoginSession {
|
||||
fn release_control(&self) -> fdo::Result<()> {
|
||||
let mut controlled = self.control_state()?;
|
||||
*controlled = false;
|
||||
eprintln!("redbear-sessiond: ReleaseControl requested for session {}", self.id);
|
||||
self.taken_devices()?.clear();
|
||||
eprintln!("redbear-sessiond: ReleaseControl requested for session {}", self.runtime()?.session_id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn take_device(&self, major: u32, minor: u32) -> fdo::Result<OwnedFd> {
|
||||
let file = self
|
||||
let runtime = self.runtime()?;
|
||||
if !*self.control_state()? {
|
||||
return Err(fdo::Error::AccessDenied(format!(
|
||||
"session {} must TakeControl before TakeDevice",
|
||||
runtime.session_id
|
||||
)));
|
||||
}
|
||||
|
||||
let mut taken_devices = self.taken_devices()?;
|
||||
if taken_devices.contains(&(major, minor)) {
|
||||
return Err(fdo::Error::Failed(format!(
|
||||
"device ({major}, {minor}) is already taken for session {}",
|
||||
runtime.session_id
|
||||
)));
|
||||
}
|
||||
|
||||
let (path, file) = self
|
||||
.device_map
|
||||
.open_device(major, minor)
|
||||
.map_err(|err| fdo::Error::Failed(format!("TakeDevice({major}, {minor}) failed: {err}")))?;
|
||||
|
||||
let mut taken_devices = self.taken_devices()?;
|
||||
taken_devices.insert((major, minor));
|
||||
|
||||
let owned_fd: StdOwnedFd = file.into();
|
||||
eprintln!(
|
||||
"redbear-sessiond: TakeDevice granted for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
"redbear-sessiond: TakeDevice granted for session {} -> ({major}, {minor}) at {}",
|
||||
runtime.session_id, path
|
||||
);
|
||||
|
||||
Ok(OwnedFd::from(owned_fd))
|
||||
}
|
||||
|
||||
fn release_device(&self, major: u32, minor: u32) -> fdo::Result<()> {
|
||||
let runtime = self.runtime()?;
|
||||
let mut taken_devices = self.taken_devices()?;
|
||||
taken_devices.remove(&(major, minor));
|
||||
if !taken_devices.remove(&(major, minor)) {
|
||||
return Err(fdo::Error::Failed(format!(
|
||||
"device ({major}, {minor}) was not taken for session {}",
|
||||
runtime.session_id
|
||||
)));
|
||||
}
|
||||
eprintln!(
|
||||
"redbear-sessiond: ReleaseDevice requested for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
runtime.session_id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
@@ -114,14 +146,14 @@ impl LoginSession {
|
||||
fn pause_device_complete(&self, major: u32, minor: u32) -> fdo::Result<()> {
|
||||
eprintln!(
|
||||
"redbear-sessiond: PauseDeviceComplete received for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
self.runtime()?.session_id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Active")]
|
||||
fn active(&self) -> bool {
|
||||
true
|
||||
self.runtime().map(|runtime| runtime.active).unwrap_or(true)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Remote")]
|
||||
@@ -156,32 +188,40 @@ impl LoginSession {
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Id")]
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
self.runtime().map(|runtime| runtime.session_id).unwrap_or_else(|_| String::from("c1"))
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "State")]
|
||||
fn state(&self) -> String {
|
||||
String::from("online")
|
||||
self.runtime().map(|runtime| runtime.state).unwrap_or_else(|_| String::from("online"))
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Seat")]
|
||||
fn seat(&self) -> (String, OwnedObjectPath) {
|
||||
(self.seat_id.clone(), self.seat_path.clone())
|
||||
(
|
||||
self.runtime()
|
||||
.map(|runtime| runtime.seat_id)
|
||||
.unwrap_or_else(|_| String::from("seat0")),
|
||||
self.seat_path.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "User")]
|
||||
fn user(&self) -> (u32, OwnedObjectPath) {
|
||||
(self.user_uid, self.user_path.clone())
|
||||
(
|
||||
self.runtime().map(|runtime| runtime.uid).unwrap_or(0),
|
||||
self.user_path.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "VTNr")]
|
||||
fn vt_nr(&self) -> u32 {
|
||||
1
|
||||
self.runtime().map(|runtime| runtime.vt).unwrap_or(3)
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Leader")]
|
||||
fn leader(&self) -> u32 {
|
||||
self.leader
|
||||
self.runtime().map(|runtime| runtime.leader).unwrap_or(process::id())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Audit")]
|
||||
@@ -191,7 +231,7 @@ impl LoginSession {
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "TTY")]
|
||||
fn tty(&self) -> String {
|
||||
String::new()
|
||||
format!("tty{}", self.runtime().map(|runtime| runtime.vt).unwrap_or(3))
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "RemoteUser")]
|
||||
|
||||
Reference in New Issue
Block a user