Compare commits

..
3 Commits
11 changed files with 99 additions and 953 deletions
Generated
+5 -181
View File
@@ -52,26 +52,11 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.13.1" version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -125,39 +110,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.5" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@@ -174,35 +132,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.17.1" version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heapless"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version",
"serde",
"spin",
"stable_deref_trait",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@@ -211,14 +146,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hive-up" name = "hive-up"
version = "0.1.2" version = "0.2.0"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
"postcard",
"regex-lite", "regex-lite",
"serde", "serde",
"serde_json",
"signal-hook", "signal-hook",
"time-format", "time-format",
"toml", "toml",
@@ -240,33 +173,12 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.189" version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.31.3" version = "0.31.3"
@@ -285,19 +197,6 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"heapless",
"serde",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.107" version = "1.0.107"
@@ -322,27 +221,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.229" version = "1.0.229"
@@ -373,19 +251,6 @@ dependencies = [
"syn", "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]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "1.1.1" version = "1.1.1"
@@ -415,21 +280,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "spin"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@@ -447,26 +297,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "thiserror"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "time-format" name = "time-format"
version = "1.2.3" version = "1.2.3"
@@ -475,9 +305,9 @@ checksum = "fb54c799611991d3d4a66fee3ff17b9f600c2a0f8c0d34e8209dbd153ff0a87b"
[[package]] [[package]]
name = "toml" name = "toml"
version = "1.1.5+spec-1.1.0" version = "1.1.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12c0ba9680044b4ce98d391a62094047eada0d64860b80166c39f4a6b5640785" checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde_core", "serde_core",
@@ -544,9 +374,3 @@ name = "winnow"
version = "1.0.4" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
+1 -3
View File
@@ -1,15 +1,13 @@
[package] [package]
name = "hive-up" name = "hive-up"
version = "0.1.2" version = "0.2.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
clap = { version = "4.6", features = ["derive"] } clap = { version = "4.6", features = ["derive"] }
nix = { version = "0", features = ["user"] } nix = { version = "0", features = ["user"] }
postcard = { version = "1.1", features = ["use-std"] }
regex-lite = "0.1" regex-lite = "0.1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1.0"
signal-hook = "0.4" signal-hook = "0.4"
time-format = "1.2" time-format = "1.2"
toml = "1.1" toml = "1.1"
+2 -1
View File
@@ -9,4 +9,5 @@ Target = linux-kira-server-lts
[Action] [Action]
Description = Running custom command after kernel update Description = Running custom command after kernel update
When = PostTransaction When = PostTransaction
Exec = /usr/bin/hive-up cli --update-boot Exec = /usr/bin/hive-up boot update
-6
View File
@@ -1,6 +0,0 @@
type = process
command = /usr/bin/hive-up daemon
stop-command = /usr/bin/hive-up cli --upgrade
depends-on = network.target
logfile = /var/log/dinit/hive-up.log
log-type = file
-7
View File
@@ -1,11 +1,4 @@
# Section (Table) headers # Section (Table) headers
[update]
# Interval between updates check in hours. 0 - no auto check for updates.
check_interval = 58
# Tells hive-up to automatically download updates when awailable.
download_updates = true
# Tells hive-up to automatically perform updates during system reboot
auto_update = false
# In [kernel] section user may specify kernel cmd # In [kernel] section user may specify kernel cmd
# [kernel] # [kernel]
-264
View File
@@ -1,264 +0,0 @@
// <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::os::unix::net::UnixDatagram;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::hive_config;
use crate::hive_config::HiveConfig;
use crate::hive_db::{self, HiveDb};
use crate::hive_intercom::{self, BzzReq, BzzResp, IntercomError};
use crate::hive_system;
#[derive(Debug)]
pub enum DaemonError {
IoError(std::io::Error),
DBError(hive_db::DBError),
ConfigError(hive_config::ConfigError),
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_config::ConfigError> for DaemonError {
fn from(err: hive_config::ConfigError) -> Self {
DaemonError::ConfigError(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::ConfigError(e) => write!(f, "Config 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()
}
/// bloking function. Bloaks for configured socker recv timeout
fn process_remoute(
bzz_db: &mut HiveDb,
listening_socket: &UnixDatagram,
recv_buf: &mut [u8],
) -> Result<(), DaemonError> {
// waiting on socket recv_from untill timeout (also using this as a timer)
match hive_intercom::socket_recv(&listening_socket, recv_buf) {
// we get some request to process
Ok((bzz_req, client_addr)) => {
match bzz_req {
// return awailable updates number
BzzReq::UpdatesAvailable => {
let resp = BzzResp::UpdatesAvailable(bzz_db.updates_available);
if let Err(ex) =
hive_intercom::socket_send(&listening_socket, &client_addr, resp)
{
println!("Error while ansvering cli request: {}", ex);
}
}
// we should apply updates if any on reboot
BzzReq::ScheduleUpdate => {
// but only if we have actually any updates
if bzz_db.updates_available > 0 {
bzz_db.update_on_reboot = true;
// keep it simple Kira
// lets just return err from the loop if something wrong with db
hive_db::write_db(&bzz_db)?;
// signal remoute that evertyhing go OK
if let Err(ex) = hive_intercom::socket_send(
&listening_socket,
&client_addr,
BzzResp::Finish,
) {
println!("Error while ansvering cli request: {}", ex);
}
}
}
BzzReq::CheckForUpdates => {
let resp = BzzResp::Working(1);
if let Err(ex) =
hive_intercom::socket_send(&listening_socket, &client_addr, resp)
{
println!("Error while ansvering cli request: {}", ex);
} else {
// perform update check
println!("Cheking for updates...");
// now that may fail because of bad internet and idealy we
// want to just log error and retry in other time
bzz_db.updates_available = match hive_system::check_updates() {
Ok(updates_num) => updates_num,
Err(ex) => {
println!("Error while shecking for updates: {}", ex);
0u32
}
};
hive_db::write_db(&bzz_db)?;
println!(
"Found {} packages that needs to be updated.",
bzz_db.updates_available
);
// send evailable updates numbet to client
let resp = BzzResp::UpdatesAvailable(bzz_db.updates_available);
if let Err(ex) =
hive_intercom::socket_send(&listening_socket, &client_addr, resp)
{
println!("Error while ansvering cli request: {}", ex);
}
}
}
}
Ok(())
}
// if time out - do nothing
Err(IntercomError::Timeout) => Ok(()),
// if some actual IO error then return it
Err(IntercomError::IoError(ex)) => Err(ex.into()),
// if other kinds of errors - log and continue
Err(ex) => {
println!("Got error while listenin to unix socket: {}", ex);
print!("Sleeping for 1 secong and continue...");
thread::sleep(Duration::from_secs(1));
Ok(())
}
}
}
// doing what daemons usually beezz
fn do_local_work(config: &HiveConfig, bzz_db: &mut HiveDb) -> Result<(), DaemonError> {
// if updates check is turned on
if config.update.check_interval != 0 {
let timestamp = get_timestamp_sec();
// calculate how many hours passed sinse last update
let hours_since_update_check = timestamp
.checked_sub(bzz_db.update_check_timestamp)
.ok_or(DaemonError::TimestampError)?
/ 3600;
// if more than updates_check_interval specifiyed in config - check for updates
if hours_since_update_check > config.update.check_interval {
// perform update check
println!("Cheking for updates...");
// now that may fail because of bad internet and idealy we
// want to just log error and retry in other time
bzz_db.updates_available = match hive_system::check_updates() {
Ok(updates_num) => updates_num,
Err(ex) => {
println!("Error while shecking for updates: {}", ex);
0u32
}
};
hive_db::write_db(&bzz_db)?;
println!(
"Found {} packages that needs to be updated.",
bzz_db.updates_available
);
// if auto download for updates is enabled and there is some updates - download them
if config.update.download_updates && bzz_db.updates_available != 0 {
println!("Downloadin updates...");
match hive_system::download_updates() {
Ok(()) => {
println!("Updates downloaded...");
}
Err(ex) => {
println!("Error downloading updates: {}", ex);
}
}
}
// updating las tcheck for updates timestamp in db
bzz_db.update_check_timestamp = get_timestamp_sec();
hive_db::write_db(&bzz_db)?;
}
}
Ok(())
}
pub fn run(
mut bzz_config: HiveConfig,
term_flag: Arc<AtomicBool>,
reload_flag: Arc<AtomicBool>,
) -> Result<(), DaemonError> {
// reading db from disk
let mut bzz_db = hive_db::read_db()?;
// stop flag
let mut keep_going = true;
// init udp unix socket for communication with cli and such
let listening_socket = hive_intercom::socket_bind(1)?;
let mut recv_buf: Vec<u8> = Vec::with_capacity(1024);
// main loop (I love loops) (No please just do recursion properly)
while keep_going {
process_remoute(&mut bzz_db, &listening_socket, recv_buf.as_mut_slice())?;
do_local_work(&bzz_config, &mut bzz_db)?;
// check termination flags
if term_flag.load(Ordering::Relaxed) {
println!("SIGTERM recieved - wrapping things up.");
keep_going = false;
}
// checking reload signal flag
if reload_flag.load(Ordering::Relaxed) {
println!("SIGHUP recieved - reloading config and DB.");
bzz_config = hive_config::read_config()?;
bzz_db = hive_db::read_db()?;
println!("Reloaded!");
}
}
println!("Exiting...");
Ok(())
}
-11
View File
@@ -28,8 +28,6 @@ const CONFIG_PATH: &str = "/etc/hive-up.toml";
pub struct HiveConfig { pub struct HiveConfig {
// Matches [kernel] in TOML // Matches [kernel] in TOML
pub kernel: Option<KernelConfig>, pub kernel: Option<KernelConfig>,
// Updates [update] in TOML
pub update: UpdateConfig,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@@ -38,15 +36,6 @@ pub struct KernelConfig {
pub cmd: Option<String>, pub cmd: Option<String>,
} }
#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateConfig {
/// Interval between updates check in hours. 0 - no auto check for updates.
pub 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)] #[derive(Debug)]
pub enum ConfigError { pub enum ConfigError {
-105
View File
@@ -1,105 +0,0 @@
// <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 {
/// Timestamp of last check for updates in seconds from UNIX_EPOCH
pub update_check_timestamp: u64,
/// non zero if there is updates that can bee applied, showing numbers of packages that can be updated
pub updates_available: u32,
/// true if last update was successful
/// if it is false - nyanit need to roll back snapshots
pub update_status: bool,
/// datetime of last snapshot in format "%Y-%m-%dT%H:%M:%S"
pub last_snapshot_time: String,
/// set to true if we want to apply available updates on reboot
pub update_on_reboot: bool,
}
fn init_db() -> Result<HiveDb, DBError> {
let bzz_db = HiveDb{
update_check_timestamp: 0,
updates_available: 0,
update_status: false,
last_snapshot_time: "".into(),
update_on_reboot: false,
};
write_db(&bzz_db)?;
Ok(bzz_db)
}
pub fn read_db() -> Result<HiveDb, DBError> {
if fs::exists(DB_PATH)? {
let file_content = fs::read_to_string(DB_PATH)?;
let db: HiveDb = serde_json::from_str(&file_content)?;
Ok(db)
}
else {
println!("WARNING database file do not exist {}", DB_PATH);
print!("Creating default db file...");
init_db()
}
}
pub fn write_db(db: &HiveDb) -> Result<(), DBError> {
let serialized_db = serde_json::to_string(db)?;
fs::write(DB_PATH, serialized_db)?;
Ok(())
}
-205
View File
@@ -1,205 +0,0 @@
// <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 unix socket communication
*/
use postcard;
use serde::{Deserialize, Serialize};
use std::fs;
use std::os::unix::net::{SocketAddr, UnixDatagram};
use std::time::Duration;
pub const SOCKET_DIR: &str = "/run/hive-up";
pub const SOCKET_PATH: &str = "/run/hive-up/hive-intercom.soc";
pub const CLINET_READ_TIMEOUT_SECONDS: u64 = 88;
#[derive(Debug)]
pub enum IntercomError {
IoError(std::io::Error),
PostcardError(postcard::Error),
ConnectionClosed,
Timeout,
UnexpectedResponse,
ServerError(String),
}
// Wrapping IO errors but separating time out error
impl From<std::io::Error> for IntercomError {
fn from(err: std::io::Error) -> Self {
if err.kind() == std::io::ErrorKind::TimedOut
|| err.kind() == std::io::ErrorKind::WouldBlock
{
IntercomError::Timeout
} else {
IntercomError::IoError(err)
}
}
}
impl From<postcard::Error> for IntercomError {
fn from(err: postcard::Error) -> Self {
IntercomError::PostcardError(err)
}
}
impl From<String> for IntercomError {
fn from(err: String) -> Self {
IntercomError::ServerError(err)
}
}
impl std::fmt::Display for IntercomError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
IntercomError::IoError(e) => write!(f, "IO Error: {}", e),
IntercomError::PostcardError(e) => {
write!(f, "Data parsing (postcard) error: {}", e)
}
IntercomError::Timeout => write!(f, "Operation Timeout"),
IntercomError::ConnectionClosed => write!(f, "Connection closed"),
IntercomError::UnexpectedResponse => write!(f, "Unexpected response"),
IntercomError::ServerError(err) => write!(f, "Server side error: {}", err),
}
}
}
// Implement std::error::Error
impl std::error::Error for IntercomError {}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum BzzResp {
/// signalls progress of a task as u16 integer.
/// interpretation is up to you.
Working(u16),
Finish,
UpdatesAvailable(u32),
Error(String),
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[repr(u8)]
pub enum BzzReq {
UpdatesAvailable,
CheckForUpdates,
ScheduleUpdate,
}
pub fn socket_bind(read_timeout_sec: u64) -> Result<UnixDatagram, std::io::Error> {
// create socket directory if it is does not exist
if let Ok(path_exist) = fs::exists(SOCKET_DIR)
&& path_exist == false
{
fs::create_dir(SOCKET_DIR)?;
}
// remove socket file if any present
let _ = fs::remove_file(SOCKET_PATH);
// bind datagram unix socket
let socket = UnixDatagram::bind(SOCKET_PATH)?;
socket.set_read_timeout(Some(Duration::from_secs(read_timeout_sec)))?;
Ok(socket)
}
// for daemon side
pub fn socket_send(
socket: &UnixDatagram,
client_addr: &SocketAddr,
resp: BzzResp,
) -> Result<(), IntercomError> {
let resp_buff = postcard::to_stdvec(&resp)?;
socket.send_to_addr(resp_buff.as_slice(), client_addr)?;
Ok(())
}
// for daemon side
pub fn socket_recv(
socket: &UnixDatagram,
recv_buf: &mut [u8],
) -> Result<(BzzReq, SocketAddr), IntercomError> {
match socket.recv_from(recv_buf) {
Ok((rec_count, client_addr)) => {
if rec_count != 0 {
println!("DEBUG: Total bytes recieved {}", rec_count);
let decoded_req: BzzReq = postcard::from_bytes(&recv_buf)?;
Ok((decoded_req, client_addr))
} else {
Err(IntercomError::ConnectionClosed)
}
}
Err(ex) => Err(ex.into()),
}
}
fn send_and_recv(request: BzzReq) -> Result<BzzResp, IntercomError> {
let socket = UnixDatagram::unbound()?;
socket.connect(SOCKET_PATH)?;
socket.set_read_timeout(Some(Duration::from_secs(CLINET_READ_TIMEOUT_SECONDS)))?;
let encoded_buf = postcard::to_stdvec(&request)?;
socket.send(encoded_buf.as_slice())?;
let mut recv_buf: Vec<u8> = Vec::with_capacity(1024);
loop {
match socket.recv(recv_buf.as_mut_slice()) {
Ok(rec_count) => {
if rec_count != 0 {
println!("DEBUG: Total bytes recieved {}", rec_count);
let decoded_resp: BzzResp = postcard::from_bytes(&recv_buf)?;
if let BzzResp::Working(progress) = decoded_resp {
println!("Working... {}", progress);
continue;
} else {
return Ok(decoded_resp);
}
} else {
return Err(IntercomError::ConnectionClosed);
}
}
Err(e) => return Err(e.into()),
}
}
}
pub fn client_updates_available() -> Result<u32, IntercomError> {
let resp = send_and_recv(BzzReq::UpdatesAvailable)?;
match resp {
BzzResp::UpdatesAvailable(updates_count) => Ok(updates_count),
BzzResp::Error(ex) => Err(IntercomError::ServerError(ex)),
_ => Err(IntercomError::UnexpectedResponse),
}
}
pub fn client_check_for_updates() -> Result<u32, IntercomError> {
let resp = send_and_recv(BzzReq::CheckForUpdates)?;
match resp {
BzzResp::UpdatesAvailable(updates_count) => Ok(updates_count),
BzzResp::Error(ex) => Err(IntercomError::ServerError(ex)),
_ => Err(IntercomError::UnexpectedResponse),
}
}
pub fn client_schedule_update() -> Result<(), IntercomError> {
let resp = send_and_recv(BzzReq::ScheduleUpdate)?;
match resp {
BzzResp::Finish => Ok(()),
BzzResp::Error(ex) => Err(IntercomError::ServerError(ex)),
_ => Err(IntercomError::UnexpectedResponse),
}
}
+54 -54
View File
@@ -143,46 +143,46 @@ pub fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result<String, ExecComma
/// pacman -Sy /// pacman -Sy
/// pacman -Qu /// pacman -Qu
/// returns number of updatable packages, returns 0 if there is no updates awailable /// returns number of updatable packages, returns 0 if there is no updates awailable
pub fn check_updates() -> Result<u32, ExecCommandError> { // pub fn check_updates() -> Result<u32, ExecCommandError> {
// Synchronize pacman DB // // Synchronize pacman DB
exec_command("pacman", &vec!["-Sy"])?; // exec_command("pacman", &vec!["-Sy"])?;
// Check for updates // // Check for updates
let out = Command::new("pacman").arg("-Qu").output()?; // let out = Command::new("pacman").arg("-Qu").output()?;
if out.status.success() { // if out.status.success() {
Ok(String::from_utf8(out.stdout)? // Ok(String::from_utf8(out.stdout)?
.lines() // .lines()
.count() // .count()
.try_into() // .try_into()
.unwrap()) // .unwrap())
} else { // } else {
if let Some(code) = out.status.code() // if let Some(code) = out.status.code()
&& code == 1 // && code == 1
{ // {
Ok(0) // Ok(0)
} else { // } else {
Err(ExecCommandError::Other(format!( // Err(ExecCommandError::Other(format!(
"pacman -Qu failed: {}", // "pacman -Qu failed: {}",
String::from_utf8(out.stderr)? // String::from_utf8(out.stderr)?
))) // )))
} // }
} // }
} // }
/// ///
/// sudo pacman -Suw --noconfirm --noprogressbar /// sudo pacman -Suw --noconfirm --noprogressbar
/// Download updates (need to check for updates first) /// Download updates (need to check for updates first)
/// ///
pub fn download_updates() -> Result<(), ExecCommandError> { // pub fn download_updates() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"]) // exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"])
} // }
/// ///
/// sudo pacman -Su --noconfirm --noprogressbar /// sudo pacman -Su --noconfirm --noprogressbar
/// Perform updates /// Perform updates
/// ///
pub fn pkg_upgrade() -> Result<(), ExecCommandError> { // pub fn pkg_upgrade() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"]) // exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"])
} // }
/// ///
@@ -264,38 +264,38 @@ pub fn check_if_run_as_root() -> bool {
} }
} }
#[derive(Debug)] // #[derive(Debug)]
pub enum SysUpgradeError { // pub enum SysUpgradeError {
SnapshotError(ExecCommandError), // SnapshotError(ExecCommandError),
PkgUpgradeErr((String, ExecCommandError)), // PkgUpgradeErr((String, ExecCommandError)),
} // }
impl std::fmt::Display for SysUpgradeError { // impl std::fmt::Display for SysUpgradeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { // fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { // match self {
SysUpgradeError::SnapshotError(e) => write!(f, "Snapshot creation error: {}", e), // SysUpgradeError::SnapshotError(e) => write!(f, "Snapshot creation error: {}", e),
SysUpgradeError::PkgUpgradeErr((_, e)) => write!(f, "Packages upgrade error: {}", e), // SysUpgradeError::PkgUpgradeErr((_, e)) => write!(f, "Packages upgrade error: {}", e),
} // }
} // }
} // }
// Implement std::error::Error // // Implement std::error::Error
impl std::error::Error for SysUpgradeError {} // impl std::error::Error for SysUpgradeError {}
/// ///
/// Perform system upgrade /// Perform system upgrade
/// Reruns root snapshot name on success /// Reruns root snapshot name on success
/// In case of upgrade error SysUpgradeError::PkgUpgradeErr contains snapshot time is str format /// In case of upgrade error SysUpgradeError::PkgUpgradeErr contains snapshot time is str format
/// ///
pub fn sys_upgrade() -> Result<String, SysUpgradeError> { // pub fn sys_upgrade() -> Result<String, SysUpgradeError> {
// snapshooting root // // snapshooting root
let snap_time = snapshot_system().map_err(SysUpgradeError::SnapshotError)?; // let snap_time = snapshot_system().map_err(SysUpgradeError::SnapshotError)?;
// try to perform packages upgrade // // try to perform packages upgrade
match pkg_upgrade() { // match pkg_upgrade() {
Ok(_) => Ok(snap_time), // Ok(_) => Ok(snap_time),
Err(ex) => Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))), // Err(ex) => Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))),
} // }
} // }
/// Gets device node aka /dev/sda1 from gpr partition label /// Gets device node aka /dev/sda1 from gpr partition label
/// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary" /// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary"
+37 -116
View File
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use clap::{Args, Parser, Subcommand}; use clap::{Parser, Subcommand};
use signal_hook; use signal_hook;
use std; use std;
use std::sync::Arc; use std::sync::Arc;
@@ -24,21 +24,11 @@ mod hive_system;
mod hive_config; mod hive_config;
use crate::hive_config::HiveConfig;
use crate::hive_system::SysUpgradeError;
mod daemon;
mod hive_db;
mod hive_intercom;
#[derive(Debug)] #[derive(Debug)]
pub enum HiveUpError { pub enum HiveUpError {
IoError(std::io::Error), IoError(std::io::Error),
HiveSystemCommandError(hive_system::ExecCommandError), HiveSystemCommandError(hive_system::ExecCommandError),
HiveDbError(hive_db::DBError),
HiveConfigError(hive_config::ConfigError), HiveConfigError(hive_config::ConfigError),
HiveIntercomError(hive_intercom::IntercomError),
HiveDaemonErr(daemon::DaemonError),
Other(String), Other(String),
} }
@@ -54,30 +44,12 @@ impl From<hive_system::ExecCommandError> for HiveUpError {
} }
} }
impl From<hive_db::DBError> for HiveUpError {
fn from(err: hive_db::DBError) -> Self {
HiveUpError::HiveDbError(err)
}
}
impl From<hive_config::ConfigError> for HiveUpError { impl From<hive_config::ConfigError> for HiveUpError {
fn from(err: hive_config::ConfigError) -> Self { fn from(err: hive_config::ConfigError) -> Self {
HiveUpError::HiveConfigError(err) HiveUpError::HiveConfigError(err)
} }
} }
impl From<hive_intercom::IntercomError> for HiveUpError {
fn from(err: hive_intercom::IntercomError) -> Self {
HiveUpError::HiveIntercomError(err)
}
}
impl From<daemon::DaemonError> for HiveUpError {
fn from(err: daemon::DaemonError) -> Self {
HiveUpError::HiveDaemonErr(err)
}
}
impl From<String> for HiveUpError { impl From<String> for HiveUpError {
fn from(err: String) -> Self { fn from(err: String) -> Self {
HiveUpError::Other(err) HiveUpError::Other(err)
@@ -95,10 +67,7 @@ impl std::fmt::Display for HiveUpError {
match self { match self {
HiveUpError::IoError(e) => write!(f, "IO Error: {}", e), HiveUpError::IoError(e) => write!(f, "IO Error: {}", e),
HiveUpError::HiveSystemCommandError(e) => write!(f, "ExecCommandError: {}", e), HiveUpError::HiveSystemCommandError(e) => write!(f, "ExecCommandError: {}", e),
HiveUpError::HiveDbError(ex) => write!(f, "DBError: {}", ex),
HiveUpError::HiveConfigError(ex) => write!(f, "Config error: {}", ex), HiveUpError::HiveConfigError(ex) => write!(f, "Config error: {}", ex),
HiveUpError::HiveIntercomError(e) => write!(f, "IntercomError: {}", e),
HiveUpError::HiveDaemonErr(e) => write!(f, "HiveDaemonErr: {}", e),
HiveUpError::Other(msg) => write!(f, "Error: {}", msg), HiveUpError::Other(msg) => write!(f, "Error: {}", msg),
} }
} }
@@ -107,49 +76,34 @@ impl std::fmt::Display for HiveUpError {
// Implement std::error::Error // Implement std::error::Error
impl std::error::Error for HiveUpError {} impl std::error::Error for HiveUpError {}
// Define the mutually exclusive group #[derive(Subcommand, Debug)]
#[derive(Args, Debug)] #[group(required = true)]
#[group(required = true, multiple = false)] enum BootCommand {
struct RemoteArgs { /// Install new kernel into boot partition
/// Ask daemon to check for updates Update,
#[arg(long)] /// Cleans up and recreates UFI boot menu
check_updates: bool, EfiMenuInit,
/// Cleans up and recreates UFI boot menu and /EFI dir content
/// Ask daemon if there is any updates available Init,
#[arg(long)]
updates_avail: bool,
/// Ask daemon to perform system update on next reboot
#[arg(long)]
schedule_update: bool,
} }
#[derive(Args, Debug)] #[derive(Subcommand, Debug)]
#[group(required = true, multiple = false)] #[group(required = true)]
struct CliArgs { enum Pac {
/// Perform system upgrade /// Creates snapshoots of /usr and /var subvolumea
#[arg(long)] SnapshotSystem,
upgrade: bool,
/// Install new kernel into boot partition
#[arg(long)]
update_boot: bool,
/// Cleans up and recreates UFI boot menu
#[arg(long)]
init_boot_menu: bool,
/// Cleans up and recreates UFI boot menu and /EFI dir content
#[arg(long)]
init_boot: bool,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
#[group(required = true)] // 'multiple = false' enforces exclusivity #[group(required = true)] // 'multiple = false' enforces exclusivity
enum HiveUpMode { enum HiveUpMode {
/// Perform local operations /// Manage system boot
Cli(CliArgs), #[command(subcommand)]
/// Ask hive-up daemon something Boot(BootCommand),
Remote(RemoteArgs),
/// Run hive-up in daemon mode /// Intended to be used by pacman hooks
Daemon, #[command(subcommand)]
Pac(Pac),
} }
/// Update program fot Kira Linux :3 /// Update program fot Kira Linux :3
@@ -161,40 +115,14 @@ struct Cli {
mode: HiveUpMode, mode: HiveUpMode,
} }
fn cli_upgrade(bzz_config: HiveConfig) -> Result<(), HiveUpError> {
let mut bzz_db = hive_db::read_db()?;
if (bzz_db.updates_available !=0) && (bzz_db.update_on_reboot || bzz_config.update.auto_update) {
println!("Starting full system upgrade");
bzz_db.update_status = false;
hive_db::write_db(&bzz_db)?;
match hive_system::sys_upgrade() {
Ok(snap_time) => {
bzz_db.update_status = true;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
}
Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))) => {
bzz_db.update_status = false;
bzz_db.update_on_reboot = false;
bzz_db.last_snapshot_time = snap_time;
hive_db::write_db(&bzz_db)?;
return Err(ex.into());
}
Err(ex) => return Err(ex.to_string().into()),
}
}
Ok(())
}
fn main() -> Result<(), HiveUpError> { fn main() -> Result<(), HiveUpError> {
// registering signals handling // registering signals handling
// we really do not want for this program to get terminated in a middle of something,
// so doing nothing with signals.
// second sigtrm should kill it tho
let term_flag: Arc<AtomicBool> = Arc::new(AtomicBool::new(false)); 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::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::SIGINT, Arc::clone(&term_flag)).unwrap();
signal_hook::flag::register(signal_hook::consts::SIGHUP, Arc::clone(&reload_flag)).unwrap();
let args = Cli::parse(); let args = Cli::parse();
@@ -206,18 +134,17 @@ fn main() -> Result<(), HiveUpError> {
let bzz_config = hive_config::read_config()?; let bzz_config = hive_config::read_config()?;
match args.mode { match args.mode {
HiveUpMode::Daemon => daemon::run(bzz_config, term_flag.clone(), reload_flag.clone())?, HiveUpMode::Boot(boot_submode) => match boot_submode {
HiveUpMode::Cli(cli_args) => { BootCommand::Update => {
if cli_args.upgrade {
cli_upgrade(bzz_config)?;
} else if cli_args.update_boot {
println!("Updating boot..."); println!("Updating boot...");
hive_system::boot_update()?; hive_system::boot_update()?;
} else if cli_args.init_boot_menu { }
BootCommand::EfiMenuInit => {
println!("Init EFI boot menu..."); println!("Init EFI boot menu...");
let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone()); let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone());
hive_system::init_efi_boot_record(&kernel_cmd)?; hive_system::init_efi_boot_record(&kernel_cmd)?;
} else if cli_args.init_boot { }
BootCommand::Init => {
println!("Init EFI boot menu and EFI partition content..."); println!("Init EFI boot menu and EFI partition content...");
println!("Init EFI Partition content..."); println!("Init EFI Partition content...");
let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone()); let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone());
@@ -225,18 +152,12 @@ fn main() -> Result<(), HiveUpError> {
println!("Init EFI boot menu..."); println!("Init EFI boot menu...");
hive_system::init_efi_boot_partition_content()?; hive_system::init_efi_boot_partition_content()?;
} }
} },
HiveUpMode::Remote(remote_args) => { HiveUpMode::Pac(pac_mode) => match pac_mode {
if remote_args.check_updates { Pac::SnapshotSystem => {
let up_num = hive_intercom::client_check_for_updates()?; println!("Creating system snapshot...");
println!("Updates awailable: {}", up_num); let _ = hive_system::snapshot_system()?;
} else if remote_args.updates_avail { println!("Ok.");
let up_num = hive_intercom::client_updates_available()?;
println!("Updates awailable: {}", up_num);
} else if remote_args.schedule_update {
println!("Scheduling system update...");
hive_intercom::client_schedule_update()?;
print!("Done!")
} }
} }
} }