Merge pull request #968 from knight42/uucore-entries

Add uucore::entries to get passwd/group file entry
This commit is contained in:
mpkh
2016-08-19 21:10:50 +00:00
committed by GitHub
24 changed files with 588 additions and 663 deletions
+5 -6
View File
@@ -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"
+28 -107
View File
@@ -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<String>) -> 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<String>) -> 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<String>) -> 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<u32>, Option<u32>), 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
}
-59
View File
@@ -1,59 +0,0 @@
// (c) Jian Zeng <Anonymousknight96@gmail.com>
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<u32> {
if let Ok(id) = name_or_id.parse::<u32>() {
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<String> {
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);
+5 -2
View File
@@ -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"
+10 -24
View File
@@ -4,39 +4,25 @@
* This file is part of the uutils coreutils package.
*
* (c) Vsevolod Velichko <torkvemada@sorokdva.net>
* (c) Jian Zeng <anonymousknight96 AT gmail.com>
*
* 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<libc::gid_t> = 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())
+5 -2
View File
@@ -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"
+159 -254
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -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"
+5 -27
View File
@@ -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))]
+1 -1
View File
@@ -10,7 +10,7 @@ path = "pinky.rs"
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["utmpx", "c_types"]
features = ["utmpx", "entries"]
[[bin]]
name = "pinky"
+12 -61
View File
@@ -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<String>) -> i32 {
@@ -152,52 +149,6 @@ struct Pinky {
names: Vec<String>,
}
#[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<Passwd> {
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:");
+5 -2
View File
@@ -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"
+6 -6
View File
@@ -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;
+3 -27
View File
@@ -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<Vec<Token>, 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;
}
+2 -1
View File
@@ -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"
+5 -5
View File
@@ -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
})
);
}
}
+245
View File
@@ -0,0 +1,245 @@
// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// 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<Vec<gid_t>> {
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<str> {
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<str> {
cstr2cow!(self.inner.pw_gecos)
}
/// AKA passwd.pw_shell
pub fn user_shell(&self) -> Cow<str> {
cstr2cow!(self.inner.pw_shell)
}
/// AKA passwd.pw_dir
pub fn user_dir(&self) -> Cow<str> {
cstr2cow!(self.inner.pw_dir)
}
/// AKA passwd.pw_passwd
pub fn user_passwd(&self) -> Cow<str> {
cstr2cow!(self.inner.pw_passwd)
}
/// AKA passwd.pw_class
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
pub fn user_access_class(&self) -> Cow<str> {
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<gid_t> {
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<str> {
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<K> {
fn locate(key: K) -> IOResult<Self> 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<Self> {
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<Self> {
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<String> {
Passwd::locate(id).map(|p| p.name().into_owned())
}
#[inline]
pub fn gid2grp(id: gid_t) -> IOResult<String> {
Group::locate(id).map(|p| p.name().into_owned())
}
#[inline]
pub fn usr2uid(name: &str) -> IOResult<uid_t> {
Passwd::locate(name).map(|p| p.uid())
}
#[inline]
pub fn grp2gid(name: &str) -> IOResult<gid_t> {
Group::locate(name).map(|p| p.gid())
}
+2
View File
@@ -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"))]
+39 -19
View File
@@ -1,15 +1,14 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Maciej Dziardziel <fiedzia@gmail.com>
*
* 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 <fiedzia@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// 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<Option<ExitStatus>> {
// 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::<io::Result<ExitStatus>>),
Condvar::new(),
));
let state = Arc::new((Mutex::new(Option::None::<io::Result<ExitStatus>>), 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;
+25 -26
View File
@@ -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 <anonymousknight96@gmail.com>
@@ -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,
}

Some files were not shown because too many files have changed in this diff Show More