diff --git a/moss/src/client/mod.rs b/moss/src/client/mod.rs index cb3f0edb..8f0965c1 100644 --- a/moss/src/client/mod.rs +++ b/moss/src/client/mod.rs @@ -38,9 +38,9 @@ use self::verify::verify; use crate::{ db, environment, installation, package, registry::plugin::{self, Plugin}, - repository, runtime, + repository, runtime, signal, state::{self, Selection}, - Installation, Package, Registry, State, + Installation, Package, Registry, Signal, State, }; pub mod boot; @@ -277,6 +277,8 @@ impl Client { /// /// Returns `None` if the client is ephemeral pub fn new_state(&self, selections: &[Selection], summary: impl ToString) -> Result, Error> { + let _guard = signal::ignore([Signal::SIGINT])?; + let old_state = self.installation.active_state; let fstree = self.blit_root(selections.iter().map(|s| &s.package))?; @@ -952,4 +954,6 @@ pub enum Error { /// The operation was explicitly cancelled at the user's request #[error("cancelled")] Cancelled, + #[error("ignore signals during blit")] + BlitSignalIgnore(#[from] signal::Error), } diff --git a/moss/src/client/verify.rs b/moss/src/client/verify.rs index 5d0063ac..c8efcf03 100644 --- a/moss/src/client/verify.rs +++ b/moss/src/client/verify.rs @@ -15,7 +15,7 @@ use vfs::tree::BlitFile; use crate::{ client::{self, cache}, - package, runtime, state, Client, + package, runtime, signal, state, Client, Signal, }; pub fn verify(client: &Client, yes: bool, verbose: bool) -> Result<(), client::Error> { @@ -224,6 +224,8 @@ pub fn verify(client: &Client, yes: bool, verbose: bool) -> Result<(), client::E println!("Reblitting affected states"); + let _guard = signal::ignore([Signal::SIGINT])?; + // Reblit each state for id in issue_states { let state = states diff --git a/moss/src/lib.rs b/moss/src/lib.rs index 2a28deea..f1cb8cf8 100644 --- a/moss/src/lib.rs +++ b/moss/src/lib.rs @@ -8,6 +8,7 @@ pub use self::installation::Installation; pub use self::package::Package; pub use self::registry::Registry; pub use self::repository::Repository; +pub use self::signal::Signal; pub use self::state::State; pub mod client; @@ -20,4 +21,5 @@ pub mod registry; pub mod repository; pub mod request; pub mod runtime; +pub mod signal; pub mod state; diff --git a/moss/src/signal.rs b/moss/src/signal.rs new file mode 100644 index 00000000..3af1c1e4 --- /dev/null +++ b/moss/src/signal.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright © 2020-2024 Serpent OS Developers +// +// SPDX-License-Identifier: MPL-2.0 + +//! Signal handling + +use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet}; +use thiserror::Error; + +pub use nix::sys::signal::Signal; + +/// Ignore the provided signals until [`Guard`] is dropped +pub fn ignore(signals: impl IntoIterator) -> Result { + Ok(Guard( + signals + .into_iter() + .map(|signal| unsafe { + let action = sigaction( + signal, + &SigAction::new(SigHandler::SigIgn, SaFlags::empty(), SigSet::empty()), + ) + .map_err(Error::Ignore)?; + + Ok(PrevHandler { signal, action }) + }) + .collect::>()?, + )) +} + +/// A guard which restores the previous signal +/// handlers when dropped +pub struct Guard(Vec); + +impl Drop for Guard { + fn drop(&mut self) { + for PrevHandler { signal, action } in &self.0 { + unsafe { + let _ = sigaction(*signal, action); + }; + } + } +} + +struct PrevHandler { + signal: Signal, + action: SigAction, +} + +#[derive(Debug, Error)] +pub enum Error { + #[error("ignore signal")] + Ignore(#[source] nix::Error), +}