diff --git a/Cargo.lock b/Cargo.lock index 410787f082..2b9f61f1bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,8 @@ +[[package]] +name = "ansi_term" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arg_parser" version = "0.1.0" @@ -20,6 +25,16 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "backtrace" version = "0.3.5" @@ -65,6 +80,20 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "clap" +version = "2.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "constant_time_eq" version = "0.1.3" @@ -158,7 +187,7 @@ dependencies = [ [[package]] name = "redox_users" version = "0.1.0" -source = "git+https://github.com/redox-os/users.git#0fc602398887533c947b3f428e9fe0037f829478" +source = "git+https://github.com/redox-os/users.git#0c56faee77dd86d0b48460b6e588e2c96a8a0d99" dependencies = [ "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", @@ -177,6 +206,11 @@ name = "scoped_threadpool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.11.11" @@ -214,6 +248,14 @@ dependencies = [ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.4" @@ -229,6 +271,7 @@ name = "userutils" version = "0.1.0" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", + "clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "liner 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -237,6 +280,11 @@ dependencies = [ "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.4" @@ -257,15 +305,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum clap 2.29.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b8f59bcebcfe4269b09f71dab0da15b355c75916a8f975d3876ce81561893ee" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" @@ -282,12 +333,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_users 0.1.0 (git+https://github.com/redox-os/users.git)" = "" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum scoped_threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4ea459fe3ceff01e09534847c49860891d3ff1c12b4eb7731b67f2778fb60190" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" +"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index e3db1c22aa..6f91776677 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ path = "src/bin/whoami.rs" [dependencies] arg_parser = { git = "https://github.com/redox-os/arg-parser.git" } +clap = "~2.29.4" extra = { git = "https://github.com/redox-os/libextra.git" } liner = "0.1" redox_syscall = "0.1" diff --git a/src/bin/getty.rs b/src/bin/getty.rs index 0e51e8e171..3f1da23ff9 100644 --- a/src/bin/getty.rs +++ b/src/bin/getty.rs @@ -1,21 +1,20 @@ #![deny(warnings)] +#[macro_use] +extern crate clap; extern crate redox_termios; extern crate syscall; -extern crate arg_parser; extern crate extra; -use std::{env, process, str}; +use std::str; use std::fs::File; -use std::io::{self, ErrorKind, Read, Write, Stderr}; +use std::io::{self, ErrorKind, Read, Stderr}; use std::os::unix::io::{FromRawFd, RawFd}; -use std::process::{exit, Child, Command, Stdio}; +use std::process::{Child, Command, Stdio}; -use arg_parser::ArgParser; use extra::io::fail; -use extra::option::OptionalExt; -const MAN_PAGE: &'static str = /* @MANSTART{getty} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{getty} */ r#" NAME getty - set terminal mode @@ -29,19 +28,16 @@ DESCRIPTION OPTIONS - -h - --help + -h, --help Display this help and exit. - -J - --noclear + -J, --noclear Do not clear the screen before forking login(1). AUTHOR Written by Jeremy Soller. "#; /* @MANEND */ -const HELP_INFO: &'static str = "Try ‘getty --help’ for more information.\n"; const DEFAULT_COLS: u32 = 80; const DEFAULT_LINES: u32 = 30; @@ -182,37 +178,18 @@ fn daemon(tty_fd: RawFd, clear: bool, stderr: &mut Stderr) { } pub fn main() { - let mut stdout = io::stdout(); let mut stderr = io::stderr(); - let mut parser = ArgParser::new(1) - .add_flag(&["h", "help"]) - .add_flag(&["J", "noclear"]); - parser.parse(env::args()); + let args = clap_app!(getty => + (author: "Jeremy Soller") + (about: "Set terminal mode") + (@arg TTY: +required "") + (@arg NO_CLEAR: -J --("no-clear") "Do not clear the screen before forking") + ).get_matches(); - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr); - stdout.flush().try(&mut stderr);; - exit(0); - } + let clear = !args.is_present("NO_CLEAR"); - if let Err(err) = parser.found_invalid() { - stderr.write_all(err.as_bytes()).try(&mut stderr); - stdout.write_all(HELP_INFO.as_bytes()).try(&mut stderr); - stderr.flush().try(&mut stderr); - process::exit(1); - } - - let mut clear = true; - if parser.found("noclear") { - clear = false - } - - if parser.args.len() < 1 { - fail("getty: no TTY provided", &mut stderr); - } - - let tty = &parser.args[0]; + let tty = args.value_of("TTY").unwrap(); let tty_fd = match syscall::open(tty, syscall::O_CLOEXEC | syscall::flag::O_RDWR | syscall::flag::O_NONBLOCK) { Ok(fd) => fd, Err(err) => fail(&format!("getty: failed to open TTY {}: {}", tty, err), &mut stderr), diff --git a/src/bin/groupadd.rs b/src/bin/groupadd.rs index d5dbbd1c22..8eda178e38 100644 --- a/src/bin/groupadd.rs +++ b/src/bin/groupadd.rs @@ -1,24 +1,22 @@ #![deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; use extra::option::OptionalExt; -use std::{io, env}; -use std::io::Write; use std::process::exit; -use arg_parser::ArgParser; use redox_users::{AllGroups, UsersError}; -const MAN_PAGE: &'static str = /* @MANSTART{groupadd} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{groupadd} */ r#" NAME groupadd - add a user group SYNOPSIS - groupadd [ -f | --force ] group + groupadd [ -f | --force ] GROUP groupadd [ -h | --help ] DESCRIPTION @@ -44,57 +42,36 @@ AUTHOR "#; /* @MANEND */ fn main() { - let stdout = io::stdout(); - let mut stdout = stdout.lock(); - let mut stderr = io::stderr(); - - let mut parser = ArgParser::new(1) - .add_flag(&["h", "help"]) - .add_flag(&["f", "force"]) - .add_opt("g", "gid"); - parser.parse(env::args()); - - // Shows the help - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr); - stdout.flush().try(&mut stderr); - exit(0); - } + let args = clap_app!(groupadd => + (author: "Wesley Hershberger") + (about: "Add groups based on the system's redox_users backend") + (@arg GROUP: +required "Add group GROUP") + (@arg FORCE: -f --force "Force the status of the program to be 0 even if the group exists") + (@arg GID: -g --gid "Group id. Positive integer and must not be in use") + ).get_matches(); let mut sys_groups = AllGroups::new().unwrap_or_exit(1); - let groupname = if parser.args.is_empty() { - eprintln!("groupadd: no group name specified"); - exit(1); - } else { - &parser.args[0] - }; + let groupname = args.value_of("GROUP").unwrap(); - let gid = if let Some(gid) = parser.get_opt("gid") { - let gid = gid.parse::().unwrap_or_exit(1); - - match sys_groups.get_by_id(gid) { - Some(_) => { + let gid = match args.value_of("GID") { + Some(gid) => { + let id = gid.parse::().unwrap_or_exit(1); + if let Some(_group) = sys_groups.get_by_id(id) { eprintln!("groupadd: group already exists"); exit(1); - }, - None => { - gid } - } - } else { - match sys_groups.get_unique_id() { - Some(gid) => gid, - None => { - eprintln!("groupadd: no available gid"); - exit(1); - } - } + id + }, + None => sys_groups.get_unique_id().unwrap_or_else(|| { + eprintln!("groupadd: no available gid"); + exit(1); + }) }; match sys_groups.add_group(groupname, gid, &[""]) { Ok(_) => { }, - Err(ref err) if err.downcast_ref::() == Some(&UsersError::AlreadyExists) && parser.found("force") => { + Err(ref err) if err.downcast_ref::() == Some(&UsersError::AlreadyExists) && args.is_present("FORCE") => { exit(0); }, Err(err) => { diff --git a/src/bin/groupdel.rs b/src/bin/groupdel.rs index 01bfcb27aa..9c3e5953f1 100644 --- a/src/bin/groupdel.rs +++ b/src/bin/groupdel.rs @@ -1,23 +1,19 @@ #[deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; -use std::env; -use std::io::{stdout, Write}; -use std::process::exit; - -use arg_parser::ArgParser; use extra::option::OptionalExt; use redox_users::AllGroups; -const MAN_PAGE: &'static str = /* @MANSTART{groupdel} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{groupdel} */ r#" NAME groupdel - modify system files to delete groups SYNOPSYS - groupdel [ options ] LOGIN + groupdel [ options ] GROUP groupdel [ -h | --help ] DESCRIPTION @@ -37,24 +33,13 @@ AUTHORS "#; /* @MANEND */ fn main() { - let mut stdout = stdout(); + let matches = clap_app!(groupdel => + (author: "Wesley Hershberger") + (about: "Removes a group from the system using redox_users") + (@arg GROUP: +required "Removes group GROUP") + ).get_matches(); - let mut parser = ArgParser::new(9) - .add_flag(&["h", "help"]); - parser.parse(env::args()); - - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).unwrap(); - stdout.flush().unwrap(); - exit(0); - } - - let group = if parser.args.is_empty() { - eprintln!("groupdel: no login specified"); - exit(1); - } else { - &parser.args[0] - }; + let group = matches.value_of("GROUP").unwrap(); let mut sys_groups = AllGroups::new().unwrap_or_exit(1); diff --git a/src/bin/groupmod.rs b/src/bin/groupmod.rs index ad8590b0b1..fb983bf020 100644 --- a/src/bin/groupmod.rs +++ b/src/bin/groupmod.rs @@ -1,18 +1,16 @@ #[deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; -use std::env; -use std::io::{stdout, Write}; use std::process::exit; -use arg_parser::ArgParser; use extra::option::OptionalExt; use redox_users::AllGroups; -const MAN_PAGE: &'static str = /* @MANSTART{groupmod} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{groupmod} */ r#" NAME groupmod - modify group information @@ -45,48 +43,33 @@ AUTHORS "#; /* @MANEND */ fn main() { - let mut stdout = stdout(); + let args = clap_app!(groupmod => + (author: "Wesley Hershberger") + (about: "Modify users according to the system's redox_users backend") + (@arg GROUP: +required "Modify GROUP") + (@arg GID: -g --gid +takes_value "Change GROUP's group id. See man page for details") + (@arg NAME: -n --name +takes_value "Change GROUP's name") + ).get_matches(); - let mut parser = ArgParser::new(9) - .add_flag(&["h", "help"]) - .add_opt("g", "gid") - .add_opt("n", "name"); - parser.parse(env::args()); - - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).unwrap(); - stdout.flush().unwrap(); - exit(0); - } - - let groupname = if parser.args.is_empty() { - eprintln!("groupmod: no login specified"); - exit(1); - } else { - &parser.args[0] - }; + let groupname = args.value_of("GROUP").unwrap(); let mut sys_groups = AllGroups::new().unwrap_or_exit(1); { - let group = sys_groups.get_mut_by_name(groupname).unwrap_or_else(|| { - eprintln!("groupmod: group does not exist: {}", groupname); - exit(1); - }); + let group = sys_groups + .get_mut_by_name(groupname) + .unwrap_or_else(|| { + eprintln!("groupmod: group not found: {}", groupname); + exit(1); + }); //TODO: Update user's primary GID, if gid is used as such - if let Some(gid) = parser.get_opt("gid") { + if let Some(gid) = args.value_of("GID") { let gid = gid.parse::().unwrap_or_exit(1); group.gid = gid; - } else if parser.found("gid") { - eprintln!("groupmod: no gid found"); - exit(1); } - if let Some(name) = parser.get_opt("name") { - group.group = name; - } else if parser.found("name") { - eprintln!("groupmod: no name found"); - exit(1); + if let Some(name) = args.value_of("NAME") { + group.group = name.to_string(); } } diff --git a/src/bin/id.rs b/src/bin/id.rs index 69e697ae73..c2680cf7f5 100644 --- a/src/bin/id.rs +++ b/src/bin/id.rs @@ -1,20 +1,16 @@ -extern crate arg_parser; +#![deny(warnings)] + +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; -use std::borrow::Borrow; -use std::hash::Hash; -use std::env; -use std::io::{self, Write, Stderr, StdoutLock}; use std::process::exit; -use extra::io::fail; use extra::option::OptionalExt; -use arg_parser::{ArgParser, Param}; use redox_users::{get_egid, get_gid, get_euid, get_uid, AllUsers, AllGroups}; -const HELP_INFO: &'static str = "Try ‘id --help’ for more information.\n"; -const MAN_PAGE: &'static str = /* @MANSTART{id} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{id} */ r#" NAME id - display user identity @@ -29,202 +25,143 @@ DESCRIPTION the calling process, to the standard output. OPTIONS - -G + -G, --groups Display the different group IDs (effective and real) as white-space separated numbers, in no particular order. - -g + -g, --group Display the effective group ID as a number. - -n Display the name of the user or group ID for the -g and -u options + -n, --name + Display the name of the user or group ID for the -g and -u options instead of the number. - -u + -u, --user Display the effective user ID as a number. -a Ignored for compatibility with other id implementations. - -r + -r, --real Display the real ID for the -g and -u options instead of the effective ID. - -h - --help - Display this help and exit. - -EXIT STATUS - The whoami utility exits 0 on success, and >0 if an error occurs. + -h, --help + Display help and exit. AUTHOR Written by Jose Narvaez. "#; /* @MANEND */ pub fn main() { - let stdout = io::stdout(); - let mut stdout = stdout.lock(); - let mut stderr = io::stderr(); - - let mut parser = ArgParser::new(1) - .add_flag(&["h", "help"]) - .add_flag(&["a"]) - .add_flag(&["G"]) - .add_flag(&["g"]) - .add_flag(&["u"]) - .add_flag(&["n"]) - .add_flag(&["r"]); - parser.parse(env::args()); - - // Shows the help - if parser.found("help") { - print_msg(MAN_PAGE, &mut stdout, &mut stderr); - exit(0); - } - - // Unrecognized flags - if let Err(err) = parser.found_invalid() { - stderr.write_all(err.as_bytes()).try(&mut stderr); - print_msg(HELP_INFO, &mut stdout, &mut stderr); - exit(1); - } - - let groups = AllGroups::new().unwrap_or_exit(1); - let users = AllUsers::new().unwrap_or_exit(1); + let args = clap_app!(id => + (author: "Jose Narvaez") + (about: "Get user and group information about the current user") + (@arg IGNORE: -a "Ignored for compatibility with other impls of id") + (@arg GROUPS: -G --groups conflicts_with[selector modifier] "Display current user's real and effective group id's") + (@group selector => + (@arg GROUP: -g --group "Display current user's effective group id") + (@arg USER: -u --user "Display the effective userid") + ) + (@group modifier => + (@arg NAME: -n --name requires[selector] "Display names of groups/users instead of ids (use with -g or -u)") + (@arg REAL: -r --real requires[selector] "Display real id's instead of effective ids (use with -g and -u)") + ) + ).get_matches(); // Display the different group IDs (effective and real) // as white-space separated numbers, in no particular order. - if parser.found(&'G') { - if any_of_found(&parser, &[&'g', &'u']) { - let msg = "id: -G option must be used without others\n"; - print_msg(msg, &mut stdout, &mut stderr); - print_msg(HELP_INFO, &mut stdout, &mut stderr); - exit(1); - } - + if args.is_present("GROUPS") { let egid = get_egid().unwrap_or_exit(1); let gid = get_gid().unwrap_or_exit(1); - print_msg(&format!("{} {}\n", egid, gid), &mut stdout, &mut stderr); + println!("{} {}", egid, gid); exit(0); } - + + /* // Check if people passed both -g -u which are mutually exclusive if parser.found(&'u') && parser.found(&'g') { let msg = "id: specify either -u or -g but not both\n"; print_msg(msg, &mut stdout, &mut stderr); print_msg(HELP_INFO, &mut stdout, &mut stderr); exit(1); - } + }*/ // Display effective/real process user ID UNIX user name - if parser.found(&'u') && parser.found(&'n') { + if args.is_present("USER") && args.is_present("NAME") { // Did they pass -r? F so, we show the real - let uid_result = if parser.found(&'r') { + let uid = if args.is_present("REAL") { get_uid() } else { get_euid() - }; - - let uid = uid_result.unwrap_or_exit(1); + }.unwrap_or_exit(1); + + let users = AllUsers::new().unwrap_or_exit(1); let user = users.get_by_id(uid).unwrap_or_exit(1); - print_msg(&format!("{}\n", user.user), &mut stdout, &mut stderr); + println!("{}", user.user); exit(0); } // Display real user ID - if parser.found(&'u') && parser.found(&'r') { + if args.is_present("USER") && args.is_present("REAL") { let uid = get_uid().unwrap_or_exit(1); - print_msg(&format!("{}\n", uid), &mut stdout, &mut stderr); + println!("{}", uid); exit(0); } // Display effective user ID - if parser.found(&'u') { + if args.is_present("USER") { let euid = get_euid().unwrap_or_exit(1); - print_msg(&format!("{}\n", euid), &mut stdout, &mut stderr); + println!("{}", euid); exit(0); } // Display effective/real process group ID UNIX group name - if parser.found(&'g') && parser.found(&'n') { + if args.is_present("GROUP") && args.is_present("NAME") { // Did they pass -r? If so we show the real one - let gid_result = if parser.found(&'r') { + let gid = if args.is_present("REAL") { get_gid() } else { get_egid() - }; - - let gid = gid_result.unwrap_or_exit(1); + }.unwrap_or_exit(1); let groups = AllGroups::new().unwrap_or_exit(1); let group = groups.get_by_id(gid).unwrap_or_exit(1); - print_msg(&format!("{}\n", group.group), &mut stdout, &mut stderr); + println!("{}", group.group); exit(0); } // Display the real group ID - if parser.found(&'g') && parser.found(&'r') { + if args.is_present("GROUP") && args.is_present("REAL") { let gid = get_gid().unwrap_or_exit(1); - print_msg(&format!("{}\n", gid), &mut stdout, &mut stderr); + println!("{}", gid); exit(0); } // Display effective group ID - if parser.found(&'g') { + if args.is_present("GROUP") { let egid = get_egid().unwrap_or_exit(1); - print_msg(&format!("{}\n", egid), &mut stdout, &mut stderr); + println!("{}", egid); exit(0); } - // -n does not apply if there is no -u or -g - if parser.found(&'n') && none_of_found(&parser, &[&'u', &'g']) { - let msg = "id: the -n option must be used with either -u or -g\n"; - fail(msg, &mut stderr); - } - - // -r does not apply if there is no -u or -g - if parser.found(&'r') && none_of_found(&parser, &[&'u', &'g']) { - let msg = "id: the -r option must be used with either -u or -g\n"; - fail(msg, &mut stderr); - } - // We get everything we can and show let euid = get_euid().unwrap_or_exit(1); - let egid = get_egid().unwrap_or_exit(1); + let users = AllUsers::new().unwrap_or_exit(1); + let groups = AllGroups::new().unwrap_or_exit(1); + let user = users.get_by_id(euid).unwrap_or_exit(1); - let group = groups.get_by_id(egid).unwrap_or_exit(1); - let msg = format!("uid={}({}) gid={}({})\n", euid, user.user, egid, group.group); - print_msg(&msg, &mut stdout, &mut stderr); + println!("uid={}({}) gid={}({})", euid, user.user, egid, group.group); exit(0); } - -pub fn any_of_found(parser: &ArgParser, flags: &[&P]) -> bool - where Param: Borrow

-{ - for flag in flags { - if parser.found(*flag) { return true } - } - - false -} - -fn none_of_found(parser: &ArgParser, flags: &[&P]) -> bool - where Param: Borrow

-{ - !any_of_found(parser, flags) -} - -fn print_msg(msg: &str, stdout: &mut StdoutLock, stderr: &mut Stderr) { - stdout.write_all(msg.as_bytes()).try(stderr); - stdout.flush().try(stderr); -} diff --git a/src/bin/passwd.rs b/src/bin/passwd.rs index 3316fbd678..4b4d93e39b 100644 --- a/src/bin/passwd.rs +++ b/src/bin/passwd.rs @@ -1,25 +1,25 @@ #![deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate termion; extern crate redox_users; -use std::{env, io}; +use std::io; use std::io::Write; use std::process::exit; -use arg_parser::ArgParser; use extra::option::OptionalExt; use termion::input::TermRead; use redox_users::{get_uid, AllUsers}; -const MAN_PAGE: &'static str = /* @MANSTART{passwd} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{passwd} */ r#" NAME passwd - modify a user's password SYNOPSIS - passwd [ user ] + passwd [ LOGIN ] passwd [ -h | --help ] DESCRIPTION @@ -49,35 +49,29 @@ fn main() { let mut stdout = stdout.lock(); let mut stderr = io::stderr(); - let mut parser = ArgParser::new(1) - .add_flag(&["h", "help"]); - parser.parse(env::args()); - - // Shows the help - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr); - stdout.flush().try(&mut stderr); - exit(0); - } + let args = clap_app!(passwd => + (author: "Jeremy Soller, Jose Narvaez") + (about: "Set user passwords") + (@arg LOGIN: "Apply to login. Sets password for current user if not supplied") + (@arg LOCK: -l --lock "Lock the password for an account (no login)") + ).get_matches(); let uid = get_uid().unwrap_or_exit(1); let mut users = AllUsers::new().unwrap_or_exit(1); { - let user = if parser.args.is_empty() { - users.get_mut_by_id(uid).unwrap_or_else(|| { - eprintln!("passwd: you do not exist"); - exit(1); - }) - } else { - let username = &parser.args[0]; - users.get_mut_by_name(username).unwrap_or_else(|| { - eprintln!("passwd: user does not exist: {}", username); - exit(1); - }) + let user = match args.value_of("LOGIN") { + Some(login) => users.get_mut_by_name(login).unwrap_or_else(|| { + eprintln!("passwd: user does not exist: {}", login); + exit(1); + }), + None => users.get_mut_by_id(uid).unwrap_or_else(|| { + eprintln!("passwd: you do not exist"); + exit(1); + }) }; - if parser.found("lock") { + if args.is_present("LOCK") { user.unset_passwd(); } else if user.uid == uid || uid == 0 { let msg = format!("changing password for '{}' \n", user.user); @@ -87,7 +81,7 @@ fn main() { let mut verified = false; if user.is_passwd_blank() { verified = true; - } else if user.is_passwd_unset() { + } else if user.is_passwd_unset() && uid != 0 { verified = false; } else if user.uid == uid || uid != 0 { stdout.write_all(b"current password: ").try(&mut stderr); diff --git a/src/bin/su.rs b/src/bin/su.rs index e83181c071..6fd20c4482 100644 --- a/src/bin/su.rs +++ b/src/bin/su.rs @@ -1,23 +1,22 @@ #![deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate termion; extern crate redox_users; extern crate userutils; -use std::env; use std::io::{self, Write}; use std::process::exit; use std::str; -use arg_parser::ArgParser; use extra::option::OptionalExt; use termion::input::TermRead; use redox_users::{get_uid, AllUsers}; use userutils::spawn_shell; -const MAN_PAGE: &'static str = /* @MANSTART{su} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{su} */ r#" NAME su - substitute user identity @@ -31,8 +30,7 @@ DESCRIPTION OPTIONS - -h - --help + -h, --help Display this help and exit. AUTHOR @@ -46,21 +44,15 @@ pub fn main() { let mut stdout = stdout.lock(); let mut stderr = io::stderr(); - let mut parser = ArgParser::new(1) - .add_flag(&["h", "help"]); - parser.parse(env::args()); + let args = clap_app!(su => + (author: "Jeremy Soller, Jose Narvaez") + (about: "substitue user identity") + (@arg LOGIN: "Login as LOGIN. Default is \'root\'") + ).get_matches(); - // Shows the help - if parser.found("help") { - write!(stdout, "{}", MAN_PAGE).unwrap_or_exit(1); - exit(0); - } - - let target_user = if parser.args.is_empty() { - String::from("root") - } else { - parser.args[0].to_string() - }; + let target_user = args + .value_of("LOGIN") + .unwrap_or("root"); let uid = get_uid().unwrap_or_exit(1); diff --git a/src/bin/useradd.rs b/src/bin/useradd.rs index 1a8301c829..c029576378 100644 --- a/src/bin/useradd.rs +++ b/src/bin/useradd.rs @@ -1,21 +1,19 @@ #![deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate syscall; extern crate redox_users; extern crate userutils; -use std::{env, io}; -use std::io::Write; use std::process::exit; -use arg_parser::ArgParser; use extra::option::OptionalExt; use redox_users::{AllGroups, AllUsers}; use userutils::create_user_dir; -const MAN_PAGE: &'static str = /* @MANSTART{useradd} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{useradd} */ r#" NAME useradd - add a new user @@ -75,168 +73,139 @@ OPTIONS AUTHORS Written by Wesley Hershberger. "#; /* @MANEND */ -const DEFAULT_SHELL: &'static str = "/bin/ion"; -const DEFAULT_HOME: &'static str = "/home"; +const DEFAULT_SHELL: &'static str = "file:/bin/ion"; +const DEFAULT_HOME: &'static str = "file:/home"; +const DEFAULT_NO_GROUP: &'static str = "nobody"; fn main() { - let mut stdout = io::stdout(); + let args = clap_app!(useradd => + (author: "Wesley Hershberger") + (about: "Add users based on the system's redox_users backend") + (@arg LOGIN: + +required + "Add user LOGIN") + (@arg COMMENT: + -c --comment + +takes_value + "Set user description (GECOS field)") + (@arg HOME_DIR: + -d --("home-dir") + +takes_value + "Set LOGIN's home dir to HOME_DIR (does not create directory)") + (@arg CREATE_HOME: + -m --("create-home") + "Create the user's home directory") + (@arg SHELL: + -s --shell + +takes_value + "Set user's default login shell") + (@arg GID: + -g --gid + +takes_value + "Set LOGIN's primary group id. Positive integer and must not be in use.") + (@arg NO_USER_GROUP: + -N --("no-user-group") + conflicts_with[GID] + "Do not create primary user group (set gid to 99, \"nobody\")") + (@arg UID: + -u --uid + +takes_value + "Set LOGIN's user id. Positive ineger and must not be in use.") + ).get_matches(); - let mut parser = ArgParser::new(8) - .add_flag(&["h", "help"]) - .add_opt("c", "comment") - .add_opt("d", "home-dir") - .add_opt("g", "gid") - .add_flag(&["m", "create-home"]) - .add_flag(&["N", "no-user-group"]) - .add_opt("s", "shell") - .add_opt("u", "uid"); - parser.parse(env::args()); - - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).unwrap(); - stdout.flush().unwrap(); - exit(0); - } - - let login = if parser.args.is_empty() { - eprintln!("useradd: no login specified"); - exit(1); - } else { - &parser.args[0] - }; + // unwrap is safe because of "+required". clap-rs is cool... + let login = args.value_of("LOGIN").unwrap(); let mut sys_users = AllUsers::new().unwrap_or_exit(1); - let mut sys_groups; + let mut sys_groups = AllGroups::new().unwrap_or_exit(1); - let uid = if parser.found("uid") { - match parser.get_opt("uid") { - Some(uid) => { - let id = uid.parse::().unwrap_or_exit(1); - if let Some(_user) = sys_users.get_by_id(id) { - eprintln!("useradd: user already exists with uid: {}", id); + let uid = match args.value_of("UID") { + Some(uid) => { + let id = uid.parse::().unwrap_or_exit(1); + if let Some(_user) = sys_users.get_by_id(id) { + eprintln!("useradd: userid already in use: {}", id); + exit(1); + } + id + }, + None => sys_users + .get_unique_id() + .unwrap_or_else(|| { + eprintln!("useradd: no available uid"); + exit(1); + }) + }; + + let gid = if args.is_present("NO_USER_GROUP") { + let nobody = sys_groups + .get_mut_by_name(DEFAULT_NO_GROUP) + .unwrap_or_else(|| { + eprintln!("useradd: group not found: {}", DEFAULT_NO_GROUP); + exit(1) + }); + nobody.users.push(login.to_string()); + 99 + } else { + let id = match args.value_of("GID") { + Some(id) => { + let id = id.parse::().unwrap_or_exit(1); + if let Some(_group) = sys_groups.get_by_id(id) { + eprintln!("useradd: group already exists with gid: {}", id); exit(1); } id }, - None => { - eprintln!("useradd: missing uid value"); + None => sys_groups + .get_unique_id() + .unwrap_or_else(|| { + eprintln!("useradd: no available gid"); + exit(1); + }) + }; + sys_groups + .add_group(login, id, &[login]) + .unwrap_or_else(|err| { + eprintln!("useradd: {}: {}", err, login); exit(1); - } - } - } else { - match sys_users.get_unique_id() { - Some(id) => id, - None => { - eprintln!("useradd: no available uid"); - exit(1); - } - } - }; - - //This is a ridiculous mess and could use reworking - let gid: usize; - if parser.found("no-user-group") { - sys_groups = AllGroups::new().unwrap_or_exit(1); - gid = 99; - { - let nobody = sys_groups.get_mut_by_name("nobody").unwrap_or_else(|| { - eprintln!("useradd: group \"nobody\" not found"); - exit(1) }); - nobody.users.push(String::from(login.as_str())); - } - sys_groups.save().unwrap_or_exit(1); - } else { - sys_groups = AllGroups::new().unwrap_or_exit(1); - - if parser.found("gid") { - gid = match parser.get_opt("gid") { - Some(gid) => { - let id = gid.parse::().unwrap_or_exit(1); - if let Some(_group) = sys_groups.get_by_id(id) { - eprintln!("useradd: group already exists with gid: {}", id); - exit(1); - } - id - }, - None => { - eprintln!("useradd: missing gid argument"); - exit(1); - } - }; - } else { - gid = match sys_groups.get_unique_id() { - Some(id) => id, - None => { - eprintln!("useradd: no available gid"); - exit(1); - } - }; - } - match sys_groups.add_group(login, gid, &[login]) { - Ok(_) => {}, - Err(err) => { - eprintln!("useradd: error creating group {}: {}", login, err); - exit(1); - } - } - sys_groups.save().unwrap_or_exit(1); - } - - let username = if parser.found("comment") { - match parser.get_opt("comment") { - Some(user) => user, - None => { - eprintln!("useradd: invalid argument: -c"); - exit(1); - } - } - } else { - login.to_owned() + id }; - let userhome = if parser.found("home-dir") { - match parser.get_opt("home-dir") { - Some(dir) => dir, - None => { - eprintln!("useradd: missing directory argument"); - exit(1); - } - } - } else if parser.found("create-home") { - format!("{}/{}", DEFAULT_HOME, login) - } else { - "/".to_string() - }; + let gecos = args + .value_of("COMMENT") + .unwrap_or(login); - let shell = if parser.found("shell") { - match parser.get_opt("shell") { - Some(sh) => sh, - None => { - eprintln!("useradd: invalid argument: -s"); - exit(1); + //Ugly way to satisfy the borrow checker... + let mut sys_homes = String::from(DEFAULT_HOME); + let userhome = args + .value_of("HOME_DIR") + .unwrap_or_else(|| { + if args.is_present("CREATE_HOME") { + sys_homes.push_str(&login); + sys_homes.as_str() + } else { + "/" } - } - } else { - DEFAULT_SHELL.to_string() - }; + }); - match sys_users.add_user(login, uid, gid, username.as_str(), userhome.as_str(), shell.as_str()) { - Ok(_) => {}, - Err(err) => { + let shell = args + .value_of("SHELL") + .unwrap_or(DEFAULT_SHELL); + + sys_users + .add_user(login, uid, gid, gecos, userhome, shell) + .unwrap_or_else(|err| { eprintln!("useradd: {}: {}", err, login); exit(1); - } - } + }); - println!("Got info: {};{};{};{};{};{}", login, uid, gid, username, userhome, shell); - - // Make sure to try and create the user before we create + // Make sure to try and create the user/groups before we create // their home, that way we get a permissions error that makes // more sense + sys_groups.save().unwrap_or_exit(1); sys_users.save().unwrap_or_exit(1); - if parser.found("create-home") { + if args.is_present("CREATE_HOME") { //Shouldn't ever error... let user = sys_users.get_by_id(uid).unwrap_or_exit(1); create_user_dir(user, userhome).unwrap_or_exit(1); diff --git a/src/bin/userdel.rs b/src/bin/userdel.rs index 5d11b25ccd..187cd9a18d 100644 --- a/src/bin/userdel.rs +++ b/src/bin/userdel.rs @@ -1,19 +1,17 @@ #[deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; -use std::env; -use std::io::{stdout, Write}; use std::fs::remove_dir; use std::process::exit; -use arg_parser::ArgParser; use extra::option::OptionalExt; use redox_users::AllUsers; -const MAN_PAGE: &'static str = /* @MANSTART{userdel} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{userdel} */ r#" NAME userdel - modify system files to delete users @@ -43,25 +41,14 @@ AUTHORS "#; /* @MANEND */ fn main() { - let mut stdout = stdout(); + let args = clap_app!(userdel => + (author: "Wesley Hershberger") + (about: "Removes system users using redox_users") + (@arg LOGIN: +required "Remove user LOGIN") + (@arg REMOVE: -r --remove "Remove the user's home and all files and directories inside") + ).get_matches(); - let mut parser = ArgParser::new(9) - .add_flag(&["h", "help"]) - .add_flag(&["r", "remove"]); - parser.parse(env::args()); - - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).unwrap(); - stdout.flush().unwrap(); - exit(0); - } - - let login = if parser.args.is_empty() { - eprintln!("userdel: no login specified"); - exit(1); - } else { - &parser.args[0] - }; + let login = args.value_of("LOGIN").unwrap(); let mut sys_users = AllUsers::new().unwrap_or_exit(1); { @@ -70,7 +57,7 @@ fn main() { exit(1); }); - if parser.found("remove") { + if args.is_present("REMOVE") { remove_dir(&user.home).unwrap_or_exit(1); } } diff --git a/src/bin/usermod.rs b/src/bin/usermod.rs index 061c2502ed..60f80282ad 100644 --- a/src/bin/usermod.rs +++ b/src/bin/usermod.rs @@ -1,21 +1,19 @@ #![deny(warnings)] -extern crate arg_parser; +#[macro_use] +extern crate clap; extern crate extra; extern crate redox_users; extern crate userutils; -use std::env; -use std::io::{stdout, Write}; use std::fs::{remove_dir, rename}; use std::process::exit; -use arg_parser::ArgParser; use extra::option::OptionalExt; use redox_users::{AllGroups, AllUsers}; use userutils::create_user_dir; -const MAN_PAGE: &'static str = /* @MANSTART{usermod} */ r#" +const _MAN_PAGE: &'static str = /* @MANSTART{usermod} */ r#" NAME usermod - modify user information @@ -76,43 +74,63 @@ AUTHORS "#; /* @MANEND */ fn main() { - let mut stdout = stdout(); + let args = clap_app!(usermod => + (author: "Wesley Hershberger") + (about: "Modify users according to the system's redox_users backend") + (@arg LOGIN: + +required + "Apply modifications to LOGIN") + (@arg COMMENT: + -c --comment + +takes_value + "Set LOGIN's description (GECOS field)") + (@arg HOME_DIR: + -d --("home-dir") + +takes_value + "Create and set LOGIN's home directory") + (@arg MOVE_HOME: + -m --("move-home") + requires[HOME_DIR] + "Move LOGIN's old home to HOME_DIR (see --home-dir) instead of creating it. Requires -d") + (@arg APPEND_GROUPS: + -G --("append-groups") + +takes_value conflicts_with[SET_GROUPS] + "Add user to groups specified (comma separated list, see man page)") + (@arg SET_GROUPS: + -S --("set-groups") + +takes_value conflicts_with[APPEND_GROUPS] + "Set LOGIN's groups as specified (truncates existing, see man page)") + (@arg GID: + -g --gid + +takes_value + "Set LOGIN's primary group id. Group must exist") + (@arg NEW_LOGIN: + -l --login + +takes_value + "Set LOGIN's name to NEW_LOGIN") + (@arg SHELL: + -s --shell + +takes_value + "Set LOGIN's default login shell") + (@arg UID: + -u --uid + +takes_value + "Set LOGIN's user id. See man page for details") + ).get_matches(); - let mut parser = ArgParser::new(9) - .add_flag(&["h", "help"]) - .add_flag(&["m", "move-home"]) - .add_opt("c", "comment") - .add_opt("d", "home-dir") - .add_opt("G", "groups") - .add_opt("g", "gid") - .add_opt("l", "login") - .add_opt("s", "shell") - .add_opt("u", "uid"); - parser.parse(env::args()); - - if parser.found("help") { - stdout.write_all(MAN_PAGE.as_bytes()).unwrap(); - stdout.flush().unwrap(); - exit(0); - } - - let login = if parser.args.is_empty() { - eprintln!("usermod: no login specified"); - exit(1); - } else { - &parser.args[0] - }; + let login = args.value_of("LOGIN").unwrap(); let mut sys_users = AllUsers::new().unwrap_or_exit(1); let mut sys_groups; - if parser.found("groups") { + //Requires iteration over system groups, which requires additions to redox_users + if let Some(_new_groups) = args.value_of("SET_GROUPS") { + unimplemented!(); + } + + if let Some(new_groups) = args.value_of("APPEND_GROUPS") { sys_groups = AllGroups::new().unwrap_or_exit(1); - let new_groups = parser.get_opt("groups").unwrap_or_else(|| { - eprintln!("usermod: no groups found"); - exit(1); - }); let new_groups = new_groups.split(','); for groupname in new_groups { @@ -120,27 +138,22 @@ fn main() { eprintln!("usermod: no group found: {}", groupname); exit(1); }); - group.users.push(String::from(login.as_str())); + group.users.push(login.to_string()); } sys_groups.save().unwrap_or_exit(1); } - // Nasty to satisfy borrow checker. See line ~174 too - let uid = if let Some(uid) = parser.get_opt("uid") { - let uid = uid.parse::().unwrap_or_exit(1); - if let Some(_user) = sys_users.get_by_id(uid) { - eprintln!("usermod: userid already in use: {}", uid); - exit(1); - } else { - Some(uid) - } - } else if parser.found("uid") { - eprintln!("usermod: no uid found"); - exit(1); - } else { - None - }; + let uid = args + .value_of("UID") + .map(|uid| { + let uid = uid.parse::().unwrap_or_exit(1); + if let Some(_user) = sys_users.get_by_id(uid) { + eprintln!("usermod: userid already in use: {}", uid); + exit(1); + } + uid + }); { let user = sys_users.get_mut_by_name(&login).unwrap_or_else(|| { @@ -148,46 +161,33 @@ fn main() { exit(1); }); - if let Some(gecos) = parser.get_opt("comment") { - user.name = gecos; - // If we found it but ^that^ was None, problem - } else if parser.found("comment") { - eprintln!("usermod: no comment found"); - exit(1); + if let Some(gecos) = args.value_of("COMMENT") { + user.name = gecos.to_string(); } - if let Some(new_login) = parser.get_opt("login") { - user.user = new_login; - } else if parser.found("login") { - eprintln!("usermod: no login found"); - exit(1); + if let Some(new_login) = args.value_of("NEW_LOGIN") { + user.user = new_login.to_string(); } - if let Some(shell) = parser.get_opt("shell") { - user.shell = shell; - } else if parser.found("shell") { - eprintln!("usermod: no shell found"); - exit(1); + if let Some(shell) = args.value_of("SHELL") { + user.shell = shell.to_string(); } - if let Some(home) = parser.get_opt("home-dir") { - if parser.found("move-home") { + if let Some(home) = args.value_of("HOME_DIR") { + if args.is_present("MOVE_HOME") { rename(&user.home, &home).unwrap_or_exit(1); } else { create_user_dir(user, &home).unwrap_or_exit(1); remove_dir(&user.home).unwrap_or_exit(1); } - user.home = home; - } else if parser.found("home-dir") { - eprintln!("usermod: no home dir found"); - exit(1); + user.home = home.to_string(); } if let Some(uid) = uid { user.uid = uid; } - if let Some(gid) = parser.get_opt("gid") { + if let Some(gid) = args.value_of("GID") { sys_groups = AllGroups::new().unwrap_or_exit(1); let gid = gid.parse::().unwrap_or_exit(1); @@ -195,10 +195,8 @@ fn main() { user.gid = gid; } else { eprintln!("usermod: no group found for id: {}", gid); + exit(1); } - } else if parser.found("gid") { - eprintln!("usermod: no gid found"); - exit(1); } }