kanit

Toy init system
Log | Files | Refs | README | LICENSE

clock.rs (3627B)


      1 use std::path::Path;
      2 
      3 use async_process::{Command, Stdio};
      4 use async_trait::async_trait;
      5 use futures_lite::StreamExt;
      6 use log::{info, warn};
      7 
      8 use kanit_common::error::{Context, ErrorKind, Result, StaticError};
      9 use kanit_unit::{Dependencies, Unit};
     10 
     11 use crate::oneshot::Modules;
     12 use crate::unit_name;
     13 
     14 // chronos <3 - Sparkles
     15 pub struct Clock;
     16 
     17 fn check_rtc(name: &Path) -> bool {
     18     let f_str = name.to_string_lossy();
     19 
     20     if f_str == "/dev/rtc"
     21         || f_str.starts_with("/dev/rtc")
     22             && f_str
     23                 .chars()
     24                 .nth(8)
     25                 .map(|c| c.is_ascii_digit())
     26                 .unwrap_or(false)
     27     {
     28         return true;
     29     }
     30 
     31     false
     32 }
     33 
     34 impl Clock {
     35     async fn rtc_exists() -> Result<bool> {
     36         Ok(async_fs::read_dir("/dev")
     37             .await
     38             .context("failed to open /dev")?
     39             .filter_map(|res| res.map(|e| e.path()).ok())
     40             .find(|p| check_rtc(p))
     41             .await
     42             .is_some())
     43     }
     44 }
     45 
     46 const RTC_MODS: [&str; 3] = ["rtc-cmos", "rtc", "genrtc"];
     47 
     48 #[async_trait]
     49 impl Unit for Clock {
     50     unit_name!("clock");
     51 
     52     fn dependencies(&self) -> Dependencies {
     53         Dependencies::new().want(Modules.name()).clone()
     54     }
     55 
     56     async fn start(&mut self) -> Result<()> {
     57         info!("setting time with hardware clock");
     58 
     59         if !Self::rtc_exists().await? {
     60             let mut loaded = false;
     61 
     62             for module in RTC_MODS {
     63                 let succ = Command::new("modprobe")
     64                     .args(["-q", module])
     65                     .spawn()
     66                     .context("failed to spawn modprobe")?
     67                     .status()
     68                     .await
     69                     .context("failed to wait")?
     70                     .success();
     71 
     72                 if succ && Self::rtc_exists().await? {
     73                     warn!("module {module} should be built in or configured to load");
     74                     loaded = true;
     75                     break;
     76                 }
     77             }
     78 
     79             if !loaded {
     80                 Err(StaticError("failed to set hardware clock")).kind(ErrorKind::Recoverable)?;
     81             }
     82         }
     83 
     84         // todo; UTC
     85 
     86         let succ = Command::new("hwclock")
     87             .args(["--systz", "--localtime"])
     88             .stderr(Stdio::piped())
     89             .stdout(Stdio::piped())
     90             .spawn()
     91             .context("failed to spawn hwclock")?
     92             .output()
     93             .await
     94             .context("failed to wait")?
     95             .stderr
     96             .is_empty();
     97 
     98         if !succ {
     99             warn!("failed to set system timezone");
    100         }
    101 
    102         let succ = Command::new("hwclock")
    103             .args(["--hctosys", "--localtime"])
    104             .stderr(Stdio::piped())
    105             .stdout(Stdio::piped())
    106             .spawn()
    107             .context("failed to spawn hwclock")?
    108             .output()
    109             .await
    110             .context("failed to wait")?
    111             .stderr
    112             .is_empty();
    113 
    114         if !succ {
    115             warn!("failed to set system time");
    116         }
    117 
    118         Ok(())
    119     }
    120 
    121     async fn stop(&mut self) -> Result<()> {
    122         info!("setting hardware clock with system time");
    123 
    124         let succ = Command::new("hwclock")
    125             .args(["--systohc", "--localtime"])
    126             .stderr(Stdio::piped())
    127             .stdout(Stdio::piped())
    128             .spawn()
    129             .context("failed to spawn hwclock")?
    130             .output()
    131             .await
    132             .context("failed to wait")?
    133             .stderr
    134             .is_empty();
    135 
    136         if !succ {
    137             warn!("failed to set hardware clock");
    138         }
    139 
    140         Ok(())
    141     }
    142 }