1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 03:57:44 +00:00

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
commit 8781df81fb
24 changed files with 588 additions and 663 deletions

View file

@ -8,19 +8,18 @@ name = "uu_chown"
path = "chown.rs" path = "chown.rs"
[dependencies] [dependencies]
getopts = "*"
glob = "*" glob = "*"
libc = "*"
uucore = { path="../uucore" }
walkdir = "0.1" walkdir = "0.1"
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[dependencies.clippy] [dependencies.clippy]
version = "*" version = "*"
optional = true optional = true
[features]
default = []
[[bin]] [[bin]]
name = "chown" name = "chown"
path = "main.rs" path = "main.rs"

View file

@ -11,20 +11,14 @@
#![cfg_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))] #![cfg_attr(feature="clippy", plugin(clippy))]
extern crate libc;
use libc::{uid_t, gid_t, c_char, c_int};
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::libc::{self, uid_t, gid_t, lchown};
extern crate getopts; pub use uucore::entries::{self, Locate, Passwd, Group};
use getopts::Options;
extern crate walkdir; extern crate walkdir;
use walkdir::WalkDir; use walkdir::WalkDir;
pub mod passwd;
use std::fs::{self, Metadata}; use std::fs::{self, Metadata};
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
@ -37,21 +31,15 @@ use std::convert::AsRef;
use std::ffi::CString; use std::ffi::CString;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
static NAME: &'static str = "chown"; static SYNTAX: &'static str = "[OPTION]... [OWNER][:[GROUP]] FILE...\n chown [OPTION]... --reference=RFILE FILE...";
static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static SUMMARY: &'static str = "change file owner and group";
const FTS_COMFOLLOW: u8 = 1; const FTS_COMFOLLOW: u8 = 1;
const FTS_PHYSICAL: u8 = 1 << 1; const FTS_PHYSICAL: u8 = 1 << 1;
const FTS_LOGICAL: u8 = 1 << 2; 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 { pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new(); let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");
opts.optflag("c", opts.optflag("c",
"changes", "changes",
"like verbose but report only when a change is made"); "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"); "traverse every symbolic link to a directory encountered");
opts.optflag("P", "", "do not traverse any symbolic links (default)"); opts.optflag("P", "", "do not traverse any symbolic links (default)");
opts.optflag("", "help", "display this help and exit"); let matches = opts.parse(args.clone());
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 mut bit_flag = FTS_PHYSICAL; let mut bit_flag = FTS_PHYSICAL;
let mut preserve_root = false; 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"); let recursive = matches.opt_present("recursive");
if recursive { if recursive {
if bit_flag == FTS_PHYSICAL { 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(); let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();
if usr_only { if usr_only {
Ok((Some(match passwd::getuid(args[0]) { Ok((Some(match Passwd::locate(args[0]) {
Ok(uid) => uid, Ok(v) => v.uid(),
Err(_) => return Err(format!("invalid user: {}", spec)), _ => return Err(format!("invalid user: {}", spec)),
}), }),
None)) None))
} else if grp_only { } else if grp_only {
Ok((None, Ok((None,
Some(match passwd::getgid(args[1]) { Some(match Group::locate(args[1]) {
Ok(gid) => gid, Ok(v) => v.gid(),
Err(_) => return Err(format!("invalid group: {}", spec)), _ => return Err(format!("invalid group: {}", spec)),
}))) })))
} else if usr_grp { } else if usr_grp {
Ok((Some(match passwd::getuid(args[0]) { Ok((Some(match Passwd::locate(args[0]) {
Ok(uid) => uid, Ok(v) => v.uid(),
Err(_) => return Err(format!("invalid user: {}", spec)), _ => return Err(format!("invalid user: {}", spec)),
}), }),
Some(match passwd::getgid(args[1]) { Some(match Group::locate(args[1]) {
Ok(gid) => gid, Ok(v) => v.gid(),
Err(_) => return Err(format!("invalid group: {}", spec)), _ => return Err(format!("invalid group: {}", spec)),
}))) })))
} else { } else {
Ok((None, None)) Ok((None, None))
@ -401,10 +373,10 @@ impl Chowner {
if self.verbosity == Verbose { if self.verbosity == Verbose {
println!("failed to change ownership of {} from {}:{} to {}:{}", println!("failed to change ownership of {} from {}:{} to {}:{}",
path.display(), path.display(),
passwd::uid2usr(meta.uid()).unwrap(), entries::uid2usr(meta.uid()).unwrap(),
passwd::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
passwd::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
passwd::gid2grp(dest_gid).unwrap()); entries::gid2grp(dest_gid).unwrap());
}; };
} }
} }
@ -416,18 +388,18 @@ impl Chowner {
Changes | Verbose => { Changes | Verbose => {
println!("changed ownership of {} from {}:{} to {}:{}", println!("changed ownership of {} from {}:{} to {}:{}",
path.display(), path.display(),
passwd::uid2usr(meta.uid()).unwrap(), entries::uid2usr(meta.uid()).unwrap(),
passwd::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
passwd::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
passwd::gid2grp(dest_gid).unwrap()); entries::gid2grp(dest_gid).unwrap());
} }
_ => (), _ => (),
}; };
} else if self.verbosity == Verbose { } else if self.verbosity == Verbose {
println!("ownership of {} retained as {}:{}", println!("ownership of {} retained as {}:{}",
path.display(), path.display(),
passwd::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
passwd::gid2grp(dest_gid).unwrap()); entries::gid2grp(dest_gid).unwrap());
} }
} }
ret 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
}

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);

View file

@ -9,8 +9,11 @@ path = "chroot.rs"
[dependencies] [dependencies]
getopts = "*" getopts = "*"
libc = "*"
uucore = { path="../uucore" } [dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[[bin]] [[bin]]
name = "chroot" name = "chroot"

View file

@ -4,39 +4,25 @@
* This file is part of the uutils coreutils package. * This file is part of the uutils coreutils package.
* *
* (c) Vsevolod Velichko <torkvemada@sorokdva.net> * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
* (c) Jian Zeng <anonymousknight96 AT gmail.com>
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
extern crate getopts; extern crate getopts;
extern crate libc;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::libc::{self, setgid, setuid, chroot, setgroups};
use uucore::entries;
use getopts::Options; use getopts::Options;
use libc::{setgid, setuid};
use std::ffi::CString; use std::ffi::CString;
use std::io::{Error, Write}; use std::io::{Error, Write};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::path::Path; use std::path::Path;
use std::process::Command; 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 NAME: &'static str = "chroot";
static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static VERSION: &'static str = env!("CARGO_PKG_VERSION");
@ -146,9 +132,9 @@ fn enter_chroot(root: &Path) {
fn set_main_group(group: &str) { fn set_main_group(group: &str) {
if !group.is_empty() { if !group.is_empty() {
let group_id = match get_group(group) { let group_id = match entries::grp2gid(group) {
None => crash!(1, "no such group: {}", group), Ok(g) => g,
Some(g) => g.gr_gid _ => crash!(1, "no such group: {}", group),
}; };
let err = unsafe { setgid(group_id) }; let err = unsafe { setgid(group_id) };
if err != 0 { if err != 0 {
@ -177,9 +163,9 @@ fn set_groups_from_str(groups: &str) {
if !groups.is_empty() { if !groups.is_empty() {
let groups_vec: Vec<libc::gid_t> = FromIterator::from_iter( let groups_vec: Vec<libc::gid_t> = FromIterator::from_iter(
groups.split(',').map( groups.split(',').map(
|x| match get_group(x) { |x| match entries::grp2gid(x) {
None => crash!(1, "no such group: {}", x), Ok(g) => g,
Some(g) => g.gr_gid _ => crash!(1, "no such group: {}", x),
}) })
); );
let err = set_groups(groups_vec); let err = set_groups(groups_vec);
@ -191,7 +177,7 @@ fn set_groups_from_str(groups: &str) {
fn set_user(user: &str) { fn set_user(user: &str) {
if !user.is_empty() { 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) }; let err = unsafe { setuid(user_id as libc::uid_t) };
if err != 0 { if err != 0 {
crash!(1, "cannot set user to {}: {}", user, Error::last_os_error()) crash!(1, "cannot set user to {}: {}", user, Error::last_os_error())

View file

@ -9,8 +9,11 @@ path = "id.rs"
[dependencies] [dependencies]
getopts = "*" getopts = "*"
libc = "*"
uucore = { path="../uucore" } [dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries", "process"]
[[bin]] [[bin]]
name = "id" name = "id"

View file

@ -1,54 +1,51 @@
#![crate_name = "uu_id"] #![crate_name = "uu_id"]
/* // This file is part of the uutils coreutils package.
* This file is part of the uutils coreutils package. //
* // (c) Alan Andrade <alan.andradec@gmail.com>
* (c) Alan Andrade <alan.andradec@gmail.com> // (c) Jian Zeng <anonymousknight96 AT gmail.com>
* //
* For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. // file that was distributed with this source code.
* //
* Synced with: // Synced with:
* http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c // 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 // http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c
*/ //
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
extern crate getopts; #![allow(dead_code)]
extern crate libc;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
pub use uucore::libc;
use libc::{getgid, getuid, uid_t, getegid, geteuid, getlogin}; use uucore::libc::{getlogin, uid_t};
use std::ffi::CStr; use uucore::entries::{self, Passwd, Group, Locate};
use uucore::process::{getgid, getuid, getegid, geteuid};
use std::io::Write; use std::io::Write;
use std::ptr::read; use std::ffi::CStr;
use uucore::c_types::{
c_passwd,
c_group,
get_groups,
get_group_list,
get_pw_from_args,
getpwuid,
group
};
#[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 { mod audit {
pub use std::mem::uninitialized; 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_id_t = uid_t;
pub type au_asid_t = pid_t; pub type au_asid_t = pid_t;
pub type au_event_t = c_uint; 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; pub type au_class_t = c_int;
#[repr(C)] #[repr(C)]
pub struct au_mask { pub struct au_mask {
pub am_success: c_uint, pub am_success: c_uint,
pub am_failure: c_uint pub am_failure: c_uint,
} }
pub type au_mask_t = au_mask; pub type au_mask_t = au_mask;
@ -60,56 +57,52 @@ mod audit {
#[repr(C)] #[repr(C)]
pub struct c_auditinfo_addr { pub struct c_auditinfo_addr {
pub ai_auid: au_id_t, /* Audit user ID */ pub ai_auid: au_id_t, // Audit user ID
pub ai_mask: au_mask_t, /* Audit masks. */ pub ai_mask: au_mask_t, // Audit masks.
pub ai_termid: au_tid_addr_t, /* Terminal ID. */ pub ai_termid: au_tid_addr_t, // Terminal ID.
pub ai_asid: au_asid_t, /* Audit session ID. */ pub ai_asid: au_asid_t, // Audit session ID.
pub ai_flags: uint64_t /* Audit session flags */ pub ai_flags: uint64_t, // Audit session flags
} }
pub type c_auditinfo_addr_t = c_auditinfo_addr; pub type c_auditinfo_addr_t = c_auditinfo_addr;
extern { extern "C" {
pub fn getaudit(auditinfo_addr: *mut c_auditinfo_addr_t) -> c_int; pub fn getaudit(auditinfo_addr: *mut c_auditinfo_addr_t) -> c_int;
} }
} }
extern { static SYNTAX: &'static str = "[OPTION]... [USER]";
fn getgrgid(gid: uid_t) -> *const c_group; static SUMMARY: &'static str = "Print user and group information for the specified USER,\n or (when USER omitted) for the current user.";
}
static NAME: &'static str = "id";
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new(); let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");
opts.optflag("h", "", "Show help"); opts.optflag("A",
opts.optflag("A", "", "Display the process audit (not available on Linux)"); "",
"Display the process audit (not available on Linux)");
opts.optflag("G", "", "Display the different group IDs"); opts.optflag("G", "", "Display the different group IDs");
opts.optflag("g", "", "Display the effective group ID as a number"); 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", "", "Display the id as a password file entry");
opts.optflag("p", "", "Make the output human-readable"); opts.optflag("p", "", "Make the output human-readable");
opts.optflag("r", "", "Display the real ID for the -g and -u options"); opts.optflag("r", "", "Display the real ID for the -g and -u options");
opts.optflag("u", "", "Display the effective user ID as a number"); opts.optflag("u", "", "Display the effective user ID as a number");
let matches = match opts.parse(&args[1..]) { let matches = opts.parse(args);
Ok(m) => { m },
Err(_) => {
println!("{}", opts.usage(NAME));
return 1;
}
};
if matches.opt_present("h") {
println!("{}", opts.usage(NAME));
return 0;
}
if matches.opt_present("A") { if matches.opt_present("A") {
auditid(); auditid();
return 0; 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 nflag = matches.opt_present("n");
let uflag = matches.opt_present("u"); let uflag = matches.opt_present("u");
@ -117,55 +110,57 @@ pub fn uumain(args: Vec<String>) -> i32 {
let rflag = matches.opt_present("r"); let rflag = matches.opt_present("r");
if gflag { if gflag {
let id = if possible_pw.is_some() { let id = possible_pw.map(|p| p.gid()).unwrap_or(if rflag {
possible_pw.unwrap().pw_gid getgid()
} else { } else {
if rflag { getegid()
unsafe { getgid() } });
} else { println!("{}",
unsafe { getegid() } if nflag {
} entries::gid2grp(id).unwrap_or(id.to_string())
}; } else {
let gr = unsafe { getgrgid(id) }; id.to_string()
});
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);
}
return 0; return 0;
} }
if uflag { if uflag {
let id = if possible_pw.is_some() { let id = possible_pw.map(|p| p.uid()).unwrap_or(if rflag {
possible_pw.unwrap().pw_uid getuid()
} else if rflag {
unsafe { getuid() }
} else { } else {
unsafe { geteuid() } geteuid()
}; });
println!("{}",
let pw = unsafe { getpwuid(id) }; if nflag {
if nflag && !pw.is_null() { entries::uid2usr(id).unwrap_or(id.to_string())
let pw_name = unsafe { } else {
String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() id.to_string()
}; });
println!("{}", pw_name);
} else {
println!("{}", id);
}
return 0; return 0;
} }
if matches.opt_present("G") { 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::<Vec<_>>()
.join(" ")
} else {
possible_pw.map(|p| p.belongs_to())
.unwrap_or(entries::get_groups().unwrap())
.iter()
.map(|&id| id.to_string())
.collect::<Vec<_>>()
.join(" ")
});
return 0; return 0;
} }
if matches.opt_present("P") { if matches.opt_present("P") {
pline(possible_pw); pline(possible_pw.map(|v| v.uid()));
return 0; return 0;
}; };
@ -183,126 +178,92 @@ pub fn uumain(args: Vec<String>) -> i32 {
0 0
} }
fn pretty(possible_pw: Option<c_passwd>) { fn pretty(possible_pw: Option<Passwd>) {
if possible_pw.is_some() { if let Some(p) = possible_pw {
let pw = possible_pw.unwrap(); print!("uid\t{}\ngroups\t", p.name());
println!("{}",
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name).to_bytes()).to_string() }; p.belongs_to().iter().map(|&gr| entries::gid2grp(gr).unwrap()).collect::<Vec<_>>().join(" "));
print!("uid\t{}\ngroups\t", pw_name);
group(possible_pw, true);
} else { } else {
let login = unsafe { String::from_utf8_lossy(CStr::from_ptr((getlogin() as *const _)).to_bytes()).to_string() }; let login = cstr2cow!(getlogin() as *const _);
let rid = unsafe { getuid() }; let rid = getuid();
let pw = unsafe { getpwuid(rid) }; if let Ok(p) = Passwd::locate(rid) {
if login == p.name() {
let is_same_user = unsafe { println!("login\t{}", login);
String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()) == login }
}; println!("uid\t{}", p.name());
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() })
} else { } else {
println!("uid\t{}\n", rid); println!("uid\t{}", rid);
} }
let eid = unsafe { getegid() }; let eid = getegid();
if eid == rid { if eid == rid {
let pw = unsafe { getpwuid(eid) }; if let Ok(p) = Passwd::locate(eid) {
if !pw.is_null() { println!("euid\t{}", p.name());
println!(
"euid\t{}",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() });
} else { } else {
println!("euid\t{}", eid); println!("euid\t{}", eid);
} }
} }
let rid = unsafe { getgid() }; let rid = getgid();
if rid != eid { if rid != eid {
let gr = unsafe { getgrgid(rid) }; if let Ok(g) = Group::locate(rid) {
if !gr.is_null() { println!("euid\t{}", g.name());
println!(
"rgid\t{}",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() });
} else { } else {
println!("rgid\t{}", rid); println!("euid\t{}", rid);
} }
} }
print!("groups\t"); println!("groups\t{}",
group(None, true); entries::get_groups()
.unwrap()
.iter()
.map(|&gr| entries::gid2grp(gr).unwrap())
.collect::<Vec<_>>()
.join(" "));
} }
} }
#[cfg(any(target_os = "macos", target_os = "freebsd"))] #[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn pline(possible_pw: Option<c_passwd>) { fn pline(possible_uid: Option<uid_t>) {
let pw = if possible_pw.is_none() { let uid = possible_uid.unwrap_or(getuid());
unsafe { read(getpwuid(getuid())) } let pw = Passwd::locate(uid).unwrap();
} else {
possible_pw.unwrap()
};
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()}; println!("{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()}; pw.name(),
let pw_class = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_class ).to_bytes()).to_string()}; pw.user_passwd(),
let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()}; pw.uid(),
let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()}; pw.gid(),
let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()}; pw.user_access_class(),
pw.passwd_change_time(),
println!( pw.expiration(),
"{}:{}:{}:{}:{}:{}:{}:{}:{}:{}", pw.user_info(),
pw_name, pw.user_dir(),
pw_passwd, pw.user_shell());
pw.pw_uid,
pw.pw_gid,
pw_class,
pw.pw_change,
pw.pw_expire,
pw_gecos,
pw_dir,
pw_shell);
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn pline(possible_pw: Option<c_passwd>) { fn pline(possible_uid: Option<uid_t>) {
let pw = if possible_pw.is_none() { let uid = possible_uid.unwrap_or(getuid());
unsafe { read(getpwuid(getuid())) } let pw = Passwd::locate(uid).unwrap();
} else {
possible_pw.unwrap()
};
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()}; println!("{}:{}:{}:{}:{}:{}:{}",
let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()}; pw.name(),
let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()}; pw.user_passwd(),
let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()}; pw.uid(),
let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()}; pw.gid(),
pw.user_info(),
println!( pw.user_dir(),
"{}:{}:{}:{}:{}:{}:{}", pw.user_shell());
pw_name,
pw_passwd,
pw.pw_uid,
pw.pw_gid,
pw_gecos,
pw_dir,
pw_shell);
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn auditid() { } fn auditid() {}
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn auditid() { fn auditid() {
let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { audit::uninitialized() }; let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { audit::uninitialized() };
let address = &mut auditinfo as *mut audit::c_auditinfo_addr_t; 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"); println!("couldn't retrieve information");
return; return;
} }
@ -314,83 +275,27 @@ fn auditid() {
println!("asid={}", auditinfo.ai_asid); println!("asid={}", auditinfo.ai_asid);
} }
fn id_print(possible_pw: Option<c_passwd>, p_euid: bool, p_egid: bool) { fn id_print(possible_pw: Option<Passwd>, p_euid: bool, p_egid: bool) {
let uid; let (uid, gid) = possible_pw.map(|p| (p.uid(), p.gid())).unwrap_or((getuid(), getgid()));;
let gid;
if possible_pw.is_some() { let groups = Passwd::locate(uid).unwrap().belongs_to();
uid = possible_pw.unwrap().pw_uid;
gid = possible_pw.unwrap().pw_gid;
} else {
uid = unsafe { getuid() };
gid = unsafe { getgid() };
}
let groups = match possible_pw { print!("uid={}({})", uid, entries::uid2usr(uid).unwrap());
Some(pw) => Ok(get_group_list(pw.pw_name, pw.pw_gid)), print!(" gid={}({})", gid, entries::gid2grp(gid).unwrap());
None => get_groups(),
};
let groups = groups.unwrap_or_else(|errno| { let euid = geteuid();
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() };
if p_euid && (euid != uid) { if p_euid && (euid != uid) {
print!(" euid={}", euid); print!(" euid={}({})", euid, entries::uid2usr(euid).unwrap());
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() });
}
} }
let egid = unsafe { getegid() }; let egid = getegid();
if p_egid && (egid != gid) { if p_egid && (egid != gid) {
print!(" egid={}", egid); print!(" egid={}({})", euid, entries::gid2grp(egid).unwrap());
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());
}
}
} }
if !groups.is_empty() { println!(" groups={}",
print!(" groups="); groups.iter()
.map(|&gr| format!("{}({})", gr, entries::gid2grp(gr).unwrap()))
let mut first = true; .collect::<Vec<_>>()
for &gr in &groups { .join(","));
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!("");
} }

View file

@ -9,8 +9,6 @@ path = "ls.rs"
[dependencies] [dependencies]
getopts = "*" getopts = "*"
libc = "*"
uucore = { path="../uucore" }
pretty-bytes = "0.1.0" pretty-bytes = "0.1.0"
term_grid = "*" term_grid = "*"
termsize = "*" termsize = "*"
@ -18,6 +16,11 @@ time = "*"
lazy_static = "*" lazy_static = "*"
unicode-width = "*" unicode-width = "*"
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[[bin]] [[bin]]
name = "ls" name = "ls"
path = "main.rs" path = "main.rs"

View file

@ -23,11 +23,9 @@ extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
extern crate libc;
#[cfg(unix)] #[cfg(unix)]
use self::libc::{S_ISUID, S_ISGID, S_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, 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, c_char}; S_IROTH, S_IWOTH, S_IXOTH, mode_t};
use getopts::Options; use getopts::Options;
use std::fs; use std::fs;
@ -41,10 +39,6 @@ use std::os::unix::fs::MetadataExt;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::FileTypeExt; use std::os::unix::fs::FileTypeExt;
#[cfg(unix)] #[cfg(unix)]
use std::ptr;
#[cfg(unix)]
use std::ffi::CStr;
#[cfg(unix)]
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
#[cfg(windows)] #[cfg(windows)]
@ -407,32 +401,16 @@ fn display_item_long(item: &PathBuf,
// Currently getpwuid is `linux` target only. If it's broken out into // Currently getpwuid is `linux` target only. If it's broken out into
// a posix-compliant attribute this can be updated... // a posix-compliant attribute this can be updated...
#[cfg(unix)] #[cfg(unix)]
use uucore::c_types::{getpwuid, getgrgid}; use uucore::entries;
// 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() }
}
#[cfg(unix)] #[cfg(unix)]
fn display_uname(metadata: &Metadata) -> String { fn display_uname(metadata: &Metadata) -> String {
let pw = unsafe { getpwuid(metadata.uid()) }; entries::uid2usr(metadata.uid()).unwrap_or(metadata.uid().to_string())
if !pw.is_null() {
cstr2string(unsafe { ptr::read(pw).pw_name })
} else {
metadata.uid().to_string()
}
} }
#[cfg(unix)] #[cfg(unix)]
fn display_group(metadata: &Metadata) -> String { fn display_group(metadata: &Metadata) -> String {
let ent = unsafe { getgrgid(metadata.gid()) }; entries::gid2grp(metadata.gid()).unwrap_or(metadata.gid().to_string())
if !ent.is_null() {
cstr2string(unsafe { ptr::read(ent).gr_name })
} else {
metadata.gid().to_string()
}
} }
#[cfg(not(unix))] #[cfg(not(unix))]

View file

@ -10,7 +10,7 @@ path = "pinky.rs"
[dependencies.uucore] [dependencies.uucore]
path = "../uucore" path = "../uucore"
default-features = false default-features = false
features = ["utmpx", "c_types"] features = ["utmpx", "entries"]
[[bin]] [[bin]]
name = "pinky" name = "pinky"

View file

@ -12,9 +12,9 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::c_types::getpwnam;
use uucore::utmpx::{self, time, Utmpx}; 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::prelude::*;
use std::io::BufReader; use std::io::BufReader;
@ -23,14 +23,11 @@ use std::io::Result as IOResult;
use std::fs::File; use std::fs::File;
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
use std::ptr;
use std::ffi::{CStr, CString};
use std::path::PathBuf; use std::path::PathBuf;
static SYNTAX: &'static str = "[OPTION]... [USER]..."; static SYNTAX: &'static str = "[OPTION]... [USER]...";
static SUMMARY: &'static str = "A lightweight 'finger' program; print user information."; static SUMMARY: &'static str = "A lightweight 'finger' program; print user information.";
const BUFSIZE: usize = 1024; const BUFSIZE: usize = 1024;
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
@ -152,52 +149,6 @@ struct Pinky {
names: Vec<String>, 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 { pub trait Capitalize {
fn capitalize(&self) -> String; fn capitalize(&self) -> String;
} }
@ -267,12 +218,12 @@ impl Pinky {
print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user()); print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user());
if self.include_fullname { if self.include_fullname {
if let Some(pw) = getpw(ut.user().as_ref()) { if let Ok(pw) = Passwd::locate(ut.user().as_ref()) {
let mut gecos = pw.pw_gecos; let mut gecos = pw.user_info().into_owned();
if let Some(n) = gecos.find(',') { if let Some(n) = gecos.find(',') {
gecos.truncate(n + 1); gecos.truncate(n + 1);
} }
print!(" {:<19.19}", gecos.replace("&", &pw.pw_name.capitalize())); print!(" {:<19.19}", gecos.replace("&", &pw.name().capitalize()));
} else { } else {
print!(" {:19}", " ???"); print!(" {:19}", " ???");
} }
@ -344,14 +295,14 @@ impl Pinky {
fn long_pinky(&self) -> i32 { fn long_pinky(&self) -> i32 {
for u in &self.names { for u in &self.names {
print!("Login name: {:<28}In real life: ", u); print!("Login name: {:<28}In real life: ", u);
if let Some(pw) = getpw(u) { if let Ok(pw) = Passwd::locate(u.as_str()) {
println!(" {}", pw.pw_gecos.replace("&", &pw.pw_name.capitalize())); println!(" {}", pw.user_info().replace("&", &pw.name().capitalize()));
if self.include_home_and_shell { if self.include_home_and_shell {
print!("Directory: {:<29}", pw.pw_dir); print!("Directory: {:<29}", pw.user_dir());
println!("Shell: {}", pw.pw_shell); println!("Shell: {}", pw.user_shell());
} }
if self.include_project { 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"); p.push(".project");
if let Ok(f) = File::open(p) { if let Ok(f) = File::open(p) {
print!("Project: "); print!("Project: ");
@ -359,7 +310,7 @@ impl Pinky {
} }
} }
if self.include_plan { 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"); p.push(".plan");
if let Ok(f) = File::open(p) { if let Ok(f) = File::open(p) {
println!("Plan:"); println!("Plan:");

View file

@ -9,9 +9,12 @@ path = "stat.rs"
[dependencies] [dependencies]
getopts = "*" getopts = "*"
libc = "^0.2"
time = "*" time = "*"
uucore = { path="../uucore" }
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[[bin]] [[bin]]
name = "stat" name = "stat"

View file

@ -6,13 +6,13 @@
// that was distributed with this source code. // that was distributed with this source code.
// //
extern crate libc; pub use super::uucore::libc;
extern crate time; extern crate time;
use self::time::Timespec; 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, 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_ISVTX, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, mode_t, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH, mode_t, c_int,
c_int, strerror}; strerror};
pub trait BirthTime { pub trait BirthTime {
fn pretty_birth(&self) -> String; fn pretty_birth(&self) -> String;
@ -176,12 +176,12 @@ use std::error::Error;
use std::io::Error as IOError; use std::io::Error as IOError;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] #[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"))] // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
// use self::libc::statvfs as Sstatfs; // use self::libc::statvfs as Sstatfs;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "android"))] #[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"))] // #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "bitrig", target_os = "dragonfly"))]
// use self::libc::statvfs as statfs_fn; // use self::libc::statvfs as statfs_fn;

View file

@ -17,6 +17,7 @@ pub use fsext::*;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::entries;
use std::{fs, iter, cmp}; use std::{fs, iter, cmp};
use std::fs::File; 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 { impl Stater {
pub fn generate_tokens(fmtstr: &str, use_printf: bool) -> Result<Vec<Token>, String> { pub fn generate_tokens(fmtstr: &str, use_printf: bool) -> Result<Vec<Token>, String> {
@ -613,7 +589,7 @@ impl Stater {
} }
// group name of owner // group name of owner
'G' => { 'G' => {
arg = get_grp_name(meta.gid()); arg = entries::gid2grp(meta.gid()).unwrap_or("UNKNOWN".to_owned());
otype = OutputType::Str; otype = OutputType::Str;
} }
// number of hard links // number of hard links
@ -683,7 +659,7 @@ impl Stater {
} }
// user name of owner // user name of owner
'U' => { 'U' => {
arg = get_usr_name(meta.uid()); arg = entries::uid2usr(meta.uid()).unwrap_or("UNKNOWN".to_owned());
otype = OutputType::Str; otype = OutputType::Str;
} }

View file

@ -21,8 +21,9 @@ utmpx = ["time", "libc"]
c_types = ["libc"] c_types = ["libc"]
process = ["libc"] process = ["libc"]
signals = [] signals = []
entries = ["libc"]
wide = [] 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] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -44,11 +44,11 @@ impl<'a> CoreOptions<'a> {
crash!(1, "{}", f); crash!(1, "{}", f);
} }
}.unwrap(); }.unwrap();
if matches.opt_present("help") { if matches.opt_present("help") {
let usage_str = if self.help_text.display_usage { 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) self.options.usage(self.help_text.summary)
).replace("Options:", " Options:") ).replace("Options:", " Options:")
} else { String::new() }; } else { String::new() };
print!(" print!("
{0} {1} {0} {1}
@ -66,7 +66,7 @@ impl<'a> CoreOptions<'a> {
} }
#[macro_export] #[macro_export]
macro_rules! new_coreopts { macro_rules! new_coreopts {
($syntax: expr, $summary: expr, $long_help: expr) => ( ($syntax: expr, $summary: expr, $long_help: expr) => (
uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText { uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
name: executable!(), name: executable!(),
@ -87,4 +87,4 @@ macro_rules! new_coreopts {
display_usage: $display_usage display_usage: $display_usage
}) })
); );
} }

245
src/uucore/entries.rs Normal file
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())
}

View file

@ -20,6 +20,8 @@ pub mod parse_time;
pub mod utmpx; pub mod utmpx;
#[cfg(all(unix, feature = "c_types"))] #[cfg(all(unix, feature = "c_types"))]
pub mod c_types; pub mod c_types;
#[cfg(all(unix, feature = "entries"))]
pub mod entries;
#[cfg(all(unix, feature = "process"))] #[cfg(all(unix, feature = "process"))]
pub mod process; pub mod process;
#[cfg(all(unix, feature = "signals"))] #[cfg(all(unix, feature = "signals"))]

View file

@ -1,15 +1,14 @@
/* // This file is part of the uutils coreutils package.
* This file is part of the uutils coreutils package. //
* // (c) Maciej Dziardziel <fiedzia@gmail.com>
* (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 // For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code. // that was distributed with this source code.
*/ //
extern crate libc; use super::libc;
use libc::{c_int, pid_t, uid_t, gid_t};
use libc::{c_int, pid_t};
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::process::Child; use std::process::Child;
@ -17,6 +16,30 @@ use std::sync::{Arc, Condvar, Mutex};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; 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 // This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)] #[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus { pub enum ExitStatus {
@ -26,7 +49,8 @@ pub enum ExitStatus {
impl ExitStatus { impl ExitStatus {
fn from_status(status: c_int) -> ExitStatus { fn from_status(status: c_int) -> ExitStatus {
if status & 0x7F != 0 { // WIFSIGNALED(status) if status & 0x7F != 0 {
// WIFSIGNALED(status)
ExitStatus::Signal(status & 0x7F) ExitStatus::Signal(status & 0x7F)
} else { } else {
ExitStatus::Code(status & 0xFF00 >> 8) ExitStatus::Code(status & 0xFF00 >> 8)
@ -75,8 +99,7 @@ pub trait ChildExt {
impl ChildExt for Child { impl ChildExt for Child {
fn send_signal(&mut self, signal: usize) -> io::Result<()> { fn send_signal(&mut self, signal: usize) -> io::Result<()> {
if unsafe { libc::kill(self.id() as pid_t, if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 {
signal as i32) } != 0 {
Err(io::Error::last_os_error()) Err(io::Error::last_os_error())
} else { } else {
Ok(()) Ok(())
@ -86,10 +109,7 @@ impl ChildExt for Child {
fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> { fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
// The result will be written to that Option, protected by a Mutex // The result will be written to that Option, protected by a Mutex
// Then the Condvar will be signaled // Then the Condvar will be signaled
let state = Arc::new(( let state = Arc::new((Mutex::new(Option::None::<io::Result<ExitStatus>>), Condvar::new()));
Mutex::new(Option::None::<io::Result<ExitStatus>>),
Condvar::new(),
));
// Start the waiting thread // Start the waiting thread
let state_th = state.clone(); let state_th = state.clone();
@ -121,7 +141,7 @@ impl ChildExt for Child {
return exitstatus.map(Some); return exitstatus.map(Some);
} }
if start.elapsed() >= timeout { if start.elapsed() >= timeout {
return Ok(None) return Ok(None);
} }
let cvar_timeout = timeout - start.elapsed(); let cvar_timeout = timeout - start.elapsed();
exitstatus = cvar.wait_timeout(exitstatus, cvar_timeout).unwrap().0; exitstatus = cvar.wait_timeout(exitstatus, cvar_timeout).unwrap().0;

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. // This file is part of the uutils coreutils package.
// //
// (c) Jian Zeng <anonymousknight96@gmail.com> // (c) Jian Zeng <anonymousknight96@gmail.com>
@ -9,6 +5,31 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // 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; use super::libc;
pub extern crate time; pub extern crate time;
@ -107,28 +128,6 @@ mod ut {
pub use libc::SHUTDOWN_TIME; 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 { pub struct Utmpx {
inner: utmpx, inner: utmpx,
} }

View file

@ -9,10 +9,13 @@ path = "whoami.rs"
[dependencies] [dependencies]
getopts = "*" getopts = "*"
libc = "*"
winapi = "*" winapi = "*"
advapi32-sys = "*" advapi32-sys = "*"
uucore = { path="../uucore" }
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[[bin]] [[bin]]
name = "whoami" name = "whoami"

View file

@ -2,31 +2,18 @@
* This file is part of the uutils coreutils package. * This file is part of the uutils coreutils package.
* *
* (c) Jordi Boggiano <j.boggiano@seld.be> * (c) Jordi Boggiano <j.boggiano@seld.be>
* (c) Jian Zeng <anonymousknight96 AT gmail.com>
* *
* For the full copyright and license information, please view the LICENSE * For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
use std::io::{Result, Error}; use std::io::Result;
use ::libc; use uucore::libc::geteuid;
use uucore::c_types::{c_passwd, getpwuid}; use uucore::entries::uid2usr;
extern {
pub fn geteuid() -> libc::uid_t;
}
pub unsafe fn getusername() -> Result<String> { pub unsafe fn getusername() -> Result<String> {
// Get effective user id // Get effective user id
let uid = geteuid(); let uid = geteuid();
uid2usr(uid)
// 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)
} }

View file

@ -12,7 +12,6 @@
/* last synced with: whoami (GNU coreutils) 8.21 */ /* last synced with: whoami (GNU coreutils) 8.21 */
extern crate getopts; extern crate getopts;
extern crate libc;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;

View file

@ -9,25 +9,25 @@ fn new_ucmd() -> UCommand {
} }
#[cfg(test)] #[cfg(test)]
mod test_passwd { mod test_passgrp {
use super::passwd::*; use super::uu_chown::entries::{usr2uid,grp2gid,uid2usr,gid2grp};
#[test] #[test]
fn test_getuid() { fn test_usr2uid() {
assert_eq!(0, getuid("root").unwrap()); assert_eq!(0, usr2uid("root").unwrap());
assert!(getuid("88888888").is_err()); assert!(usr2uid("88888888").is_err());
assert!(getuid("auserthatdoesntexist").is_err()); assert!(usr2uid("auserthatdoesntexist").is_err());
} }
#[test] #[test]
fn test_getgid() { fn test_grp2gid() {
if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
assert_eq!(0, getgid("wheel").unwrap()); assert_eq!(0, grp2gid("wheel").unwrap());
} else { } else {
assert_eq!(0, getgid("root").unwrap()); assert_eq!(0, grp2gid("root").unwrap());
} }
assert!(getgid("88888888").is_err()); assert!(grp2gid("88888888").is_err());
assert!(getgid("agroupthatdoesntexist").is_err()); assert!(grp2gid("agroupthatdoesntexist").is_err());
} }
#[test] #[test]