Implement uptime

Move utmp struct from users to common/utmpx.rs
This commit is contained in:
José Neder 2014-03-18 09:17:32 -03:00
parent 786b39019b
commit ef4a5e965d
5 changed files with 270 additions and 83 deletions

View file

@ -39,7 +39,8 @@ UNIX_PROGS := \
whoami \
tty \
groups \
id
id \
uptime
ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS)

View file

@ -32,6 +32,18 @@ pub struct c_group {
gr_name: *c_char /* group name */
}
pub struct c_tm {
tm_sec: c_int, /* seconds */
tm_min: c_int, /* minutes */
tm_hour: c_int, /* hours */
tm_mday: c_int, /* day of the month */
tm_mon: c_int, /* month */
tm_year: c_int, /* year */
tm_wday: c_int, /* day of the week */
tm_yday: c_int, /* day in the year */
tm_isdst: c_int /* daylight saving time */
}
extern {
pub fn getpwuid(uid: c_int) -> *c_passwd;
pub fn getpwnam(login: *c_char) -> *c_passwd;

86
common/utmpx.rs Normal file
View file

@ -0,0 +1,86 @@
#[allow(non_camel_case_types)];
pub use self::utmpx::{DEFAULT_FILE,USER_PROCESS,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
use std::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmp";
pub static UT_LINESIZE: uint = 32;
pub static UT_NAMESIZE: uint = 32;
pub static UT_IDSIZE: uint = 4;
pub static UT_HOSTSIZE: uint = 256;
pub static EMPTY: libc::c_short = 0;
pub static RUN_LVL: libc::c_short = 1;
pub static BOOT_TIME: libc::c_short = 2;
pub static NEW_TIME: libc::c_short = 3;
pub static OLD_TIME: libc::c_short = 4;
pub static INIT_PROCESS: libc::c_short = 5;
pub static LOGIN_PROCESS: libc::c_short = 6;
pub static USER_PROCESS: libc::c_short = 7;
pub static DEAD_PROCESS: libc::c_short = 8;
pub static ACCOUNTING: libc::c_short = 9;
pub struct c_exit_status {
e_termination: libc::c_short,
e_exit: libc::c_short,
}
pub struct c_utmp {
ut_type: libc::c_short,
ut_pid: libc::pid_t,
ut_line: [libc::c_char, ..UT_LINESIZE],
ut_id: [libc::c_char, ..UT_IDSIZE],
ut_user: [libc::c_char, ..UT_NAMESIZE],
ut_host: [libc::c_char, ..UT_HOSTSIZE],
ut_exit: c_exit_status,
ut_session: libc::c_long,
ut_tv: libc::timeval,
ut_addr_v6: [libc::int32_t, ..4],
__unused: [libc::c_char, ..20],
}
}
#[cfg(target_os = "macos")]
mod utmpx {
use std::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";
pub static UT_LINESIZE: uint = 32;
pub static UT_NAMESIZE: uint = 256;
pub static UT_IDSIZE: uint = 4;
pub static UT_HOSTSIZE: uint = 256;
pub static EMPTY: libc::c_short = 0;
pub static RUN_LVL: libc::c_short = 1;
pub static BOOT_TIME: libc::c_short = 2;
pub static OLD_TIME: libc::c_short = 3;
pub static NEW_TIME: libc::c_short = 4;
pub static INIT_PROCESS: libc::c_short = 5;
pub static LOGIN_PROCESS: libc::c_short = 6;
pub static USER_PROCESS: libc::c_short = 7;
pub static DEAD_PROCESS: libc::c_short = 8;
pub static ACCOUNTING: libc::c_short = 9;
pub struct c_exit_status {
e_termination: libc::c_short,
e_exit: libc::c_short,
}
pub struct c_utmp {
ut_user: [libc::c_char, ..UT_NAMESIZE],
ut_id: [libc::c_char, ..UT_IDSIZE],
ut_line: [libc::c_char, ..UT_LINESIZE],
ut_pid: libc::pid_t,
ut_type: libc::c_short,
ut_tv: libc::timeval,
ut_host: [libc::c_char, ..UT_HOSTSIZE],
__unused: [libc::c_char, ..16]
}
}

168
uptime/uptime.rs Normal file
View file

@ -0,0 +1,168 @@
#[crate_id(name="uptime", vers="1.0.0", author="José Neder")];
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* last synced with: cat (GNU coreutils) 8.13 */
#[allow(non_camel_case_types)];
#[feature(macro_rules, globs)];
extern crate getopts;
use std::os;
use std::cast::transmute;
use std::io::{print,File};
use std::libc::{time_t,c_double,c_int,size_t,c_char};
use std::ptr::null;
use std::from_str::from_str;
use c_types::c_tm;
use utmpx::*;
#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;
#[path = "../common/utmpx.rs"] mod utmpx;
static NAME: &'static str = "uptime";
extern {
fn time(timep: *time_t) -> time_t;
fn localtime(timep: *time_t) -> *c_tm;
fn getloadavg(loadavg: *c_double, nelem: c_int) -> c_int;
fn getutxent() -> *c_utmp;
fn setutxent();
fn endutxent();
fn utmpxname(file: *c_char) -> c_int;
}
fn main() {
let args = os::args();
let program = args[0].clone();
let opts = ~[
getopts::optflag("v", "version", "output version information and exit"),
getopts::optflag("h", "help", "display this help and exit"),
];
let matches = match getopts::getopts(args.tail(), opts) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f.to_err_msg())
};
if matches.opt_present("version") {
println!("uptime 1.0.0");
return;
}
if matches.opt_present("help") || matches.free.len() > 0 {
println!("Usage:");
println!(" {0:s} [OPTION]", program);
println!("");
print(getopts::usage("Print the current time, the length of time the system has been up,\n\
the number of users on the system, and the average number of jobs\n\
in the run queue over the last 1, 5 and 15 minutes.", opts));
return;
}
print_time();
print_uptime();
print_nusers();
print_loadavg();
}
fn print_loadavg() {
let avg: [c_double, ..3] = [0.0, ..3];
let loads: i32 = unsafe { transmute(getloadavg(avg.as_ptr(), 3)) };
if loads == -1 {
print!("\n");
}
else {
print!("load average: ")
for n in range(0, loads) {
print!("{}{}", avg[n], if n == loads - 1 { "\n" }
else { ", " } );
}
}
}
fn print_nusers() {
DEFAULT_FILE.with_c_str(|filename| {
unsafe {
utmpxname(filename);
}
});
let mut nusers = 0;
unsafe {
setutxent();
loop {
let line = getutxent();
if line == null() {
break;
}
if (*line).ut_type == USER_PROCESS {
nusers += 1;
}
}
endutxent();
}
if nusers == 1 {
print!("1 user, ");
} else if nusers > 1 {
print!("{} users, ", nusers);
}
}
fn print_time() {
let local_time = unsafe { *localtime(&time(null())) };
if local_time.tm_hour >= 0 && local_time.tm_min >= 0 &&
local_time.tm_sec >= 0 {
print!(" {:02d}:{:02d}:{:02d} ", local_time.tm_hour,
local_time.tm_min, local_time.tm_sec);
}
}
fn get_uptime() -> int {
let uptime_text = File::open(&Path::new("/proc/uptime"))
.read_to_str().unwrap();
return match uptime_text.words().next() {
Some(s) => match from_str(s.replace(".","")) {
Some(n) => n,
None => -1
},
None => -1
};
}
fn print_uptime() {
let uptime = get_uptime() / 100;
let updays = uptime / 86400;
let uphours = (uptime - (updays * 86400)) / 3600;
let upmins = (uptime - (updays * 86400) - (uphours * 3600)) / 60;
if updays == 1 {
print!("up {:1d} day, {:2d}:{:02d}, ", updays, uphours, upmins);
}
else if updays > 1 {
print!("up {:1d} days, {:2d}:{:02d}, ", updays, uphours, upmins);
}
else {
print!("up {:2d}:{:02d}, ", uphours, upmins);
}
}

View file

@ -29,88 +29,8 @@ use utmpx::*;
#[path = "../common/util.rs"]
mod util;
#[cfg(target_os = "linux")]
mod utmpx {
use std::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmp";
pub static UT_LINESIZE: uint = 32;
pub static UT_NAMESIZE: uint = 32;
pub static UT_IDSIZE: uint = 4;
pub static UT_HOSTSIZE: uint = 256;
pub static EMPTY: libc::c_short = 0;
pub static RUN_LVL: libc::c_short = 1;
pub static BOOT_TIME: libc::c_short = 2;
pub static NEW_TIME: libc::c_short = 3;
pub static OLD_TIME: libc::c_short = 4;
pub static INIT_PROCESS: libc::c_short = 5;
pub static LOGIN_PROCESS: libc::c_short = 6;
pub static USER_PROCESS: libc::c_short = 7;
pub static DEAD_PROCESS: libc::c_short = 8;
pub static ACCOUNTING: libc::c_short = 9;
pub struct c_exit_status {
e_termination: libc::c_short,
e_exit: libc::c_short,
}
pub struct c_utmp {
ut_type: libc::c_short,
ut_pid: libc::pid_t,
ut_line: [libc::c_char, ..UT_LINESIZE],
ut_id: [libc::c_char, ..UT_IDSIZE],
ut_user: [libc::c_char, ..UT_NAMESIZE],
ut_host: [libc::c_char, ..UT_HOSTSIZE],
ut_exit: c_exit_status,
ut_session: libc::c_long,
ut_tv: libc::timeval,
ut_addr_v6: [libc::int32_t, ..4],
__unused: [libc::c_char, ..20],
}
}
#[cfg(target_os = "macos")]
mod utmpx {
use std::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";
pub static UT_LINESIZE: uint = 32;
pub static UT_NAMESIZE: uint = 256;
pub static UT_IDSIZE: uint = 4;
pub static UT_HOSTSIZE: uint = 256;
pub static EMPTY: libc::c_short = 0;
pub static RUN_LVL: libc::c_short = 1;
pub static BOOT_TIME: libc::c_short = 2;
pub static OLD_TIME: libc::c_short = 3;
pub static NEW_TIME: libc::c_short = 4;
pub static INIT_PROCESS: libc::c_short = 5;
pub static LOGIN_PROCESS: libc::c_short = 6;
pub static USER_PROCESS: libc::c_short = 7;
pub static DEAD_PROCESS: libc::c_short = 8;
pub static ACCOUNTING: libc::c_short = 9;
pub struct c_exit_status {
e_termination: libc::c_short,
e_exit: libc::c_short,
}
pub struct c_utmp {
ut_user: [libc::c_char, ..UT_NAMESIZE],
ut_id: [libc::c_char, ..UT_IDSIZE],
ut_line: [libc::c_char, ..UT_LINESIZE],
ut_pid: libc::pid_t,
ut_type: libc::c_short,
ut_tv: libc::timeval,
ut_host: [libc::c_char, ..UT_HOSTSIZE],
__unused: [libc::c_char, ..16]
}
}
#[path = "../common/utmpx.rs"]
mod utmpx;
extern {
fn getutxent() -> *c_utmp;