1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37: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"
[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"

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
}

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]
getopts = "*"
libc = "*"
uucore = { path="../uucore" }
[dependencies.uucore]
path = "../uucore"
default-features = false
features = ["entries"]
[[bin]]
name = "chroot"

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

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"

View file

@ -1,54 +1,51 @@
#![crate_name = "uu_id"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alan Andrade <alan.andradec@gmail.com>
*
* 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 <alan.andradec@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.
//
// 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<String>) -> 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<String>) -> 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::<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;
}
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<String>) -> i32 {
0
}
fn pretty(possible_pw: Option<c_passwd>) {
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<Passwd>) {
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::<Vec<_>>().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::<Vec<_>>()
.join(" "));
}
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn pline(possible_pw: Option<c_passwd>) {
let pw = if possible_pw.is_none() {
unsafe { read(getpwuid(getuid())) }
} else {
possible_pw.unwrap()
};
fn pline(possible_uid: Option<uid_t>) {
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<c_passwd>) {
let pw = if possible_pw.is_none() {
unsafe { read(getpwuid(getuid())) }
} else {
possible_pw.unwrap()
};
fn pline(possible_uid: Option<uid_t>) {
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<c_passwd>, p_euid: bool, p_egid: bool) {
let uid;
let gid;
fn id_print(possible_pw: Option<Passwd>, 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::<Vec<_>>()
.join(","));
}

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"

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

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"

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

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"

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;

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

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"

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
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;
#[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"))]

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;

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,
}

View file

@ -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"

View file

@ -2,31 +2,18 @@
* This file is part of the uutils coreutils package.
*
* (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
* 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<String> {
// 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)
}

View file

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

View file

@ -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]