From e94d09da9449cabd7ece2acd98d52b1946a922a4 Mon Sep 17 00:00:00 2001 From: Rory Dudley Date: Tue, 27 Feb 2024 03:49:01 -0700 Subject: Remove custom errors and fix background forking Removes the custom errors in src/recite/erro.rs, and replaces them with std::io::Errors throughout (recite(), incant_, macros). Fixed a bug with the way forking to the background is handled, where registering the signal handler in main for all processes would break couplets (i.e. pipes). Instead, this sets up a new signal handler each time a process is forked into the background. It uses a Vec to keep track of all the background processes. --- Cargo.lock | 56 -------------------------------------------------- Cargo.toml | 1 - src/main.rs | 23 ++++++++++----------- src/recite.rs | 60 ++++++++++++++++++++++++++++++++++++------------------ src/recite/erro.rs | 15 -------------- src/recite/ps.rs | 44 ++++++++------------------------------- 6 files changed, 59 insertions(+), 140 deletions(-) delete mode 100644 src/recite/erro.rs diff --git a/Cargo.lock b/Cargo.lock index 7654911..dc481fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,6 @@ version = "0.0.0" dependencies = [ "libc", "signal-hook", - "thiserror", ] [[package]] @@ -17,24 +16,6 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - [[package]] name = "signal-hook" version = "0.3.17" @@ -53,40 +34,3 @@ checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] - -[[package]] -name = "syn" -version = "2.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml index 0f5a2c3..f560813 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,3 @@ path = "src/main.rs" [dependencies] libc = "0.2.153" signal-hook = "0.3.17" -thiserror = "1.0.57" diff --git a/src/main.rs b/src/main.rs index 44f2726..b87089a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod recite; -use libc::{waitpid, WNOHANG}; use recite::path::prefresh; use recite::Poem; use std::io::{self, Write}; @@ -43,6 +42,16 @@ fn repl(path: &Vec<&Path>, prompt: &str) { break; } + // Kill zombies + // TODO: Remove this (since it was implemented in incant_quiet()) + // unsafe { + // let mut status = -1; + // let mut pid = waitpid(-1, &mut status, WNOHANG); + // while pid > 0 { + // pid = waitpid(-1, &mut status, WNOHANG); + // } + // } + // Trim the input let poetry = String::from(poetry.trim()); @@ -56,7 +65,7 @@ fn repl(path: &Vec<&Path>, prompt: &str) { match poem { Some(poem) => match poem.recite(path, &mut bins) { Ok(_) => {} - Err(e) => eprintln!("dwvsh: {}", e), + Err(e) => eprintln!("dwvsh: {}", e.to_string().to_lowercase()), }, None => {} }; @@ -89,16 +98,6 @@ fn main() { io::stdout().flush().unwrap(); }) .unwrap(); - - signal_hook::low_level::register(signal_hook::consts::SIGCHLD, move || { - let mut status: i32 = -1; - let pid: i32 = waitpid(-1, &mut status, WNOHANG); - if pid != -1 { - print!("[&] + done {}", pid); - io::stdout().flush().unwrap(); - } - }) - .unwrap(); }; // Begin evaluating commands diff --git a/src/recite.rs b/src/recite.rs index bfcd6b1..f21a905 100644 --- a/src/recite.rs +++ b/src/recite.rs @@ -1,14 +1,13 @@ -pub mod erro; pub mod path; mod ps; -use crate::ctask; -use crate::task; +use crate::{ctask, task}; use core::fmt; -use erro::Mishap; +use libc::{waitpid, WNOHANG}; use path::prefresh; use std::io::{self, Write}; use std::path::Path; use std::process::{exit, Command, Stdio}; +use std::sync::{Arc, Mutex}; /// Describes the ending of a [Verse] /// @@ -50,29 +49,25 @@ impl fmt::Display for Meter { } impl Meter { - fn incant_none(verse: &Verse, out: &mut String) -> Result { + fn incant_none(verse: &Verse, out: &mut String) -> Result { let child = task!(verse, out); - let output = child - .wait_with_output() - .map_err(|_| Mishap::Terminated(verse.stanza.to_string()))?; + let output = child.wait_with_output()?; if !output.status.success() { - return Err(Mishap::Else(verse.stanza.to_string())); + return Ok(output.status.code().unwrap_or(-1)); } Ok(output.status.code().unwrap_or(0)) } - fn incant_couplet(verse: &Verse, out: &mut String) -> Result { + fn incant_couplet(verse: &Verse, out: &mut String) -> Result { let child = ctask!(verse, out); - let output = child - .wait_with_output() - .map_err(|_| Mishap::Terminated(verse.stanza.to_string()))?; + let output = child.wait_with_output()?; if !output.status.success() { - return Err(Mishap::Else(verse.stanza.to_string())); + return Ok(output.status.code().unwrap_or(-1)); } out.push_str( @@ -84,17 +79,41 @@ impl Meter { Ok(output.status.code().unwrap_or(0)) } - fn incant_quiet(verse: &Verse, out: &mut String) -> Result { + fn incant_quiet( + verse: &Verse, + out: &mut String, + pids: &mut Arc>>, + ) -> Result { let child = task!(verse, out); println!("[&] {}", child.id()); + + pids.lock().unwrap().push(child.id() as i32); + let stanza = verse.stanza.to_string(); + let pids = Arc::clone(pids); + + unsafe { + signal_hook::low_level::register(signal_hook::consts::SIGCHLD, move || { + for pid in pids.lock().unwrap().iter() { + let mut pid = *pid; + let mut status: i32 = 0; + pid = waitpid(pid, &mut status, WNOHANG); + if pid > 0 { + print!("\n[&] + done {}", stanza); + io::stdout().flush().unwrap(); + } + } + }) + .unwrap(); + } + Ok(0) } - fn incant_and(verse: &Verse, out: &mut String) -> Result { + fn incant_and(verse: &Verse, out: &mut String) -> Result { Meter::incant_none(verse, out) } - fn incant_string(verse: &Verse, out: &mut String) -> Result { + fn incant_string(verse: &Verse, out: &mut String) -> Result { Meter::incant_none(verse, out) } } @@ -314,9 +333,10 @@ impl Poem { /// None => {} /// } /// ``` - pub fn recite(&self, path: &Vec<&Path>, bins: &mut Vec) -> Result<(), Mishap> { + pub fn recite(&self, path: &Vec<&Path>, bins: &mut Vec) -> Result<(), io::Error> { // Variable for storing the output of a piped verse let mut out: String = String::new(); + let mut pids: Arc>> = Arc::new(Mutex::new(Vec::new())); // Loop through each verse in the poem for verse in self.verses.iter() { @@ -359,12 +379,12 @@ impl Poem { match verse.meter { Meter::None => Meter::incant_none(verse, &mut out)?, Meter::Couplet => Meter::incant_couplet(verse, &mut out)?, - Meter::Quiet => Meter::incant_quiet(verse, &mut out)?, + Meter::Quiet => Meter::incant_quiet(verse, &mut out, &mut pids)?, Meter::And => Meter::incant_and(verse, &mut out)?, Meter::String => match Meter::incant_string(verse, &mut out) { Ok(_) => 0, Err(e) => { - eprintln!("dwvsh: {}", e); + eprintln!("dwvsh: {}", e.to_string().to_lowercase()); 1 } }, diff --git a/src/recite/erro.rs b/src/recite/erro.rs deleted file mode 100644 index 00f57b3..0000000 --- a/src/recite/erro.rs +++ /dev/null @@ -1,15 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Mishap { - #[error("broken pipe: {0}")] - BrokenPipe(String), - // #[error("exec format error: {0}")] - // ExecFormat(String), - #[error("permission denied: {0}")] - PermissionDenied(String), - #[error("terminated: {0}")] - Terminated(String), - #[error("exec error: {0}")] - Else(String), -} diff --git a/src/recite/ps.rs b/src/recite/ps.rs index 3557505..30c3d7c 100644 --- a/src/recite/ps.rs +++ b/src/recite/ps.rs @@ -5,30 +5,15 @@ macro_rules! task { let mut child = Command::new($verse.verb()) .args($verse.clause()) .stdin(Stdio::piped()) - .spawn() - .map_err(|e| match e.kind() { - io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), - _ => Mishap::Else($verse.verb()), - })?; + .spawn()?; - let stdin = child - .stdin - .as_mut() - .ok_or(Mishap::BrokenPipe($verse.verb()))?; - stdin - .write_all(&$out.as_bytes()) - .map_err(|_| Mishap::BrokenPipe($verse.verb()))?; + let stdin = child.stdin.as_mut().ok_or(io::ErrorKind::BrokenPipe)?; + stdin.write_all(&$out.as_bytes())?; $out.clear(); child } else { - Command::new($verse.verb()) - .args($verse.clause()) - .spawn() - .map_err(|e| match e.kind() { - io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), - _ => Mishap::Else($verse.verb()), - })? + Command::new($verse.verb()).args($verse.clause()).spawn()? } }; } @@ -41,19 +26,10 @@ macro_rules! ctask { .args($verse.clause()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) - .spawn() - .map_err(|e| match e.kind() { - io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), - _ => Mishap::Else($verse.verb()), - })?; + .spawn()?; - let stdin = child - .stdin - .as_mut() - .ok_or(Mishap::BrokenPipe($verse.verb()))?; - stdin - .write_all(&$out.as_bytes()) - .map_err(|_| Mishap::BrokenPipe($verse.verb()))?; + let stdin = child.stdin.as_mut().ok_or(io::ErrorKind::BrokenPipe)?; + stdin.write_all(&$out.as_bytes())?; $out.clear(); child @@ -61,11 +37,7 @@ macro_rules! ctask { Command::new($verse.verb()) .args($verse.clause()) .stdout(Stdio::piped()) - .spawn() - .map_err(|e| match e.kind() { - io::ErrorKind::PermissionDenied => Mishap::PermissionDenied($verse.verb()), - _ => Mishap::Else($verse.verb()), - })? + .spawn()? } }; } -- cgit v1.2.3