use crate::ProbeResult;
use chrono::{DateTime, Duration, Utc};
use std::io;
#[derive(Debug)]
pub enum SyncError {
NotSupported,
Permission(io::Error),
Sys(io::Error),
}
pub fn sync_from_probe(probe: &ProbeResult, dry_run: bool) -> Result<(), SyncError> {
let offset_us = (probe.offset_ms * 1000.0).round() as i64; let target = Utc::now() + Duration::microseconds(offset_us);
step_to_utc(&target, dry_run)
}
#[allow(clippy::needless_return)]
pub fn get_sys_permissions() -> bool {
#[cfg(unix)]
unsafe {
if libc::geteuid() != 0 {
return false;
}
}
return true;
}
#[cfg(unix)]
fn step_to_utc(utc: &DateTime<Utc>, dry_run: bool) -> Result<(), SyncError> {
use libc::{CLOCK_REALTIME, clock_settime, timespec};
if dry_run {
return Ok(());
}
let ts = timespec {
tv_sec: utc.timestamp() as libc::time_t,
tv_nsec: utc.timestamp_subsec_nanos() as libc::c_long,
};
let rc = unsafe { clock_settime(CLOCK_REALTIME, &ts as *const timespec) };
if rc != 0 {
let e = std::io::Error::last_os_error();
return Err(match e.raw_os_error() {
Some(code) if code == libc::EPERM || code == libc::EACCES => SyncError::Permission(e),
_ => SyncError::Sys(e),
});
}
Ok(())
}
#[cfg(not(unix))]
fn step_to_utc(_: &DateTime<Utc>, _: bool) -> Result<(), SyncError> {
Err(SyncError::NotSupported)
}