diff --git a/proxmox-rest-server/Cargo.toml b/proxmox-rest-server/Cargo.toml index 33ed6f39..4d1f1459 100644 --- a/proxmox-rest-server/Cargo.toml +++ b/proxmox-rest-server/Cargo.toml @@ -13,6 +13,7 @@ http = "0.2" hyper = { version = "0.14", features = [ "full" ] } lazy_static = "1.4" libc = "0.2" +log = "0.4" nix = "0.19.1" serde = { version = "1.0", features = [] } serde_json = "1.0" diff --git a/src/tools/daemon.rs b/proxmox-rest-server/src/daemon.rs similarity index 97% rename from src/tools/daemon.rs rename to proxmox-rest-server/src/daemon.rs index 1291601b..5401e30c 100644 --- a/src/tools/daemon.rs +++ b/proxmox-rest-server/src/daemon.rs @@ -15,8 +15,9 @@ use anyhow::{bail, format_err, Error}; use futures::future::{self, Either}; use proxmox::tools::io::{ReadExt, WriteExt}; +use proxmox::tools::fd::Fd; -use crate::tools::{fd_change_cloexec, self}; +use crate::fd_change_cloexec; #[link(name = "systemd")] extern "C" { @@ -218,7 +219,7 @@ impl Reloadable for tokio::net::TcpListener { // FIXME: We could become "independent" of the TcpListener and its reference to the file // descriptor by `dup()`ing it (and check if the listener still exists via kcmp()?) fn get_store_func(&self) -> Result { - let mut fd_opt = Some(tools::Fd( + let mut fd_opt = Some(Fd( nix::fcntl::fcntl(self.as_raw_fd(), nix::fcntl::FcntlArg::F_DUPFD_CLOEXEC(0))? )); Ok(Box::new(move || { @@ -273,11 +274,11 @@ where ).await?; let server_future = create_service(listener, NotifyReady)?; - let shutdown_future = proxmox_rest_server::shutdown_future(); + let shutdown_future = crate::shutdown_future(); let finish_future = match future::select(server_future, shutdown_future).await { Either::Left((_, _)) => { - proxmox_rest_server::request_shutdown(); // make sure we are in shutdown mode + crate::request_shutdown(); // make sure we are in shutdown mode None } Either::Right((_, server_future)) => Some(server_future), @@ -285,7 +286,7 @@ where let mut reloader = Some(reloader); - if proxmox_rest_server::is_reload_request() { + if crate::is_reload_request() { log::info!("daemon reload..."); if let Err(e) = systemd_notify(SystemdNotify::Reloading) { log::error!("failed to notify systemd about the state change: {}", e); @@ -304,7 +305,7 @@ where } // FIXME: this is a hack, replace with sd_notify_barrier when available - if proxmox_rest_server::is_reload_request() { + if crate::is_reload_request() { wait_service_is_not_state(service_name, "reloading").await?; } diff --git a/proxmox-rest-server/src/lib.rs b/proxmox-rest-server/src/lib.rs index 38dd610c..21a91115 100644 --- a/proxmox-rest-server/src/lib.rs +++ b/proxmox-rest-server/src/lib.rs @@ -1,4 +1,10 @@ -use anyhow::{bail, Error}; +use std::os::unix::io::RawFd; + +use anyhow::{bail, format_err, Error}; + +use proxmox::tools::fd::Fd; + +pub mod daemon; mod state; pub use state::*; @@ -52,3 +58,26 @@ pub fn fail_on_shutdown() -> Result<(), Error> { Ok(()) } +/// Helper to set/clear the FD_CLOEXEC flag on file descriptors +pub fn fd_change_cloexec(fd: RawFd, on: bool) -> Result<(), Error> { + use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD}; + let mut flags = FdFlag::from_bits(fcntl(fd, F_GETFD)?) + .ok_or_else(|| format_err!("unhandled file flags"))?; // nix crate is stupid this way... + flags.set(FdFlag::FD_CLOEXEC, on); + fcntl(fd, F_SETFD(flags))?; + Ok(()) +} + +/// safe wrapper for `nix::sys::socket::socketpair` defaulting to `O_CLOEXEC` and guarding the file +/// descriptors. +pub fn socketpair() -> Result<(Fd, Fd), Error> { + use nix::sys::socket; + let (pa, pb) = socket::socketpair( + socket::AddressFamily::Unix, + socket::SockType::Stream, + None, + socket::SockFlag::SOCK_CLOEXEC, + )?; + Ok((Fd(pa), Fd(pb))) +} +