diff --git a/src/chown/Cargo.toml b/src/chown/Cargo.toml index a17692dc1..599d65b9c 100644 --- a/src/chown/Cargo.toml +++ b/src/chown/Cargo.toml @@ -8,19 +8,18 @@ name = "uu_chown" path = "chown.rs" [dependencies] -getopts = "*" glob = "*" -libc = "*" -uucore = { path="../uucore" } walkdir = "0.1" +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries"] + [dependencies.clippy] version = "*" optional = true -[features] -default = [] - [[bin]] name = "chown" path = "main.rs" diff --git a/src/chown/chown.rs b/src/chown/chown.rs index 79ff80b4e..558ce9ce1 100644 --- a/src/chown/chown.rs +++ b/src/chown/chown.rs @@ -11,20 +11,14 @@ #![cfg_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", plugin(clippy))] -extern crate libc; -use libc::{uid_t, gid_t, c_char, c_int}; - #[macro_use] extern crate uucore; - -extern crate getopts; -use getopts::Options; +use uucore::libc::{self, uid_t, gid_t, lchown}; +pub use uucore::entries::{self, Locate, Passwd, Group}; extern crate walkdir; use walkdir::WalkDir; -pub mod passwd; - use std::fs::{self, Metadata}; use std::os::unix::fs::MetadataExt; @@ -37,21 +31,15 @@ use std::convert::AsRef; use std::ffi::CString; use std::os::unix::ffi::OsStrExt; -static NAME: &'static str = "chown"; -static VERSION: &'static str = env!("CARGO_PKG_VERSION"); +static SYNTAX: &'static str = "[OPTION]... [OWNER][:[GROUP]] FILE...\n chown [OPTION]... --reference=RFILE FILE..."; +static SUMMARY: &'static str = "change file owner and group"; const FTS_COMFOLLOW: u8 = 1; const FTS_PHYSICAL: u8 = 1 << 1; const FTS_LOGICAL: u8 = 1 << 2; -extern "C" { - #[cfg_attr(all(target_os = "macos", target_arch = "x86"), link_name = "lchown$UNIX2003")] - pub fn lchown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int; -} - pub fn uumain(args: Vec) -> i32 { - let mut opts = Options::new(); - + let mut opts = new_coreopts!(SYNTAX, SUMMARY, ""); opts.optflag("c", "changes", "like verbose but report only when a change is made"); @@ -85,16 +73,7 @@ pub fn uumain(args: Vec) -> i32 { "traverse every symbolic link to a directory encountered"); opts.optflag("P", "", "do not traverse any symbolic links (default)"); - opts.optflag("", "help", "display this help and exit"); - opts.optflag("", "version", "output version information and exit"); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - disp_err!("{}", f); - return 1; - } - }; + let matches = opts.parse(args.clone()); let mut bit_flag = FTS_PHYSICAL; let mut preserve_root = false; @@ -121,13 +100,6 @@ pub fn uumain(args: Vec) -> i32 { } } - if matches.opt_present("help") { - return help(); - } else if matches.opt_present("version") { - println!("{} {}", NAME, VERSION); - return 0; - } - let recursive = matches.opt_present("recursive"); if recursive { if bit_flag == FTS_PHYSICAL { @@ -222,25 +194,25 @@ fn parse_spec(spec: &str) -> Result<(Option, Option), String> { let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty(); if usr_only { - Ok((Some(match passwd::getuid(args[0]) { - Ok(uid) => uid, - Err(_) => return Err(format!("invalid user: ‘{}’", spec)), + Ok((Some(match Passwd::locate(args[0]) { + Ok(v) => v.uid(), + _ => return Err(format!("invalid user: ‘{}’", spec)), }), None)) } else if grp_only { Ok((None, - Some(match passwd::getgid(args[1]) { - Ok(gid) => gid, - Err(_) => return Err(format!("invalid group: ‘{}’", spec)), + Some(match Group::locate(args[1]) { + Ok(v) => v.gid(), + _ => return Err(format!("invalid group: ‘{}’", spec)), }))) } else if usr_grp { - Ok((Some(match passwd::getuid(args[0]) { - Ok(uid) => uid, - Err(_) => return Err(format!("invalid user: ‘{}’", spec)), + Ok((Some(match Passwd::locate(args[0]) { + Ok(v) => v.uid(), + _ => return Err(format!("invalid user: ‘{}’", spec)), }), - Some(match passwd::getgid(args[1]) { - Ok(gid) => gid, - Err(_) => return Err(format!("invalid group: ‘{}’", spec)), + Some(match Group::locate(args[1]) { + Ok(v) => v.gid(), + _ => return Err(format!("invalid group: ‘{}’", spec)), }))) } else { Ok((None, None)) @@ -401,10 +373,10 @@ impl Chowner { if self.verbosity == Verbose { println!("failed to change ownership of {} from {}:{} to {}:{}", path.display(), - passwd::uid2usr(meta.uid()).unwrap(), - passwd::gid2grp(meta.gid()).unwrap(), - passwd::uid2usr(dest_uid).unwrap(), - passwd::gid2grp(dest_gid).unwrap()); + entries::uid2usr(meta.uid()).unwrap(), + entries::gid2grp(meta.gid()).unwrap(), + entries::uid2usr(dest_uid).unwrap(), + entries::gid2grp(dest_gid).unwrap()); }; } } @@ -416,18 +388,18 @@ impl Chowner { Changes | Verbose => { println!("changed ownership of {} from {}:{} to {}:{}", path.display(), - passwd::uid2usr(meta.uid()).unwrap(), - passwd::gid2grp(meta.gid()).unwrap(), - passwd::uid2usr(dest_uid).unwrap(), - passwd::gid2grp(dest_gid).unwrap()); + entries::uid2usr(meta.uid()).unwrap(), + entries::gid2grp(meta.gid()).unwrap(), + entries::uid2usr(dest_uid).unwrap(), + entries::gid2grp(dest_gid).unwrap()); } _ => (), }; } else if self.verbosity == Verbose { println!("ownership of {} retained as {}:{}", path.display(), - passwd::uid2usr(dest_uid).unwrap(), - passwd::gid2grp(dest_gid).unwrap()); + entries::uid2usr(dest_uid).unwrap(), + entries::gid2grp(dest_gid).unwrap()); } } ret @@ -444,54 +416,3 @@ impl Chowner { } } -fn help() -> i32 { - println!(r#" -Usage: {0} [OPTION]... [OWNER][:[GROUP]] FILE... - or: {0} [OPTION]... --reference=RFILE FILE... -Change the owner and/or group of each FILE to OWNER and/or GROUP. -With --reference, change the owner and group of each FILE to those of RFILE. - - -c, --changes like verbose but report only when a change is made - -f, --silent, --quiet suppress most error messages - -v, --verbose output a diagnostic for every file processed - --dereference affect the referent of each symbolic link (this is - the default), rather than the symbolic link itself - -h, --no-dereference affect symbolic links instead of any referenced file - (useful only on systems that can change the - ownership of a symlink) - --from=CURRENT_OWNER:CURRENT_GROUP - change the owner and/or group of each file only if - its current owner and/or group match those specified - here. Either may be omitted, in which case a match - is not required for the omitted attribute - --no-preserve-root do not treat '/' specially (the default) - --preserve-root fail to operate recursively on '/' - --reference=RFILE use RFILE's owner and group rather than - specifying OWNER:GROUP values - -R, --recursive operate on files and directories recursively - -The following options modify how a hierarchy is traversed when the -R -option is also specified. If more than one is specified, only the final -one takes effect. - - -H if a command line argument is a symbolic link - to a directory, traverse it - -L traverse every symbolic link to a directory - encountered - -P do not traverse any symbolic links (default) - - --help display this help and exit - --version output version information and exit - -Owner is unchanged if missing. Group is unchanged if missing, but changed -to login group if implied by a ':' following a symbolic OWNER. -OWNER and GROUP may be numeric as well as symbolic. - -Examples: - chown root /u Change the owner of /u to "root". - chown root:staff /u Likewise, but also change its group to "staff". - chown -hR root /u Change the owner of /u and subfiles to "root". - "#, - NAME); - 0 -} diff --git a/src/chown/passwd.rs b/src/chown/passwd.rs deleted file mode 100644 index ff0707228..000000000 --- a/src/chown/passwd.rs +++ /dev/null @@ -1,59 +0,0 @@ -// (c) Jian Zeng - -extern crate uucore; -use self::uucore::c_types::{getpwuid, getpwnam, getgrgid, getgrnam}; - -use std::ptr; -use std::ffi::{CString, CStr}; -use std::io::Result as IOResult; -use std::io::{ErrorKind, Error}; - -macro_rules! gen_func { - ($fun:ident, $getid:ident, $getnm:ident, $field:ident) => ( - pub fn $fun(name_or_id: &str) -> IOResult { - if let Ok(id) = name_or_id.parse::() { - let data = unsafe { - $getid(id) - }; - if !data.is_null() { - return Ok(id); - } else { - // last_os_error() returns success - return Err(Error::new(ErrorKind::NotFound, format!("No such id `{}`", id))); - } - } else { - let name = CString::new(name_or_id).unwrap(); - let data = unsafe { - $getnm(name.as_ptr()) - }; - if !data.is_null() { - return Ok(unsafe { - ptr::read(data).$field - }); - } else { - // last_os_error() returns success - return Err(Error::new(ErrorKind::NotFound, format!("No such name `{}`", name_or_id))); - } - } - } - ); - ($fun:ident, $getid:ident, $field:ident) => ( - pub fn $fun(id: u32) -> IOResult { - let data = unsafe { - $getid(id) - }; - if !data.is_null() { - Ok(unsafe { - CStr::from_ptr(ptr::read(data).$field).to_string_lossy().into_owned() - }) - } else { - Err(Error::new(ErrorKind::NotFound, format!("No such id `{}`", id))) - } - } - ); -} - -gen_func!(getuid, getpwuid, getpwnam, pw_uid); -gen_func!(getgid, getgrgid, getgrnam, gr_gid); -gen_func!(uid2usr, getpwuid, pw_name); -gen_func!(gid2grp, getgrgid, gr_name); diff --git a/tests/test_chown.rs b/tests/test_chown.rs index a3058988a..3c021ff55 100644 --- a/tests/test_chown.rs +++ b/tests/test_chown.rs @@ -9,25 +9,25 @@ fn new_ucmd() -> UCommand { } #[cfg(test)] -mod test_passwd { - use super::passwd::*; +mod test_passgrp { + use super::uu_chown::entries::{usr2uid,grp2gid,uid2usr,gid2grp}; #[test] - fn test_getuid() { - assert_eq!(0, getuid("root").unwrap()); - assert!(getuid("88888888").is_err()); - assert!(getuid("auserthatdoesntexist").is_err()); + fn test_usr2uid() { + assert_eq!(0, usr2uid("root").unwrap()); + assert!(usr2uid("88888888").is_err()); + assert!(usr2uid("auserthatdoesntexist").is_err()); } #[test] - fn test_getgid() { + fn test_grp2gid() { if cfg!(target_os = "macos") { - assert_eq!(0, getgid("wheel").unwrap()); + assert_eq!(0, grp2gid("wheel").unwrap()); } else { - assert_eq!(0, getgid("root").unwrap()); + assert_eq!(0, grp2gid("root").unwrap()); } - assert!(getgid("88888888").is_err()); - assert!(getgid("agroupthatdoesntexist").is_err()); + assert!(grp2gid("88888888").is_err()); + assert!(grp2gid("agroupthatdoesntexist").is_err()); } #[test]