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:
commit
5faf7a37f9
1 changed files with 67 additions and 26 deletions
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue