diff --git a/Makefile b/Makefile index 4e57679d1..45a92ed76 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ PROGS := \ head \ UNIX_PROGS := \ + kill \ logname \ users \ whoami \ diff --git a/README.md b/README.md index cf06b8650..f6addf164 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,6 @@ To do - hostid - install - join -- kill - lbracket - libstdbuf - link diff --git a/common/util.rs b/common/util.rs index 9bd9bb5ae..05542598e 100644 --- a/common/util.rs +++ b/common/util.rs @@ -12,7 +12,7 @@ #[macro_export] macro_rules! show_error( ($exitcode:expr, $($args:expr),+) => ({ - ::std::os::set_exit_status($exitcode); + ::std::os::set_exit_status($exitcode as int); safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME); safe_writeln!(&mut ::std::io::stderr(), $($args),+); }) @@ -30,6 +30,14 @@ macro_rules! show_warning( macro_rules! crash( ($exitcode:expr, $($args:expr),+) => ({ show_error!($exitcode, $($args),+); + unsafe { ::std::libc::exit($exitcode as ::std::libc::c_int); } + }) +) + + +#[macro_export] +macro_rules! exit( + ($exitcode:expr) => ({ unsafe { ::std::libc::exit($exitcode); } }) ) diff --git a/kill/kill.rs b/kill/kill.rs new file mode 100644 index 000000000..f44f0b285 --- /dev/null +++ b/kill/kill.rs @@ -0,0 +1,209 @@ +#![crate_id(name="kill", vers="0.0.1", author="Maciej Dziardziel")] +#![feature(macro_rules)] +#![feature(phase)] + +/* + * This file is part of the uutils coreutils package. + * + * (c) Maciej Dziardziel + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + + +extern crate getopts; +extern crate collections; +extern crate serialize; + +#[phase(syntax, link)] extern crate log; + +use std::os; +use std::from_str::from_str; +use std::io::process::Process; + +use getopts::{ + getopts, + optopt, + optflag, + optflagopt, + usage, +}; + +use signals::{ + ALL_SIGNALS, + DEFAULT_SIGNAL, +}; + +mod signals; + +#[path = "../common/util.rs"] +mod util; + +static NAME: &'static str = "kill"; +static VERSION: &'static str = "0.0.1"; + +static EXIT_OK: i32 = 0; +static EXIT_ERR: i32 = 1; + + + +pub enum Mode { + Kill, + Table, + List, + Help, + Version, +} + + +fn main() { + let args = os::args(); + + let opts = ~[ + optflag("h", "help", "display this help and exit"), + optflag("V", "version", "output version information and exit"), + optopt("s", "signal", "specify the to be sent", "SIGNAL"), + optflagopt("l", "list", "list all signal names, or convert one to a name", "LIST"), + optflag("L", "table", "list all signal names in a nice table"), + ]; + + let usage = usage("[options] [...]", opts); + + + let matches = match getopts(args.tail(), opts) { + Ok(m) => m, + Err(e) => { + let msg = format!("{}\n{}", e.to_err_msg(), get_help_text(NAME, usage)); + show_error!(EXIT_ERR, "{}", msg); + return + }, + }; + + + let mode = if matches.opt_present("version") { + Version + } else if matches.opt_present("help") { + Help + } else if matches.opt_present("table") { + Table + } else if matches.opt_present("list") { + List + } else { + Kill + }; + + match mode { + Kill => kill(matches.opt_str("signal").unwrap_or(~"9"), matches.free), + Table => table(), + List => list(matches.opt_str("list")), + Help => help(NAME, usage), + Version => version(), + } +} + +fn version() { + println!("{} {}", NAME, VERSION); +} + +fn table() { + + let mut name_width = 0; + /* Compute the maximum width of a signal name. */ + for s in ALL_SIGNALS.iter() { + if s.name.len() > name_width { + name_width = s.name.len() + } + } + + for (idx, signal) in ALL_SIGNALS.iter().enumerate() { + print!("{0: >#2} {1: <#8}", idx+1, signal.name); + //TODO: obtain max signal width here + + if (idx+1) % 7 == 0 { + println!(""); + } + } +} + +fn print_signal(signal_name_or_value: ~str) { + for signal in ALL_SIGNALS.iter() { + if signal.name == signal_name_or_value || ("SIG" + signal.name) == signal_name_or_value { + println!("{}", signal.value) + exit!(EXIT_OK) + } else if signal_name_or_value == signal.value.to_str() { + println!("{}", signal.name); + exit!(EXIT_OK) + } + } + crash!(EXIT_ERR, "unknown signal name {}", signal_name_or_value) +} + +fn print_signals() { + let mut pos = 0; + for (idx, signal) in ALL_SIGNALS.iter().enumerate() { + pos += signal.name.len(); + print!("{}", signal.name); + if idx > 0 && pos > 73 { + println!(""); + pos = 0; + } else { + pos += 1; + print!(" "); + } + } +} + +fn list(arg: Option<~str>) { + match arg { + Some(x) => print_signal(x), + None => print_signals(), + }; +} + +fn get_help_text(progname: &str, usage: &str) -> ~str { + let msg = format!("Usage: \n {0} {1}", progname, usage); + msg +} + +fn help(progname: &str, usage: &str) { + println!("{}", get_help_text(progname, usage)); +} + +fn signal_by_name_or_value(signal_name_or_value:~str) -> Option { + if signal_name_or_value == ~"0"{ + return Some(0); + } + for signal in ALL_SIGNALS.iter() { + let long_name = "SIG" + signal.name; + if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_str()) || (long_name == signal_name_or_value) { + return Some(signal.value); + } + } + return None; +} + +fn kill(signalname: ~str, pids: std::vec::Vec<~str>) { + let optional_signal_value = signal_by_name_or_value(signalname.clone()); + let mut signal_value:uint = DEFAULT_SIGNAL; + match optional_signal_value { + Some(x) => signal_value = x, + None => { + crash!(EXIT_ERR, "unknown signal name {}", signalname) + } + } + for pid in pids.iter() { + match from_str::(*pid) { + Some(x) => { + let result = Process::kill(x, signal_value as int); + match result { + Ok(_) => (), + Err(_) => () + }; + }, + None => { + crash!(EXIT_ERR, "failed to parse argument {}", signalname) + }, + }; + } +} diff --git a/kill/signals.rs b/kill/signals.rs new file mode 100644 index 000000000..74039a565 --- /dev/null +++ b/kill/signals.rs @@ -0,0 +1,138 @@ +/* + * This file is part of the uutils coreutils package. + * + * (c) Maciej Dziardziel + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +pub static DEFAULT_SIGNAL:uint = 15; + + +pub struct Signal<'a> { pub name:&'a str, pub value: uint} + +/* + +Linux Programmer's Manual + + 1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS + 8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM +15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN +22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH +29 POLL 30 PWR 31 SYS + + +*/ + +#[cfg(target_os = "linux")] +pub static ALL_SIGNALS:[Signal<'static>, ..31] = [ + Signal{ name: "HUP", value:1 }, + Signal{ name: "INT", value:2 }, + Signal{ name: "QUIT", value:3 }, + Signal{ name: "ILL", value:4 }, + Signal{ name: "TRAP", value:5 }, + Signal{ name: "ABRT", value:6 }, + Signal{ name: "BUS", value:7 }, + Signal{ name: "FPE", value:8 }, + Signal{ name: "KILL", value:9 }, + Signal{ name: "USR1", value:10 }, + Signal{ name: "SEGV", value:11 }, + Signal{ name: "USR2", value:12 }, + Signal{ name: "PIPE", value:13 }, + Signal{ name: "ALRM", value:14 }, + Signal{ name: "TERM", value:15 }, + Signal{ name: "STKFLT", value:16 }, + Signal{ name: "CHLD", value:17 }, + Signal{ name: "CONT", value:18 }, + Signal{ name: "STOP", value:19 }, + Signal{ name: "TSTP", value:20 }, + Signal{ name: "TTIN", value:21 }, + Signal{ name: "TTOU", value:22 }, + Signal{ name: "URG", value:23 }, + Signal{ name: "XCPU", value:24 }, + Signal{ name: "XFSZ", value:25 }, + Signal{ name: "VTALRM", value:26 }, + Signal{ name: "PROF", value:27 }, + Signal{ name: "WINCH", value:28 }, + Signal{ name: "POLL", value:29 }, + Signal{ name: "PWR", value:30 }, + Signal{ name: "SYS", value:31 }, +]; + + +/* + + +https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html + + +No Name Default Action Description +1 SIGHUP terminate process terminal line hangup +2 SIGINT terminate process interrupt program +3 SIGQUIT create core image quit program +4 SIGILL create core image illegal instruction +5 SIGTRAP create core image trace trap +6 SIGABRT create core image abort program (formerly SIGIOT) +7 SIGEMT create core image emulate instruction executed +8 SIGFPE create core image floating-point exception +9 SIGKILL terminate process kill program +10 SIGBUS create core image bus error +11 SIGSEGV create core image segmentation violation +12 SIGSYS create core image non-existent system call invoked +13 SIGPIPE terminate process write on a pipe with no reader +14 SIGALRM terminate process real-time timer expired +15 SIGTERM terminate process software termination signal +16 SIGURG discard signal urgent condition present on socket +17 SIGSTOP stop process stop (cannot be caught or ignored) +18 SIGTSTP stop process stop signal generated from keyboard +19 SIGCONT discard signal continue after stop +20 SIGCHLD discard signal child status has changed +21 SIGTTIN stop process background read attempted from control terminal +22 SIGTTOU stop process background write attempted to control terminal +23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2)) +24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2)) +25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2)) +26 SIGVTALRM terminate process virtual time alarm (see setitimer(2)) +27 SIGPROF terminate process profiling timer alarm (see setitimer(2)) +28 SIGWINCH discard signal Window size change +29 SIGINFO discard signal status request from keyboard +30 SIGUSR1 terminate process User defined signal 1 +31 SIGUSR2 terminate process User defined signal 2 + +*/ + +#[cfg(target_os = "macos")] +pub static ALL_SIGNALS:[Signal<'static>, ..31] = [ + Signal{ name: "HUP", value:1 }, + Signal{ name: "INT", value:2 }, + Signal{ name: "QUIT", value:3 }, + Signal{ name: "ILL", value:4 }, + Signal{ name: "TRAP", value:5 }, + Signal{ name: "ABRT", value:6 }, + Signal{ name: "EMT", value:7 }, + Signal{ name: "FPE", value:8 }, + Signal{ name: "KILL", value:9 }, + Signal{ name: "BUS", value:10 }, + Signal{ name: "SEGV", value:11 }, + Signal{ name: "SYS", value:12 }, + Signal{ name: "PIPE", value:13 }, + Signal{ name: "ALRM", value:14 }, + Signal{ name: "TERM", value:15 }, + Signal{ name: "URG", value:16 }, + Signal{ name: "STOP", value:17 }, + Signal{ name: "TSTP", value:18 }, + Signal{ name: "CONT", value:19 }, + Signal{ name: "CHLD", value:20 }, + Signal{ name: "TTIN", value:21 }, + Signal{ name: "TTOU", value:22 }, + Signal{ name: "IO", value:23 }, + Signal{ name: "XCPU", value:24 }, + Signal{ name: "XFSZ", value:25 }, + Signal{ name: "VTALRM", value:26 }, + Signal{ name: "PROF", value:27 }, + Signal{ name: "WINCH", value:28 }, + Signal{ name: "INFO", value:29 }, + Signal{ name: "USR1", value:30 }, + Signal{ name: "USR2", value:31 }, +];