1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

pinky: use uucore::utmpx

This commit is contained in:
Knight 2016-08-10 15:24:29 +08:00
parent 301a240b73
commit 77ef1580c2
3 changed files with 25 additions and 150 deletions

View file

@ -7,11 +7,10 @@ authors = []
name = "uu_pinky" name = "uu_pinky"
path = "pinky.rs" path = "pinky.rs"
[dependencies] [dependencies.uucore]
getopts = "*" path = "../uucore"
time = "*" default-features = false
libc = "^0.2" features = ["utmpx", "c_types"]
uucore = { path="../uucore" }
[[bin]] [[bin]]
name = "pinky" name = "pinky"

View file

@ -13,13 +13,9 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::c_types::getpwnam; use uucore::c_types::getpwnam;
use uucore::utmpx; use uucore::utmpx::{self, time, Utmpx};
use uucore::coreopts;
extern crate getopts; use uucore::libc::{uid_t, gid_t, c_char, S_IWGRP};
extern crate libc;
use libc::{uid_t, gid_t, c_char, S_IWGRP};
extern crate time;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufReader; use std::io::BufReader;
@ -29,21 +25,16 @@ use std::fs::File;
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
use std::ptr; use std::ptr;
use std::ffi::{CStr, CString, OsStr}; use std::ffi::{CStr, CString};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
mod utmp;
static NAME: &'static str = "pinky"; static NAME: &'static str = "pinky";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUFSIZE: usize = 1024; const BUFSIZE: usize = 1024;
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new(); let mut opts = coreopts::CoreOptions::new(NAME);
opts.optflag("l", opts.optflag("l",
"l", "l",
"produce long format output for the specified USERs"); "produce long format output for the specified USERs");
@ -64,16 +55,8 @@ pub fn uumain(args: Vec<String>) -> i32 {
opts.optflag("", "help", "display this help and exit"); opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit"); opts.optflag("", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) { opts.help(format!(
Ok(m) => m, "Usage: {} [OPTION]... [USER]...
Err(f) => {
disp_err!("{}", f);
return 1;
}
};
if matches.opt_present("help") {
println!("Usage: {} [OPTION]... [USER]...
-l produce long format output for the specified USERs -l produce long format output for the specified USERs
-b omit the user's home directory and shell in long format -b omit the user's home directory and shell in long format
@ -91,14 +74,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
A lightweight 'finger' program; print user information. A lightweight 'finger' program; print user information.
The utmp file will be {}", The utmp file will be {}",
NAME, NAME,
utmpx::DEFAULT_FILE); utmpx::DEFAULT_FILE));
return 0;
}
if matches.opt_present("version") { let matches = opts.parse(args);
println!("{} {}", NAME, VERSION);
return 0;
}
// If true, display the hours:minutes since each user has touched // If true, display the hours:minutes since each user has touched
// the keyboard, or blank if within the last minute, or days followed // 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 { fn idle_string(when: i64) -> String {
thread_local! { thread_local! {
static NOW: time::Tm = time::now() static NOW: time::Tm = time::now()
@ -276,59 +244,14 @@ fn idle_string(when: i64) -> String {
}) })
} }
fn time_string(ut: &utmpx::c_utmp) -> String { fn time_string(ut: &Utmpx) -> 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", &ut.login_time()).unwrap()
time::strftime("%Y-%m-%d %H:%M", &tm).unwrap()
}
const AI_CANONNAME: libc::c_int = 0x2;
fn canon_host(host: &str) -> Option<String> {
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
}
} }
impl Pinky { impl Pinky {
fn print_entry(&self, ut: &utmpx::c_utmp) { fn print_entry(&self, ut: &Utmpx) {
let mut pts_path = PathBuf::from("/dev"); let mut pts_path = PathBuf::from("/dev");
let line: &Path = OsStr::from_bytes(unsafe { pts_path.push(ut.tty_device().as_ref());
CStr::from_ptr(ut.ut_line.as_ref().as_ptr()).to_bytes()
}).as_ref();
pts_path.push(line);
let mesg; let mesg;
let last_change; 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 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; let mut gecos = pw.pw_gecos;
if let Some(n) = gecos.find(',') { if let Some(n) = gecos.find(',') {
gecos.truncate(n + 1); 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 self.include_idle {
if last_change != 0 { if last_change != 0 {
@ -375,11 +297,11 @@ impl Pinky {
print!(" {}", time_string(&ut)); print!(" {}", time_string(&ut));
if self.include_where && ut.ut_host[0] != 0 { if self.include_where && !ut.host().is_empty() {
let ut_host = String::from_chars(ut.ut_host.as_ref().as_ptr()); let ut_host = ut.host().into_owned();
let mut res = ut_host.split(':'); let mut res = ut_host.split(':');
let host = match res.next() { 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(), None => ut_host.clone(),
}; };
match res.next() { match res.next() {
@ -411,15 +333,12 @@ impl Pinky {
if self.include_heading { if self.include_heading {
self.print_heading(); self.print_heading();
} }
for ut in utmp::read_utmps() { for ut in Utmpx::iter_all_records() {
if ut.is_user_process() { if ut.is_user_process() {
if self.names.is_empty() { if self.names.is_empty() {
self.print_entry(&ut) self.print_entry(&ut)
} else { } else {
let ut_user = unsafe { if self.names.iter().any(|n| n.as_str() == ut.user()) {
CStr::from_ptr(ut.ut_user.as_ref().as_ptr()).to_bytes()
};
if self.names.iter().any(|n| n.as_bytes() == ut_user) {
self.print_entry(&ut); self.print_entry(&ut);
} }
} }

View file

@ -1,43 +0,0 @@
// 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.
//
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<Self::Item> {
unsafe {
let line = utmpx::getutxent();
if line.is_null() {
utmpx::endutxent();
return None;
}
Some(ptr::read(line))
}
}
}
pub fn read_utmps() -> UtmpIter {
UtmpIter::new()
}