#[cfg(not(target_os = "haiku"))]
use std::ptr;
use std::{io, mem::MaybeUninit};
use libc::localtime_r;
use super::{Time, TimeVal, Tm};
#[cfg(not(target_os = "haiku"))]
#[inline]
pub fn set_time_of_day(timeval: TimeVal) -> io::Result<()> {
let result = unsafe { libc::settimeofday(&timeval as *const TimeVal, ptr::null()) };
match result {
0 => Ok(()),
_ => Err(io::Error::last_os_error()),
}
}
#[inline]
pub fn local_time(timestamp: i64) -> io::Result<Tm> {
extern "C" {
fn tzset();
}
let mut tm = MaybeUninit::uninit();
unsafe { tzset() };
let tm_ptr = unsafe { localtime_r(&(timestamp as Time), tm.as_mut_ptr()) };
if tm_ptr.is_null() { Err(io::Error::last_os_error()) } else { Ok(unsafe { tm.assume_init() }) }
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Io(io::Error),
Time(std::time::SystemTimeError),
TargetNotSupported,
}
impl std::error::Error for Error {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(err) => Some(err),
Self::Time(err) => Some(err),
Self::TargetNotSupported => None,
}
}
}
impl std::fmt::Display for Error {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(err) => write!(f, "{}", err),
Self::Time(err) => write!(f, "{}", err),
Self::TargetNotSupported => write!(f, "This platform are not supported"),
}
}
}
impl From<io::Error> for Error {
#[inline]
fn from(err: io::Error) -> Self {
Self::Io(err)
}
}
impl From<std::time::SystemTimeError> for Error {
#[inline]
fn from(err: std::time::SystemTimeError) -> Self {
Self::Time(err)
}
}
#[cfg(not(target_os = "fuchsia"))]
#[cfg_attr(feature = "inline-more", inline)]
pub fn boottime() -> Result<TimeVal, Error> {
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
let mut bootime = TimeVal { tv_sec: 0, tv_usec: 0 };
#[cfg(target_os = "linux")]
{
use std::time::SystemTime;
let string = std::fs::read_to_string("/proc/uptime")?;
let mut secs =
string.trim().split_whitespace().take(2).filter_map(|val| val.parse::<f64>().ok());
let sec = secs.next().unwrap() as libc::time_t;
let micro = secs.next().unwrap() as libc::suseconds_t;
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
bootime.tv_sec = now.as_secs() as libc::time_t - sec;
bootime.tv_usec = micro;
Ok(bootime)
}
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "macos"
))]
{
static CTL_KERN: libc::c_int = 1;
static KERN_BOOTTIME: libc::c_int = 21;
let mut syscall = [CTL_KERN, KERN_BOOTTIME];
let mut size: libc::size_t = std::mem::size_of_val(&bootime) as libc::size_t;
let res = unsafe {
libc::sysctl(
syscall.as_mut_ptr(),
2,
&mut bootime as *mut libc::timeval as *mut libc::c_void,
&mut size,
ptr::null_mut(),
0,
)
};
match res {
0 => Ok(bootime),
_ => Err(Error::Io(io::Error::last_os_error())),
}
}
#[cfg(target_os = "haiku")]
{
Err(Error::TargetNotSupported)
}
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
{
Err(Error::TargetNotSupported)
}
}
#[cfg(not(target_os = "fuchsia"))]
#[cfg_attr(feature = "inline-more", inline)]
pub fn uptime() -> Result<TimeVal, Error> {
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
let mut uptime = TimeVal { tv_sec: 0, tv_usec: 0 };
#[cfg(target_os = "linux")]
{
let string = std::fs::read_to_string("/proc/uptime")?;
let mut secs =
string.trim().split_whitespace().take(2).filter_map(|val| val.parse::<f64>().ok());
uptime.tv_sec = secs.next().unwrap() as libc::time_t;
uptime.tv_usec = secs.next().unwrap() as libc::suseconds_t;
Ok(uptime)
}
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "macos"
))]
{
use std::time::SystemTime;
static CTL_KERN: libc::c_int = 1;
static KERN_BOOTTIME: libc::c_int = 21;
let mut syscall = [CTL_KERN, KERN_BOOTTIME];
let mut size: libc::size_t = std::mem::size_of_val(&uptime) as libc::size_t;
let res = unsafe {
libc::sysctl(
syscall.as_mut_ptr(),
2,
&mut uptime as *mut libc::timeval as *mut libc::c_void,
&mut size,
ptr::null_mut(),
0,
)
};
match res {
0 => {
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
let now = now.as_secs();
uptime.tv_sec = now as i64 - uptime.tv_sec;
Ok(uptime)
},
_ => Err(Error::Io(io::Error::last_os_error())),
}
}
#[cfg(target_os = "haiku")]
{
use libc::system_time;
const USECS_PER_SEC: i64 = 1_000_000;
let uptime_usecs = unsafe { system_time() };
let mut uptime_secs = uptime_usecs / USECS_PER_SEC;
let uptime_usecs = uptime_usecs % USECS_PER_SEC;
if uptime_usecs >= (USECS_PER_SEC / 2) {
uptime_secs += 1;
}
uptime.tv_sec = uptime_secs;
uptime.tv_usec = uptime_usecs as _;
Ok(uptime)
}
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
{
Err(Error::TargetNotSupported)
}
}