mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Implement uptime
Move utmp struct from users to common/utmpx.rs
This commit is contained in:
parent
786b39019b
commit
ef4a5e965d
5 changed files with 270 additions and 83 deletions
3
Makefile
3
Makefile
|
@ -39,7 +39,8 @@ UNIX_PROGS := \
|
||||||
whoami \
|
whoami \
|
||||||
tty \
|
tty \
|
||||||
groups \
|
groups \
|
||||||
id
|
id \
|
||||||
|
uptime
|
||||||
|
|
||||||
ifneq ($(OS),Windows_NT)
|
ifneq ($(OS),Windows_NT)
|
||||||
PROGS := $(PROGS) $(UNIX_PROGS)
|
PROGS := $(PROGS) $(UNIX_PROGS)
|
||||||
|
|
|
@ -32,6 +32,18 @@ pub struct c_group {
|
||||||
gr_name: *c_char /* group name */
|
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 {
|
extern {
|
||||||
pub fn getpwuid(uid: c_int) -> *c_passwd;
|
pub fn getpwuid(uid: c_int) -> *c_passwd;
|
||||||
pub fn getpwnam(login: *c_char) -> *c_passwd;
|
pub fn getpwnam(login: *c_char) -> *c_passwd;
|
||||||
|
|
86
common/utmpx.rs
Normal file
86
common/utmpx.rs
Normal 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
168
uptime/uptime.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,88 +29,8 @@ use utmpx::*;
|
||||||
#[path = "../common/util.rs"]
|
#[path = "../common/util.rs"]
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[path = "../common/utmpx.rs"]
|
||||||
mod utmpx {
|
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]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
fn getutxent() -> *c_utmp;
|
fn getutxent() -> *c_utmp;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue