summaryrefslogtreecommitdiff
path: root/src/locking.rs
blob: 1c39471ebf0c7e02c698fc0919c0e8eb21990654 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use anyhow::{Context, Result, ensure};
use std::{
    fs::{File, OpenOptions},
    os::fd::AsRawFd,
    os::unix::fs::{MetadataExt, OpenOptionsExt},
    path::Path,
};

pub fn controller_lock() -> Result<File> {
    let directory = Path::new("/run/roentgen");
    std::fs::create_dir_all(directory)?;
    let metadata = std::fs::symlink_metadata(directory)?;
    ensure!(
        metadata.is_dir()
            && metadata.uid() == unsafe { libc::geteuid() }
            && metadata.mode() & 0o022 == 0,
        "Runtime directory must be service-owned and not writable by other users"
    );
    let file = OpenOptions::new()
        .create(true)
        .truncate(false)
        .read(true)
        .write(true)
        .mode(0o600)
        .custom_flags(libc::O_NOFOLLOW)
        .open(directory.join("controller.lock"))
        .context("Open controller lock")?;
    // SAFETY: file owns this live fd; flock does not retain a pointer.
    let result = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
    ensure!(
        result == 0,
        "Another controller is running; stop it before explicit recovery"
    );
    Ok(file)
}