summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-11-14 22:43:21 +0100
committermetamuffin <metamuffin@disroot.org>2025-11-14 22:43:21 +0100
commita4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa (patch)
tree05806e218a7ba3a53ab0a5df9b664be97e472edb
parent057031d68d0ab93aa6cc668bb5e37ad575a8ff8f (diff)
downloadgnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar
gnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar.bz2
gnix-a4d828cfa4ba9ff7ae4e21df49b2f3f9c695e4fa.tar.zst
add back watch option
-rw-r--r--Cargo.lock74
-rw-r--r--Cargo.toml2
-rw-r--r--src/control_socket.rs6
-rw-r--r--src/main.rs97
4 files changed, 156 insertions, 23 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ab5b6df..0f39214 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -190,7 +190,7 @@ version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
- "bitflags",
+ "bitflags 2.10.0",
"cexpr",
"clang-sys",
"itertools",
@@ -206,6 +206,12 @@ dependencies = [
[[package]]
name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
@@ -534,6 +540,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
+name = "fsevent-sys"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -689,10 +704,10 @@ dependencies = [
"humansize",
"hyper",
"hyper-util",
- "inotify",
"log",
"markup",
"mime_guess",
+ "notify",
"percent-encoding",
"pin-project",
"quinn",
@@ -922,11 +937,9 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
- "bitflags",
- "futures-core",
+ "bitflags 2.10.0",
"inotify-sys",
"libc",
- "tokio",
]
[[package]]
@@ -1035,6 +1048,26 @@ dependencies = [
]
[[package]]
+name = "kqueue"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+]
+
+[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1142,6 +1175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
dependencies = [
"libc",
+ "log",
"wasi",
"windows-sys 0.61.2",
]
@@ -1157,6 +1191,30 @@ dependencies = [
]
[[package]]
+name = "notify"
+version = "8.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
+dependencies = [
+ "bitflags 2.10.0",
+ "fsevent-sys",
+ "inotify",
+ "kqueue",
+ "libc",
+ "log",
+ "mio",
+ "notify-types",
+ "walkdir",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "notify-types"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
+
+[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1450,7 +1508,7 @@ version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
- "bitflags",
+ "bitflags 2.10.0",
]
[[package]]
@@ -1630,7 +1688,7 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
dependencies = [
- "bitflags",
+ "bitflags 2.10.0",
"core-foundation",
"core-foundation-sys",
"libc",
@@ -2094,7 +2152,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 5a8ebaf..2d05089 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,7 @@ pin-project = "1.1.10"
serde = { version = "1.0.228", features = ["derive"] }
serde_yml = "0.0.12"
serde_json = "1.0.145"
-inotify = "0.11.0"
+notify = "8.2.0"
clap = { version = "4.5.51", features = ["derive"] }
# Logging
diff --git a/src/control_socket.rs b/src/control_socket.rs
index c56c632..5d0a3e1 100644
--- a/src/control_socket.rs
+++ b/src/control_socket.rs
@@ -18,13 +18,13 @@ use tokio::{
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-enum ControlSocketRequest {
+pub enum ControlSocketRequest {
Config(ConfigPackage),
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
-enum ControlSocketResponse {
+pub enum ControlSocketResponse {
Ok,
Error(String),
}
@@ -76,7 +76,7 @@ async fn handle_control_socket_conn(state: Arc<State>, conn: UnixStream) -> Resu
Ok(())
}
-async fn handle_control_socket_request(
+pub async fn handle_control_socket_request(
state: Arc<State>,
request: ControlSocketRequest,
) -> Result<ControlSocketResponse> {
diff --git a/src/main.rs b/src/main.rs
index 3f437ba..b59c325 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,7 +22,9 @@ pub mod modules;
use crate::{
config::ConfigPackage,
- control_socket::{cs_client_reload, serve_control_socket},
+ control_socket::{
+ cs_client_reload, handle_control_socket_request, serve_control_socket, ControlSocketRequest,
+ },
generation::Generation,
};
use aes_gcm_siv::{aead::generic_array::GenericArray, Aes256GcmSiv, KeyInit};
@@ -46,9 +48,11 @@ use hyper::{
use hyper_util::rt::{TokioExecutor, TokioIo};
use log::{debug, error, info, warn, LevelFilter};
use modules::NodeContext;
+use notify::{RecursiveMode, Watcher};
use std::{
+ future::Future,
net::{IpAddr, SocketAddr},
- path::PathBuf,
+ path::{Path, PathBuf},
process::exit,
str::FromStr,
sync::Arc,
@@ -57,8 +61,9 @@ use tokio::{
net::TcpListener,
signal::ctrl_c,
spawn,
- sync::{RwLock, Semaphore},
+ sync::{mpsc::channel, RwLock, Semaphore},
};
+use users::{get_user_by_name, switch::set_current_uid};
pub struct State {
pub crypto_key: Aes256GcmSiv,
@@ -72,7 +77,7 @@ pub struct State {
#[derive(Parser)]
struct Args {
#[arg(long)]
- setuid: Option<String>,
+ user: Option<String>,
#[arg(long)]
control_socket: Option<PathBuf>,
#[arg(short, long)]
@@ -102,17 +107,33 @@ async fn main() -> anyhow::Result<()> {
let cs_path = args
.control_socket
.ok_or(anyhow!("reload needs control socket path"))?;
- match cs_client_reload(&cs_path, config_package).await {
- Ok(()) => {
- exit(0);
- }
- Err(e) => {
- eprintln!("Error: {e}");
- exit(1);
+ if args.watch {
+ watch_config(&args.config, || async {
+ let config_package = ConfigPackage::new(&args.config)?;
+ cs_client_reload(&cs_path, config_package).await?;
+ info!("Config updated");
+ Ok(())
+ })
+ .await?;
+ exit(1);
+ } else {
+ match cs_client_reload(&cs_path, config_package).await {
+ Ok(()) => {
+ exit(0);
+ }
+ Err(e) => {
+ eprintln!("Error: {e}");
+ exit(1);
+ }
}
}
}
+ if let Some(username) = args.user {
+ let user = get_user_by_name(&username).ok_or(anyhow!("user for setuid not found"))?;
+ set_current_uid(user.uid()).context("setuid")?;
+ }
+
let generation = Generation::new(config_package)?;
let state = Arc::new(State {
crypto_key: aes_gcm_siv::Aes256GcmSiv::new(GenericArray::from_slice(
@@ -125,6 +146,27 @@ async fn main() -> anyhow::Result<()> {
generation: RwLock::new(Arc::new(generation)),
});
+ if args.watch {
+ let state = state.clone();
+ spawn(async move {
+ if let Err(e) = watch_config(&args.config, || async {
+ let config_package = ConfigPackage::new(&args.config)?;
+ handle_control_socket_request(
+ state.clone(),
+ ControlSocketRequest::Config(config_package),
+ )
+ .await?;
+ info!("Config updated");
+ Ok(())
+ })
+ .await
+ {
+ error!("{e:?}");
+ exit(1)
+ }
+ });
+ }
+
if let Some(path) = args.control_socket {
let state = state.clone();
tokio::spawn(async move {
@@ -493,3 +535,36 @@ async fn service(
Ok(resp)
}
+
+async fn watch_config<R: Future<Output = Result<()>>>(
+ path: &Path,
+ mut reload: impl FnMut() -> R,
+) -> Result<()> {
+ let (tx, mut rx) = channel(1);
+ let mut w = notify::recommended_watcher(move |r| {
+ let _ = tx.blocking_send(r);
+ })?;
+ w.watch(path.parent().unwrap(), RecursiveMode::NonRecursive)?;
+
+ let path = path.canonicalize()?;
+ while let Some(r) = rx.recv().await {
+ match r {
+ Ok(ev) => {
+ if matches!(
+ ev.kind,
+ notify::EventKind::Access(notify::event::AccessKind::Close(
+ notify::event::AccessMode::Write
+ )) | notify::EventKind::Modify(notify::event::ModifyKind::Data(_))
+ ) && ev.paths.contains(&path)
+ {
+ if let Err(e) = reload().await {
+ error!("Error: {e:#}")
+ }
+ }
+ }
+ Err(e) => error!("watch error: {e:#}"),
+ }
+ }
+
+ Ok(())
+}