rehash: write the pidfile only when configured + CLI verifies a live echoircd, so a stale/clobbered pid can't misfire

This commit is contained in:
Jean Chevronnet 2026-08-23 02:17:44 +00:00
parent a7ae0d86a9
commit 34342e110f
No known key found for this signature in database
GPG key ID: 439666D63A9477E4

View file

@ -38,18 +38,21 @@ fn rehash_cli(cfgpath: &str) -> i32 {
return 1; return 1;
} }
}; };
if pid.parse::<u32>().is_err() { // Verify the pid is a live echoircd — guards a stale pidfile or a reused pid.
eprintln!("echoircd: bad pidfile {pidfile} (contents: {pid:?})"); let comm = std::fs::read_to_string(format!("/proc/{pid}/comm")).unwrap_or_default();
if pid.parse::<u32>().is_err() || comm.trim() != "echoircd" {
eprintln!("echoircd: no running echoircd for pid {pid} (stale {pidfile}?) — start the server first.");
return 1; return 1;
} }
println!("rehashing server config file."); println!("rehashing server config file.");
let sent = std::process::Command::new("kill") let sent = std::process::Command::new("kill")
.args(["-s", "HUP", &pid]) .args(["-s", "HUP", &pid])
.stderr(std::process::Stdio::null())
.status() .status()
.map(|st| st.success()) .map(|st| st.success())
.unwrap_or(false); .unwrap_or(false);
if !sent { if !sent {
eprintln!("echoircd: could not signal pid {pid} — is the server running?"); eprintln!("echoircd: could not signal pid {pid}.");
return 1; return 1;
} }
println!("server configuration is reloaded."); println!("server configuration is reloaded.");
@ -102,16 +105,14 @@ fn main() {
std::process::exit(1); std::process::exit(1);
} }
// Write a pidfile (default echoircd.pid) so `echoircd rehash` can find us. // Write a pidfile only when `pidfile` is configured, so throwaway instances in
let pidfile = cfg // the same directory (e.g. the integration-test harness) can't clobber a real
.raw // server's pidfile and leave `echoircd rehash` pointing at a dead process.
.get("pidfile") if let Some(pidfile) = cfg.raw.get("pidfile").and_then(|v| v.first()).filter(|p| !p.is_empty()) {
.and_then(|v| v.first()) if let Err(e) = std::fs::write(pidfile, format!("{}\n", std::process::id())) {
.cloned()
.unwrap_or_else(|| "echoircd.pid".to_string());
if let Err(e) = std::fs::write(&pidfile, format!("{}\n", std::process::id())) {
eprintln!("echoircd: could not write pidfile {pidfile}: {e}"); eprintln!("echoircd: could not write pidfile {pidfile}: {e}");
} }
}
// global queue limits (per-class overrides layer on top of these in the reactor) // global queue limits (per-class overrides layer on top of these in the reactor)
let raw_num = |k: &str, d: usize| { let raw_num = |k: &str, d: usize| {