From f91773037ec0567fb2e90cd087887df192a1978a Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Tue, 28 Dec 2021 14:45:29 -0500 Subject: [PATCH] nohup: return UResult from uumain() function --- src/uu/nohup/src/nohup.rs | 93 ++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 26 deletions(-) diff --git a/src/uu/nohup/src/nohup.rs b/src/uu/nohup/src/nohup.rs index d83170ae8..505911b3e 100644 --- a/src/uu/nohup/src/nohup.rs +++ b/src/uu/nohup/src/nohup.rs @@ -15,11 +15,13 @@ use libc::{c_char, dup2, execvp, signal}; use libc::{SIGHUP, SIG_IGN}; use std::env; use std::ffi::CString; +use std::fmt::{Display, Formatter}; use std::fs::{File, OpenOptions}; use std::io::Error; use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use uucore::display::Quotable; +use uucore::error::{set_exit_code, UError, UResult}; use uucore::InvalidEncodingHandling; static ABOUT: &str = "Run COMMAND ignoring hangup signals."; @@ -40,7 +42,47 @@ mod options { pub const CMD: &str = "cmd"; } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[derive(Debug)] +enum NohupError { + CannotDetach, + CannotReplace(&'static str, std::io::Error), + OpenFailed(i32, std::io::Error), + OpenFailed2(i32, std::io::Error, String, std::io::Error), +} + +impl std::error::Error for NohupError {} + +impl UError for NohupError { + fn code(&self) -> i32 { + match self { + NohupError::OpenFailed(code, _) | NohupError::OpenFailed2(code, _, _, _) => *code, + _ => 2, + } + } +} + +impl Display for NohupError { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + match self { + NohupError::CannotDetach => write!(f, "Cannot detach from console"), + NohupError::CannotReplace(s, e) => write!(f, "Cannot replace {}: {}", s, e), + NohupError::OpenFailed(_, e) => { + write!(f, "failed to open {}: {}", NOHUP_OUT.quote(), e) + } + NohupError::OpenFailed2(_, e1, s, e2) => write!( + f, + "failed to open {}: {}\nfailed to open {}: {}", + NOHUP_OUT.quote(), + e1, + s.quote(), + e2 + ), + } + } +} + +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let usage = usage(); let args = args .collect_str(InvalidEncodingHandling::ConvertLossy) @@ -48,12 +90,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let matches = uu_app().usage(&usage[..]).get_matches_from(args); - replace_fds(); + replace_fds()?; unsafe { signal(SIGHUP, SIG_IGN) }; if unsafe { !_vprocmgr_detach_from_console(0).is_null() } { - crash!(2, "Cannot detach from console") + return Err(NohupError::CannotDetach.into()); }; let cstrs: Vec = matches @@ -66,9 +108,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let ret = unsafe { execvp(args[0], args.as_mut_ptr()) }; match ret { - libc::ENOENT => EXIT_ENOENT, - _ => EXIT_CANNOT_INVOKE, + libc::ENOENT => set_exit_code(EXIT_ENOENT), + _ => set_exit_code(EXIT_CANNOT_INVOKE), } + Ok(()) } pub fn uu_app() -> App<'static, 'static> { @@ -85,32 +128,31 @@ pub fn uu_app() -> App<'static, 'static> { .setting(AppSettings::TrailingVarArg) } -fn replace_fds() { +fn replace_fds() -> UResult<()> { if atty::is(atty::Stream::Stdin) { - let new_stdin = match File::open(Path::new("/dev/null")) { - Ok(t) => t, - Err(e) => crash!(2, "Cannot replace STDIN: {}", e), - }; + let new_stdin = File::open(Path::new("/dev/null")) + .map_err(|e| NohupError::CannotReplace("STDIN", e))?; if unsafe { dup2(new_stdin.as_raw_fd(), 0) } != 0 { - crash!(2, "Cannot replace STDIN: {}", Error::last_os_error()) + return Err(NohupError::CannotReplace("STDIN", Error::last_os_error()).into()); } } if atty::is(atty::Stream::Stdout) { - let new_stdout = find_stdout(); + let new_stdout = find_stdout()?; let fd = new_stdout.as_raw_fd(); if unsafe { dup2(fd, 1) } != 1 { - crash!(2, "Cannot replace STDOUT: {}", Error::last_os_error()) + return Err(NohupError::CannotReplace("STDOUT", Error::last_os_error()).into()); } } if atty::is(atty::Stream::Stderr) && unsafe { dup2(1, 2) } != 2 { - crash!(2, "Cannot replace STDERR: {}", Error::last_os_error()) + return Err(NohupError::CannotReplace("STDERR", Error::last_os_error()).into()); } + Ok(()) } -fn find_stdout() -> File { +fn find_stdout() -> UResult { let internal_failure_code = match std::env::var("POSIXLY_CORRECT") { Ok(_) => POSIX_NOHUP_FAILURE, Err(_) => EXIT_CANCELED, @@ -127,14 +169,11 @@ fn find_stdout() -> File { "ignoring input and appending output to {}", NOHUP_OUT.quote() ); - t + Ok(t) } Err(e1) => { let home = match env::var("HOME") { - Err(_) => { - show_error!("failed to open {}: {}", NOHUP_OUT.quote(), e1); - exit!(internal_failure_code) - } + Err(_) => return Err(NohupError::OpenFailed(internal_failure_code, e1).into()), Ok(h) => h, }; let mut homeout = PathBuf::from(home); @@ -151,13 +190,15 @@ fn find_stdout() -> File { "ignoring input and appending output to {}", homeout_str.quote() ); - t - } - Err(e2) => { - show_error!("failed to open {}: {}", NOHUP_OUT.quote(), e1); - show_error!("failed to open {}: {}", homeout_str.quote(), e2); - exit!(internal_failure_code) + Ok(t) } + Err(e2) => Err(NohupError::OpenFailed2( + internal_failure_code, + e1, + homeout_str.to_string(), + e2, + ) + .into()), } } }