Files
RedBear-OS/local/recipes/system/udev-shim/source/src/main.rs
T
vasilito 8b872979ef fix: udev-shim panic, sessiond duplicate, scheme Bad-fd handling
- udev-shim: replace .expect() with graceful errors (no more panic on Broken pipe)
- P4-initfs: remove duplicate sessiond (conflicted with config)
- accessibility/ime/keymapd: break instead of exit(1) on EBADF
- P6 driver patches rebased
- Docs: archive old reports, add implementation master plan
2026-05-04 14:04:03 +01:00

180 lines
5.1 KiB
Rust

mod naming;
mod device_db;
mod scheme;
use std::env;
use std::os::fd::RawFd;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use log::{error, info, warn, LevelFilter, Metadata, Record};
use redox_scheme::{
scheme::{SchemeState, SchemeSync},
SignalBehavior, Socket,
};
use naming::write_default_rules_file;
use scheme::UdevScheme;
struct StderrLogger {
level: LevelFilter,
}
impl log::Log for StderrLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
eprintln!("[{}] {}", record.level(), record.args());
}
}
fn flush(&self) {}
}
fn init_logging(level: LevelFilter) {
if log::set_boxed_logger(Box::new(StderrLogger { level })).is_err() {
return;
}
log::set_max_level(level);
}
unsafe fn get_init_notify_fd() -> Option<RawFd> {
let fd_str = match env::var("INIT_NOTIFY") {
Ok(v) => v,
Err(_) => {
warn!("udev-shim: INIT_NOTIFY not set; init notification skipped");
return None;
}
};
match fd_str.parse::<RawFd>() {
Ok(fd) => {
libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC);
Some(fd)
}
Err(_) => {
warn!("udev-shim: INIT_NOTIFY is not a valid fd: {fd_str}");
None
}
}
}
fn notify_scheme_ready(notify_fd: RawFd, socket: &Socket, scheme: &mut UdevScheme) {
let cap_id = match scheme.scheme_root() {
Ok(id) => id,
Err(e) => {
error!("udev-shim: scheme_root failed: {e:?}");
return;
}
};
let cap_fd = match socket.create_this_scheme_fd(0, cap_id, 0, 0) {
Ok(fd) => fd,
Err(e) => {
error!("udev-shim: create_this_scheme_fd failed: {e:?}");
return;
}
};
if let Err(e) = syscall::call_wo(
notify_fd as usize,
&libredox::Fd::new(cap_fd).into_raw().to_ne_bytes(),
syscall::CallFlags::FD,
&[],
) {
warn!("udev-shim: init notification failed: {e:?}");
}
}
fn main() {
let log_level = match env::var("UDEV_SHIM_LOG").as_deref() {
Ok("debug") => LevelFilter::Debug,
Ok("trace") => LevelFilter::Trace,
_ => LevelFilter::Info,
};
init_logging(log_level);
let mut scheme = UdevScheme::new();
match scheme.scan_pci_devices() {
Ok(n) => info!("udev-shim: enumerated {} PCI device(s)", n),
Err(e) => error!("udev-shim: PCI scan failed: {}", e),
}
match write_default_rules_file() {
Ok(path) => info!("udev-shim: wrote default rules to {path}"),
Err(err) => warn!("udev-shim: failed to write default rules: {err}"),
}
let socket = match Socket::create() {
Ok(s) => s,
Err(e) => {
error!("udev-shim: failed to create udev scheme: {e:?}");
std::process::exit(1);
}
};
let mut state = SchemeState::new();
if let Some(notify_fd) = unsafe { get_init_notify_fd() } {
notify_scheme_ready(notify_fd, &socket, &mut scheme);
}
if let Err(e) = libredox::call::setrens(0, 0) {
error!("udev-shim: failed to enter null namespace: {e:?}");
}
info!("udev-shim: registered scheme:udev");
let scheme = Arc::new(Mutex::new(scheme));
let scheme_clone = Arc::clone(&scheme);
thread::spawn(move || {
loop {
thread::sleep(Duration::from_secs(2));
if let Ok(mut s) = scheme_clone.lock() {
match s.scan_pci_devices() {
Ok(n) if n > 0 => info!("udev-shim: hotplug detected {} device(s)", n),
Err(e) => error!("udev-shim: hotplug scan failed: {}", e),
_ => {}
}
}
}
});
loop {
match socket.next_request(SignalBehavior::Restart) {
Ok(Some(request)) => {
match request.kind() {
redox_scheme::RequestKind::Call(request) => {
let response = {
let mut guard = match scheme.lock() {
Ok(guard) => guard,
Err(poisoned) => {
error!("udev-shim: recovering from poisoned scheme lock");
poisoned.into_inner()
}
};
request.handle_sync(&mut *guard, &mut state)
};
if let Err(e) = socket.write_response(response, SignalBehavior::Restart) {
error!("udev-shim: failed to write response: {e:?}");
}
}
_ => (),
}
}
Ok(None) => {
info!("udev-shim: scheme unmounted, exiting");
break;
}
Err(e) => {
error!("udev-shim: failed to read scheme request: {e:?}");
break;
}
}
}
std::process::exit(0);
}