From c9dde462c734bb13b4c0ef0557bea4ac71138815 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 00:49:04 +0800 Subject: [PATCH 1/7] uucore: export latest libc --- src/uucore/Cargo.toml | 3 +-- src/uucore/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 1689c734e..bb1cf397a 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -4,8 +4,7 @@ version = "0.0.1" authors = [] [dependencies] -libc = "*" -winapi = "*" +libc = { git = "https://github.com/rust-lang/libc.git" } getopts = "*" data-encoding = "^1.1" diff --git a/src/uucore/lib.rs b/src/uucore/lib.rs index f3cd5bebc..bbe7bb713 100644 --- a/src/uucore/lib.rs +++ b/src/uucore/lib.rs @@ -1,5 +1,4 @@ -extern crate libc; -#[cfg(windows)] extern crate winapi; +pub extern crate libc; #[macro_use] mod macros; From 23979542af9585dfdaf5054c3fa53c5d90e6cb73 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 13:57:40 +0800 Subject: [PATCH 2/7] uucore: conditional enable different features --- src/uucore/Cargo.toml | 15 ++++++++++++++- src/uucore/lib.rs | 28 +++++++++++++++++++--------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index bb1cf397a..a62afa620 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -6,7 +6,20 @@ authors = [] [dependencies] libc = { git = "https://github.com/rust-lang/libc.git" } getopts = "*" -data-encoding = "^1.1" +time = { version = "*", optional = true } +data-encoding = { version = "^1.1", optional = true } + +[features] +fs = [] +utf8 = [] +encoding = ["data-encoding"] +parse_time = [] +utmpx = ["time"] +c_types = [] +process = [] +signals = [] +wide = [] +default = ["fs", "utf8", "encoding", "parse_time", "utmpx", "c_types", "process", "signals", "wide"] [lib] path = "lib.rs" diff --git a/src/uucore/lib.rs b/src/uucore/lib.rs index bbe7bb713..61b3624ae 100644 --- a/src/uucore/lib.rs +++ b/src/uucore/lib.rs @@ -3,15 +3,25 @@ pub extern crate libc; #[macro_use] mod macros; -pub mod fs; -pub mod parse_time; -pub mod utf8; -pub mod encoding; pub mod coreopts; -#[cfg(unix)] pub mod c_types; -#[cfg(unix)] pub mod process; -#[cfg(unix)] pub mod signals; -#[cfg(unix)] pub mod utmpx; +#[cfg(feature = "fs")] +pub mod fs; +#[cfg(feature = "utf8")] +pub mod utf8; +#[cfg(feature = "encoding")] +pub mod encoding; +#[cfg(feature = "parse_time")] +pub mod parse_time; -#[cfg(windows)] pub mod wide; +#[cfg(all(unix, feature = "utmpx"))] +pub mod utmpx; +#[cfg(all(unix, feature = "c_types"))] +pub mod c_types; +#[cfg(all(unix, feature = "process"))] +pub mod process; +#[cfg(all(unix, feature = "signals"))] +pub mod signals; + +#[cfg(all(windows, feature = "wide"))] +pub mod wide; From 163a3a25405e44c63604235353d6504c90d4ad4b Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 13:59:30 +0800 Subject: [PATCH 3/7] coreopts: fix error when using `msg_wrong_number_of_arguments` macro --- src/uucore/macros.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/uucore/macros.rs b/src/uucore/macros.rs index e3a4f06a2..c3e7b0c8e 100644 --- a/src/uucore/macros.rs +++ b/src/uucore/macros.rs @@ -322,15 +322,21 @@ macro_rules! msg_arg_invalid_value { ($expects:expr, $received:expr) => ( msg_invalid_input!(format!("expects its argument to be {}, but was provided {}", $expects, $received)) ); } #[macro_export] -macro_rules! msg_args_invalid_value { ($expects:expr, $received:expr) => ( - msg_invalid_input!(format!("expects its arguments to be {}, but was provided {}", $expects, $received)) ); } +macro_rules! msg_args_invalid_value { + ($expects:expr, $received:expr) => ( + msg_invalid_input!(format!("expects its arguments to be {}, but was provided {}", $expects, $received)) + ); + ($msg:expr) => ( + msg_invalid_input!($msg) + ); +} #[macro_export] macro_rules! msg_args_nonexistent_file { ($received:expr) => ( msg_args_invalid_value!("paths to files", snippet_no_file_at_path!($received)));} #[macro_export] -macro_rules! msg_wrong_number_of_arguments { ($received:expr) => ( +macro_rules! msg_wrong_number_of_arguments { () => ( msg_args_invalid_value!("wrong number of arguments") ); } // -- message templates : invalid input : input combinations From 301a240b736685fcf7f707677711c23e8a40310b Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 15:23:07 +0800 Subject: [PATCH 4/7] uucore::utmpx: refine implementation --- src/uucore/utmpx.rs | 335 ++++++++++++++++++++++++++++---------------- 1 file changed, 215 insertions(+), 120 deletions(-) diff --git a/src/uucore/utmpx.rs b/src/uucore/utmpx.rs index c249e2a94..67b959541 100644 --- a/src/uucore/utmpx.rs +++ b/src/uucore/utmpx.rs @@ -1,125 +1,87 @@ -#![allow(dead_code, non_camel_case_types)] +//! Aim to provide platform-independent methods to obtain login records +//! +//! **ONLY** support linux, macos and freebsd for the time being -extern crate libc; +use super::libc; +pub extern crate time; +use self::time::{Tm, Timespec}; -pub use self::utmpx::{UT_NAMESIZE, UT_LINESIZE, DEFAULT_FILE, USER_PROCESS, BOOT_TIME}; -pub use self::utmpx::c_utmp; - -extern "C" { - pub fn getutxent() -> *const c_utmp; - pub fn getutxid(ut: *const c_utmp) -> *const c_utmp; - pub fn getutxline(ut: *const c_utmp) -> *const c_utmp; - pub fn pututxline(ut: *const c_utmp) -> *const c_utmp; - pub fn setutxent(); - pub fn endutxent(); - - #[cfg(any(target_os = "macos", target_os = "linux"))] - pub fn utmpxname(file: *const libc::c_char) -> libc::c_int; -} +use ::std::io::Result as IOResult; +use ::std::io::Error as IOError; +use ::std::ptr; +use ::std::borrow::Cow; +use ::std::ffi::CStr; +use ::std::ffi::CString; +pub use self::ut::*; +use libc::utmpx; +// pub use libc::getutxid; +// pub use libc::getutxline; +// pub use libc::pututxline; +pub use libc::getutxent; +pub use libc::setutxent; +pub use libc::endutxent; +#[cfg(any(target_os = "macos", target_os = "linux"))] +pub use libc::utmpxname; #[cfg(target_os = "freebsd")] -pub unsafe extern fn utmpxname(_file: *const libc::c_char) -> libc::c_int { +pub unsafe extern "C" fn utmpxname(_file: *const libc::c_char) -> libc::c_int { 0 } -#[cfg(target_os = "linux")] -mod utmpx { - use super::libc; +macro_rules! bytes2cow { + ($name:expr) => ( + unsafe { + CStr::from_ptr($name.as_ref().as_ptr()).to_string_lossy() + } + ) +} +#[cfg(target_os = "linux")] +mod ut { pub static DEFAULT_FILE: &'static str = "/var/run/utmp"; - pub const UT_LINESIZE: usize = 32; - pub const UT_NAMESIZE: usize = 32; + pub use libc::__UT_LINESIZE as UT_LINESIZE; + pub use libc::__UT_NAMESIZE as UT_NAMESIZE; + pub use libc::__UT_HOSTSIZE as UT_HOSTSIZE; pub const UT_IDSIZE: usize = 4; - pub const UT_HOSTSIZE: usize = 256; - pub const EMPTY: libc::c_short = 0; - pub const RUN_LVL: libc::c_short = 1; - pub const BOOT_TIME: libc::c_short = 2; - pub const NEW_TIME: libc::c_short = 3; - pub const OLD_TIME: libc::c_short = 4; - pub const INIT_PROCESS: libc::c_short = 5; - pub const LOGIN_PROCESS: libc::c_short = 6; - pub const USER_PROCESS: libc::c_short = 7; - pub const DEAD_PROCESS: libc::c_short = 8; - pub const ACCOUNTING: libc::c_short = 9; - - #[repr(C)] - pub struct __exit_status { - pub e_termination: libc::c_short, - pub e_exit: libc::c_short, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct __timeval { - pub tv_sec: libc::int32_t, - pub tv_usec: libc::int32_t, - } - - #[repr(C)] - pub struct c_utmp { - pub ut_type: libc::c_short, - pub ut_pid: libc::pid_t, - pub ut_line: [libc::c_char; UT_LINESIZE], - pub ut_id: [libc::c_char; UT_IDSIZE], - - pub ut_user: [libc::c_char; UT_NAMESIZE], - pub ut_host: [libc::c_char; UT_HOSTSIZE], - pub ut_exit: __exit_status, - - #[cfg(target_pointer_width = "32")] - pub ut_session: libc::c_long, - #[cfg(target_pointer_width = "32")] - pub ut_tv: libc::timeval, - - #[cfg(target_pointer_width = "64")] - pub ut_session: libc::int32_t, - #[cfg(target_pointer_width = "64")] - pub ut_tv: __timeval, - - pub ut_addr_v6: [libc::int32_t; 4], - __glibc_reserved: [libc::c_char; 20], - } + pub use libc::EMPTY; + pub use libc::RUN_LVL; + pub use libc::BOOT_TIME; + pub use libc::NEW_TIME; + pub use libc::OLD_TIME; + pub use libc::INIT_PROCESS; + pub use libc::LOGIN_PROCESS; + pub use libc::USER_PROCESS; + pub use libc::DEAD_PROCESS; + pub use libc::ACCOUNTING; } #[cfg(target_os = "macos")] -mod utmpx { - use super::libc; - +mod ut { pub static DEFAULT_FILE: &'static str = "/var/run/utmpx"; - pub const UT_LINESIZE: usize = 32; - pub const UT_NAMESIZE: usize = 256; - pub const UT_IDSIZE: usize = 4; - pub const UT_HOSTSIZE: usize = 256; + pub use libc::_UTX_LINESIZE as UT_LINESIZE; + pub use libc::_UTX_USERSIZE as UT_NAMESIZE; + pub use libc::_UTX_HOSTSIZE as UT_HOSTSIZE; + pub use libc::_UTX_IDSIZE as UT_IDSIZE; - pub const EMPTY: libc::c_short = 0; - pub const RUN_LVL: libc::c_short = 1; - pub const BOOT_TIME: libc::c_short = 2; - pub const OLD_TIME: libc::c_short = 3; - pub const NEW_TIME: libc::c_short = 4; - pub const INIT_PROCESS: libc::c_short = 5; - pub const LOGIN_PROCESS: libc::c_short = 6; - pub const USER_PROCESS: libc::c_short = 7; - pub const DEAD_PROCESS: libc::c_short = 8; - pub const ACCOUNTING: libc::c_short = 9; - - #[repr(C)] - pub struct c_utmp { - pub ut_user: [libc::c_char; UT_NAMESIZE], - pub ut_id: [libc::c_char; UT_IDSIZE], - pub ut_line: [libc::c_char; UT_LINESIZE], - pub ut_pid: libc::pid_t, - pub ut_type: libc::c_short, - pub ut_tv: libc::timeval, - pub ut_host: [libc::c_char; UT_HOSTSIZE], - pub __unused: [libc::uint32_t; 16], - } + pub use libc::EMPTY; + pub use libc::RUN_LVL; + pub use libc::BOOT_TIME; + pub use libc::NEW_TIME; + pub use libc::OLD_TIME; + pub use libc::INIT_PROCESS; + pub use libc::LOGIN_PROCESS; + pub use libc::USER_PROCESS; + pub use libc::DEAD_PROCESS; + pub use libc::ACCOUNTING; + pub use libc::SIGNATURE; + pub use libc::SHUTDOWN_TIME; } #[cfg(target_os = "freebsd")] -mod utmpx { +mod ut { use super::libc; pub static DEFAULT_FILE: &'static str = ""; @@ -129,25 +91,158 @@ mod utmpx { pub const UT_IDSIZE: usize = 8; pub const UT_HOSTSIZE: usize = 128; - pub const EMPTY: libc::c_short = 0; - pub const BOOT_TIME: libc::c_short = 1; - pub const OLD_TIME: libc::c_short = 2; - pub const NEW_TIME: libc::c_short = 3; - pub const USER_PROCESS: libc::c_short = 4; - pub const INIT_PROCESS: libc::c_short = 5; - pub const LOGIN_PROCESS: libc::c_short = 6; - pub const DEAD_PROCESS: libc::c_short = 7; - pub const SHUTDOWN_TIME: libc::c_short = 8; + pub use libc::EMPTY; + pub use libc::BOOT_TIME; + pub use libc::OLD_TIME; + pub use libc::NEW_TIME; + pub use libc::USER_PROCESS; + pub use libc::INIT_PROCESS; + pub use libc::LOGIN_PROCESS; + pub use libc::DEAD_PROCESS; + pub use libc::SHUTDOWN_TIME; +} - #[repr(C)] - pub struct c_utmp { - pub ut_type: libc::c_short, - pub ut_tv: libc::timeval, - pub ut_id: [libc::c_char; UT_IDSIZE], - pub ut_pid: libc::pid_t, - pub ut_user: [libc::c_char; UT_NAMESIZE], - pub ut_line: [libc::c_char; UT_LINESIZE], - pub ut_host: [libc::c_char; UT_HOSTSIZE], - pub ut_spare: [libc::c_char; 64], +/// 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, +} + +impl Utmpx { + /// A.K.A. ut.ut_type + pub fn record_type(&self) -> i16 { + self.inner.ut_type as i16 + } + /// A.K.A. ut.ut_pid + pub fn pid(&self) -> i32 { + self.inner.ut_pid as i32 + } + /// A.K.A. ut.ut_id + pub fn terminal_suffix(&self) -> Cow { + bytes2cow!(self.inner.ut_id) + } + /// A.K.A. ut.ut_user + pub fn user(&self) -> Cow { + bytes2cow!(self.inner.ut_user) + } + /// A.K.A. ut.ut_host + pub fn host(&self) -> Cow { + bytes2cow!(self.inner.ut_host) + } + /// A.K.A. ut.ut_line + pub fn tty_device(&self) -> Cow { + bytes2cow!(self.inner.ut_line) + } + /// A.K.A. ut.ut_tv + pub fn login_time(&self) -> Tm { + time::at(Timespec::new(self.inner.ut_tv.tv_sec as i64, + self.inner.ut_tv.tv_usec as i32)) + } + /// Consumes the `Utmpx`, returning the underlying C struct utmpx + pub fn into_inner(self) -> utmpx { + self.inner + } + pub fn is_user_process(&self) -> bool { + !self.user().is_empty() && self.record_type() == USER_PROCESS + } + + /// Canonicalize host name using DNS + pub fn canon_host(&self) -> IOResult { + const AI_CANONNAME: libc::c_int = 0x2; + let host = self.host(); + let hints = libc::addrinfo { + ai_flags: AI_CANONNAME, + ai_family: 0, + ai_socktype: 0, + ai_protocol: 0, + ai_addrlen: 0, + ai_addr: ptr::null_mut(), + ai_canonname: ptr::null_mut(), + ai_next: ptr::null_mut(), + }; + let c_host = CString::new(host.as_ref()).unwrap(); + let mut res = ptr::null_mut(); + let status = unsafe { + libc::getaddrinfo(c_host.as_ptr(), + ptr::null(), + &hints as *const _, + &mut res as *mut _) + }; + if status == 0 { + let info: libc::addrinfo = unsafe { ptr::read(res as *const _) }; + // http://lists.gnu.org/archive/html/bug-coreutils/2006-09/msg00300.html + // says Darwin 7.9.0 getaddrinfo returns 0 but sets + // res->ai_canonname to NULL. + let ret = if info.ai_canonname.is_null() { + Ok(String::from(host.as_ref())) + } else { + Ok(unsafe { CString::from_raw(info.ai_canonname).into_string().unwrap() }) + }; + unsafe { + libc::freeaddrinfo(res); + } + ret + } else { + Err(IOError::last_os_error()) + } + } + pub fn iter_all_records() -> UtmpxIter { + UtmpxIter + } +} + +/// Iterator of login records +pub struct UtmpxIter; + +impl UtmpxIter { + /// Sets the name of the utmpx-format file for the other utmpx functions to access. + /// + /// If not set, default record file will be used(file path depends on the target OS) + pub fn read_from(self, f: &str) -> Self { + let res = unsafe { utmpxname(CString::new(f).unwrap().as_ptr()) }; + if res != 0 { + println!("Warning: {}", IOError::last_os_error()); + } + unsafe { + setutxent(); + } + self + } +} + +impl Iterator for UtmpxIter { + type Item = Utmpx; + fn next(&mut self) -> Option { + unsafe { + let res = getutxent(); + if !res.is_null() { + Some(Utmpx { + inner: ptr::read(res as *const _) + }) + } else { + endutxent(); + None + } + } } } From 77ef1580c268c9c8963b32f05c3c33dd25c80a2d Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 15:24:29 +0800 Subject: [PATCH 5/7] pinky: use uucore::utmpx --- src/pinky/Cargo.toml | 9 ++-- src/pinky/pinky.rs | 123 ++++++++----------------------------------- src/pinky/utmp.rs | 43 --------------- 3 files changed, 25 insertions(+), 150 deletions(-) delete mode 100644 src/pinky/utmp.rs diff --git a/src/pinky/Cargo.toml b/src/pinky/Cargo.toml index 0e83fbf4a..6c9d10af0 100644 --- a/src/pinky/Cargo.toml +++ b/src/pinky/Cargo.toml @@ -7,11 +7,10 @@ authors = [] name = "uu_pinky" path = "pinky.rs" -[dependencies] -getopts = "*" -time = "*" -libc = "^0.2" -uucore = { path="../uucore" } +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["utmpx", "c_types"] [[bin]] name = "pinky" diff --git a/src/pinky/pinky.rs b/src/pinky/pinky.rs index e441cd33e..64e78dbd3 100644 --- a/src/pinky/pinky.rs +++ b/src/pinky/pinky.rs @@ -13,13 +13,9 @@ #[macro_use] extern crate uucore; use uucore::c_types::getpwnam; -use uucore::utmpx; - -extern crate getopts; -extern crate libc; -use libc::{uid_t, gid_t, c_char, S_IWGRP}; - -extern crate time; +use uucore::utmpx::{self, time, Utmpx}; +use uucore::coreopts; +use uucore::libc::{uid_t, gid_t, c_char, S_IWGRP}; use std::io::prelude::*; use std::io::BufReader; @@ -29,21 +25,16 @@ use std::fs::File; use std::os::unix::fs::MetadataExt; use std::ptr; -use std::ffi::{CStr, CString, OsStr}; -use std::os::unix::ffi::OsStrExt; +use std::ffi::{CStr, CString}; -use std::path::Path; use std::path::PathBuf; -mod utmp; - static NAME: &'static str = "pinky"; -static VERSION: &'static str = env!("CARGO_PKG_VERSION"); const BUFSIZE: usize = 1024; pub fn uumain(args: Vec) -> i32 { - let mut opts = getopts::Options::new(); + let mut opts = coreopts::CoreOptions::new(NAME); opts.optflag("l", "l", "produce long format output for the specified USERs"); @@ -64,16 +55,8 @@ pub fn uumain(args: Vec) -> i32 { 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; - } - }; - - if matches.opt_present("help") { - println!("Usage: {} [OPTION]... [USER]... + opts.help(format!( + "Usage: {} [OPTION]... [USER]... -l produce long format output for the specified USERs -b omit the user's home directory and shell in long format @@ -91,14 +74,9 @@ pub fn uumain(args: Vec) -> i32 { A lightweight 'finger' program; print user information. The utmp file will be {}", NAME, - utmpx::DEFAULT_FILE); - return 0; - } + utmpx::DEFAULT_FILE)); - if matches.opt_present("version") { - println!("{} {}", NAME, VERSION); - return 0; - } + let matches = opts.parse(args); // If true, display the hours:minutes since each user has touched // the keyboard, or blank if within the last minute, or days followed @@ -244,16 +222,6 @@ impl Capitalize for str { } } -trait UtmpUtils { - fn is_user_process(&self) -> bool; -} - -impl UtmpUtils for utmpx::c_utmp { - fn is_user_process(&self) -> bool { - self.ut_user[0] != 0 && self.ut_type == utmpx::USER_PROCESS - } -} - fn idle_string(when: i64) -> String { thread_local! { static NOW: time::Tm = time::now() @@ -276,59 +244,14 @@ fn idle_string(when: i64) -> String { }) } -fn time_string(ut: &utmpx::c_utmp) -> String { - let tm = time::at(time::Timespec::new(ut.ut_tv.tv_sec as i64, ut.ut_tv.tv_usec as i32)); - time::strftime("%Y-%m-%d %H:%M", &tm).unwrap() -} - -const AI_CANONNAME: libc::c_int = 0x2; - -fn canon_host(host: &str) -> Option { - let hints = libc::addrinfo { - ai_flags: AI_CANONNAME, - ai_family: 0, - ai_socktype: 0, - ai_protocol: 0, - ai_addrlen: 0, - ai_addr: ptr::null_mut(), - ai_canonname: ptr::null_mut(), - ai_next: ptr::null_mut(), - }; - let c_host = CString::new(host).unwrap(); - let mut res = ptr::null_mut(); - let status = unsafe { - libc::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints as *const _, &mut res as *mut _) - }; - if status == 0 { - let info: libc::addrinfo = unsafe { - ptr::read(res as *const _) - }; - // http://lists.gnu.org/archive/html/bug-coreutils/2006-09/msg00300.html - // says Darwin 7.9.0 getaddrinfo returns 0 but sets - // res->ai_canonname to NULL. - let ret = if info.ai_canonname.is_null() { - Some(String::from(host)) - } else { - Some(unsafe { - CString::from_raw(info.ai_canonname).into_string().unwrap() - }) - }; - unsafe { - libc::freeaddrinfo(res); - } - ret - } else { - None - } +fn time_string(ut: &Utmpx) -> String { + time::strftime("%Y-%m-%d %H:%M", &ut.login_time()).unwrap() } impl Pinky { - fn print_entry(&self, ut: &utmpx::c_utmp) { + fn print_entry(&self, ut: &Utmpx) { let mut pts_path = PathBuf::from("/dev"); - let line: &Path = OsStr::from_bytes(unsafe { - CStr::from_ptr(ut.ut_line.as_ref().as_ptr()).to_bytes() - }).as_ref(); - pts_path.push(line); + pts_path.push(ut.tty_device().as_ref()); let mesg; let last_change; @@ -347,11 +270,10 @@ impl Pinky { } } - let ut_user = String::from_chars(ut.ut_user.as_ref().as_ptr()); - print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut_user); + print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user()); if self.include_fullname { - if let Some(pw) = getpw(&ut_user) { + if let Some(pw) = getpw(ut.user().as_ref()) { let mut gecos = pw.pw_gecos; if let Some(n) = gecos.find(',') { gecos.truncate(n + 1); @@ -363,7 +285,7 @@ impl Pinky { } - print!(" {}{:<8.*}", mesg, utmpx::UT_LINESIZE, String::from_chars(ut.ut_line.as_ref().as_ptr())); + print!(" {}{:<8.*}", mesg, utmpx::UT_LINESIZE, ut.tty_device()); if self.include_idle { if last_change != 0 { @@ -375,11 +297,11 @@ impl Pinky { print!(" {}", time_string(&ut)); - if self.include_where && ut.ut_host[0] != 0 { - let ut_host = String::from_chars(ut.ut_host.as_ref().as_ptr()); + if self.include_where && !ut.host().is_empty() { + let ut_host = ut.host().into_owned(); let mut res = ut_host.split(':'); let host = match res.next() { - Some(h) => canon_host(&h).unwrap_or(ut_host.clone()), + Some(_) => ut.canon_host().unwrap_or(ut_host.clone()), None => ut_host.clone(), }; match res.next() { @@ -411,15 +333,12 @@ impl Pinky { if self.include_heading { self.print_heading(); } - for ut in utmp::read_utmps() { + for ut in Utmpx::iter_all_records() { if ut.is_user_process() { if self.names.is_empty() { self.print_entry(&ut) } else { - let ut_user = unsafe { - CStr::from_ptr(ut.ut_user.as_ref().as_ptr()).to_bytes() - }; - if self.names.iter().any(|n| n.as_bytes() == ut_user) { + if self.names.iter().any(|n| n.as_str() == ut.user()) { self.print_entry(&ut); } } diff --git a/src/pinky/utmp.rs b/src/pinky/utmp.rs deleted file mode 100644 index 413994a68..000000000 --- a/src/pinky/utmp.rs +++ /dev/null @@ -1,43 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// (c) Jian Zeng -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. -// -extern crate uucore; -use uucore::utmpx; - -use std::ptr; - -pub struct UtmpIter; - -impl UtmpIter { - fn new() -> Self { - unsafe { - utmpx::setutxent(); - } - UtmpIter - } -} - -impl Iterator for UtmpIter { - type Item = utmpx::c_utmp; - - fn next(&mut self) -> Option { - unsafe { - let line = utmpx::getutxent(); - - if line.is_null() { - utmpx::endutxent(); - return None; - } - - Some(ptr::read(line)) - } - } -} - -pub fn read_utmps() -> UtmpIter { - UtmpIter::new() -} From f4c50921d8fbf61263e7110c9418580a6fe5ff92 Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 15:24:45 +0800 Subject: [PATCH 6/7] uptime: use uucore::utmpx --- src/uptime/Cargo.toml | 8 ++++--- src/uptime/uptime.rs | 56 +++++++++++++++---------------------------- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/uptime/Cargo.toml b/src/uptime/Cargo.toml index 78fd30902..4ee431eb8 100644 --- a/src/uptime/Cargo.toml +++ b/src/uptime/Cargo.toml @@ -9,9 +9,11 @@ path = "uptime.rs" [dependencies] getopts = "*" -libc = { git = "https://github.com/rust-lang/libc.git" } -time = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +path = "../uucore" +default-features = false +features = ["utmpx"] [[bin]] name = "uptime" diff --git a/src/uptime/uptime.rs b/src/uptime/uptime.rs index 942fee683..675e4b093 100644 --- a/src/uptime/uptime.rs +++ b/src/uptime/uptime.rs @@ -4,6 +4,7 @@ * This file is part of the uutils coreutils package. * * (c) Jordi Boggiano + * (c) Jian Zeng * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,20 +13,18 @@ /* last synced with: cat (GNU coreutils) 8.13 */ extern crate getopts; -extern crate libc; -extern crate time as rtime; #[macro_use] extern crate uucore; +// import crate time from utmpx +use uucore::utmpx::*; +use uucore::libc::{time_t, c_double}; +pub use uucore::libc; use getopts::Options; -use libc::{time_t, c_double}; -use std::ffi::CString; use std::fs::File; use std::io::{Read, Write}; use std::mem::transmute; -use std::ptr::null; -use uucore::utmpx::*; static NAME: &'static str = "uptime"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -92,38 +91,21 @@ fn print_loadavg() { #[cfg(unix)] fn process_utmpx() -> (Option, usize) { - unsafe { - utmpxname(CString::new(DEFAULT_FILE).unwrap().as_ptr()); - } - let mut nusers = 0; let mut boot_time = None; - unsafe { - setutxent(); - - loop { - let line = getutxent(); - - if line == null() { - break; - } - - match (*line).ut_type { - USER_PROCESS => nusers += 1, - BOOT_TIME => { - let t = (*line).ut_tv; - if t.tv_sec > 0 { - boot_time = Some(t.tv_sec as time_t); - } - }, - _ => continue - } + for line in Utmpx::iter_all_records() { + match line.record_type() { + USER_PROCESS => nusers += 1, + BOOT_TIME => { + let t = line.login_time().to_timespec(); + if t.sec > 0 { + boot_time = Some(t.sec as time_t); + } + }, + _ => continue } - - endutxent(); } - (boot_time, nusers) } @@ -141,7 +123,7 @@ fn print_nusers(nusers: usize) { } fn print_time() { - let local_time = rtime::now(); + let local_time = time::now(); print!(" {:02}:{:02}:{:02} ", local_time.tm_hour, local_time.tm_min, local_time.tm_sec); @@ -160,9 +142,9 @@ fn get_uptime(boot_time: Option) -> i64 { } else { match boot_time { Some(t) => { - let now = rtime::get_time().sec; - let time = t as i64; - ((now - time) * 100) + let now = time::get_time().sec; + let boottime = t as i64; + ((now - boottime) * 100) }, _ => -1, } From 963ab9d32159c49710689b8b5d2b282c4e096b2f Mon Sep 17 00:00:00 2001 From: Knight Date: Wed, 10 Aug 2016 15:24:55 +0800 Subject: [PATCH 7/7] users: use uucore::utmpx --- src/users/Cargo.toml | 7 +++++-- src/users/users.rs | 36 +++++++----------------------------- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/users/Cargo.toml b/src/users/Cargo.toml index adfa1dac4..88fe009ea 100644 --- a/src/users/Cargo.toml +++ b/src/users/Cargo.toml @@ -9,8 +9,11 @@ path = "users.rs" [dependencies] getopts = "*" -libc = "*" -uucore = { path="../uucore" } + +[dependencies.uucore] +default-features = false +features = ["utmpx"] +path = "../uucore" [[bin]] name = "users" diff --git a/src/users/users.rs b/src/users/users.rs index d4394de47..52e6f2f8d 100644 --- a/src/users/users.rs +++ b/src/users/users.rs @@ -4,6 +4,7 @@ * This file is part of the uutils coreutils package. * * (c) KokaKiwi + * (c) Jian Zeng * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,16 +16,12 @@ #![allow(dead_code)] extern crate getopts; -extern crate libc; #[macro_use] extern crate uucore; +use uucore::utmpx::*; use getopts::Options; -use std::ffi::{CStr, CString}; -use std::mem; -use std::ptr; -use uucore::utmpx::*; static NAME: &'static str = "users"; static VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -67,30 +64,11 @@ pub fn uumain(args: Vec) -> i32 { } fn exec(filename: &str) { - unsafe { - utmpxname(CString::new(filename).unwrap().as_ptr()); - } - - let mut users = vec!(); - - unsafe { - setutxent(); - - loop { - let line = getutxent(); - - if line == ptr::null() { - break; - } - - if (*line).ut_type == USER_PROCESS { - let user = String::from_utf8_lossy(CStr::from_ptr(mem::transmute(&(*line).ut_user)).to_bytes()).to_string(); - users.push(user); - } - } - - endutxent(); - } + let mut users = Utmpx::iter_all_records() + .read_from(filename) + .filter(|ut| ut.is_user_process()) + .map(|ut| ut.user().into_owned()) + .collect::>(); if !users.is_empty() { users.sort();