diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | src/opt.rs | 6 | ||||
| -rw-r--r-- | src/platform/linux.rs | 43 |
3 files changed, 42 insertions, 11 deletions
diff --git a/src/main.rs b/src/main.rs index 90efdcc..f458e24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,10 +70,12 @@ fn main_0() -> Result<()> { } opt.set_opt()?; splash_banner(); + if !opt::daemon() { + platform::bootstrap()?; + } let _guard = EnsureCleanup; - platform::bootstrap()?; platform::run()?; Ok(()) @@ -10,6 +10,7 @@ use crate::log; use log::LogLevel; +static OPT_DAEMON: OnceLock<bool> = OnceLock::new(); static OPT_LOG_LEVEL: OnceLock<LogLevel> = OnceLock::new(); static OPT_NO_SPLASH: OnceLock<bool> = OnceLock::new(); @@ -125,6 +126,7 @@ impl Opt { } pub fn set_opt(self) -> Result<()> { + set_opt("OPT_DAEMON", &OPT_DAEMON, self.daemon)?; set_opt("OPT_LOG_LEVEL", &OPT_LOG_LEVEL, self.log_level)?; set_opt("OPT_NO_SPLASH", &OPT_NO_SPLASH, self.no_splash)?; @@ -141,6 +143,10 @@ impl Opt { } } +pub fn daemon() -> bool { + *OPT_DAEMON.get().unwrap_or(&DEFAULT_DAEMON) +} + pub fn no_splash() -> bool { *OPT_NO_SPLASH.get().unwrap_or(&DEFAULT_NO_SPLASH) } diff --git a/src/platform/linux.rs b/src/platform/linux.rs index e6cf577..3668fe8 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -1,11 +1,9 @@ // SPDX-FileCopyrightText: 2025-2026 Dilluti0n <[email protected]> // SPDX-License-Identifier: GPL-3.0-or-later -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Mutex, - LazyLock -}; +use std::{os::fd::AsRawFd, sync::{ + LazyLock, Mutex, atomic::{AtomicBool, Ordering} +}}; use std::process::{Command, Stdio}; use std::io::Write; use anyhow::{Result, Context, anyhow}; @@ -22,6 +20,8 @@ pub static IS_U32_SUPPORTED: AtomicBool = AtomicBool::new(false); pub static IS_NFT_NOT_SUPPORTED: AtomicBool = AtomicBool::new(false); const INJECT_MARK: u32 = 0xD001; +const PID_FILE: &str = "/tmp/dpibreak.pid"; // TODO: unmagic this +const PKG_NAME: &str = env!("CARGO_PKG_NAME"); fn exec_process(args: &[&str], input: Option<&str>) -> Result<()> { if args.is_empty() { @@ -98,9 +98,31 @@ pub fn cleanup() -> Result<()> { Ok(()) } + +/// Only called on non-daemon run. Fail if running dpibreak is +/// existing. pub fn bootstrap() -> Result<()> { - _ = cleanup(); // In case the previous execution was not cleaned properly - install_rules() + use nix::fcntl::{flock, FlockArg}; + use std::fs::OpenOptions; + + let pid_file = OpenOptions::new() + .write(true) + .create(true) + .truncate(false) + .open(PID_FILE)?; + + if flock(pid_file.as_raw_fd(), FlockArg::LockExclusiveNonblock).is_err() { + let existing_pid = std::fs::read_to_string(PID_FILE)?; + anyhow::bail!("Fail to lock {PID_FILE}: {PKG_NAME} already running with PID {}", existing_pid.trim()); + } + + pid_file.set_len(0)?; + writeln!(&pid_file, "{}", std::process::id())?; + pid_file.sync_all()?; + + std::mem::forget(pid_file); // Tell std to do not close the file + + Ok(()) } use socket2::{Domain, Protocol, Socket, Type}; @@ -172,6 +194,9 @@ pub fn run() -> Result<()> { use crate::handle_packet; use super::PACKET_SIZE_CAP; + _ = cleanup(); // In case the previous execution was not cleaned properly + install_rules()?; + let mut q = Queue::open()?; q.bind(crate::opt::queue_num())?; log_println!(LogLevel::Info, "nfqueue: bound to queue number {}", @@ -221,7 +246,6 @@ pub fn run() -> Result<()> { Ok(()) } -const PKG_NAME: &str = env!("CARGO_PKG_NAME"); const DAEMON_PREFIX: &str = "/tmp"; fn daemonize() -> Result<()> { @@ -229,10 +253,9 @@ fn daemonize() -> Result<()> { use daemonize::Daemonize; let log_file = fs::File::create(format!("{DAEMON_PREFIX}/{PKG_NAME}.log"))?; - let pid_file = format!("{DAEMON_PREFIX}/{PKG_NAME}.pid"); let daemonize = Daemonize::new() - .pid_file(&pid_file) + .pid_file(PID_FILE) .chown_pid_file(true) .working_directory(DAEMON_PREFIX) .stdout(log_file); |
