From c2fb66dfcbf04f96c0ce980401f10a2da5a117a8 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:18:46 +0800 Subject: [PATCH 01/10] uucore::utmpx: fix doctest errors --- src/uucore/utmpx.rs | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/uucore/utmpx.rs b/src/uucore/utmpx.rs index 0122a1156..8ce06df3e 100644 --- a/src/uucore/utmpx.rs +++ b/src/uucore/utmpx.rs @@ -1,7 +1,3 @@ -//! Aim to provide platform-independent methods to obtain login records -//! -//! **ONLY** support linux, macos and freebsd for the time being - // This file is part of the uutils coreutils package. // // (c) Jian Zeng @@ -9,6 +5,31 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // +//! Aims to provide platform-independent methods to obtain login records +//! +//! **ONLY** support linux, macos and freebsd for the time being +//! +//! # Examples: +//! +//! ``` +//! use uucore::utmpx::Utmpx; +//! for ut in Utmpx::iter_all_records() { +//! if ut.is_user_process() { +//! println!("{}: {}", ut.host(), ut.user()) +//! } +//! } +//! ``` +//! +//! Specifying the path to login record: +//! +//! ``` +//! use uucore::utmpx::Utmpx; +//! for ut in Utmpx::iter_all_records().read_from("/some/where/else") { +//! if ut.is_user_process() { +//! println!("{}: {}", ut.host(), ut.user()) +//! } +//! } +//! ``` use super::libc; pub extern crate time; @@ -107,28 +128,6 @@ mod ut { pub use libc::SHUTDOWN_TIME; } -/// Login records -/// -/// Examples: -/// --------- -/// -/// ``` -/// for ut in Utmpx::iter_all_records() { -/// if ut.is_user_process() { -/// println!("{}: {}", ut.host(), ut.user()) -/// } -/// } -/// ``` -/// -/// Specifying the path to login record: -/// -/// ``` -/// for ut in Utmpx::iter_all_records().read_from("/some/where/else") { -/// if ut.is_user_process() { -/// println!("{}: {}", ut.host(), ut.user()) -/// } -/// } -/// ``` pub struct Utmpx { inner: utmpx, } From 799804e455f55cc91da19c5928d45e9c06b0cb56 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:19:57 +0800 Subject: [PATCH 02/10] Add uucore::entries --- src/uucore/Cargo.toml | 3 +- src/uucore/coreopts.rs | 10 +- src/uucore/entries.rs | 245 +++++++++++++++++++++++++++++++++++++++++ src/uucore/lib.rs | 2 + 4 files changed, 254 insertions(+), 6 deletions(-) create mode 100644 src/uucore/entries.rs diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 7a53082a7..77676c251 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -21,8 +21,9 @@ utmpx = ["time", "libc"] c_types = ["libc"] process = ["libc"] signals = [] +entries = ["libc"] wide = [] -default = ["fs", "libc", "utf8", "encoding", "parse_time", "utmpx", "c_types", "process", "signals", "wide"] +default = ["fs", "libc", "utf8", "encoding", "parse_time", "utmpx", "c_types", "process", "entries", "signals", "wide"] [lib] path = "lib.rs" diff --git a/src/uucore/coreopts.rs b/src/uucore/coreopts.rs index b2e2e0084..ec22af9dd 100644 --- a/src/uucore/coreopts.rs +++ b/src/uucore/coreopts.rs @@ -44,11 +44,11 @@ impl<'a> CoreOptions<'a> { crash!(1, "{}", f); } }.unwrap(); - if matches.opt_present("help") { + if matches.opt_present("help") { let usage_str = if self.help_text.display_usage { - format!("\n {}\n\n Reference\n", + format!("\n {}\n\n Reference\n", self.options.usage(self.help_text.summary) - ).replace("Options:", " Options:") + ).replace("Options:", " Options:") } else { String::new() }; print!(" {0} {1} @@ -66,7 +66,7 @@ impl<'a> CoreOptions<'a> { } #[macro_export] -macro_rules! new_coreopts { +macro_rules! new_coreopts { ($syntax: expr, $summary: expr, $long_help: expr) => ( uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText { name: executable!(), @@ -87,4 +87,4 @@ macro_rules! new_coreopts { display_usage: $display_usage }) ); -} \ No newline at end of file +} diff --git a/src/uucore/entries.rs b/src/uucore/entries.rs new file mode 100644 index 000000000..5dae92dd3 --- /dev/null +++ b/src/uucore/entries.rs @@ -0,0 +1,245 @@ +// This file is part of the uutils coreutils package. +// +// (c) Jian Zeng +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +//! Get password/group file entry +//! +//! # Examples: +//! +//! ``` +//! use uucore::entries::{self, Locate}; +//! assert_eq!("root", entries::uid2usr(0).unwrap()); +//! assert_eq!(0, entries::usr2uid("root").unwrap()); +//! assert!(entries::gid2grp(0).is_ok()); +//! assert!(entries::grp2gid("root").is_ok()); +//! +//! assert!(entries::Passwd::locate(0).is_ok()); +//! assert!(entries::Passwd::locate("0").is_ok()); +//! assert!(entries::Passwd::locate("root").is_ok()); +//! +//! assert!(entries::Group::locate(0).is_ok()); +//! assert!(entries::Group::locate("0").is_ok()); +//! assert!(entries::Group::locate("root").is_ok()); +//! ``` + +#[cfg(any(target_os = "freebsd", target_os = "macos"))] +use libc::time_t; +use libc::{uid_t, gid_t, c_char, c_int}; +use libc::{passwd, group, getpwnam, getpwuid, getgrnam, getgrgid, getgroups}; + +use ::std::ptr; +use ::std::io::ErrorKind; +use ::std::io::Error as IOError; +use ::std::io::Result as IOResult; +use ::std::ffi::{CStr, CString}; +use ::std::borrow::Cow; + +extern "C" { + fn getgrouplist(name: *const c_char, gid: gid_t, groups: *mut gid_t, ngroups: *mut c_int) -> c_int; +} + +pub fn get_groups() -> IOResult> { + let ngroups = unsafe { getgroups(0, ptr::null_mut()) }; + if ngroups == -1 { + return Err(IOError::last_os_error()) + } + let mut groups = Vec::with_capacity(ngroups as usize); + let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; + if ngroups == -1 { + Err(IOError::last_os_error()) + } else { + unsafe { + groups.set_len(ngroups as usize); + } + Ok(groups) + } +} + +pub struct Passwd { + inner: passwd, +} + +macro_rules! cstr2cow { + ($v:expr) => ( + unsafe { CStr::from_ptr($v).to_string_lossy() } + ) +} + +impl Passwd { + /// AKA passwd.pw_name + pub fn name(&self) -> Cow { + cstr2cow!(self.inner.pw_name) + } + + /// AKA passwd.pw_uid + pub fn uid(&self) -> uid_t { + self.inner.pw_uid + } + + /// AKA passwd.pw_gid + pub fn gid(&self) -> gid_t { + self.inner.pw_gid + } + + /// AKA passwd.pw_gecos + pub fn user_info(&self) -> Cow { + cstr2cow!(self.inner.pw_gecos) + } + + /// AKA passwd.pw_shell + pub fn user_shell(&self) -> Cow { + cstr2cow!(self.inner.pw_shell) + } + + /// AKA passwd.pw_dir + pub fn user_dir(&self) -> Cow { + cstr2cow!(self.inner.pw_dir) + } + + /// AKA passwd.pw_passwd + pub fn user_passwd(&self) -> Cow { + cstr2cow!(self.inner.pw_passwd) + } + + /// AKA passwd.pw_class + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + pub fn user_access_class(&self) -> Cow { + cstr2cow!(self.inner.pw_class) + } + + /// AKA passwd.pw_change + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + pub fn passwd_change_time(&self) -> time_t { + self.inner.pw_change + } + + /// AKA passwd.pw_expire + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + pub fn expiration(&self) -> time_t { + self.inner.pw_expire + } + + pub fn as_inner(&self) -> &passwd { + &self.inner + } + + pub fn into_inner(self) -> passwd { + self.inner + } + + pub fn belongs_to(&self) -> Vec { + let mut ngroups: c_int = 8; + let mut groups = Vec::with_capacity(ngroups as usize); + let gid = self.inner.pw_gid; + let name = self.inner.pw_name; + unsafe { + if getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups) == -1 { + groups.resize(ngroups as usize, 0); + getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups); + } + groups.set_len(ngroups as usize); + } + groups.truncate(ngroups as usize); + groups + } +} + +pub struct Group { + inner: group, +} + +impl Group { + /// AKA group.gr_name + pub fn name(&self) -> Cow { + cstr2cow!(self.inner.gr_name) + } + + /// AKA group.gr_gid + pub fn gid(&self) -> gid_t { + self.inner.gr_gid + } + + pub fn as_inner(&self) -> &group { + &self.inner + } + + pub fn into_inner(self) -> group { + self.inner + } +} + +/// Fetch desired entry. +pub trait Locate { + fn locate(key: K) -> IOResult where Self: ::std::marker::Sized; +} + +macro_rules! f { + ($fnam:ident, $fid:ident, $t:ident, $st:ident) => ( + impl Locate<$t> for $st { + fn locate(k: $t) -> IOResult { + unsafe { + let data = $fid(k); + if !data.is_null() { + Ok($st { + inner: ptr::read(data as *const _) + }) + } else { + Err(IOError::new(ErrorKind::NotFound, format!("No such id: {}", k))) + } + } + } + } + + impl<'a> Locate<&'a str> for $st { + fn locate(k: &'a str) -> IOResult { + if let Ok(id) = k.parse::<$t>() { + let data = unsafe { $fid(id) }; + if !data.is_null() { + Ok($st { + inner: unsafe {ptr::read(data as *const _)} + }) + } else { + Err(IOError::new(ErrorKind::NotFound, format!("No such id: {}", id))) + } + } else { + unsafe { + let data = $fnam(CString::new(k).unwrap().as_ptr()); + if !data.is_null() { + Ok($st { + inner: ptr::read(data as *const _) + }) + } else { + Err(IOError::new(ErrorKind::NotFound, format!("Not found: {}", k))) + } + } + } + } + } + ) +} + +f!(getpwnam, getpwuid, uid_t, Passwd); +f!(getgrnam, getgrgid, gid_t, Group); + +#[inline] +pub fn uid2usr(id: uid_t) -> IOResult { + Passwd::locate(id).map(|p| p.name().into_owned()) +} + +#[inline] +pub fn gid2grp(id: gid_t) -> IOResult { + Group::locate(id).map(|p| p.name().into_owned()) +} + +#[inline] +pub fn usr2uid(name: &str) -> IOResult { + Passwd::locate(name).map(|p| p.uid()) +} + +#[inline] +pub fn grp2gid(name: &str) -> IOResult { + Group::locate(name).map(|p| p.gid()) +} diff --git a/src/uucore/lib.rs b/src/uucore/lib.rs index 86e24a07a..ff45693aa 100644 --- a/src/uucore/lib.rs +++ b/src/uucore/lib.rs @@ -20,6 +20,8 @@ pub mod parse_time; pub mod utmpx; #[cfg(all(unix, feature = "c_types"))] pub mod c_types; +#[cfg(all(unix, feature = "entries"))] +pub mod entries; #[cfg(all(unix, feature = "process"))] pub mod process; #[cfg(all(unix, feature = "signals"))] From 40e01b94f399b6be636fcd46c318a0c44a706a61 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:22:42 +0800 Subject: [PATCH 03/10] chown: use uucore::entries --- src/chown/Cargo.toml | 11 ++-- src/chown/chown.rs | 135 +++++++++---------------------------------- src/chown/passwd.rs | 59 ------------------- tests/test_chown.rs | 22 +++---- 4 files changed, 44 insertions(+), 183 deletions(-) delete mode 100644 src/chown/passwd.rs 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] From f66aaa8b78960c2347deea7a327fcb2b79d214a2 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:23:31 +0800 Subject: [PATCH 04/10] ls: use uucore::entries --- src/ls/Cargo.toml | 7 +++++-- src/ls/ls.rs | 32 +++++--------------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/ls/Cargo.toml b/src/ls/Cargo.toml index 5da0b3818..a43734c0c 100644 --- a/src/ls/Cargo.toml +++ b/src/ls/Cargo.toml @@ -9,8 +9,6 @@ path = "ls.rs" [dependencies] getopts = "*" -libc = "*" -uucore = { path="../uucore" } pretty-bytes = "0.1.0" term_grid = "*" termsize = "*" @@ -18,6 +16,11 @@ time = "*" lazy_static = "*" unicode-width = "*" +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries"] + [[bin]] name = "ls" path = "main.rs" diff --git a/src/ls/ls.rs b/src/ls/ls.rs index 858bb736d..ac6c3fbc2 100644 --- a/src/ls/ls.rs +++ b/src/ls/ls.rs @@ -23,11 +23,9 @@ extern crate lazy_static; #[macro_use] extern crate uucore; - -extern crate libc; #[cfg(unix)] -use self::libc::{S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, - S_IROTH, S_IWOTH, S_IXOTH, mode_t, c_char}; +use uucore::libc::{S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH, mode_t}; use getopts::Options; use std::fs; @@ -41,10 +39,6 @@ use std::os::unix::fs::MetadataExt; #[cfg(unix)] use std::os::unix::fs::FileTypeExt; #[cfg(unix)] -use std::ptr; -#[cfg(unix)] -use std::ffi::CStr; -#[cfg(unix)] use unicode_width::UnicodeWidthStr; #[cfg(windows)] @@ -407,32 +401,16 @@ fn display_item_long(item: &PathBuf, // Currently getpwuid is `linux` target only. If it's broken out into // a posix-compliant attribute this can be updated... #[cfg(unix)] -use uucore::c_types::{getpwuid, getgrgid}; - -// Only used in `display_uname` and `display_group` -#[cfg(unix)] -fn cstr2string(cstr: *const c_char) -> String { - unsafe { CStr::from_ptr(cstr).to_string_lossy().into_owned() } -} +use uucore::entries; #[cfg(unix)] fn display_uname(metadata: &Metadata) -> String { - let pw = unsafe { getpwuid(metadata.uid()) }; - if !pw.is_null() { - cstr2string(unsafe { ptr::read(pw).pw_name }) - } else { - metadata.uid().to_string() - } + entries::uid2usr(metadata.uid()).unwrap_or(metadata.uid().to_string()) } #[cfg(unix)] fn display_group(metadata: &Metadata) -> String { - let ent = unsafe { getgrgid(metadata.gid()) }; - if !ent.is_null() { - cstr2string(unsafe { ptr::read(ent).gr_name }) - } else { - metadata.gid().to_string() - } + entries::gid2grp(metadata.gid()).unwrap_or(metadata.gid().to_string()) } #[cfg(not(unix))] From 40e6c5a3979089636a8dd37634b44c53352eb708 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:24:09 +0800 Subject: [PATCH 05/10] pinky: use uucore::entries --- src/pinky/Cargo.toml | 2 +- src/pinky/pinky.rs | 73 ++++++++------------------------------------ 2 files changed, 13 insertions(+), 62 deletions(-) diff --git a/src/pinky/Cargo.toml b/src/pinky/Cargo.toml index 6c9d10af0..28e1373e4 100644 --- a/src/pinky/Cargo.toml +++ b/src/pinky/Cargo.toml @@ -10,7 +10,7 @@ path = "pinky.rs" [dependencies.uucore] path = "../uucore" default-features = false -features = ["utmpx", "c_types"] +features = ["utmpx", "entries"] [[bin]] name = "pinky" diff --git a/src/pinky/pinky.rs b/src/pinky/pinky.rs index ddc8da540..783f7879a 100644 --- a/src/pinky/pinky.rs +++ b/src/pinky/pinky.rs @@ -12,9 +12,9 @@ #[macro_use] extern crate uucore; -use uucore::c_types::getpwnam; use uucore::utmpx::{self, time, Utmpx}; -use uucore::libc::{uid_t, gid_t, c_char, S_IWGRP}; +use uucore::libc::S_IWGRP; +use uucore::entries::{Locate, Passwd}; use std::io::prelude::*; use std::io::BufReader; @@ -23,14 +23,11 @@ use std::io::Result as IOResult; use std::fs::File; use std::os::unix::fs::MetadataExt; -use std::ptr; -use std::ffi::{CStr, CString}; - use std::path::PathBuf; static SYNTAX: &'static str = "[OPTION]... [USER]..."; static SUMMARY: &'static str = "A lightweight 'finger' program; print user information."; - + const BUFSIZE: usize = 1024; pub fn uumain(args: Vec) -> i32 { @@ -152,52 +149,6 @@ struct Pinky { names: Vec, } -#[derive(Debug)] -pub struct Passwd { - pw_name: String, - pw_passwd: String, - pw_uid: uid_t, - pw_gid: gid_t, - pw_gecos: String, - pw_dir: String, - pw_shell: String, -} - -trait FromChars { - fn from_chars(*const c_char) -> Self; -} - -impl FromChars for String { - #[inline] - fn from_chars(ptr: *const c_char) -> Self { - if ptr.is_null() { - return "".to_owned(); - } - let s = unsafe { CStr::from_ptr(ptr) }; - s.to_string_lossy().into_owned() - } -} - -pub fn getpw(u: &str) -> Option { - let pw = unsafe { - getpwnam(CString::new(u).unwrap().as_ptr()) - }; - if !pw.is_null() { - let data = unsafe { ptr::read(pw) }; - Some(Passwd { - pw_name: String::from_chars(data.pw_name), - pw_passwd: String::from_chars(data.pw_passwd), - pw_uid: data.pw_uid, - pw_gid: data.pw_gid, - pw_dir: String::from_chars(data.pw_dir), - pw_gecos: String::from_chars(data.pw_gecos), - pw_shell: String::from_chars(data.pw_shell), - }) - } else { - None - } -} - pub trait Capitalize { fn capitalize(&self) -> String; } @@ -267,12 +218,12 @@ impl Pinky { print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user()); if self.include_fullname { - if let Some(pw) = getpw(ut.user().as_ref()) { - let mut gecos = pw.pw_gecos; + if let Ok(pw) = Passwd::locate(ut.user().as_ref()) { + let mut gecos = pw.user_info().into_owned(); if let Some(n) = gecos.find(',') { gecos.truncate(n + 1); } - print!(" {:<19.19}", gecos.replace("&", &pw.pw_name.capitalize())); + print!(" {:<19.19}", gecos.replace("&", &pw.name().capitalize())); } else { print!(" {:19}", " ???"); } @@ -344,14 +295,14 @@ impl Pinky { fn long_pinky(&self) -> i32 { for u in &self.names { print!("Login name: {:<28}In real life: ", u); - if let Some(pw) = getpw(u) { - println!(" {}", pw.pw_gecos.replace("&", &pw.pw_name.capitalize())); + if let Ok(pw) = Passwd::locate(u.as_str()) { + println!(" {}", pw.user_info().replace("&", &pw.name().capitalize())); if self.include_home_and_shell { - print!("Directory: {:<29}", pw.pw_dir); - println!("Shell: {}", pw.pw_shell); + print!("Directory: {:<29}", pw.user_dir()); + println!("Shell: {}", pw.user_shell()); } if self.include_project { - let mut p = PathBuf::from(&pw.pw_dir); + let mut p = PathBuf::from(pw.user_dir().as_ref()); p.push(".project"); if let Ok(f) = File::open(p) { print!("Project: "); @@ -359,7 +310,7 @@ impl Pinky { } } if self.include_plan { - let mut p = PathBuf::from(&pw.pw_dir); + let mut p = PathBuf::from(pw.user_dir().as_ref()); p.push(".plan"); if let Ok(f) = File::open(p) { println!("Plan:"); From 99f0114450d59c8025470a00947de37d8817a697 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:24:50 +0800 Subject: [PATCH 06/10] stat: use uucore::entries --- src/stat/Cargo.toml | 7 +++++-- src/stat/fsext.rs | 12 ++++++------ src/stat/stat.rs | 30 +++--------------------------- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/stat/Cargo.toml b/src/stat/Cargo.toml index da3788528..51630441c 100644 --- a/src/stat/Cargo.toml +++ b/src/stat/Cargo.toml @@ -9,9 +9,12 @@ path = "stat.rs" [dependencies] getopts = "*" -libc = "^0.2" time = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries"] [[bin]] name = "stat" diff --git a/src/stat/fsext.rs b/src/stat/fsext.rs index a33c0adad..b7119f635 100644 --- a/src/stat/fsext.rs +++ b/src/stat/fsext.rs @@ -6,13 +6,13 @@ // that was distributed with this source code. // -extern crate libc; +pub use super::uucore::libc; extern crate time; use self::time::Timespec; -pub use self::libc::{S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK, S_ISUID, S_ISGID, - S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, mode_t, - c_int, strerror}; +pub use libc::{S_IFMT, S_IFDIR, S_IFCHR, S_IFBLK, S_IFREG, S_IFIFO, S_IFLNK, S_IFSOCK, S_ISUID, S_ISGID, S_ISVTX, + S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, mode_t, c_int, + strerror}; pub trait BirthTime { fn pretty_birth(&self) -> String; @@ -176,12 +176,12 @@ use std::error::Error; use std::io::Error as IOError; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] -use self::libc::statfs as Sstatfs; +use libc::statfs as Sstatfs; // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))] // use self::libc::statvfs as Sstatfs; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] -use self::libc::statfs as statfs_fn; +use libc::statfs as statfs_fn; // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))] // use self::libc::statvfs as statfs_fn; diff --git a/src/stat/stat.rs b/src/stat/stat.rs index 834396374..8450a74bc 100644 --- a/src/stat/stat.rs +++ b/src/stat/stat.rs @@ -17,6 +17,7 @@ pub use fsext::*; #[macro_use] extern crate uucore; +use uucore::entries; use std::{fs, iter, cmp}; use std::fs::File; @@ -319,31 +320,6 @@ fn print_it(arg: &str, otype: OutputType, flag: u8, width: usize, precision: i32 } } - -use std::ptr; -use std::ffi::CStr; -use uucore::c_types::{getpwuid, getgrgid}; -fn get_grp_name(gid: u32) -> String { - let p = unsafe { getgrgid(gid) }; - if !p.is_null() { - unsafe { CStr::from_ptr(ptr::read(p).gr_name).to_string_lossy().into_owned() } - } else { - "UNKNOWN".to_owned() - } -} -fn get_usr_name(uid: u32) -> String { - let p = unsafe { getpwuid(uid) }; - if !p.is_null() { - unsafe { - CStr::from_ptr(ptr::read(p).pw_name) - .to_string_lossy() - .into_owned() - } - } else { - "UNKNOWN".to_owned() - } -} - impl Stater { pub fn generate_tokens(fmtstr: &str, use_printf: bool) -> Result, String> { @@ -613,7 +589,7 @@ impl Stater { } // group name of owner 'G' => { - arg = get_grp_name(meta.gid()); + arg = entries::gid2grp(meta.gid()).unwrap_or("UNKNOWN".to_owned()); otype = OutputType::Str; } // number of hard links @@ -683,7 +659,7 @@ impl Stater { } // user name of owner 'U' => { - arg = get_usr_name(meta.uid()); + arg = entries::uid2usr(meta.uid()).unwrap_or("UNKNOWN".to_owned()); otype = OutputType::Str; } From 270290efe6497b0f0be8e7b3b09dd600a6154a93 Mon Sep 17 00:00:00 2001 From: Knight Date: Sun, 14 Aug 2016 13:53:42 +0800 Subject: [PATCH 07/10] whoami: use uucore::entries --- src/whoami/Cargo.toml | 7 +++++-- src/whoami/platform/unix.rs | 23 +++++------------------ src/whoami/whoami.rs | 1 - 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/whoami/Cargo.toml b/src/whoami/Cargo.toml index af40ed7ed..a84dddfa9 100644 --- a/src/whoami/Cargo.toml +++ b/src/whoami/Cargo.toml @@ -9,10 +9,13 @@ path = "whoami.rs" [dependencies] getopts = "*" -libc = "*" winapi = "*" advapi32-sys = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries"] [[bin]] name = "whoami" diff --git a/src/whoami/platform/unix.rs b/src/whoami/platform/unix.rs index f4db2e53e..ab7c42ff6 100644 --- a/src/whoami/platform/unix.rs +++ b/src/whoami/platform/unix.rs @@ -2,31 +2,18 @@ * This file is part of the uutils coreutils package. * * (c) Jordi Boggiano + * (c) Jian Zeng * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -use std::io::{Result, Error}; -use ::libc; -use uucore::c_types::{c_passwd, getpwuid}; - -extern { - pub fn geteuid() -> libc::uid_t; -} +use std::io::Result; +use uucore::libc::geteuid; +use uucore::entries::uid2usr; pub unsafe fn getusername() -> Result { // Get effective user id let uid = geteuid(); - - // Try to find username for uid - let passwd: *const c_passwd = getpwuid(uid); - if passwd.is_null() { - return Err(Error::last_os_error()) - } - - // Extract username from passwd struct - let pw_name: *const libc::c_char = (*passwd).pw_name; - let username = String::from_utf8_lossy(::std::ffi::CStr::from_ptr(pw_name).to_bytes()).to_string(); - Ok(username) + uid2usr(uid) } diff --git a/src/whoami/whoami.rs b/src/whoami/whoami.rs index e7d01ba15..7a69bbbd0 100644 --- a/src/whoami/whoami.rs +++ b/src/whoami/whoami.rs @@ -12,7 +12,6 @@ /* last synced with: whoami (GNU coreutils) 8.21 */ extern crate getopts; -extern crate libc; #[macro_use] extern crate uucore; From 2b96f8f0c1ce2db8ac5f97e1b476bab118e1aea8 Mon Sep 17 00:00:00 2001 From: Knight Date: Tue, 2 Aug 2016 14:25:19 +0800 Subject: [PATCH 08/10] chroot: use uucore::entries --- src/chroot/Cargo.toml | 7 +++++-- src/chroot/chroot.rs | 34 ++++++++++------------------------ 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/chroot/Cargo.toml b/src/chroot/Cargo.toml index ab19f96bf..6761366a8 100644 --- a/src/chroot/Cargo.toml +++ b/src/chroot/Cargo.toml @@ -9,8 +9,11 @@ path = "chroot.rs" [dependencies] getopts = "*" -libc = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries"] [[bin]] name = "chroot" diff --git a/src/chroot/chroot.rs b/src/chroot/chroot.rs index fa7f8bcff..6f5c63eeb 100644 --- a/src/chroot/chroot.rs +++ b/src/chroot/chroot.rs @@ -4,39 +4,25 @@ * This file is part of the uutils coreutils package. * * (c) Vsevolod Velichko + * (c) Jian Zeng * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ extern crate getopts; -extern crate libc; #[macro_use] extern crate uucore; +use uucore::libc::{self, setgid, setuid, chroot, setgroups}; +use uucore::entries; use getopts::Options; -use libc::{setgid, setuid}; use std::ffi::CString; use std::io::{Error, Write}; use std::iter::FromIterator; use std::path::Path; use std::process::Command; -use uucore::c_types::{get_pw_from_args, get_group}; - -extern { - fn chroot(path: *const libc::c_char) -> libc::c_int; -} - -#[cfg(any(target_os = "macos", target_os = "freebsd"))] -extern { - fn setgroups(size: libc::c_int, list: *const libc::gid_t) -> libc::c_int; -} - -#[cfg(target_os = "linux")] -extern { - fn setgroups(size: libc::size_t, list: *const libc::gid_t) -> libc::c_int; -} static NAME: &'static str = "chroot"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -146,9 +132,9 @@ fn enter_chroot(root: &Path) { fn set_main_group(group: &str) { if !group.is_empty() { - let group_id = match get_group(group) { - None => crash!(1, "no such group: {}", group), - Some(g) => g.gr_gid + let group_id = match entries::grp2gid(group) { + Ok(g) => g, + _ => crash!(1, "no such group: {}", group), }; let err = unsafe { setgid(group_id) }; if err != 0 { @@ -177,9 +163,9 @@ fn set_groups_from_str(groups: &str) { if !groups.is_empty() { let groups_vec: Vec = FromIterator::from_iter( groups.split(',').map( - |x| match get_group(x) { - None => crash!(1, "no such group: {}", x), - Some(g) => g.gr_gid + |x| match entries::grp2gid(x) { + Ok(g) => g, + _ => crash!(1, "no such group: {}", x), }) ); let err = set_groups(groups_vec); @@ -191,7 +177,7 @@ fn set_groups_from_str(groups: &str) { fn set_user(user: &str) { if !user.is_empty() { - let user_id = get_pw_from_args(&vec!(user.to_owned())).unwrap().pw_uid; + let user_id = entries::usr2uid(user).unwrap(); let err = unsafe { setuid(user_id as libc::uid_t) }; if err != 0 { crash!(1, "cannot set user to {}: {}", user, Error::last_os_error()) From 369c2c2d83b49fedbfce81c7b1fe9acdc7b5ccdd Mon Sep 17 00:00:00 2001 From: Knight Date: Sat, 20 Aug 2016 02:10:18 +0800 Subject: [PATCH 09/10] id: use uucore::entries --- src/id/Cargo.toml | 7 +- src/id/id.rs | 413 ++++++++++++++++++---------------------------- 2 files changed, 164 insertions(+), 256 deletions(-) diff --git a/src/id/Cargo.toml b/src/id/Cargo.toml index 664cb7399..63eec9112 100644 --- a/src/id/Cargo.toml +++ b/src/id/Cargo.toml @@ -9,8 +9,11 @@ path = "id.rs" [dependencies] getopts = "*" -libc = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["entries", "process"] [[bin]] name = "id" diff --git a/src/id/id.rs b/src/id/id.rs index 71140122b..fae1ce078 100644 --- a/src/id/id.rs +++ b/src/id/id.rs @@ -1,54 +1,51 @@ #![crate_name = "uu_id"] -/* - * This file is part of the uutils coreutils package. - * - * (c) Alan Andrade - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - * - * Synced with: - * http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c - * http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c - */ +// This file is part of the uutils coreutils package. +// +// (c) Alan Andrade +// (c) Jian Zeng +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. +// +// Synced with: +// http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c +// http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c +// #![allow(non_camel_case_types)] -extern crate getopts; -extern crate libc; +#![allow(dead_code)] #[macro_use] extern crate uucore; - -use libc::{getgid, getuid, uid_t, getegid, geteuid, getlogin}; -use std::ffi::CStr; +pub use uucore::libc; +use uucore::libc::{getlogin, uid_t}; +use uucore::entries::{self, Passwd, Group, Locate}; +use uucore::process::{getgid, getuid, getegid, geteuid}; use std::io::Write; -use std::ptr::read; -use uucore::c_types::{ - c_passwd, - c_group, - get_groups, - get_group_list, - get_pw_from_args, - getpwuid, - group -}; +use std::ffi::CStr; -#[cfg(not(target_os = "linux"))] +macro_rules! cstr2cow { + ($v:expr) => ( + unsafe { CStr::from_ptr($v).to_string_lossy() } + ) +} + +#[cfg(not(target_os = "linu"))] mod audit { pub use std::mem::uninitialized; - use libc::{uid_t, pid_t, c_int, c_uint, uint64_t, dev_t}; + use super::libc::{uid_t, pid_t, c_int, c_uint, uint64_t, dev_t}; - pub type au_id_t = uid_t; - pub type au_asid_t = pid_t; + pub type au_id_t = uid_t; + pub type au_asid_t = pid_t; pub type au_event_t = c_uint; - pub type au_emod_t = c_uint; + pub type au_emod_t = c_uint; pub type au_class_t = c_int; #[repr(C)] pub struct au_mask { pub am_success: c_uint, - pub am_failure: c_uint + pub am_failure: c_uint, } pub type au_mask_t = au_mask; @@ -60,56 +57,52 @@ mod audit { #[repr(C)] pub struct c_auditinfo_addr { - pub ai_auid: au_id_t, /* Audit user ID */ - pub ai_mask: au_mask_t, /* Audit masks. */ - pub ai_termid: au_tid_addr_t, /* Terminal ID. */ - pub ai_asid: au_asid_t, /* Audit session ID. */ - pub ai_flags: uint64_t /* Audit session flags */ + pub ai_auid: au_id_t, // Audit user ID + pub ai_mask: au_mask_t, // Audit masks. + pub ai_termid: au_tid_addr_t, // Terminal ID. + pub ai_asid: au_asid_t, // Audit session ID. + pub ai_flags: uint64_t, // Audit session flags } pub type c_auditinfo_addr_t = c_auditinfo_addr; - extern { + extern "C" { pub fn getaudit(auditinfo_addr: *mut c_auditinfo_addr_t) -> c_int; } } -extern { - fn getgrgid(gid: uid_t) -> *const c_group; -} - -static NAME: &'static str = "id"; +static SYNTAX: &'static str = "[OPTION]... [USER]"; +static SUMMARY: &'static str = "Print user and group information for the specified USER,\n or (when USER omitted) for the current user."; pub fn uumain(args: Vec) -> i32 { - let mut opts = getopts::Options::new(); - opts.optflag("h", "", "Show help"); - opts.optflag("A", "", "Display the process audit (not available on Linux)"); + let mut opts = new_coreopts!(SYNTAX, SUMMARY, ""); + opts.optflag("A", + "", + "Display the process audit (not available on Linux)"); opts.optflag("G", "", "Display the different group IDs"); opts.optflag("g", "", "Display the effective group ID as a number"); - opts.optflag("n", "", "Display the name of the user or group ID for the -G, -g and -u options"); + opts.optflag("n", + "", + "Display the name of the user or group ID for the -G, -g and -u options"); opts.optflag("P", "", "Display the id as a password file entry"); opts.optflag("p", "", "Make the output human-readable"); opts.optflag("r", "", "Display the real ID for the -g and -u options"); opts.optflag("u", "", "Display the effective user ID as a number"); - let matches = match opts.parse(&args[1..]) { - Ok(m) => { m }, - Err(_) => { - println!("{}", opts.usage(NAME)); - return 1; - } - }; - - if matches.opt_present("h") { - println!("{}", opts.usage(NAME)); - return 0; - } + let matches = opts.parse(args); if matches.opt_present("A") { auditid(); return 0; } - let possible_pw = get_pw_from_args(&matches.free); + let possible_pw = if matches.free.is_empty() { + None + } else { + match Passwd::locate(matches.free[0].as_str()) { + Ok(p) => Some(p), + Err(_) => crash!(1, "No such user/group: {}", matches.free[0]), + } + }; let nflag = matches.opt_present("n"); let uflag = matches.opt_present("u"); @@ -117,55 +110,57 @@ pub fn uumain(args: Vec) -> i32 { let rflag = matches.opt_present("r"); if gflag { - let id = if possible_pw.is_some() { - possible_pw.unwrap().pw_gid + let id = possible_pw.map(|p| p.gid()).unwrap_or(if rflag { + getgid() } else { - if rflag { - unsafe { getgid() } - } else { - unsafe { getegid() } - } - }; - let gr = unsafe { getgrgid(id) }; - - if nflag && !gr.is_null() { - let gr_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() }; - println!("{}", gr_name); - } else { - println!("{}", id); - } + getegid() + }); + println!("{}", + if nflag { + entries::gid2grp(id).unwrap_or(id.to_string()) + } else { + id.to_string() + }); return 0; } if uflag { - let id = if possible_pw.is_some() { - possible_pw.unwrap().pw_uid - } else if rflag { - unsafe { getuid() } + let id = possible_pw.map(|p| p.uid()).unwrap_or(if rflag { + getuid() } else { - unsafe { geteuid() } - }; - - let pw = unsafe { getpwuid(id) }; - if nflag && !pw.is_null() { - let pw_name = unsafe { - String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() - }; - println!("{}", pw_name); - } else { - println!("{}", id); - } - + geteuid() + }); + println!("{}", + if nflag { + entries::uid2usr(id).unwrap_or(id.to_string()) + } else { + id.to_string() + }); return 0; } if matches.opt_present("G") { - group(possible_pw, nflag); + println!("{}", + if nflag { + possible_pw.map(|p| p.belongs_to()) + .unwrap_or(entries::get_groups().unwrap()) + .iter() + .map(|&id| entries::gid2grp(id).unwrap()) + .collect::>() + .join(" ") + } else { + possible_pw.map(|p| p.belongs_to()) + .unwrap_or(entries::get_groups().unwrap()) + .iter() + .map(|&id| id.to_string()) + .collect::>() + .join(" ") + }); return 0; } if matches.opt_present("P") { - pline(possible_pw); + pline(possible_pw.map(|v| v.uid())); return 0; }; @@ -183,126 +178,92 @@ pub fn uumain(args: Vec) -> i32 { 0 } -fn pretty(possible_pw: Option) { - if possible_pw.is_some() { - let pw = possible_pw.unwrap(); - - let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name).to_bytes()).to_string() }; - print!("uid\t{}\ngroups\t", pw_name); - group(possible_pw, true); +fn pretty(possible_pw: Option) { + if let Some(p) = possible_pw { + print!("uid\t{}\ngroups\t", p.name()); + println!("{}", + p.belongs_to().iter().map(|&gr| entries::gid2grp(gr).unwrap()).collect::>().join(" ")); } else { - let login = unsafe { String::from_utf8_lossy(CStr::from_ptr((getlogin() as *const _)).to_bytes()).to_string() }; - let rid = unsafe { getuid() }; - let pw = unsafe { getpwuid(rid) }; - - let is_same_user = unsafe { - String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()) == login - }; - - if pw.is_null() || is_same_user { - println!("login\t{}", login); - } - - if !pw.is_null() { - println!( - "uid\t{}", - unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() }) + let login = cstr2cow!(getlogin() as *const _); + let rid = getuid(); + if let Ok(p) = Passwd::locate(rid) { + if login == p.name() { + println!("login\t{}", login); + } + println!("uid\t{}", p.name()); } else { - println!("uid\t{}\n", rid); + println!("uid\t{}", rid); } - let eid = unsafe { getegid() }; + let eid = getegid(); if eid == rid { - let pw = unsafe { getpwuid(eid) }; - if !pw.is_null() { - println!( - "euid\t{}", - unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() }); + if let Ok(p) = Passwd::locate(eid) { + println!("euid\t{}", p.name()); } else { println!("euid\t{}", eid); } } - let rid = unsafe { getgid() }; - + let rid = getgid(); if rid != eid { - let gr = unsafe { getgrgid(rid) }; - if !gr.is_null() { - println!( - "rgid\t{}", - unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() }); + if let Ok(g) = Group::locate(rid) { + println!("euid\t{}", g.name()); } else { - println!("rgid\t{}", rid); + println!("euid\t{}", rid); } } - print!("groups\t"); - group(None, true); + println!("groups\t{}", + entries::get_groups() + .unwrap() + .iter() + .map(|&gr| entries::gid2grp(gr).unwrap()) + .collect::>() + .join(" ")); } } #[cfg(any(target_os = "macos", target_os = "freebsd"))] -fn pline(possible_pw: Option) { - let pw = if possible_pw.is_none() { - unsafe { read(getpwuid(getuid())) } - } else { - possible_pw.unwrap() - }; +fn pline(possible_uid: Option) { + let uid = possible_uid.unwrap_or(getuid()); + let pw = Passwd::locate(uid).unwrap(); - let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()}; - let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()}; - let pw_class = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_class ).to_bytes()).to_string()}; - let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()}; - let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()}; - let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()}; - - println!( - "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}", - pw_name, - pw_passwd, - pw.pw_uid, - pw.pw_gid, - pw_class, - pw.pw_change, - pw.pw_expire, - pw_gecos, - pw_dir, - pw_shell); + println!("{}:{}:{}:{}:{}:{}:{}:{}:{}:{}", + pw.name(), + pw.user_passwd(), + pw.uid(), + pw.gid(), + pw.user_access_class(), + pw.passwd_change_time(), + pw.expiration(), + pw.user_info(), + pw.user_dir(), + pw.user_shell()); } #[cfg(target_os = "linux")] -fn pline(possible_pw: Option) { - let pw = if possible_pw.is_none() { - unsafe { read(getpwuid(getuid())) } - } else { - possible_pw.unwrap() - }; +fn pline(possible_uid: Option) { + let uid = possible_uid.unwrap_or(getuid()); + let pw = Passwd::locate(uid).unwrap(); - let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()}; - let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()}; - let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()}; - let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()}; - let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()}; - - println!( - "{}:{}:{}:{}:{}:{}:{}", - pw_name, - pw_passwd, - pw.pw_uid, - pw.pw_gid, - pw_gecos, - pw_dir, - pw_shell); + println!("{}:{}:{}:{}:{}:{}:{}", + pw.name(), + pw.user_passwd(), + pw.uid(), + pw.gid(), + pw.user_info(), + pw.user_dir(), + pw.user_shell()); } #[cfg(target_os = "linux")] -fn auditid() { } +fn auditid() {} #[cfg(not(target_os = "linux"))] fn auditid() { let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { audit::uninitialized() }; let address = &mut auditinfo as *mut audit::c_auditinfo_addr_t; - if unsafe { audit::getaudit(address) } < 0 { + if unsafe { audit::getaudit(address) } < 0 { println!("couldn't retrieve information"); return; } @@ -314,83 +275,27 @@ fn auditid() { println!("asid={}", auditinfo.ai_asid); } -fn id_print(possible_pw: Option, p_euid: bool, p_egid: bool) { - let uid; - let gid; +fn id_print(possible_pw: Option, p_euid: bool, p_egid: bool) { + let (uid, gid) = possible_pw.map(|p| (p.uid(), p.gid())).unwrap_or((getuid(), getgid()));; - if possible_pw.is_some() { - uid = possible_pw.unwrap().pw_uid; - gid = possible_pw.unwrap().pw_gid; - } else { - uid = unsafe { getuid() }; - gid = unsafe { getgid() }; - } + let groups = Passwd::locate(uid).unwrap().belongs_to(); - let groups = match possible_pw { - Some(pw) => Ok(get_group_list(pw.pw_name, pw.pw_gid)), - None => get_groups(), - }; + print!("uid={}({})", uid, entries::uid2usr(uid).unwrap()); + print!(" gid={}({})", gid, entries::gid2grp(gid).unwrap()); - let groups = groups.unwrap_or_else(|errno| { - crash!(1, "failed to get group list (errno={})", errno); - }); - - if possible_pw.is_some() { - print!( - "uid={}({})", - uid, - unsafe { String::from_utf8_lossy(CStr::from_ptr(possible_pw.unwrap().pw_name).to_bytes()).to_string() }); - } else { - print!("uid={}", unsafe { getuid() }); - } - - print!(" gid={}", gid); - let gr = unsafe { getgrgid(gid) }; - if !gr.is_null() { - print!( - "({})", - unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() }); - } - - let euid = unsafe { geteuid() }; + let euid = geteuid(); if p_euid && (euid != uid) { - print!(" euid={}", euid); - let pw = unsafe { getpwuid(euid) }; - if !pw.is_null() { - print!( - "({})", - unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() }); - } + print!(" euid={}({})", euid, entries::uid2usr(euid).unwrap()); } - let egid = unsafe { getegid() }; + let egid = getegid(); if p_egid && (egid != gid) { - print!(" egid={}", egid); - unsafe { - let grp = getgrgid(egid); - if !grp.is_null() { - print!("({})", String::from_utf8_lossy(CStr::from_ptr(read(grp).gr_name).to_bytes()).to_string()); - } - } + print!(" egid={}({})", euid, entries::gid2grp(egid).unwrap()); } - if !groups.is_empty() { - print!(" groups="); - - let mut first = true; - for &gr in &groups { - if !first { print!(",") } - print!("{}", gr); - let group = unsafe { getgrgid(gr) }; - if !group.is_null() { - let name = unsafe { - String::from_utf8_lossy(CStr::from_ptr(read(group).gr_name).to_bytes()).to_string() - }; - print!("({})", name); - } - first = false - } - } - - println!(""); + println!(" groups={}", + groups.iter() + .map(|&gr| format!("{}({})", gr, entries::gid2grp(gr).unwrap())) + .collect::>() + .join(",")); } From b6c864b7f3686ba795214a609ceb31963f50496f Mon Sep 17 00:00:00 2001 From: Knight Date: Sat, 20 Aug 2016 02:12:19 +0800 Subject: [PATCH 10/10] uucore::process: add functions to obtain uid/gid, euid/egid --- src/uucore/process.rs | 58 +++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/uucore/process.rs b/src/uucore/process.rs index bb9bbbc3d..f6aec5166 100644 --- a/src/uucore/process.rs +++ b/src/uucore/process.rs @@ -1,15 +1,14 @@ -/* - * This file is part of the uutils coreutils package. - * - * (c) Maciej Dziardziel - * - * For the full copyright and license information, please view the LICENSE file - * that was distributed with this source code. - */ +// This file is part of the uutils coreutils package. +// +// (c) Maciej Dziardziel +// (c) Jian Zeng +// +// For the full copyright and license information, please view the LICENSE file +// that was distributed with this source code. +// -extern crate libc; - -use libc::{c_int, pid_t}; +use super::libc; +use libc::{c_int, pid_t, uid_t, gid_t}; use std::fmt; use std::io; use std::process::Child; @@ -17,6 +16,30 @@ use std::sync::{Arc, Condvar, Mutex}; use std::thread; use std::time::{Duration, Instant}; +pub fn geteuid() -> uid_t { + unsafe { + libc::geteuid() + } +} + +pub fn getegid() -> gid_t { + unsafe { + libc::getegid() + } +} + +pub fn getgid() -> gid_t { + unsafe { + libc::getgid() + } +} + +pub fn getuid() -> uid_t { + unsafe { + libc::getuid() + } +} + // This is basically sys::unix::process::ExitStatus #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum ExitStatus { @@ -26,7 +49,8 @@ pub enum ExitStatus { impl ExitStatus { fn from_status(status: c_int) -> ExitStatus { - if status & 0x7F != 0 { // WIFSIGNALED(status) + if status & 0x7F != 0 { + // WIFSIGNALED(status) ExitStatus::Signal(status & 0x7F) } else { ExitStatus::Code(status & 0xFF00 >> 8) @@ -75,8 +99,7 @@ pub trait ChildExt { impl ChildExt for Child { fn send_signal(&mut self, signal: usize) -> io::Result<()> { - if unsafe { libc::kill(self.id() as pid_t, - signal as i32) } != 0 { + if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 { Err(io::Error::last_os_error()) } else { Ok(()) @@ -86,10 +109,7 @@ impl ChildExt for Child { fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result> { // The result will be written to that Option, protected by a Mutex // Then the Condvar will be signaled - let state = Arc::new(( - Mutex::new(Option::None::>), - Condvar::new(), - )); + let state = Arc::new((Mutex::new(Option::None::>), Condvar::new())); // Start the waiting thread let state_th = state.clone(); @@ -121,7 +141,7 @@ impl ChildExt for Child { return exitstatus.map(Some); } if start.elapsed() >= timeout { - return Ok(None) + return Ok(None); } let cvar_timeout = timeout - start.elapsed(); exitstatus = cvar.wait_timeout(exitstatus, cvar_timeout).unwrap().0;