1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-09-13 18:47:58 +00:00

Merge pull request #304 from torkve/master

nohup implementation
This commit is contained in:
Arcterus 2014-06-25 23:46:30 -07:00
commit 8568d41a09
5 changed files with 185 additions and 2 deletions

View file

@ -111,6 +111,10 @@ path = "mkfifo/mkfifo.rs"
name = "nl"
path = "nl/nl.rs"
[[bin]]
name = "nohup"
path = "nohup/nohup.rs"
[[bin]]
name = "paste"
path = "paste/paste.rs"

View file

@ -56,6 +56,7 @@ UNIX_PROGS := \
kill \
logname \
mkfifo \
nohup \
tty \
uname \
uptime \

View file

@ -113,7 +113,9 @@ these steps:
1. Open an issue named "Implement [the utility of your choice]", e.g. "Implement ls"
2. State that you are working on this utility.
3. Develop the utility.
4. Submit a pull request and close the issue. Your pull request should include deleting the utility from the to-do list on this README.
4. Add the reference to your utility into uutils/uutils.rs (required for multibinary).
5. Remove utility from the to-do list on this README.
6. Submit a pull request and close the issue.
The steps above imply that, before starting to work on a utility, you should search the issues to make sure no one else is working on it.
@ -144,7 +146,6 @@ To do
- mktemp
- mv
- nice
- nohup
- nproc
- numfmt
- od

175
nohup/nohup.rs Normal file
View file

@ -0,0 +1,175 @@
#![crate_id = "nohup#1.0.0"]
/*
* This file is part of the uutils coreutils package.
*
* (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#![feature(macro_rules)]
extern crate getopts;
extern crate libc;
extern crate native;
use getopts::{optflag, getopts, usage};
use std::io::stdio::{stdin_raw, stdout_raw, stderr_raw};
use std::rt::rtio::{Open, Read, Append, Write};
use libc::funcs::posix88::unistd::{dup2, execvp};
use libc::consts::os::posix88::SIGHUP;
use libc::funcs::posix01::signal::signal;
use libc::consts::os::posix01::SIG_IGN;
#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;
static NAME: &'static str = "nohup";
static VERSION: &'static str = "1.0.0";
#[cfg(target_os = "macos")]
extern {
fn _vprocmgr_detach_from_console(flags: u32) -> *libc::c_int;
}
#[cfg(target_os = "macos")]
fn rewind_stdout<T: std::rt::rtio::RtioFileStream>(s: &mut T) {
s.seek(0, std::rt::rtio::SeekEnd);
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
fn _vprocmgr_detach_from_console(_: u32) -> *libc::c_int { std::ptr::null() }
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
fn rewind_stdout<T: std::rt::rtio::RtioFileStream>(_: &mut T) {}
#[allow(dead_code)]
fn main () { std::os::set_exit_status(uumain(std::os::args())); }
pub fn uumain(args: Vec<String>) -> int {
let program = args.get(0);
let options = [
optflag("h", "help", "Show help and exit"),
optflag("V", "version", "Show version and exit"),
];
let opts = match getopts(args.tail(), options) {
Ok(m) => m,
Err(f) => {
show_error!("{}", f);
show_usage(program.as_slice(), options);
return 1
}
};
if opts.opt_present("V") { version(); return 0 }
if opts.opt_present("h") { show_usage(program.as_slice(), options); return 0 }
if opts.free.len() == 0 {
show_error!("Missing operand: COMMAND");
println!("Try `{:s} --help` for more information.", program.as_slice());
return 1
}
replace_fds();
unsafe { signal(SIGHUP, SIG_IGN) };
if _vprocmgr_detach_from_console(0) != std::ptr::null() { crash!(2, "Cannot detach from console")};
unsafe {
// we ignore the memory leak here because it doesn't matter anymore
let executable = opts.free.get(0).as_slice().to_c_str().unwrap();
let mut args: Vec<*i8> = opts.free.iter().map(|x| x.to_c_str().unwrap()).collect();
args.push(std::ptr::null());
execvp(executable as *libc::c_char, args.as_ptr() as **libc::c_char) as int
}
}
fn replace_fds() {
let replace_stdin = stdin_raw().isatty();
let replace_stdout = stdout_raw().isatty();
let replace_stderr = stderr_raw().isatty();
if replace_stdin {
let devnull = "/dev/null".to_c_str();
let new_stdin = match native::io::file::open(&devnull, Open, Read) {
Ok(t) => t,
Err(_) => {
let e = std::io::IoError::last_error();
crash!(2, "Cannot replace STDIN: {}", e)
}
};
if unsafe { dup2(new_stdin.fd(), 0) } != 0 {
crash!(2, "Cannot replace STDIN: {}", std::io::IoError::last_error())
}
}
if replace_stdout {
let mut new_stdout = find_stdout();
rewind_stdout(&mut new_stdout);
if unsafe { dup2(new_stdout.fd(), 1) } != 1 {
crash!(2, "Cannot replace STDOUT: {}", std::io::IoError::last_error())
}
}
if replace_stderr {
if unsafe { dup2(1, 2) } != 2 {
crash!(2, "Cannot replace STDERR: {}", std::io::IoError::last_error())
}
}
}
fn find_stdout() -> native::io::file::FileDesc {
let localout = "nohup.out".to_c_str();
match native::io::file::open(&localout, Append, Write) {
Ok(t) => {
show_warning!("Output is redirected to: nohup.out");
t
},
Err(_) => {
let e = std::io::IoError::last_error();
let home = match std::os::getenv("HOME") {
None => crash!(2, "Cannot replace STDOUT: {}", e),
Some(h) => h
};
let mut homeoutpath = Path::new(home);
homeoutpath.push("nohup.out");
let homeout = homeoutpath.to_c_str();
match native::io::file::open(&homeout, Append, Write) {
Ok(t) => {
show_warning!("Output is redirected to: {}", homeoutpath.display());
t
},
Err(_) => {
let e = std::io::IoError::last_error();
crash!(2, "Cannot replace STDOUT: {}", e)
}
}
}
}
}
fn version() {
println!("{} v{}", NAME, VERSION)
}
fn show_usage(program: &str, options: &[getopts::OptGroup]) {
version();
println!("Usage:");
println!(" {:s} COMMAND [ARG]…", program);
println!(" {:s} OPTION", program);
println!("");
print!("{:s}", usage(
"Run COMMAND ignoring hangup signals.\n\
If standard input is terminal, it'll be replaced with /dev/null.\n\
If standard output is terminal, it'll be appended to nohup.out instead, \
or $HOME/nohup.out, if nohup.out open failed.\n\
If standard error is terminal, it'll be redirected to stdout.", options)
);
}

View file

@ -37,6 +37,7 @@ extern crate hashsum;
extern crate mkdir;
extern crate mkfifo;
extern crate nl;
extern crate nohup;
extern crate paste;
extern crate printenv;
extern crate pwd;
@ -104,6 +105,7 @@ fn util_map() -> HashMap<&str, fn(Vec<String>) -> int> {
map.insert("mkdir", mkdir::uumain);
map.insert("mkfifo", mkfifo::uumain);
map.insert("nl", nl::uumain);
map.insert("nohup", nohup::uumain);
map.insert("paste", paste::uumain);
map.insert("printenv", printenv::uumain);
map.insert("pwd", pwd::uumain);