Commit 6c27cca
7
files
+122
added
-4
deleted
@@ -170,7 +170,8 @@ Po instalacji sesja „Luna” pojawia się w menedżerze logowania (`share/wayl
170
170
Na sprzęcie Selene przejmuje ekran przez DRM/KMS — trzeba **wylogować bieżący pulpit** (wolny
171
171
master DRM) i mieć dostęp do `/dev/input` (grupa `input`) dla wejścia. Testowo, obok działającej
172
172
sesji, można uruchomić `SELENE_BACKEND=nested selene` (okno na obecnym pulpicie) i podłączyć
173
-`luna-shell`. Szczegóły: `de/README.md`.
173
+`luna-shell`. Gdy sesja od razu wraca do menedżera logowania, sprawdź `XDG_RUNTIME_DIR` —
174
+Selene i `luna-session` wybierają go awaryjnie same. Szczegóły: `de/README.md`.
174
175
175
176
## Budowanie własnej aplikacji na libLunie
176
177
@@ -102,6 +102,11 @@ XDG_RUNTIME_DIR="$PWD/.selene-runtime" cargo run -p selene
102
102
# → "Selene compositor started (wayland-0)" + gniazdo wayland-0 w katalogu runtime
103
103
```
104
104
105
+`XDG_RUNTIME_DIR` zwykle ustawia menedżer sesji. Gdy go brak (np. `pam_systemd` nie
106
+założył sesji), Selene wybiera katalog sam: najpierw `/run/user/<uid>`, a gdy ten nie
107
+istnieje — tworzy prywatny katalog `0700` pod `$TMPDIR`. Skrypt `luna-session` robi ten
108
+sam wybór wcześniej, żeby zmienną dziedziczyli także klienci.
109
+
105
110
Tryb nested (domyślny) uruchamia okno na nadrzędnym kompozytorze. **Realne wyjście DRM**
106
111
(gdy masz wolnego mastera, np. z osobnej konsoli):
107
112
@@ -20,4 +20,4 @@ libluna-platform.workspace = true
20
20
wayland-server = "0.31"
21
21
wayland-protocols = { version = "0.32", features = ["server", "unstable"] }
22
22
wayland-protocols-wlr = { version = "0.3", features = ["server"] }
23
-rustix = { version = "0.38", features = ["event", "fs", "time", "mm"] }
23
+rustix = { version = "0.38", features = ["event", "fs", "time", "mm", "process"] }
@@ -21,6 +21,8 @@ mod state;
21
21
22
22
use std::error::Error;
23
23
use std::os::fd::{AsRawFd, BorrowedFd};
24
+use std::os::unix::fs::MetadataExt;
25
+use std::path::{Path, PathBuf};
24
26
use std::sync::Arc;
25
27
26
28
use libluna_core::Event;
@@ -81,6 +83,7 @@ fn main() -> Result<(), Box<dyn Error>> {
81
83
handle.create_global::<State, wl_seat::WlSeat, ()>(1, ());
82
84
83
85
// Gniazdo nasłuchu: `wayland-0`, `wayland-1`, …
86
+ ensure_runtime_dir()?;
84
87
let socket =
85
88
ListeningSocket::bind_auto("wayland", 0..33).map_err(|e| format!("bind socket: {e:?}"))?;
86
89
println!(
@@ -195,3 +198,92 @@ fn main() -> Result<(), Box<dyn Error>> {
195
198
display.flush_clients()?;
196
199
}
197
200
}
201
+
202
+/// Zapewnia, że `XDG_RUNTIME_DIR` wskazuje prywatny katalog użytkownika, zanim
203
+/// zwiążemy gniazdo Wayland.
204
+///
205
+/// Menedżer sesji (logind/`pam_systemd`) normalnie ustawia tę zmienną. Gdy jej brak
206
+/// lub jest bezużyteczna (np. `pam_systemd` nie zdołał założyć sesji i zmienna nie
207
+/// trafiła do środowiska), `ListeningSocket::bind_auto` kończy się błędem
208
+/// `RuntimeDirNotSet`, a kompozytor wychodzi natychmiast — co z zewnątrz wygląda jak
209
+/// „sesja się nie uruchomiła”. Dlatego wybieramy `/run/user/<uid>`, a gdy ono nie
210
+/// istnieje — tworzymy własny katalog `0700` pod `$TMPDIR`.
211
+fn ensure_runtime_dir() -> Result<(), Box<dyn Error>> {
212
+ let uid = rustix::process::getuid().as_raw() as u32;
213
+
214
+ if let Some(dir) = std::env::var_os("XDG_RUNTIME_DIR") {
215
+ if is_private_dir_owned_by(&PathBuf::from(dir), uid) {
216
+ return Ok(());
217
+ }
218
+ }
219
+
220
+ let run_user = PathBuf::from(format!("/run/user/{uid}"));
221
+ let dir = if is_private_dir_owned_by(&run_user, uid) {
222
+ run_user
223
+ } else {
224
+ let base = std::env::var_os("TMPDIR")
225
+ .map(PathBuf::from)
226
+ .filter(|p| p.is_absolute())
227
+ .unwrap_or_else(|| PathBuf::from("/tmp"));
228
+ let dir = base.join(format!("selene-runtime-{uid}"));
229
+ match rustix::fs::mkdir(&dir, rustix::fs::Mode::RWXU) {
230
+ Ok(()) | Err(rustix::io::Errno::EXIST) => {}
231
+ Err(e) => return Err(format!("mkdir {}: {e}", dir.display()).into()),
232
+ }
233
+ if !is_private_dir_owned_by(&dir, uid) {
234
+ return Err(format!(
235
+ "runtime dir {} nie należy do uid {uid} lub jest dostępny dla grupy/innych",
236
+ dir.display()
237
+ )
238
+ .into());
239
+ }
240
+ dir
241
+ };
242
+
243
+ println!(
244
+ "{} {}",
245
+ libluna_i18n::tr("XDG_RUNTIME_DIR not set, using"),
246
+ dir.display()
247
+ );
248
+ std::env::set_var("XDG_RUNTIME_DIR", &dir);
249
+ Ok(())
250
+}
251
+
252
+/// Czy `path` to istniejący, bezwzględny katalog należący do `uid`, bez dostępu dla
253
+/// grupy i innych użytkowników (tryb `0700`)?
254
+fn is_private_dir_owned_by(path: &Path, uid: u32) -> bool {
255
+ path.is_absolute()
256
+ && std::fs::metadata(path)
257
+ .map(|m| m.is_dir() && m.uid() == uid && m.mode() & 0o077 == 0)
258
+ .unwrap_or(false)
259
+}
260
+
261
+#[cfg(test)]
262
+mod runtime_dir_tests {
263
+ use super::*;
264
+ use std::os::unix::fs::PermissionsExt as _;
265
+
266
+ #[test]
267
+ fn private_dir_owned_by_uid_is_accepted() {
268
+ let uid = rustix::process::getuid().as_raw() as u32;
269
+ let dir = std::env::temp_dir().join(format!("selene-rdir-{}", std::process::id()));
270
+ std::fs::create_dir_all(&dir).unwrap();
271
+ std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o700)).unwrap();
272
+
273
+ assert!(
274
+ is_private_dir_owned_by(&dir, uid),
275
+ "katalog 0700 naszego uid"
276
+ );
277
+ // Obcy uid: nie jest nasz.
278
+ assert!(!is_private_dir_owned_by(&dir, uid.wrapping_add(1)));
279
+ // Zbyt otwarte uprawnienia: grupa/inny mają dostęp.
280
+ std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o755)).unwrap();
281
+ assert!(!is_private_dir_owned_by(&dir, uid));
282
+ // Nieistniejąca ścieżka.
283
+ assert!(!is_private_dir_owned_by(&dir.join("missing"), uid));
284
+ // Ścieżka względna nie nadaje się na `XDG_RUNTIME_DIR`.
285
+ assert!(!is_private_dir_owned_by(Path::new("relative/dir"), uid));
286
+
287
+ std::fs::remove_dir_all(&dir).ok();
288
+ }
289
+}
@@ -10,6 +10,14 @@ export XDG_CURRENT_DESKTOP=Luna
10
10
export XDG_SESSION_TYPE=wayland
11
11
export XDG_SESSION_DESKTOP=Luna
12
12
13
+# XDG_RUNTIME_DIR normalnie ustawia menedżer sesji (logind/pam_systemd). Gdy go brak
14
+# (np. pam_systemd nie zdołał założyć sesji), wskazujemy katalog per-uid, żeby Selene
15
+# i klienci mieli gdzie założyć gniazdo Wayland. Selene sam waliduje ten katalog.
16
+if [ -z "${XDG_RUNTIME_DIR:-}" ] && [ -d "/run/user/$(id -u)" ]; then
17
+ XDG_RUNTIME_DIR="/run/user/$(id -u)"
18
+ export XDG_RUNTIME_DIR
19
+fi
20
+
13
21
: "${SELENE_BACKEND:=drm}"
14
22
export SELENE_BACKEND
15
23
@@ -54,6 +54,9 @@ sum — te wpisuje dopiero skrypt, bo zależą od konkretnego commita/taga.
54
54
55
55
- `Selene` to kompozytor Wayland; wpis sesji startuje na DRM/KMS (`SELENE_BACKEND=drm`).
56
56
Gdy master DRM trzyma inna sesja, Selene **bezpiecznie** spada do wyjścia nested.
57
+- `XDG_RUNTIME_DIR` pochodzi od menedżera sesji; gdy go brak (np. `pam_systemd` nie założył
58
+ sesji), `luna-session` i sam Selene wybierają katalog awaryjnie (`/run/user/<uid>`, dalej
59
+ prywatny `0700` pod `$TMPDIR`).
57
60
- Wejście w trybie DRM (evdev) to kolejny krok — póki go nie ma, sesja jest „podglądowa”.
58
61
- `selene` nie deklaruje zależności od pakietu `libluna`, bo linkuje toolkit statycznie
59
62
(Rust) — zależność nie jest potrzebna w runtime.
@@ -1,14 +1,23 @@
1
1
#!/bin/sh
2
2
# Sesja środowiska Luna — uruchamia kompozytor Selene.
3
3
#
4
-# Domyślnie startujemy na DRM/KMS. Gdy master DRM trzyma inna sesja, Selene sam
5
-# zgłosi to i spadnie do wyjścia nested — ustaw wtedy SELENE_BACKEND=nested.
4
+# Domyślnie startujemy na DRM/KMS (własny ekran, bez nadrzędnego kompozytora).
5
+# Gdy master DRM trzyma inna sesja, Selene sam to zgłosi i spadnie do wyjścia
6
+# nested — ustaw wtedy SELENE_BACKEND=nested (albo wyloguj bieżącą sesję).
6
7
set -eu
7
8
8
9
export XDG_CURRENT_DESKTOP=Luna
9
10
export XDG_SESSION_TYPE=wayland
10
11
export XDG_SESSION_DESKTOP=Luna
11
12
13
+# XDG_RUNTIME_DIR normalnie ustawia menedżer sesji (logind/pam_systemd). Gdy go brak
14
+# (np. pam_systemd nie zdołał założyć sesji), wskazujemy katalog per-uid, żeby Selene
15
+# i klienci mieli gdzie założyć gniazdo Wayland. Selene sam waliduje ten katalog.
16
+if [ -z "${XDG_RUNTIME_DIR:-}" ] && [ -d "/run/user/$(id -u)" ]; then
17
+ XDG_RUNTIME_DIR="/run/user/$(id -u)"
18
+ export XDG_RUNTIME_DIR
19
+fi
20
+
12
21
: "${SELENE_BACKEND:=drm}"
13
22
export SELENE_BACKEND
14
23