Saving status, lots of development.

This commit is contained in:
2026-08-21 20:58:06 +02:00
parent 2b7a8ea8ec
commit 225c3f48b7
7 changed files with 589 additions and 21 deletions
+122
View File
@@ -0,0 +1,122 @@
// <hive-up - update program fot Kira Linux.>
// Copyright (C) <2026> <Kira Foundation>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
hive-up daemon logic
*/
use std::fs;
use std::process::Command;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use time_format;
use crate::hive_config::HiveConfig;
use crate::hive_db;
use crate::hive_system;
#[derive(Debug)]
pub enum DaemonError {
IoError(std::io::Error),
DBError(hive_db::DBError),
ExecCommandError(hive_system::ExecCommandError),
TimestampError,
}
// 2. Implement From for each wrapped error type
impl From<std::io::Error> for DaemonError {
fn from(err: std::io::Error) -> Self {
DaemonError::IoError(err)
}
}
impl From<hive_db::DBError> for DaemonError {
fn from(err: hive_db::DBError) -> Self {
DaemonError::DBError(err)
}
}
impl From<hive_system::ExecCommandError> for DaemonError {
fn from(err: hive_system::ExecCommandError) -> Self {
DaemonError::ExecCommandError(err)
}
}
impl std::fmt::Display for DaemonError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DaemonError::IoError(e) => write!(f, "IO Error: {}", e),
DaemonError::DBError(e) => {
write!(f, "Database error: {}", e)
},
DaemonError::ExecCommandError(e) => {
write!(f, "Exec Command Error: {}", e)
},
DaemonError::TimestampError => write!(f, "Timestamp Error"),
}
}
}
// Implement std::error::Error
impl std::error::Error for DaemonError {}
fn get_timestamp_sec() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs()
}
pub fn run(
config: HiveConfig,
term_flag: Arc<AtomicBool>,
reload_flag: Arc<AtomicBool>,
) -> Result<(), DaemonError> {
let duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let mut bzz_db = hive_db::read_db()?;
//duration.as_secs()
let keep_going = true;
//last_check.
while keep_going {
thread::sleep(Duration::from_secs(1));
// if updates check is turned on
if config.update.updates_check_interval != 0 {
let timestamp = get_timestamp_sec();
let hours_since_update_check = timestamp
.checked_sub(bzz_db.last_update_check)
.ok_or(DaemonError::TimestampError)?
/ 3600;
if hours_since_update_check > config.update.updates_check_interval {
// perform update check
let packages_num = hive_system::check_updates()?;
// updating las tupdate timestamp in db
bzz_db.last_update_check = get_timestamp_sec();
hive_db::write_db(&bzz_db)?;
}
}
}
Ok(())
}
+109
View File
@@ -0,0 +1,109 @@
// <hive-up - update program fot Kira Linux.>
// Copyright (C) <2026> <Kira Foundation>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
Functions fot system interaction
*/
use serde::{Serialize, Deserialize};
use std::{fs, io};
use toml;
#[derive(Debug, Serialize, Deserialize)]
pub struct HiveConfig {
// Matches [kernel] in TOML
pub kernel: KernelConfig,
// Updates process config
pub update: UpdateConfig,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct KernelConfig {
/// kernel cmd string that will be passed as kernel boot parameter.
cmd: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateConfig {
/// Interval between updates check in hours. 0 - no auto check for updates.
pub updates_check_interval: u64,
/// Tells hive-up to automatically download updates when awailable.
pub download_updates: bool,
/// Tells hive-up to automatically perform updates during system reboot.
pub auto_update: bool,
}
#[derive(Debug)]
pub enum ConfigError {
IoError(std::io::Error),
TomlParseError(toml::de::Error),
TomlSerError(toml::ser::Error),
}
// 2. Implement From for each wrapped error type
impl From<std::io::Error> for ConfigError {
fn from(err: std::io::Error) -> Self {
ConfigError::IoError(err)
}
}
impl From<toml::de::Error> for ConfigError {
fn from(err: toml::de::Error) -> Self {
ConfigError::TomlParseError(err)
}
}
impl From<toml::ser::Error> for ConfigError {
fn from(err: toml::ser::Error) -> Self {
ConfigError::TomlSerError(err)
}
}
impl std::fmt::Display for ConfigError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ConfigError::IoError(e) => write!(f, "IO Error: {}", e),
ConfigError::TomlParseError(e) => {
write!(f, "TOML parse error: {}", e)
},
ConfigError::TomlSerError(e) => {
write!(f, "TOML serialize error: {}", e)
},
}
}
}
// Implement std::error::Error
impl std::error::Error for ConfigError {}
pub fn read_config(conf_file: &str) -> Result<HiveConfig, ConfigError> {
let file_content = fs::read_to_string(conf_file)?;
let config:HiveConfig = toml::from_str(&file_content)?;
Ok(config)
}
pub fn change_updates_check_interval(conf_file: &str, new_interval: u64) -> Result<HiveConfig, ConfigError> {
let mut config: HiveConfig = read_config(conf_file)?;
config.update.updates_check_interval = new_interval;
let conf_str = toml::to_string_pretty(&config)?;
fs::write(conf_file, conf_str)?;
Ok(config)
}
+112
View File
@@ -0,0 +1,112 @@
// <hive-up - update program fot Kira Linux.>
// Copyright (C) <2026> <Kira Foundation>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
Functions for reading and writyng daemon and updates state
*/
const DB_PATH: &str = "/var/lib/hive-up/hyve-db.json";
use serde::{Deserialize, Serialize};
use std::fs;
#[derive(Debug)]
pub enum DBError {
IoError(std::io::Error),
JsonError(serde_json::Error),
}
// 2. Implement From for each wrapped error type
impl From<std::io::Error> for DBError {
fn from(err: std::io::Error) -> Self {
DBError::IoError(err)
}
}
impl From<serde_json::Error> for DBError {
fn from(err: serde_json::Error) -> Self {
DBError::JsonError(err)
}
}
impl std::fmt::Display for DBError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DBError::IoError(e) => write!(f, "IO Error: {}", e),
DBError::JsonError(e) => {
write!(f, "Json parse error: {}", e)
}
}
}
}
// Implement std::error::Error
impl std::error::Error for DBError {}
#[derive(Serialize, Deserialize, Debug)]
pub struct HiveDb {
pub last_update_check: u64,
pub update_sucess_status: bool,
pub last_update_timestamp: String,
}
pub fn read_db() -> Result<HiveDb, DBError> {
let file_content = fs::read_to_string(DB_PATH)?;
let db: HiveDb = serde_json::from_str(&file_content)?;
Ok(db)
}
pub fn write_db(db: &HiveDb) -> Result<(), DBError> {
let serialized_db = serde_json::to_string(db)?;
fs::write(DB_PATH, serialized_db)?;
Ok(())
}
///
/// writes new last update check time to db
/// and returns old db value on success
///
pub fn update_last_check_update_time(new_timestamp: u64) -> Result<u64, DBError> {
let mut db = read_db()?;
let old_value = db.last_update_check;
db.last_update_check = new_timestamp;
write_db(&db)?;
Ok(old_value)
}
///
/// writes new update_status to db
/// and returns old db value on success
///
pub fn update_update_status(sucess_status: bool) -> Result<bool, DBError> {
let mut db = read_db()?;
let old_value = db.update_sucess_status;
db.update_sucess_status = sucess_status;
write_db(&db)?;
Ok(old_value)
}
///
/// writes new last_update_timestamp to db
/// and returns old value on success
///
pub fn update_last_update_timestamp(new_timestamp: String) -> Result<String, DBError> {
let mut db = read_db()?;
let old_value = db.last_update_timestamp;
db.last_update_timestamp = new_timestamp;
write_db(&db)?;
Ok(old_value)
}
+22 -4
View File
@@ -1,4 +1,4 @@
// <kira-update - update program fot Kira Linux.>
// <hive-up - update program fot Kira Linux.>
// Copyright (C) <2026> <Kira Foundation>
// This program is free software: you can redistribute it and/or modify
@@ -148,14 +148,32 @@ pub fn check_updates() -> Result<usize, ExecCommandError> {
}
///
/// bcachefs subvolume snapshot / /snap1
/// sudo pacman -Suw --noconfirm --noprogressbar
/// Dopwnload updates (need to check for updates first)
///
pub fn download_updates() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"])
}
///
/// sudo pacman -Su --noconfirm --noprogressbar
/// Perform updates
///
pub fn do_updates() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"])
}
///
/// bcachefs subvolume snapshot -r / /snap1
/// -r creates read only snapshot
/// returns snapshot name on sucess
pub fn snapshoot_root() -> Result<String, ExecCommandError> {
pub fn snapshot_root() -> Result<String, ExecCommandError> {
let ts = time_format::now().unwrap();
let local_time = time_format::strftime_local("%Y-%m-%dT%H:%M:%S", ts).unwrap();
let snapshot_name = format!("{}/bzz-{}",SNAPS_DIR,local_time);
exec_command("bcachefs", &vec!["subvolume", "snapshot", "/", &snapshot_name])?;
exec_command("bcachefs", &vec!["subvolume", "snapshot", "-r", "/", &snapshot_name])?;
Ok(snapshot_name)
}
+54 -16
View File
@@ -14,14 +14,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use clap::{Args, Parser};
use signal_hook::{consts::SIGINT, iterator::Signals};
use std::{error::Error, thread, time::Duration};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use clap::{Parser, Args};
mod hive_system;
use hive_system::ExecCommandError;
mod nyan_system;
use nyan_system::ExecCommandError;
mod hive_config;
use hive_config::{HiveConfig, KernelConfig};
mod hive_db;
const CONFIG_PATH_STR: &str = "kira_config.toml";
mod daemon;
const CONFIG_PATH_STR: &str = "/etc/hive_up.toml";
// Define the mutually exclusive group
#[derive(Args, Debug)]
@@ -34,10 +43,14 @@ struct HiveUpMode {
/// Perform system update
#[arg(long)]
update: bool,
/// Try to rollback unsuccessful update if any
/// Boot update
#[arg(long)]
fix: bool,
boot_update: bool,
/// Run hive-up in daemon mode
#[arg(long)]
daemon: bool,
}
/// Update program fot Kira Linux :3
@@ -50,28 +63,53 @@ struct Cli {
}
fn main() {
// registering signals handling
let term_flag: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
let reload_flag = Arc::new(AtomicBool::new(false));
signal_hook::flag::register(signal_hook::consts::SIGTERM, Arc::clone(&term_flag)).unwrap();
signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&term_flag)).unwrap();
signal_hook::flag::register(signal_hook::consts::SIGHUP, Arc::clone(&reload_flag)).unwrap();
let args = Cli::parse();
if !nyan_system::check_if_run_as_root() {
if !hive_system::check_if_run_as_root() {
eprintln!("Error: This program requires root privileges.");
std::process::exit(1);
}
// read config
let hive_config = match hive_config::read_config(CONFIG_PATH_STR) {
Ok(conf) => conf,
Err(ex) => {
println!("Error reading \"{}\" hive-up config file: {}", CONFIG_PATH_STR, ex);
std::process::exit(2);
}
};
// Logic to check which one was set
if args.mode.check {
match nyan_system::check_updates() {
Ok(up_num) => println!("Updates awailable: {}", up_num),
Err(ex) => println!("Error: {}", ex)
}
match hive_system::check_updates() {
Ok(up_num) => println!("Updates awailable: {}", up_num),
Err(ex) => println!("Error: {}", ex),
}
} else if args.mode.boot_update {
// update boot
println!("update mode");
} else if args.mode.update {
println!("update mode");
} else if args.mode.fix {
let snaps = nyan_system::list_bzzpss_snaps().unwrap();
} else if args.mode.daemon {
let snaps = hive_system::list_bzzpss_snaps().unwrap();
println!("Snaps num: {}", snaps.len());
for sn in snaps {
println!("Snap: {}", sn);
}
}
while !term_flag.load(Ordering::Relaxed) {
// Do some time-limited stuff here
// (if this could block forever, then there's no guarantee the signal will have any
// effect).
}
}