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
Generated
+165
View File
@@ -125,6 +125,28 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
version = "0.5.0"
@@ -138,7 +160,21 @@ dependencies = [
"clap",
"nix",
"regex",
"serde",
"serde_json",
"signal-hook",
"time-format",
"toml",
]
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
@@ -147,6 +183,12 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "libc"
version = "0.2.189"
@@ -224,6 +266,78 @@ version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "serde_spanned"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
dependencies = [
"serde_core",
]
[[package]]
name = "signal-hook"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "strsim"
version = "0.11.1"
@@ -247,6 +361,45 @@ version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caa08af685f978227b475da86d38312cd1acd5024338bf53a1ab9a799219507d"
[[package]]
name = "toml"
version = "1.1.4+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
dependencies = [
"indexmap",
"serde_core",
"serde_spanned",
"toml_datetime",
"toml_parser",
"toml_writer",
"winnow",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
version = "1.1.3+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
[[package]]
name = "unicode-ident"
version = "1.0.24"
@@ -273,3 +426,15 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "winnow"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+5 -1
View File
@@ -7,4 +7,8 @@ edition = "2024"
clap = { version = "4.6", features = ["derive"] }
nix = { version = "0", features = ["user"] }
regex = "1"
time-format = "1.2.2"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.151"
signal-hook = "0.4"
time-format = "1.2"
toml = "1.1.4"
+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).
}
}