5 Commits
14 changed files with 222 additions and 1014 deletions
Generated
+25 -201
View File
@@ -52,32 +52,17 @@ dependencies = [
"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]]
name = "bitflags"
version = "2.13.1"
version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
[[package]]
name = "cfg-if"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
[[package]]
name = "cfg_aliases"
@@ -87,9 +72,9 @@ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "clap"
version = "4.6.6"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946"
dependencies = [
"clap_builder",
"clap_derive",
@@ -97,9 +82,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.6.6"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d"
dependencies = [
"anstream",
"anstyle",
@@ -109,9 +94,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.6.4"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061"
checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0"
dependencies = [
"heck",
"proc-macro2",
@@ -121,18 +106,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486"
[[package]]
name = "colorchoice"
@@ -140,24 +116,6 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "equivalent"
version = "1.0.2"
@@ -174,35 +132,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "heck"
version = "0.5.0"
@@ -211,14 +146,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hive-up"
version = "0.1.2"
version = "0.2.2"
dependencies = [
"clap",
"nix",
"postcard",
"regex-lite",
"serde",
"serde_json",
"signal-hook",
"time-format",
"toml",
@@ -240,32 +173,11 @@ 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"
version = "0.2.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
[[package]]
name = "nix"
@@ -285,19 +197,6 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "proc-macro2"
version = "1.0.107"
@@ -322,27 +221,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "serde"
version = "1.0.229"
@@ -373,19 +251,6 @@ dependencies = [
"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"
@@ -397,9 +262,9 @@ dependencies = [
[[package]]
name = "signal-hook"
version = "0.4.4"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d"
checksum = "b29ffa27d3d59a049bb328258de100f8012848d1b08d444e08bbc02ac468435e"
dependencies = [
"libc",
"signal-hook-registry",
@@ -415,21 +280,6 @@ dependencies = [
"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]]
name = "strsim"
version = "0.11.1"
@@ -438,46 +288,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "3.0.5"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
dependencies = [
"proc-macro2",
"quote",
"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]]
name = "time-format"
version = "1.2.3"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb54c799611991d3d4a66fee3ff17b9f600c2a0f8c0d34e8209dbd153ff0a87b"
checksum = "c21b401b09485cb2403a336b3c6f9d53bd8a7273463f71b71d4f6325f7f74f6c"
[[package]]
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"
checksum = "12c0ba9680044b4ce98d391a62094047eada0d64860b80166c39f4a6b5640785"
checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
dependencies = [
"indexmap",
"serde_core",
@@ -514,9 +344,9 @@ checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
[[package]]
name = "unicode-ident"
version = "1.0.24"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
[[package]]
name = "utf8parse"
@@ -544,9 +374,3 @@ 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"
+1 -3
View File
@@ -1,15 +1,13 @@
[package]
name = "hive-up"
version = "0.1.2"
version = "0.2.2"
edition = "2024"
[dependencies]
clap = { version = "4.6", features = ["derive"] }
nix = { version = "0", features = ["user"] }
postcard = { version = "1.1", features = ["use-std"] }
regex-lite = "0.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0"
signal-hook = "0.4"
time-format = "1.2"
toml = "1.1"
+27 -30
View File
@@ -4,57 +4,54 @@ Program to manage update process of Kira Linux. Creating snapshots. Dealing with
There should be some documantation here.
hive-up uses `/var/lib/hive-up/hyve-db.json` file as database for stuff
And `/etc/hive-up.toml` as config file.
As an daemon hive-up righ now doing only periodical checks for updates.
hive-up uses `/etc/hive-up.toml` as config file.
```text
Update program fot Kira Linux :3
Usage: hive-up <COMMAND>
Commands:
cli Perform local operations
remote Ask hive-up daemon something
daemon Run hive-up in daemon mode
help Print this message or the help of the given subcommand(s)
boot Manage system boot
pac Intended to be used by pacman hooks
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
```
For cli mode:
Pac mode:
```text
Usage: hive-up cli <--upgrade|--update-boot|--init-boot-menu|--init-boot>
Usage: hive-up pac <COMMAND>
Commands:
snapshot-system Creates snapshoots of /usr and /var subvolumea
start This supposed to be called by pacman hook before transaction hive-up will check for /var/lib/hive-up/pac-lock and will not create snapshots in case it present Its safe lock mesure to prevent multiple snapshots on system fixing or some corner cases Lock file can be deleted by `pac finish` that should be called by pacman after transaction
finis This supposed to be called by pacman hook before transaction. Right now only thing it does is removes /var/lib/hive-up/pac-lock file
help Print this message or the help of the given subcommand(s)
Options:
--upgrade Perform system upgrade
--update-boot Install new kernel into boot partition
--init-boot-menu Cleans up and recreates UFI boot menu
--init-boot Cleans up and recreates UFI boot menu and /EFI dir content
-h, --help Print help
-h, --help Print help
Print help
```
For remote mode:
Boot mode:
```text
Usage: hive-up remote <--check-updates|--updates-avail|--schedule-update>
Usage: hive-up boot <COMMAND>
Commands:
update Install new kernel into boot partition
efi-menu-init Cleans up and recreates UFI boot menu
init Cleans up and recreates UFI boot menu and /EFI dir content
help Print this message or the help of the given subcommand(s)
Options:
--check-updates Ask daemon to check for updates
--updates-avail Ask daemon if there is any updates available
--schedule-update Ask daemon to perform system update on next reboot
-h, --help Print help
-h, --help Print help
```
`hive-up daemon` - do not have any flags for now.
`hive-up cli --upgrade` - generally not supposed to be called by user. It get called by system service manager (dinit) after hive-up service stop (on reboot or system shutdown)
When `hive-up cli --upgrade` is called, it checks if `update_on_reboot` flag is set in **DB** or `auto_update` flag checked in **config**, and if `updates_available` in **DB** is non zero. Update routine continue only if this conditios are met.
1. It creates snapshots of `/usr` and `/var` subvolumes
2. It sets `update_status` to **false** in **DB**
3. Performs update, and if everything was fine sets `update_status` to **true** in **DB**
After this, system reboots, and on system boot Nyanit figures up what to do with failed updates if any
+12
View File
@@ -0,0 +1,12 @@
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Description = Release lock and do stuff
When = PostTransaction
Exec = /usr/bin/hive-up pac finish
+12
View File
@@ -0,0 +1,12 @@
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Description = Snapshot system before any changes
When = PreTransaction
Exec = /usr/bin/hive-up pac start
@@ -9,4 +9,5 @@ Target = linux-kira-server-lts
[Action]
Description = Running custom command after kernel update
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
[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
# [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 {
// Matches [kernel] in TOML
pub kernel: Option<KernelConfig>,
// Updates [update] in TOML
pub update: UpdateConfig,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -38,15 +36,6 @@ pub struct KernelConfig {
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)]
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),
}
}
+95 -63
View File
@@ -25,14 +25,17 @@ use time_format;
const SNAPS_DIR: &str = "/bzz-snaps";
const EFI_BOOT_MOUNT_POINT: &str = "/beefi";
const UKI_IMAGE_NAME: &str = "/beefi/EFI/linux-kira-lts.efi";
const UKI_IMAGE_BACK_NAME: &str = "/beefi/EFI/linux-kira-lts-back.efi";
const EFI_BOOT_DIR: &str = "/beefi/EFI/boot";
const UKI_IMAGE_NAME: &str = "/beefi/EFI/boot/linux-kira-lts.efi";
const UKI_IMAGE_BACK_NAME: &str = "/beefi/EFI/boot/linux-kira-lts-back.efi";
const EFI_PARTLABEL: &str = "bee-efi";
const BOOT_MENU_LABEL: &str = "Kira OS";
const BOOT_MENU_LABEL_BACK: &str = "Kira OS Fallback";
const BOOT_UKI_IMAGE_NAME: &str = "\\EFI\\linux-kira-lts.efi";
const BOOT_UKI_IMAGE_NAME_BACK: &str = "\\EFI\\linux-kira-lts-back.efi";
const BOOT_UKI_IMAGE_NAME: &str = "\\EFI\\boot\\linux-kira-lts.efi";
const BOOT_UKI_IMAGE_NAME_BACK: &str = "\\EFI\\boot\\linux-kira-lts-back.efi";
const PAC_LOCK_FILE: &str = "/var/lib/hive-up/pac-lock";
#[derive(Debug)]
pub struct CommandFailed {
@@ -143,47 +146,46 @@ pub fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result<String, ExecComma
/// pacman -Sy
/// pacman -Qu
/// returns number of updatable packages, returns 0 if there is no updates awailable
pub fn check_updates() -> Result<u32, ExecCommandError> {
// Synchronize pacman DB
exec_command("pacman", &vec!["-Sy"])?;
// Check for updates
let out = Command::new("pacman").arg("-Qu").output()?;
if out.status.success() {
Ok(String::from_utf8(out.stdout)?
.lines()
.count()
.try_into()
.unwrap())
} else {
if let Some(code) = out.status.code()
&& code == 1
{
Ok(0)
} else {
Err(ExecCommandError::Other(format!(
"pacman -Qu failed: {}",
String::from_utf8(out.stderr)?
)))
}
}
}
// pub fn check_updates() -> Result<u32, ExecCommandError> {
// // Synchronize pacman DB
// exec_command("pacman", &vec!["-Sy"])?;
// // Check for updates
// let out = Command::new("pacman").arg("-Qu").output()?;
// if out.status.success() {
// Ok(String::from_utf8(out.stdout)?
// .lines()
// .count()
// .try_into()
// .unwrap())
// } else {
// if let Some(code) = out.status.code()
// && code == 1
// {
// Ok(0)
// } else {
// Err(ExecCommandError::Other(format!(
// "pacman -Qu failed: {}",
// String::from_utf8(out.stderr)?
// )))
// }
// }
// }
///
/// sudo pacman -Suw --noconfirm --noprogressbar
/// Download updates (need to check for updates first)
///
pub fn download_updates() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"])
}
// pub fn download_updates() -> Result<(), ExecCommandError> {
// exec_command("pacman", &vec!["-Suw", "--noconfirm", "--noprogressbar"])
// }
///
/// sudo pacman -Su --noconfirm --noprogressbar
/// Perform updates
///
pub fn pkg_upgrade() -> Result<(), ExecCommandError> {
exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"])
}
// pub fn pkg_upgrade() -> Result<(), ExecCommandError> {
// exec_command("pacman", &vec!["-Su", "--noconfirm", "--noprogressbar"])
// }
///
/// creates read only snapshoy of "subvolume" and places it into "target"]
@@ -192,7 +194,6 @@ pub fn pkg_upgrade() -> Result<(), ExecCommandError> {
/// returns snapshot time on sucess
///
pub fn snapshot(subvolume: &str, target: &str) -> Result<(), ExecCommandError> {
exec_command(
"bcachefs",
&vec!["subvolume", "snapshot", "-r", subvolume, target],
@@ -202,7 +203,7 @@ pub fn snapshot(subvolume: &str, target: &str) -> Result<(), ExecCommandError> {
}
///
///
///
/// bcachefs subvolume snapshot -r /target /SNAPS_DIR/bzz-target-yyyy-mm-ddTHH-MM-SS
/// Creates read only snapshots of /usr and /var subvolumes
/// And places them to /SNAPS_DIR/bzz-usr-yyyy-mm-ddTHH-MM-SS and /SNAPS_DIR/bzz-var-yyyy-mm-ddTHH-MM-SS
@@ -227,6 +228,36 @@ pub fn snapshot_system() -> Result<String, ExecCommandError> {
Ok(local_time)
}
/// Function for pacman preTransaction hook
///
pub fn pac_start() -> Result<(), ExecCommandError> {
use std::path::Path;
// Check if lock file exist
let pack_lock_path = Path::new(PAC_LOCK_FILE);
if pack_lock_path.exists() {
println!("Warning! Pac Lock file exist, skipping system snapshot...");
return Ok(());
}
println!("Creating system snapshot...");
let snap_time = snapshot_system()?;
println!("Ok.");
fs::write(PAC_LOCK_FILE, snap_time)?;
Ok(())
}
pub fn pac_finish() -> Result<(), ExecCommandError> {
use std::path::Path;
// Check if lock file exist
let pack_lock_path = Path::new(PAC_LOCK_FILE);
if pack_lock_path.exists() {
println!("Remowing pac-lock...");
fs::remove_file(pack_lock_path)?;
} else {
println!("Warning! Pac Lock file does not exist - something is wrong...");
}
Ok(())
}
//const TMP_ROOT: &str = "/mnt/bee-root";
// pub fn list_bzzpss_snaps() -> Result<Vec<String>, ExecCommandError> {
// use regex::Regex;
@@ -264,38 +295,38 @@ pub fn check_if_run_as_root() -> bool {
}
}
#[derive(Debug)]
pub enum SysUpgradeError {
SnapshotError(ExecCommandError),
PkgUpgradeErr((String, ExecCommandError)),
}
// #[derive(Debug)]
// pub enum SysUpgradeError {
// SnapshotError(ExecCommandError),
// PkgUpgradeErr((String, ExecCommandError)),
// }
impl std::fmt::Display for SysUpgradeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
SysUpgradeError::SnapshotError(e) => write!(f, "Snapshot creation error: {}", e),
SysUpgradeError::PkgUpgradeErr((_, e)) => write!(f, "Packages upgrade error: {}", e),
}
}
}
// impl std::fmt::Display for SysUpgradeError {
// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
// match self {
// SysUpgradeError::SnapshotError(e) => write!(f, "Snapshot creation error: {}", e),
// SysUpgradeError::PkgUpgradeErr((_, e)) => write!(f, "Packages upgrade error: {}", e),
// }
// }
// }
// Implement std::error::Error
impl std::error::Error for SysUpgradeError {}
// // Implement std::error::Error
// impl std::error::Error for SysUpgradeError {}
///
/// Perform system upgrade
/// Reruns root snapshot name on success
/// In case of upgrade error SysUpgradeError::PkgUpgradeErr contains snapshot time is str format
///
pub fn sys_upgrade() -> Result<String, SysUpgradeError> {
// snapshooting root
let snap_time = snapshot_system().map_err(SysUpgradeError::SnapshotError)?;
// try to perform packages upgrade
match pkg_upgrade() {
Ok(_) => Ok(snap_time),
Err(ex) => Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))),
}
}
// pub fn sys_upgrade() -> Result<String, SysUpgradeError> {
// // snapshooting root
// let snap_time = snapshot_system().map_err(SysUpgradeError::SnapshotError)?;
// // try to perform packages upgrade
// match pkg_upgrade() {
// Ok(_) => Ok(snap_time),
// Err(ex) => Err(SysUpgradeError::PkgUpgradeErr((snap_time, ex))),
// }
// }
/// Gets device node aka /dev/sda1 from gpr partition label
/// blkid -s PARTLABEL --match-token PARTLABEL="bzz-primary"
@@ -492,8 +523,9 @@ pub fn init_efi_boot_partition_content() -> Result<(), ExecCommandError> {
let efi_dir = format!("{}/EFI", EFI_BOOT_MOUNT_POINT);
println!("Romoving efi dir {}", efi_dir);
fs::remove_dir_all(&efi_dir)?;
println!("Creating efi dir {}", efi_dir);
fs::create_dir(efi_dir)?;
println!("Creating efi dir {}", EFI_BOOT_DIR);
fs::create_dir_all(EFI_BOOT_DIR)?;
println!("Copy {} to {}", kernel_img_path, UKI_IMAGE_NAME);
fs::copy(&kernel_img_path, UKI_IMAGE_NAME)?;
println!("Copy {} to {}", kernel_img_path, UKI_IMAGE_BACK_NAME);
+48 -118
View File
@@ -14,31 +14,20 @@
// 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, Subcommand};
use clap::{Parser, Subcommand};
use signal_hook;
use std;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
mod hive_system;
mod hive_config;
use crate::hive_config::HiveConfig;
use crate::hive_system::SysUpgradeError;
mod daemon;
mod hive_db;
mod hive_intercom;
#[derive(Debug)]
pub enum HiveUpError {
IoError(std::io::Error),
HiveSystemCommandError(hive_system::ExecCommandError),
HiveDbError(hive_db::DBError),
HiveConfigError(hive_config::ConfigError),
HiveIntercomError(hive_intercom::IntercomError),
HiveDaemonErr(daemon::DaemonError),
Other(String),
}
@@ -54,30 +43,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 {
fn from(err: hive_config::ConfigError) -> Self {
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 {
fn from(err: String) -> Self {
HiveUpError::Other(err)
@@ -95,10 +66,7 @@ impl std::fmt::Display for HiveUpError {
match self {
HiveUpError::IoError(e) => write!(f, "IO Error: {}", e),
HiveUpError::HiveSystemCommandError(e) => write!(f, "ExecCommandError: {}", e),
HiveUpError::HiveDbError(ex) => write!(f, "DBError: {}", 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),
}
}
@@ -107,49 +75,42 @@ impl std::fmt::Display for HiveUpError {
// Implement std::error::Error
impl std::error::Error for HiveUpError {}
// Define the mutually exclusive group
#[derive(Args, Debug)]
#[group(required = true, multiple = false)]
struct RemoteArgs {
/// Ask daemon to check for updates
#[arg(long)]
check_updates: bool,
/// Ask daemon if there is any updates available
#[arg(long)]
updates_avail: bool,
/// Ask daemon to perform system update on next reboot
#[arg(long)]
schedule_update: bool,
#[derive(Subcommand, Debug)]
#[group(required = true)]
enum BootCommand {
/// Install new kernel into boot partition
Update,
/// Cleans up and recreates UFI boot menu
EfiMenuInit,
/// Cleans up and recreates UFI boot menu and /EFI dir content
Init,
}
#[derive(Args, Debug)]
#[group(required = true, multiple = false)]
struct CliArgs {
/// Perform system upgrade
#[arg(long)]
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)]
#[group(required = true)]
enum Pac {
/// Creates snapshoots of /usr and /var subvolumea
SnapshotSystem,
/// This supposed to be called by pacman hook before transaction
/// hive-up will check for /var/lib/hive-up/pac-lock and will not create snapshots in case it present
/// Its safe lock mesure to prevent multiple snapshots on system fixing or some corner cases
/// Lock file can be deleted by `pac finish` that should be called by pacman after transaction
Start,
/// This supposed to be called by pacman hook before transaction.
/// Right now only thing it does is removes /var/lib/hive-up/pac-lock file
Finis,
}
#[derive(Subcommand, Debug)]
#[group(required = true)] // 'multiple = false' enforces exclusivity
enum HiveUpMode {
/// Perform local operations
Cli(CliArgs),
/// Ask hive-up daemon something
Remote(RemoteArgs),
/// Run hive-up in daemon mode
Daemon,
/// Manage system boot
#[command(subcommand)]
Boot(BootCommand),
/// Intended to be used by pacman hooks
#[command(subcommand)]
Pac(Pac),
}
/// Update program fot Kira Linux :3
@@ -161,40 +122,14 @@ struct Cli {
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> {
// 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 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();
@@ -206,18 +141,17 @@ fn main() -> Result<(), HiveUpError> {
let bzz_config = hive_config::read_config()?;
match args.mode {
HiveUpMode::Daemon => daemon::run(bzz_config, term_flag.clone(), reload_flag.clone())?,
HiveUpMode::Cli(cli_args) => {
if cli_args.upgrade {
cli_upgrade(bzz_config)?;
} else if cli_args.update_boot {
HiveUpMode::Boot(boot_submode) => match boot_submode {
BootCommand::Update => {
println!("Updating boot...");
hive_system::boot_update()?;
} else if cli_args.init_boot_menu {
}
BootCommand::EfiMenuInit => {
println!("Init EFI boot menu...");
let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone());
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 Partition content...");
let kernel_cmd = bzz_config.kernel.and_then(|kk| kk.cmd.clone());
@@ -225,19 +159,15 @@ fn main() -> Result<(), HiveUpError> {
println!("Init EFI boot menu...");
hive_system::init_efi_boot_partition_content()?;
}
}
HiveUpMode::Remote(remote_args) => {
if remote_args.check_updates {
let up_num = hive_intercom::client_check_for_updates()?;
println!("Updates awailable: {}", up_num);
} else if remote_args.updates_avail {
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!")
}
},
HiveUpMode::Pac(pac_mode) => match pac_mode {
Pac::SnapshotSystem => {
println!("Creating system snapshot...");
let _ = hive_system::snapshot_system()?;
println!("Ok.");
},
Pac::Start => hive_system::pac_start()?,
Pac::Finis => hive_system::pac_finish()?
}
}