Port to clap-rs

I did a number of things here:

the *add, *mod, and *del utilities, as well as id recieved substantial
changes, probably what you'd call a rewrite. This was of course using
clap-rs. These should all be very stable at this point (except
unimplemented features in usermod, grr)

getty, passwd, and su are simply ported, using clap for arg parsing. I
didn't change any of the logic, just swapped ArgParser for clap.

Fixed a bug with passwd and unset passwords

I'll open issues about the ones I didn't mention.
This commit is contained in:
MggMuggins
2018-02-08 21:10:44 -06:00
parent e997bdd197
commit fba0c70ae2
12 changed files with 411 additions and 557 deletions
Generated
+55 -1
View File
@@ -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)" = "<none>"
"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)" = "<none>"
"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)" = "<none>"
"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"
+1
View File
@@ -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"
+16 -39
View File
@@ -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),
+23 -46
View File
@@ -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::<usize>().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::<usize>().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::<UsersError>() == Some(&UsersError::AlreadyExists) && parser.found("force") => {
Err(ref err) if err.downcast_ref::<UsersError>() == Some(&UsersError::AlreadyExists) && args.is_present("FORCE") => {
exit(0);
},
Err(err) => {
+10 -25
View File
@@ -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);
+20 -37
View File
@@ -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::<usize>().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();
}
}
+54 -117
View File
@@ -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<P: Hash + Eq + ?Sized>(parser: &ArgParser, flags: &[&P]) -> bool
where Param: Borrow<P>
{
for flag in flags {
if parser.found(*flag) { return true }
}
false
}
fn none_of_found<P: Hash + Eq + ?Sized>(parser: &ArgParser, flags: &[&P]) -> bool
where Param: Borrow<P>
{
!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);
}
+22 -28
View File
@@ -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);
+12 -20
View File
@@ -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);
+112 -143
View File
@@ -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::<usize>().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::<usize>().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::<usize>().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::<usize>().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);
+11 -24
View File
@@ -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);
}
}
+75 -77
View File
@@ -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::<usize>().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::<usize>().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::<usize>().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);
}
}