Attempt 3 to fix launching permission denied

This commit is contained in:
Stephen Hellings 2026-03-09 11:21:08 -04:00
parent 5e154e19f9
commit 4dcb10d9f1
3 changed files with 69 additions and 9 deletions

View file

@ -1,10 +1,10 @@
[compositor]
socket_name = "wo-0"
ipc_socket = "/run/user/1000/wo-ipc.sock"
ipc_socket = "$XDG_RUNTIME_DIR/wo-ipc.sock"
electron_path = "electron"
background = [0.08, 0.10, 0.12, 1.0]
enable_portal = true
portal_socket = "/run/user/1000/wo-portal.sock"
portal_socket = "$XDG_RUNTIME_DIR/wo-portal.sock"
enable_syscalls = true
focus_notify = true

View file

@ -246,10 +246,17 @@ impl ApplicationConfig {
// Defaults
fn default_socket_name() -> String { "wo-0".into() }
fn default_ipc_socket() -> String { "/run/user/1000/wo-ipc.sock".into() }
fn default_electron_path() -> String { "electron".into() }
fn default_background() -> [f32; 4] { [0.1, 0.1, 0.1, 1.0] }
fn default_portal_socket() -> String { "/run/user/1000/wo-portal.sock".into() }
/// Returns $XDG_RUNTIME_DIR, falling back to /run/user/<uid>.
fn runtime_dir() -> String {
std::env::var("XDG_RUNTIME_DIR")
.unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }))
}
fn default_ipc_socket() -> String { format!("{}/wo-ipc.sock", runtime_dir()) }
fn default_portal_socket() -> String { format!("{}/wo-portal.sock", runtime_dir()) }
fn default_width() -> u32 { 1920 }
fn default_height() -> u32 { 1080 }
fn default_nested_width() -> u32 { 1920 }
@ -259,6 +266,12 @@ fn default_format() -> String { "ARGB8888".into() }
fn default_asset_prefix() -> String { "file".into() }
fn default_true() -> bool { true }
fn expand_path(s: &str) -> String {
shellexpand::full(s)
.map(|cow| cow.into_owned())
.unwrap_or_else(|_| s.to_owned())
}
impl Config {
pub fn load() -> Result<Self> {
// Try multiple locations in order of priority:
@ -278,8 +291,13 @@ impl Config {
let text = std::fs::read_to_string(&path_opt)
.with_context(|| format!("reading config {path_opt:?}"))?;
return toml::from_str(&text)
.with_context(|| format!("parsing config {path_opt:?}"));
let mut config: Self = toml::from_str(&text)
.with_context(|| format!("parsing config {path_opt:?}"))?;
config.compositor.ipc_socket =
expand_path(&config.compositor.ipc_socket);
config.compositor.portal_socket =
expand_path(&config.compositor.portal_socket);
return Ok(config);
}
}

View file

@ -778,10 +778,52 @@ fn run_drm(config: Config) -> Result<(), anyhow::Error> {
let drm_device_fd = DrmDeviceFd::new(DeviceFd::from(drm_fd));
if let Err(e) = drm::Device::acquire_master_lock(&drm_device_fd) {
// Retry acquiring DRM master: on logind-managed sessions (e.g. Ly) the VT
// switch and master hand-off from logind may not be complete at the exact
// moment session.open() returns. libseat's builtin backend logs "Unable to
// become DRM master, entering unprivileged mode" and returns the fd anyway;
// pumping the event loop lets session-activation events propagate so that
// the next drmSetMaster() attempt succeeds.
const DRM_MASTER_RETRY_MS: u64 = 100;
const DRM_MASTER_RETRY_ROUNDS: u32 = 30; // up to ~3 s
let mut last_master_err = None;
for round in 0..=DRM_MASTER_RETRY_ROUNDS {
match drm::Device::acquire_master_lock(&drm_device_fd) {
Ok(()) => {
if round > 0 {
info!("DRM master acquired after {} retries", round);
}
last_master_err = None;
break;
}
Err(e) => {
let detail = e.to_string();
if round == 0 {
warn!(
gpu = %gpu_path.display(),
"DRM master not yet available ({}); retrying up to {}×{}ms...",
detail,
DRM_MASTER_RETRY_ROUNDS,
DRM_MASTER_RETRY_MS,
);
}
last_master_err = Some(detail);
let _ = event_loop.dispatch(
Some(Duration::from_millis(DRM_MASTER_RETRY_MS)),
&mut pre_init,
);
}
}
}
if let Some(e) = last_master_err {
return Err(anyhow::anyhow!(
"failed to become DRM master on {}: {e}. The GPU is likely in use by another active session/compositor. Switch to a free VT, stop the other session, or set compositor.drm_device to a free card.",
gpu_path.display()
"failed to become DRM master on {gpu}: {e}. \
The GPU is likely in use by another active session/compositor. \
Ensure wo is launched as the session compositor by a logind-aware \
display manager (e.g. Ly, greetd) with pam_systemd.so in its PAM \
config, or switch to a free VT first. \
If using seatd, add your user to the 'seat' group.",
gpu = gpu_path.display(),
));
}