1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-02 14:07:46 +00:00

nohup: return UResult from uumain() function

This commit is contained in:
Jeffrey Finkelstein 2021-12-28 14:45:29 -05:00
parent f7584cb755
commit f91773037e

View file

@ -15,11 +15,13 @@ use libc::{c_char, dup2, execvp, signal};
use libc::{SIGHUP, SIG_IGN}; use libc::{SIGHUP, SIG_IGN};
use std::env; use std::env;
use std::ffi::CString; use std::ffi::CString;
use std::fmt::{Display, Formatter};
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::Error; use std::io::Error;
use std::os::unix::prelude::*; use std::os::unix::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{set_exit_code, UError, UResult};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static ABOUT: &str = "Run COMMAND ignoring hangup signals."; static ABOUT: &str = "Run COMMAND ignoring hangup signals.";
@ -40,7 +42,47 @@ mod options {
pub const CMD: &str = "cmd"; 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 usage = usage();
let args = args let args = args
.collect_str(InvalidEncodingHandling::ConvertLossy) .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); let matches = uu_app().usage(&usage[..]).get_matches_from(args);
replace_fds(); replace_fds()?;
unsafe { signal(SIGHUP, SIG_IGN) }; unsafe { signal(SIGHUP, SIG_IGN) };
if unsafe { !_vprocmgr_detach_from_console(0).is_null() } { if unsafe { !_vprocmgr_detach_from_console(0).is_null() } {
crash!(2, "Cannot detach from console") return Err(NohupError::CannotDetach.into());
}; };
let cstrs: Vec<CString> = matches let cstrs: Vec<CString> = matches
@ -66,9 +108,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let ret = unsafe { execvp(args[0], args.as_mut_ptr()) }; let ret = unsafe { execvp(args[0], args.as_mut_ptr()) };
match ret { match ret {
libc::ENOENT => EXIT_ENOENT, libc::ENOENT => set_exit_code(EXIT_ENOENT),
_ => EXIT_CANNOT_INVOKE, _ => set_exit_code(EXIT_CANNOT_INVOKE),
} }
Ok(())
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app() -> App<'static, 'static> {
@ -85,32 +128,31 @@ pub fn uu_app() -> App<'static, 'static> {
.setting(AppSettings::TrailingVarArg) .setting(AppSettings::TrailingVarArg)
} }
fn replace_fds() { fn replace_fds() -> UResult<()> {
if atty::is(atty::Stream::Stdin) { if atty::is(atty::Stream::Stdin) {
let new_stdin = match File::open(Path::new("/dev/null")) { let new_stdin = File::open(Path::new("/dev/null"))
Ok(t) => t, .map_err(|e| NohupError::CannotReplace("STDIN", e))?;
Err(e) => crash!(2, "Cannot replace STDIN: {}", e),
};
if unsafe { dup2(new_stdin.as_raw_fd(), 0) } != 0 { 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) { if atty::is(atty::Stream::Stdout) {
let new_stdout = find_stdout(); let new_stdout = find_stdout()?;
let fd = new_stdout.as_raw_fd(); let fd = new_stdout.as_raw_fd();
if unsafe { dup2(fd, 1) } != 1 { 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 { 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<File> {
let internal_failure_code = match std::env::var("POSIXLY_CORRECT") { let internal_failure_code = match std::env::var("POSIXLY_CORRECT") {
Ok(_) => POSIX_NOHUP_FAILURE, Ok(_) => POSIX_NOHUP_FAILURE,
Err(_) => EXIT_CANCELED, Err(_) => EXIT_CANCELED,
@ -127,14 +169,11 @@ fn find_stdout() -> File {
"ignoring input and appending output to {}", "ignoring input and appending output to {}",
NOHUP_OUT.quote() NOHUP_OUT.quote()
); );
t Ok(t)
} }
Err(e1) => { Err(e1) => {
let home = match env::var("HOME") { let home = match env::var("HOME") {
Err(_) => { Err(_) => return Err(NohupError::OpenFailed(internal_failure_code, e1).into()),
show_error!("failed to open {}: {}", NOHUP_OUT.quote(), e1);
exit!(internal_failure_code)
}
Ok(h) => h, Ok(h) => h,
}; };
let mut homeout = PathBuf::from(home); let mut homeout = PathBuf::from(home);
@ -151,13 +190,15 @@ fn find_stdout() -> File {
"ignoring input and appending output to {}", "ignoring input and appending output to {}",
homeout_str.quote() homeout_str.quote()
); );
t Ok(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)
} }
Err(e2) => Err(NohupError::OpenFailed2(
internal_failure_code,
e1,
homeout_str.to_string(),
e2,
)
.into()),
} }
} }
} }