feat(os): port Ghostty's Linux OS helpers
Ports ZIG/src/os for Linux into ghostty-os: XDG dirs, home dir, hostname, env/PATH helpers, passwd lookup (via nix), shell detection, resources dir discovery, string encodings (printf-q, URL percent), systemd sd_notify, i18n via gettextrs, xdg-open, desktop/cgroup/kernel info, temp dirs, URI parsing (port of std.Uri incl. Ghostty's extra options), and a zbus-based Flatpak HostCommand implementation. The crate stays free of unsafe. Consequences, all tracked as TODO(integration) in docs/rewrite/notes/ghostty-os.md: - locale::ensure_locale is a no-op (setlocale/setenv are unsafe; GTK calls setlocale itself); setenv/unsetenv are not exposed. - passwd's Flatpak branch needs the termio pty and falls back to the sandbox entry for now. - FlatpakHostCommand's D-Bus path is untested (no portal here). Intentional fix: a leading '@' in NOTIFY_SOCKET is treated as an abstract socket. macOS/Windows/WASM modules are out of scope. Test Plan: - cargo test -p ghostty-os (88 tests) - cargo clippy -p ghostty-os --all-targets -- -D warnings
This commit is contained in:
1 parent
04a6b7c97a
commit
b681241359
30 files changed
+3736
-1
No files matched your search
@@ -0,0 +1,40 @@
|
||||
use std::io::Read;
|
||||
|
||||
/// Maximum number of bytes read from the cgroup file (the Zig version reads
|
||||
/// into a caller-provided buffer; callers there use path-sized buffers).
|
||||
const READ_LIMIT: u64 = 4096;
|
||||
|
||||
/// Returns the path to the cgroup for the given pid.
|
||||
pub fn current(pid: u32) -> Option<String> {
|
||||
// Read our cgroup by opening /proc/<pid>/cgroup and reading the first
|
||||
// line. The first line will look something like this:
|
||||
// 0::/user.slice/user-1000.slice/session-1.scope
|
||||
// The cgroup path is the third field.
|
||||
let file = std::fs::File::open(format!("/proc/{pid}/cgroup")).ok()?;
|
||||
let mut contents = Vec::new();
|
||||
file.take(READ_LIMIT).read_to_end(&mut contents).ok()?;
|
||||
|
||||
// Find the last ':'
|
||||
let idx = contents.iter().rposition(|&b| b == b':')?;
|
||||
let rest = &contents[idx + 1..];
|
||||
let end = rest
|
||||
.iter()
|
||||
.rposition(|b| !matches!(b, b' ' | b'\r' | b'\n'))
|
||||
.map_or(0, |i| i + 1);
|
||||
Some(String::from_utf8_lossy(&rest[..end]).into_owned())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn current_cgroup_of_self() {
|
||||
// Not part of the Zig tests; sanity check that parsing works when
|
||||
// /proc is available.
|
||||
if let Some(p) = current(std::process::id()) {
|
||||
assert!(!p.ends_with('\n'));
|
||||
}
|
||||
assert!(current(u32::MAX).is_none());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user