6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 1 | use std::{ |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 2 | fs::{self, File, OpenOptions}, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 3 | io, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 4 | os::unix::{fs::OpenOptionsExt, net::UnixStream, process::CommandExt}, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 5 | process::{Command, Stdio}, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 6 | thread, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 7 | time::Duration, |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 8 | }; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 9 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 10 | use crate::paths; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 11 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 12 | pub struct Flock(File); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 13 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 14 | impl Flock { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 15 | pub fn exclusive(file: File) -> io::Result<Self> { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 16 | use std::os::fd::AsRawFd; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 17 | if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX) } != 0 { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 18 | return Err(io::Error::last_os_error()); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 19 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 20 | Ok(Self(file)) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 21 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 22 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 23 | pub fn try_exclusive(file: File) -> Option<Self> { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 24 | use std::os::fd::AsRawFd; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 25 | (unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) } == 0) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 26 | .then_some(Self(file)) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 27 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 28 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 29 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 30 | impl Drop for Flock { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 31 | fn drop(&mut self) { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 32 | use std::os::fd::AsRawFd; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 33 | unsafe { libc::flock(self.0.as_raw_fd(), libc::LOCK_UN) }; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 34 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 35 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 36 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 37 | pub fn spawn_lock() -> io::Result<Flock> { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 38 | let file = OpenOptions::new() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 39 | .create(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 40 | .truncate(false) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 41 | .write(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 42 | .mode(0o600) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 43 | .open(paths::spawn_lock())?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 44 | Flock::exclusive(file) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 45 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 46 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 47 | pub fn connect() -> Option<UnixStream> { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 48 | UnixStream::connect(paths::socket()).ok() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 49 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 50 | |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 51 | pub fn connect_or_spawn() -> io::Result<UnixStream> { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 52 | if let Some(s) = connect() { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 53 | return Ok(s); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 54 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 55 | let _lock = spawn_lock()?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 56 | if let Some(s) = connect() { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 57 | return Ok(s); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 58 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 59 | let _ = fs::remove_file(paths::socket()); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 60 | let log = OpenOptions::new() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 61 | .create(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 62 | .append(true) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 63 | .open(paths::state_dir().join("daemon.log"))?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 64 | let mut cmd = Command::new(std::env::current_exe()?); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 65 | cmd.arg("daemon") |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 66 | .stdin(Stdio::null()) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 67 | .stdout(Stdio::null()) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 68 | .stderr(log); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 69 | unsafe { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 70 | cmd.pre_exec(|| { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 71 | libc::setsid(); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 72 | Ok(()) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 73 | }); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 74 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 75 | let mut child = cmd.spawn()?; |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 76 | for _ in 0..200 { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 77 | if let Some(s) = connect() { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 78 | let _ = child.wait(); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 79 | return Ok(s); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 80 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 81 | if let Ok(Some(status)) = child.try_wait() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 82 | && !status.success() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 83 | { |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 84 | return Err(io::Error::other(format!( |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 85 | "daemon died on startup ({status}), see {}", |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 86 | paths::state_dir().join("daemon.log").display() |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 87 | ))); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 88 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 89 | thread::sleep(Duration::from_millis(10)); |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 90 | } |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 91 | Err(io::Error::other("daemon never showed up")) |
6f5b84fad3ef | atagen | 2026-09-27 03:59 UTC | 92 | } |