Skip to content

Commit 41fea00

Browse files
committed
Add SIGPIPE debugging logs and remove stderr checks from tests
1 parent 7f623af commit 41fea00

File tree

4 files changed

+167
-210
lines changed

4 files changed

+167
-210
lines changed

src/uu/dd/src/dd.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,10 @@ fn flush_caches_full_length(i: &Input, o: &Output) -> io::Result<()> {
11161116
/// If there is a problem reading from the input or writing to
11171117
/// this output.
11181118
fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
1119+
eprintln!("[DD-DEBUG] dd_copy() starting");
1120+
#[cfg(unix)]
1121+
uucore::signals::debug_sigpipe_disposition("dd_copy start");
1122+
11191123
// The read and write statistics.
11201124
//
11211125
// These objects are counters, initialized to zero. After each
@@ -1188,13 +1192,17 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
11881192
// The signal handler spawns an own thread that waits for signals.
11891193
// When the signal is received, it calls a handler function.
11901194
// We inject a handler function that manually triggers the alarm.
1195+
eprintln!("[DD-DEBUG] About to create SignalHandler");
11911196
#[cfg(target_os = "linux")]
11921197
let signal_handler = progress::SignalHandler::install_signal_handler(alarm.manual_trigger_fn());
11931198
#[cfg(target_os = "linux")]
11941199
if let Err(e) = &signal_handler {
1200+
eprintln!("[DD-DEBUG] SignalHandler creation failed: {e}");
11951201
if Some(StatusLevel::None) != i.settings.status {
11961202
eprintln!("{}\n\t{e}", translate!("dd-warning-signal-handler"));
11971203
}
1204+
} else {
1205+
eprintln!("[DD-DEBUG] SignalHandler created successfully");
11981206
}
11991207

12001208
// Index in the input file where we are reading bytes and in
@@ -1286,6 +1294,10 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
12861294
}
12871295
}
12881296

1297+
eprintln!("[DD-DEBUG] Main loop complete, about to call finalize()");
1298+
#[cfg(unix)]
1299+
uucore::signals::debug_sigpipe_disposition("dd_copy before finalize");
1300+
12891301
finalize(o, rstat, wstat, start, &prog_tx, output_thread, truncate)
12901302
}
12911303

@@ -1299,27 +1311,41 @@ fn finalize<T>(
12991311
output_thread: thread::JoinHandle<T>,
13001312
truncate: bool,
13011313
) -> io::Result<()> {
1314+
eprintln!("[DD-DEBUG] finalize() starting");
1315+
13021316
// Flush the output in case a partial write has been buffered but
13031317
// not yet written.
1318+
eprintln!("[DD-DEBUG] finalize() - flushing output");
13041319
let wstat_update = output.flush()?;
13051320

13061321
// Sync the output, if configured to do so.
1322+
eprintln!("[DD-DEBUG] finalize() - syncing output");
13071323
output.sync()?;
13081324

13091325
// Truncate the file to the final cursor location.
13101326
if truncate {
1327+
eprintln!("[DD-DEBUG] finalize() - truncating");
13111328
output.truncate();
13121329
}
13131330

13141331
// Print the final read/write statistics.
1332+
eprintln!("[DD-DEBUG] finalize() - sending final stats to progress thread");
13151333
let wstat = wstat + wstat_update;
13161334
let prog_update = ProgUpdate::new(rstat, wstat, start.elapsed(), ProgUpdateType::Final);
13171335
prog_tx.send(prog_update).unwrap_or(());
1336+
13181337
// Wait for the output thread to finish
1338+
eprintln!("[DD-DEBUG] finalize() - joining output thread");
13191339
output_thread
13201340
.join()
13211341
.expect("Failed to join with the output thread.");
13221342

1343+
eprintln!(
1344+
"[DD-DEBUG] finalize() - complete, about to return (SignalHandler will be dropped after this)"
1345+
);
1346+
#[cfg(unix)]
1347+
uucore::signals::debug_sigpipe_disposition("finalize before return");
1348+
13231349
Ok(())
13241350
}
13251351

src/uu/dd/src/progress.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,15 +463,26 @@ impl SignalHandler {
463463
use signal_hook::consts::signal::*;
464464
use signal_hook::iterator::Signals;
465465

466+
eprintln!("[DD-DEBUG] SignalHandler::install_signal_handler() - creating signal_hook pipe");
467+
uucore::signals::debug_sigpipe_disposition("SignalHandler::install before Signals::new");
468+
466469
let mut signals = Signals::new([SIGUSR1])?;
467470
let handle = signals.handle();
471+
472+
eprintln!(
473+
"[DD-DEBUG] SignalHandler::install_signal_handler() - signal_hook pipe created successfully"
474+
);
475+
uucore::signals::debug_sigpipe_disposition("SignalHandler::install after Signals::new");
476+
468477
let thread = std::thread::spawn(move || {
478+
eprintln!("[DD-DEBUG] SignalHandler signal thread started");
469479
for signal in &mut signals {
470480
match signal {
471481
SIGUSR1 => (*f)(),
472482
_ => unreachable!(),
473483
}
474484
}
485+
eprintln!("[DD-DEBUG] SignalHandler signal thread exiting");
475486
});
476487

477488
Ok(Self {
@@ -484,10 +495,19 @@ impl SignalHandler {
484495
#[cfg(target_os = "linux")]
485496
impl Drop for SignalHandler {
486497
fn drop(&mut self) {
498+
eprintln!("[DD-DEBUG] SignalHandler::drop() - about to close handle");
499+
uucore::signals::debug_sigpipe_disposition("SignalHandler::drop before handle.close");
500+
487501
self.handle.close();
502+
503+
eprintln!("[DD-DEBUG] SignalHandler::drop() - handle closed, joining thread");
504+
uucore::signals::debug_sigpipe_disposition("SignalHandler::drop after handle.close");
505+
488506
if let Some(thread) = std::mem::take(&mut self.thread) {
489507
thread.join().unwrap();
490508
}
509+
510+
eprintln!("[DD-DEBUG] SignalHandler::drop() - complete");
491511
}
492512
}
493513

src/uucore/src/lib/features/signals.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,16 +413,20 @@ pub fn signal_name_by_value(signal_value: usize) -> Option<&'static str> {
413413
/// Restores SIGPIPE to default behavior (process terminates on broken pipe).
414414
#[cfg(unix)]
415415
pub fn enable_pipe_errors() -> Result<(), Errno> {
416+
eprintln!("[SIGPIPE-DEBUG] enable_pipe_errors() called - setting SIGPIPE to SIG_DFL");
416417
// We pass the error as is, the return value would just be Ok(SigDfl), so we can safely ignore it.
417418
// SAFETY: this function is safe as long as we do not use a custom SigHandler -- we use the default one.
418-
unsafe { signal(SIGPIPE, SigDfl) }.map(|_| ())
419+
let result = unsafe { signal(SIGPIPE, SigDfl) }.map(|_| ());
420+
eprintln!("[SIGPIPE-DEBUG] enable_pipe_errors() result: {:?}", result);
421+
result
419422
}
420423

421424
/// Ignores SIGPIPE signal (broken pipe errors are returned instead of terminating).
422425
/// Use this to override the default SIGPIPE handling when you need to handle
423426
/// broken pipe errors gracefully (e.g., tee with --output-error).
424427
#[cfg(unix)]
425428
pub fn disable_pipe_errors() -> Result<(), Errno> {
429+
eprintln!("[SIGPIPE-DEBUG] disable_pipe_errors() called - setting SIGPIPE to SIG_IGN");
426430
// SAFETY: this function is safe as long as we do not use a custom SigHandler -- we use the default one.
427431
unsafe { signal(SIGPIPE, SigIgn) }.map(|_| ())
428432
}
@@ -545,14 +549,51 @@ pub const fn stderr_was_closed() -> bool {
545549
/// Returns whether SIGPIPE was ignored at process startup.
546550
#[cfg(unix)]
547551
pub fn sigpipe_was_ignored() -> bool {
548-
SIGPIPE_WAS_IGNORED.load(Ordering::Acquire)
552+
let was_ignored = SIGPIPE_WAS_IGNORED.load(Ordering::Acquire);
553+
eprintln!(
554+
"[SIGPIPE-DEBUG] sigpipe_was_ignored() returning: {}",
555+
was_ignored
556+
);
557+
was_ignored
549558
}
550559

551560
#[cfg(not(unix))]
552561
pub const fn sigpipe_was_ignored() -> bool {
553562
false
554563
}
555564

565+
/// Debug function: query and log current SIGPIPE disposition
566+
#[cfg(unix)]
567+
pub fn debug_sigpipe_disposition(context: &str) {
568+
use nix::libc;
569+
use std::mem::MaybeUninit;
570+
use std::ptr;
571+
572+
let mut current = MaybeUninit::<libc::sigaction>::uninit();
573+
if unsafe { libc::sigaction(libc::SIGPIPE, ptr::null(), current.as_mut_ptr()) } == 0 {
574+
let action = unsafe { current.assume_init() };
575+
let disposition = if action.sa_sigaction == libc::SIG_IGN {
576+
"SIG_IGN (ignored)"
577+
} else if action.sa_sigaction == libc::SIG_DFL {
578+
"SIG_DFL (default - will terminate on SIGPIPE)"
579+
} else {
580+
"custom handler"
581+
};
582+
eprintln!(
583+
"[SIGPIPE-DEBUG] {} - current SIGPIPE disposition: {}",
584+
context, disposition
585+
);
586+
} else {
587+
eprintln!(
588+
"[SIGPIPE-DEBUG] {} - failed to query SIGPIPE disposition",
589+
context
590+
);
591+
}
592+
}
593+
594+
#[cfg(not(unix))]
595+
pub fn debug_sigpipe_disposition(_context: &str) {}
596+
556597
#[cfg(target_os = "linux")]
557598
pub fn ensure_stdout_not_broken() -> std::io::Result<bool> {
558599
use nix::{

0 commit comments

Comments
 (0)