mirror of
https://github.com/uutils/coreutils
synced 2024-12-15 15:52:42 +00:00
uptime: tool unsupported on OpenBSD
- utmpx not supported on OpenBSD - add src/uu/uptime/src/platform directory and platform/mod.rs for conditional compilation according to target_os - platform/openbsd.rs: implementation on OpenBSD (unsupported tool) - platform/unix.rs: implementation on other OS - src/uu/uptime/src/uptime.rs: use platform module for uucore::main function
This commit is contained in:
parent
d3e6e7a947
commit
8c6d722916
4 changed files with 194 additions and 150 deletions
14
src/uu/uptime/src/platform/mod.rs
Normal file
14
src/uu/uptime/src/platform/mod.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// This file is part of the uutils coreutils package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "openbsd"))]
|
||||||
|
mod unix;
|
||||||
|
#[cfg(not(target_os = "openbsd"))]
|
||||||
|
pub use self::unix::*;
|
||||||
|
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
mod openbsd;
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
pub use self::openbsd::*;
|
17
src/uu/uptime/src/platform/openbsd.rs
Normal file
17
src/uu/uptime/src/platform/openbsd.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// This file is part of the uutils coreutils package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
// Specific implementation for OpenBSD: tool unsupported (utmpx not supported)
|
||||||
|
|
||||||
|
use crate::uu_app;
|
||||||
|
|
||||||
|
use uucore::error::UResult;
|
||||||
|
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
let _matches = uu_app().try_get_matches_from(args)?;
|
||||||
|
|
||||||
|
println!("unsupported command on OpenBSD");
|
||||||
|
Ok(())
|
||||||
|
}
|
161
src/uu/uptime/src/platform/unix.rs
Normal file
161
src/uu/uptime/src/platform/unix.rs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
// This file is part of the uutils coreutils package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
|
// spell-checker:ignore (ToDO) getloadavg upsecs updays nusers loadavg boottime uphours upmins
|
||||||
|
|
||||||
|
use crate::options;
|
||||||
|
use crate::uu_app;
|
||||||
|
|
||||||
|
use chrono::{Local, TimeZone, Utc};
|
||||||
|
|
||||||
|
use uucore::libc::time_t;
|
||||||
|
|
||||||
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use uucore::libc::getloadavg;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
extern "C" {
|
||||||
|
fn GetTickCount() -> uucore::libc::uint32_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
let matches = uu_app().try_get_matches_from(args)?;
|
||||||
|
|
||||||
|
let (boot_time, user_count) = process_utmpx();
|
||||||
|
let uptime = get_uptime(boot_time);
|
||||||
|
if uptime < 0 {
|
||||||
|
Err(USimpleError::new(1, "could not retrieve system uptime"))
|
||||||
|
} else {
|
||||||
|
if matches.get_flag(options::SINCE) {
|
||||||
|
let initial_date = Local
|
||||||
|
.timestamp_opt(Utc::now().timestamp() - uptime, 0)
|
||||||
|
.unwrap();
|
||||||
|
println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
print_time();
|
||||||
|
let upsecs = uptime;
|
||||||
|
print_uptime(upsecs);
|
||||||
|
print_nusers(user_count);
|
||||||
|
print_loadavg();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn print_loadavg() {
|
||||||
|
use uucore::libc::c_double;
|
||||||
|
|
||||||
|
let mut avg: [c_double; 3] = [0.0; 3];
|
||||||
|
let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };
|
||||||
|
|
||||||
|
if loads == -1 {
|
||||||
|
println!();
|
||||||
|
} else {
|
||||||
|
print!("load average: ");
|
||||||
|
for n in 0..loads {
|
||||||
|
print!(
|
||||||
|
"{:.2}{}",
|
||||||
|
avg[n as usize],
|
||||||
|
if n == loads - 1 { "\n" } else { ", " }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn print_loadavg() {
|
||||||
|
// XXX: currently this is a noop as Windows does not seem to have anything comparable to
|
||||||
|
// getloadavg()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn process_utmpx() -> (Option<time_t>, usize) {
|
||||||
|
use uucore::utmpx::*;
|
||||||
|
|
||||||
|
let mut nusers = 0;
|
||||||
|
let mut boot_time = None;
|
||||||
|
|
||||||
|
for line in Utmpx::iter_all_records() {
|
||||||
|
match line.record_type() {
|
||||||
|
USER_PROCESS => nusers += 1,
|
||||||
|
BOOT_TIME => {
|
||||||
|
let dt = line.login_time();
|
||||||
|
if dt.unix_timestamp() > 0 {
|
||||||
|
boot_time = Some(dt.unix_timestamp() as time_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(boot_time, nusers)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn process_utmpx() -> (Option<time_t>, usize) {
|
||||||
|
(None, 0) // TODO: change 0 to number of users
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_nusers(nusers: usize) {
|
||||||
|
match nusers.cmp(&1) {
|
||||||
|
std::cmp::Ordering::Equal => print!("1 user, "),
|
||||||
|
std::cmp::Ordering::Greater => print!("{nusers} users, "),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_time() {
|
||||||
|
let local_time = Local::now().time();
|
||||||
|
|
||||||
|
print!(" {} ", local_time.format("%H:%M:%S"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn get_uptime(boot_time: Option<time_t>) -> i64 {
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
let mut proc_uptime_s = String::new();
|
||||||
|
|
||||||
|
let proc_uptime = File::open("/proc/uptime")
|
||||||
|
.ok()
|
||||||
|
.and_then(|mut f| f.read_to_string(&mut proc_uptime_s).ok())
|
||||||
|
.and_then(|_| proc_uptime_s.split_whitespace().next())
|
||||||
|
.and_then(|s| s.split('.').next().unwrap_or("0").parse().ok());
|
||||||
|
|
||||||
|
proc_uptime.unwrap_or_else(|| match boot_time {
|
||||||
|
Some(t) => {
|
||||||
|
let now = Local::now().timestamp();
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
let boottime: i64 = t;
|
||||||
|
#[cfg(not(target_pointer_width = "64"))]
|
||||||
|
let boottime: i64 = t.into();
|
||||||
|
now - boottime
|
||||||
|
}
|
||||||
|
None => -1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
|
||||||
|
unsafe { GetTickCount() as i64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_uptime(upsecs: i64) {
|
||||||
|
let updays = upsecs / 86400;
|
||||||
|
let uphours = (upsecs - (updays * 86400)) / 3600;
|
||||||
|
let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
|
||||||
|
match updays.cmp(&1) {
|
||||||
|
std::cmp::Ordering::Equal => print!("up {updays:1} day, {uphours:2}:{upmins:02}, "),
|
||||||
|
std::cmp::Ordering::Greater => {
|
||||||
|
print!("up {updays:1} days, {uphours:2}:{upmins:02}, ");
|
||||||
|
}
|
||||||
|
_ => print!("up {uphours:2}:{upmins:02}, "),
|
||||||
|
};
|
||||||
|
}
|
|
@ -3,15 +3,11 @@
|
||||||
// For the full copyright and license information, please view the LICENSE
|
// For the full copyright and license information, please view the LICENSE
|
||||||
// file that was distributed with this source code.
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore (ToDO) getloadavg upsecs updays nusers loadavg boottime uphours upmins
|
|
||||||
|
|
||||||
use chrono::{Local, TimeZone, Utc};
|
|
||||||
use clap::{crate_version, Arg, ArgAction, Command};
|
use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
|
|
||||||
use uucore::libc::time_t;
|
|
||||||
use uucore::{format_usage, help_about, help_usage};
|
use uucore::{format_usage, help_about, help_usage};
|
||||||
|
|
||||||
use uucore::error::{UResult, USimpleError};
|
mod platform;
|
||||||
|
|
||||||
const ABOUT: &str = help_about!("uptime.md");
|
const ABOUT: &str = help_about!("uptime.md");
|
||||||
const USAGE: &str = help_usage!("uptime.md");
|
const USAGE: &str = help_usage!("uptime.md");
|
||||||
|
@ -19,40 +15,8 @@ pub mod options {
|
||||||
pub static SINCE: &str = "since";
|
pub static SINCE: &str = "since";
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
use uucore::libc::getloadavg;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
extern "C" {
|
|
||||||
fn GetTickCount() -> uucore::libc::uint32_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
use platform::uumain;
|
||||||
let matches = uu_app().try_get_matches_from(args)?;
|
|
||||||
|
|
||||||
let (boot_time, user_count) = process_utmpx();
|
|
||||||
let uptime = get_uptime(boot_time);
|
|
||||||
if uptime < 0 {
|
|
||||||
Err(USimpleError::new(1, "could not retrieve system uptime"))
|
|
||||||
} else {
|
|
||||||
if matches.get_flag(options::SINCE) {
|
|
||||||
let initial_date = Local
|
|
||||||
.timestamp_opt(Utc::now().timestamp() - uptime, 0)
|
|
||||||
.unwrap();
|
|
||||||
println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time();
|
|
||||||
let upsecs = uptime;
|
|
||||||
print_uptime(upsecs);
|
|
||||||
print_nusers(user_count);
|
|
||||||
print_loadavg();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uu_app() -> Command {
|
pub fn uu_app() -> Command {
|
||||||
Command::new(uucore::util_name())
|
Command::new(uucore::util_name())
|
||||||
|
@ -68,115 +32,3 @@ pub fn uu_app() -> Command {
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
fn print_loadavg() {
|
|
||||||
use uucore::libc::c_double;
|
|
||||||
|
|
||||||
let mut avg: [c_double; 3] = [0.0; 3];
|
|
||||||
let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };
|
|
||||||
|
|
||||||
if loads == -1 {
|
|
||||||
println!();
|
|
||||||
} else {
|
|
||||||
print!("load average: ");
|
|
||||||
for n in 0..loads {
|
|
||||||
print!(
|
|
||||||
"{:.2}{}",
|
|
||||||
avg[n as usize],
|
|
||||||
if n == loads - 1 { "\n" } else { ", " }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn print_loadavg() {
|
|
||||||
// XXX: currently this is a noop as Windows does not seem to have anything comparable to
|
|
||||||
// getloadavg()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
fn process_utmpx() -> (Option<time_t>, usize) {
|
|
||||||
use uucore::utmpx::*;
|
|
||||||
|
|
||||||
let mut nusers = 0;
|
|
||||||
let mut boot_time = None;
|
|
||||||
|
|
||||||
for line in Utmpx::iter_all_records() {
|
|
||||||
match line.record_type() {
|
|
||||||
USER_PROCESS => nusers += 1,
|
|
||||||
BOOT_TIME => {
|
|
||||||
let dt = line.login_time();
|
|
||||||
if dt.unix_timestamp() > 0 {
|
|
||||||
boot_time = Some(dt.unix_timestamp() as time_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(boot_time, nusers)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn process_utmpx() -> (Option<time_t>, usize) {
|
|
||||||
(None, 0) // TODO: change 0 to number of users
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_nusers(nusers: usize) {
|
|
||||||
match nusers.cmp(&1) {
|
|
||||||
std::cmp::Ordering::Equal => print!("1 user, "),
|
|
||||||
std::cmp::Ordering::Greater => print!("{nusers} users, "),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_time() {
|
|
||||||
let local_time = Local::now().time();
|
|
||||||
|
|
||||||
print!(" {} ", local_time.format("%H:%M:%S"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
fn get_uptime(boot_time: Option<time_t>) -> i64 {
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
let mut proc_uptime_s = String::new();
|
|
||||||
|
|
||||||
let proc_uptime = File::open("/proc/uptime")
|
|
||||||
.ok()
|
|
||||||
.and_then(|mut f| f.read_to_string(&mut proc_uptime_s).ok())
|
|
||||||
.and_then(|_| proc_uptime_s.split_whitespace().next())
|
|
||||||
.and_then(|s| s.split('.').next().unwrap_or("0").parse().ok());
|
|
||||||
|
|
||||||
proc_uptime.unwrap_or_else(|| match boot_time {
|
|
||||||
Some(t) => {
|
|
||||||
let now = Local::now().timestamp();
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
let boottime: i64 = t;
|
|
||||||
#[cfg(not(target_pointer_width = "64"))]
|
|
||||||
let boottime: i64 = t.into();
|
|
||||||
now - boottime
|
|
||||||
}
|
|
||||||
None => -1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn get_uptime(_boot_time: Option<time_t>) -> i64 {
|
|
||||||
unsafe { GetTickCount() as i64 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_uptime(upsecs: i64) {
|
|
||||||
let updays = upsecs / 86400;
|
|
||||||
let uphours = (upsecs - (updays * 86400)) / 3600;
|
|
||||||
let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
|
|
||||||
match updays.cmp(&1) {
|
|
||||||
std::cmp::Ordering::Equal => print!("up {updays:1} day, {uphours:2}:{upmins:02}, "),
|
|
||||||
std::cmp::Ordering::Greater => {
|
|
||||||
print!("up {updays:1} days, {uphours:2}:{upmins:02}, ");
|
|
||||||
}
|
|
||||||
_ => print!("up {uphours:2}:{upmins:02}, "),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue