Files
RedBear-OS/src/bin/useradd.rs
T
MggMuggins 5e53b4b161 Port to redox_users break-api
All the utilities use the new API I defined in mu recent PR to
redox_users. `su`'s behavior was also fixed.

I also updated Cargo.toml (removing unused deps). This may require
another commit after my first PR is merged in order to appropriately
update Cargo.lock and make sure everything builds.
2018-01-29 16:39:52 -06:00

218 lines
6.3 KiB
Rust

#![deny(warnings)]
extern crate arg_parser;
extern crate extra;
extern crate redox_users;
use std::{env, io};
use std::io::Write;
use std::fs::DirBuilder;
use std::os::unix::fs::DirBuilderExt;
use std::process::exit;
use arg_parser::ArgParser;
use extra::option::OptionalExt;
use redox_users::{AllGroups, AllUsers};
const MAN_PAGE: &'static str = /* @MANSTART{useradd} */ r#"
NAME
useradd - add a new user
SYNOPSYS
useradd [ options ] LOGIN
useradd [ -h | --help ]
DESCRIPTION
The useradd utility creates a new user based on
system defaults and values passed on the command line.
Useradd creates a new group for the user by default and
can also be instructed to create the user's home directory.
OPTIONS
-h, --help
Display this help and exit.
-c, --comment
Any text string, usually used as the user's full name.
-d, --home-dir HOME_DIR
The new user will be created with HOME_DIR as their home
directory. The default value is LOGIN prepended with "/home".
This flag DOES NOT create the home directory. See --create-home.
-g, --gid GID
The group id to use for the default login group. This value must
not be in use and must be non-negative. The default is to pick the
smallest available group id between values defined in redox_users.
-m, --create-home
Creates the user's home directory if it does not already exist.
This option is not enabled by default. This option must be specified
for a home directory to be created. If not set, the user's home dir is
set to "/".
-N, --no-user-group
Do not attempt to create the user's user group. Instead, the groupid
is set to 99 (should be the "nobody" group).
-s, --shell SHELL
The path to the user's default login shell. If left blank, the
default shell is set as "/bin/ion"
-u, --uid UID
The user id to use. This value must not be in use and must be
non-negative. The default is to pick the smallest available
user id between the defaults defined in redox_users
AUTHORS
Written by Wesley Hershberger.
"#; /* @MANEND */
const DEFAULT_SHELL: &'static str = "/bin/ion";
const DEFAULT_HOME: &'static str = "/home";
const DEFAULT_MODE: u32 = 0o700;
fn main() {
let mut stdout = io::stdout();
let mut parser = ArgParser::new(1)
.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]
};
let mut sys_users = AllUsers::new().unwrap_or_exit(1);
let mut sys_groups = AllGroups::new().unwrap_or_exit(1);
let uid = if parser.found("uid") {
match parser.get_opt("uid") {
Some(uid) => uid.parse::<usize>().unwrap_or_exit(1),
None => {
eprintln!("useradd: missing uid value");
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") {
gid = 99;
//TODO: Add this user to the "nobody" group
} else {
if parser.found("gid") {
gid = match parser.get_opt("gid") {
Some(gid) => gid.parse::<usize>().unwrap_or_exit(1),
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);
}
}
}
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()
};
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 shell = if parser.found("shell") {
match parser.get_opt("shell") {
Some(sh) => sh,
None => {
eprintln!("useradd: invalid argument: -s");
exit(1);
}
}
} 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) => {
eprintln!("useradd: {}: {}", err, login);
exit(1);
}
}
if parser.found("create-home") {
let mut builder = DirBuilder::new();
builder.mode(DEFAULT_MODE);
match builder.create(&userhome) {
Ok(_) => {},
Err(ref err) if err.kind() == io::ErrorKind::AlreadyExists => {},
Err(err) => {
eprintln!("useradd: failed to create home dir: {}", err);
exit(1);
}
};
}
sys_users.save().unwrap_or_exit(1);
sys_groups.save().unwrap_or_exit(1);
}