chiark / gitweb /
utils: Provide RawStdout and the associated SigPipeWriter
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 1 Jun 2021 12:58:22 +0000 (13:58 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 1 Jun 2021 14:47:10 +0000 (15:47 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/utils.rs

index 4b7c070420347522424cd2f321fab522bd63247a..4c239b3443ea1207e0e56bc5e7daf127846882d1 100644 (file)
@@ -694,6 +694,43 @@ where R: Read, W: Write {
   }
 }
 
+pub struct SigPipeWriter<W>(pub W);
+
+impl<W:Write> SigPipeWriter<W> {
+  fn handle_err(e: io::Error) -> io::Error {
+    if e.kind() != ErrorKind::BrokenPipe { return e }
+
+    match (||{
+      use nix::sys::signal::*;
+      use Signal::SIGPIPE;
+      unsafe {
+        sigaction(SIGPIPE, &SigAction::new(
+          SigHandler::SigDfl, SaFlags::empty(), SigSet::empty()))
+          .context("sigaction")?;
+      };
+      raise(SIGPIPE).context("raise")?;
+      Err::<Void,_>(anyhow!("continued after raise"))
+    })() {
+      Err(ae) => ae
+        .context("attempt to die with SIGPIPE failed")
+        .end_process(127),
+      Ok(v) => match v { },
+    }
+  }
+}
+
+impl<W:Write> Write for SigPipeWriter<W> {
+  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+    self.0.write(buf).map_err(Self::handle_err)
+  }
+  fn flush(&mut self)             -> io::Result<()>    {
+    self.0.flush()   .map_err(Self::handle_err)
+  }
+}
+
+pub type RawStdout = SigPipeWriter<io::Stdout>;
+impl RawStdout { pub fn new() -> Self { SigPipeWriter(io::stdout()) } }
+
 #[throws(fmt::Error)]
 pub fn fmt_hex(f: &mut Formatter, buf: &[u8]) {
   for v in buf { write!(f, "{:02x}", v)?; }