1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-01 05:27:45 +00:00

Merge pull request #2808 from jfinkels/nohup-uresult

nohup: return UResult from uumain() function
This commit is contained in:
Terts Diepraam 2021-12-29 15:08:04 +01:00 committed by GitHub
commit 5faf7a37f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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<CString> = 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<File> {
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()),
}
}
}