main: Trap SIGQUIT to trigger a blackbox

The signal_hook crate makes this easy, but unfortunately insists on
hardcoding SA_RESTART. So we have to then use libc directly to patch
that out...

Still worth using signal_hook for the atomic flag helper though.

Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
Hector Martin 2023-12-04 17:58:44 +09:00
parent 4fb7fe7b41
commit 60752494cd
3 changed files with 49 additions and 2 deletions

25
Cargo.lock generated
View file

@ -286,9 +286,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.137" version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
@ -414,6 +414,25 @@ version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "simple_logger" name = "simple_logger"
version = "1.16.0" version = "1.16.0"
@ -437,7 +456,9 @@ dependencies = [
"clap-verbosity-flag", "clap-verbosity-flag",
"configparser", "configparser",
"json", "json",
"libc",
"log", "log",
"signal-hook",
"simple_logger", "simple_logger",
] ]

View file

@ -15,3 +15,5 @@ clap-verbosity-flag = "2.0.0"
simple_logger = "1.16.0" simple_logger = "1.16.0"
chrono = "0.4.31" chrono = "0.4.31"
json = "0.12.4" json = "0.12.4"
signal-hook = "0.3.17"
libc = "0.2.150"

View file

@ -11,6 +11,8 @@ use std::collections::BTreeMap;
use std::fs; use std::fs;
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
use alsa::nix::errno::Errno; use alsa::nix::errno::Errno;
@ -88,6 +90,22 @@ impl Default for SpeakerGroup {
fn main() { fn main() {
let args = Options::parse(); let args = Options::parse();
let sigquit = Arc::new(AtomicBool::new(false));
signal_hook::flag::register(signal_hook::consts::SIGQUIT, Arc::clone(&sigquit)).unwrap();
// signal_hook insists on using SA_RESTART, which we don't want. Override it.
unsafe {
let mut act: libc::sigaction = core::mem::zeroed();
assert!(libc::sigaction(signal_hook::consts::SIGQUIT, core::ptr::null(), &mut act) == 0);
act.sa_flags &= !libc::SA_RESTART;
assert!(
libc::sigaction(
signal_hook::consts::SIGQUIT,
&mut act,
core::ptr::null_mut()
) == 0
);
}
SimpleLogger::new() SimpleLogger::new()
.with_level(args.verbose.log_level_filter()) .with_level(args.verbose.log_level_filter())
.without_timestamps() .without_timestamps()
@ -223,10 +241,16 @@ fn main() {
let mut once_nominal = false; let mut once_nominal = false;
loop { loop {
if sigquit.load(Ordering::Relaxed) {
panic!("SIGQUIT received");
}
// Block while we're reading into the buffer // Block while we're reading into the buffer
let read = io let read = io
.readi(&mut buf) .readi(&mut buf)
.or_else(|e| { .or_else(|e| {
if sigquit.load(Ordering::Relaxed) {
panic!("SIGQUIT received");
}
if e.errno() == Errno::ESTRPIPE { if e.errno() == Errno::ESTRPIPE {
warn!("Suspend detected!"); warn!("Suspend detected!");
// Resume handling // Resume handling