SHA256
Compare commits
13
Commits
a6e0134d2e
...
v0.2.2
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
25a706d6ea | ||
|
|
2fedcd0805 | ||
|
|
4a4e6927bd | ||
|
|
39fb7c55b9 | ||
|
|
6811002ca6 | ||
|
|
20bdd217c4 | ||
|
|
17cea4b89e | ||
|
|
605faa3c19 | ||
|
|
8865fde77c | ||
|
|
03bd83d1e2 | ||
|
|
f35c274e50 | ||
|
|
c61d283177 | ||
|
|
eb6ef2a19f |
Generated
+31
-239
@@ -2,15 +2,6 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
@@ -61,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"
|
||||
@@ -96,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",
|
||||
@@ -106,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",
|
||||
@@ -118,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",
|
||||
@@ -130,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"
|
||||
@@ -149,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"
|
||||
@@ -183,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"
|
||||
@@ -220,14 +146,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hive-up"
|
||||
version = "0.1.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
"postcard",
|
||||
"regex",
|
||||
"regex-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"signal-hook",
|
||||
"time-format",
|
||||
"toml",
|
||||
@@ -235,9 +159,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
version = "2.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -249,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"
|
||||
@@ -294,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"
|
||||
@@ -326,54 +216,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.13.1"
|
||||
name = "regex-lite"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[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"
|
||||
checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
@@ -405,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"
|
||||
@@ -429,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",
|
||||
@@ -447,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"
|
||||
@@ -470,46 +288,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.3"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
||||
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.2"
|
||||
version = "1.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caa08af685f978227b475da86d38312cd1acd5024338bf53a1ab9a799219507d"
|
||||
checksum = "c21b401b09485cb2403a336b3c6f9d53bd8a7273463f71b71d4f6325f7f74f6c"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.4+spec-1.1.0"
|
||||
version = "1.1.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
|
||||
checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
@@ -546,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"
|
||||
@@ -576,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"
|
||||
|
||||
+13
-4
@@ -1,15 +1,24 @@
|
||||
[package]
|
||||
name = "hive-up"
|
||||
version = "0.1.0"
|
||||
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 = "1"
|
||||
regex-lite = "0.1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
signal-hook = "0.4"
|
||||
time-format = "1.2"
|
||||
toml = "1.1"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
debug = false
|
||||
incremental = false
|
||||
codegen-units = 1
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
|
||||
[registry]
|
||||
global-min-publish-age = "14 days"
|
||||
|
||||
@@ -1,3 +1,57 @@
|
||||
# hive-up
|
||||
|
||||
Program to manage update process of Kira Linux. Creating snapshots. Dealing with pacman fail, etc.
|
||||
Program to manage update process of Kira Linux. Creating snapshots. Dealing with pacman fail, etc.
|
||||
|
||||
There should be some documantation here.
|
||||
|
||||
hive-up uses `/etc/hive-up.toml` as config file.
|
||||
|
||||
```text
|
||||
Update program fot Kira Linux :3
|
||||
|
||||
Usage: hive-up <COMMAND>
|
||||
|
||||
Commands:
|
||||
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
|
||||
|
||||
```
|
||||
|
||||
Pac mode:
|
||||
|
||||
```text
|
||||
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:
|
||||
-h, --help Print help
|
||||
Print help
|
||||
```
|
||||
|
||||
Boot mode:
|
||||
|
||||
```text
|
||||
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:
|
||||
-h, --help Print help
|
||||
|
||||
```
|
||||
|
||||
1. It creates snapshots of `/usr` and `/var` subvolumes
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[Trigger]
|
||||
Operation = Upgrade
|
||||
Operation = Install
|
||||
Type = Package
|
||||
Target = linux-kira-lts
|
||||
Target = linux-kira-virt-lts
|
||||
Target = linux-kira-server-lts
|
||||
|
||||
[Action]
|
||||
Description = Running custom command after kernel update
|
||||
When = PostTransaction
|
||||
Exec = /usr/bin/hive-up boot update
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Section (Table) headers
|
||||
|
||||
# In [kernel] section user may specify kernel cmd
|
||||
# [kernel]
|
||||
# cmd = ""
|
||||
-264
@@ -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.updates_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.updates_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(())
|
||||
}
|
||||
+10
-21
@@ -22,31 +22,20 @@ use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use toml;
|
||||
|
||||
const CONFIG_PATH: &str = "/etc/hive_up.toml";
|
||||
const CONFIG_PATH: &str = "/etc/hive-up.toml";
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct HiveConfig {
|
||||
// Matches [kernel] in TOML
|
||||
pub kernel: KernelConfig,
|
||||
// Updates process config
|
||||
pub update: UpdateConfig,
|
||||
pub kernel: Option<KernelConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct KernelConfig {
|
||||
/// kernel cmd string that will be passed as kernel boot parameter.
|
||||
cmd: 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 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 {
|
||||
@@ -97,11 +86,11 @@ pub fn read_config() -> Result<HiveConfig, ConfigError> {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn change_updates_check_interval(new_interval: u64) -> Result<HiveConfig, ConfigError> {
|
||||
let mut config: HiveConfig = read_config()?;
|
||||
config.update.updates_check_interval = new_interval;
|
||||
let conf_str = toml::to_string_pretty(&config)?;
|
||||
fs::write(CONFIG_PATH, conf_str)?;
|
||||
// pub fn change_updates_check_interval(new_interval: u64) -> Result<HiveConfig, ConfigError> {
|
||||
// let mut config: HiveConfig = read_config()?;
|
||||
// config.update.updates_check_interval = new_interval;
|
||||
// let conf_str = toml::to_string_pretty(&config)?;
|
||||
// fs::write(CONFIG_PATH, conf_str)?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
// Ok(config)
|
||||
// }
|
||||
|
||||
-119
@@ -1,119 +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 fas successful
|
||||
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,
|
||||
}
|
||||
|
||||
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.update_check_timestamp;
|
||||
db.update_check_timestamp = 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_status;
|
||||
db.update_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_snapshot_time;
|
||||
db.last_snapshot_time = new_timestamp;
|
||||
write_db(&db)?;
|
||||
Ok(old_value)
|
||||
}
|
||||
@@ -1,196 +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),
|
||||
}
|
||||
}
|
||||
+388
-84
@@ -20,9 +20,22 @@
|
||||
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use std::vec;
|
||||
use time_format;
|
||||
|
||||
const SNAPS_DIR: &str = "/bzz_snaps";
|
||||
const SNAPS_DIR: &str = "/bzz-snaps";
|
||||
const EFI_BOOT_MOUNT_POINT: &str = "/beefi";
|
||||
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\\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 {
|
||||
@@ -133,53 +146,70 @@ 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"])
|
||||
// }
|
||||
|
||||
///
|
||||
/// bcachefs subvolume snapshot -r / /snap1
|
||||
/// creates read only snapshoy of "subvolume" and places it into "target"]
|
||||
/// bcachefs subvolume snapshot -r /subvolume /target
|
||||
/// -r creates read only snapshot
|
||||
/// returns snapshot time on sucess
|
||||
///
|
||||
pub fn snapshot_root() -> Result<String, ExecCommandError> {
|
||||
pub fn snapshot(subvolume: &str, target: &str) -> Result<(), ExecCommandError> {
|
||||
exec_command(
|
||||
"bcachefs",
|
||||
&vec!["subvolume", "snapshot", "-r", subvolume, target],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
/// 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
|
||||
/// returns snapshot time on sucess
|
||||
///
|
||||
pub fn snapshot_system() -> Result<String, ExecCommandError> {
|
||||
use std::path::Path;
|
||||
// if snaps dir path do not exist - create it
|
||||
let snaps_path = Path::new(SNAPS_DIR);
|
||||
@@ -189,44 +219,73 @@ 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);
|
||||
let usr_snapshot_name = format!("{}/bzz-usr-{}", SNAPS_DIR, local_time);
|
||||
let var_snapshot_name = format!("{}/bzz-var-{}", SNAPS_DIR, local_time);
|
||||
|
||||
exec_command(
|
||||
"bcachefs",
|
||||
&vec!["subvolume", "snapshot", "-r", "/", &snapshot_name],
|
||||
)?;
|
||||
snapshot("/usr", &usr_snapshot_name)?;
|
||||
snapshot("/var", &var_snapshot_name)?;
|
||||
|
||||
Ok(local_time)
|
||||
}
|
||||
|
||||
//const TMP_ROOT: &str = "/mnt/bee-root";
|
||||
pub fn list_bzzpss_snaps() -> Result<Vec<String>, ExecCommandError> {
|
||||
use regex::Regex;
|
||||
/// Function for pacman preTransaction hook
|
||||
///
|
||||
pub fn pac_start() -> Result<(), ExecCommandError> {
|
||||
use std::path::Path;
|
||||
|
||||
// root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS
|
||||
let re = Regex::new(r"^bzz-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$").unwrap();
|
||||
|
||||
let mut res: Vec<String> = Vec::new();
|
||||
// if snaps dir path do not exist return empty list
|
||||
if !Path::new(SNAPS_DIR).exists() {
|
||||
return Ok(res);
|
||||
// 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(());
|
||||
}
|
||||
|
||||
for maybe_entry in fs::read_dir(SNAPS_DIR)? {
|
||||
let entry = maybe_entry?;
|
||||
if entry.file_type()?.is_dir() {
|
||||
if let Some(dir_name) = entry.file_name().to_str()
|
||||
&& re.is_match(dir_name)
|
||||
{
|
||||
res.push(dir_name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
res.sort();
|
||||
Ok(res)
|
||||
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;
|
||||
// use std::path::Path;
|
||||
|
||||
// // root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS
|
||||
// let re = Regex::new(r"^bzz-[a-z]+-[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$").unwrap();
|
||||
|
||||
// let mut res: Vec<String> = Vec::new();
|
||||
// // if snaps dir path do not exist return empty list
|
||||
// if !Path::new(SNAPS_DIR).exists() {
|
||||
// return Ok(res);
|
||||
// }
|
||||
|
||||
// for maybe_entry in fs::read_dir(SNAPS_DIR)? {
|
||||
// let entry = maybe_entry?;
|
||||
// if entry.file_type()?.is_dir() {
|
||||
// if let Some(dir_name) = entry.file_name().to_str()
|
||||
// && re.is_match(dir_name)
|
||||
// {
|
||||
// res.push(dir_name.to_string());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// res.sort();
|
||||
// Ok(res)
|
||||
// }
|
||||
|
||||
pub fn check_if_run_as_root() -> bool {
|
||||
use nix::unistd::Uid;
|
||||
if Uid::effective().is_root() {
|
||||
@@ -236,35 +295,280 @@ 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_root().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"
|
||||
// pub fn find_partlabel(partlabel: &str) -> Result<Option<String>, ExecCommandError> {
|
||||
// let out = Command::new("/usr/bin/blkid")
|
||||
// .args([
|
||||
// "-s",
|
||||
// "PARTLABEL",
|
||||
// "-t",
|
||||
// format!("PARTLABEL=\"{}\"", partlabel).as_str(),
|
||||
// ])
|
||||
// .output()?;
|
||||
// if out.status.success() {
|
||||
// let out_text = String::from_utf8(out.stdout)?;
|
||||
|
||||
// let split_res = out_text.split_once(':').ok_or_else(|| {
|
||||
// ExecCommandError::Other(format!("Unexpected blkid output format: \"{}\"", out_text))
|
||||
// })?;
|
||||
|
||||
// Ok(Some(split_res.0.to_string()))
|
||||
// } else {
|
||||
// if let Some(code) = out.status.code()
|
||||
// && code == 2
|
||||
// {
|
||||
// Ok(None)
|
||||
// } else {
|
||||
// Err(ExecCommandError::Other(format!(
|
||||
// "Error while looking for partlabel={}: \"{}\"",
|
||||
// partlabel,
|
||||
// String::from_utf8(out.stderr).unwrap_or_else(|ex| ex.to_string())
|
||||
// )))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
///
|
||||
/// We need to use lsblk to find out parent device, or read topology from sysfs
|
||||
/// (basename $(readlink -f /sys/class/block/sda1/..))
|
||||
/// But lsblk approach looks more reasonable
|
||||
/// NAME="/dev/nvme0n1p1" PARTLABEL="nyazefi" PARTN="1" PKNAME="/dev/nvme0n1"
|
||||
/// lsblk -P -p -Q 'PARTLABEL=="nyazefi"' -o NAME,PARTLABEL,PARTN,PKNAME
|
||||
/// Returns: touple of partition number and parent device as Strings (part_num, par_dev)
|
||||
/// Returns Error if no efi partition was found
|
||||
///
|
||||
/// We need more complex logic for it.
|
||||
/// Need to alterate between two boot records.
|
||||
///
|
||||
///
|
||||
fn get_efi_part_info() -> Result<(String, String), ExecCommandError> {
|
||||
use regex_lite::Regex;
|
||||
let re = Regex::new(r#"^PARTN="([0-9]+)" PKNAME="([0-9a-Z]+)"$"#).unwrap();
|
||||
|
||||
let lsblk_query = format!("PARTLABEL==\"{}\"", EFI_PARTLABEL);
|
||||
let lsblk_args: Vec<&str> = vec!["-P", "-p", "-Q", &lsblk_query, "-o", "PARTN,PKNAME"];
|
||||
let lsblk_res = exec_command_out("lsblk", &lsblk_args)?;
|
||||
|
||||
if let Some(captured) = re.captures(&lsblk_res) {
|
||||
// let part_no = captured[1];
|
||||
// let parent_dev = captured[2];
|
||||
Ok((captured[1].to_string(), captured[2].to_string()))
|
||||
} else {
|
||||
Err(ExecCommandError::Other(format!(
|
||||
"No EFI partition (with PARTLABEL={}) was found!",
|
||||
EFI_PARTLABEL
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// List all boot entries hex numbers
|
||||
/// Boot0000* Nyan
|
||||
///
|
||||
fn list_efi_bootnums() -> Result<Vec<String>, ExecCommandError> {
|
||||
use regex_lite::Regex;
|
||||
let re = Regex::new(r#"^Boot([0-9A-F]{4})\* "#).unwrap();
|
||||
let str_res = exec_command_out("efibootmgr", &vec![])?;
|
||||
|
||||
// for each line in output match bootnum
|
||||
// and collect to vector
|
||||
Ok(str_res
|
||||
.lines()
|
||||
.filter_map(|hs| re.captures(hs))
|
||||
.map(|captured| captured[1].to_string())
|
||||
.collect())
|
||||
}
|
||||
|
||||
///
|
||||
/// sudo efibootmgr -B -b 0001
|
||||
/// -B (--delete-bootnum)
|
||||
///
|
||||
fn delete_efi_bootnum(bootnum: &str) -> Result<(), ExecCommandError> {
|
||||
exec_command("efibootmgr", &vec!["-B", "-b", bootnum])
|
||||
}
|
||||
|
||||
///
|
||||
/// Delets all EFI bootnums
|
||||
/// Returns number of deleted bootnums on success
|
||||
///
|
||||
fn delete_all_efi_bootnums() -> Result<usize, ExecCommandError> {
|
||||
let bootnums = list_efi_bootnums()?;
|
||||
for bootnum in &bootnums {
|
||||
delete_efi_bootnum(bootnum)?;
|
||||
}
|
||||
Ok(bootnums.len())
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates EFI boot record
|
||||
/// boot_index - inserting it at specified boot index (bootorder)
|
||||
/// Assuming boot partition has "bee-efi" PARTLABEL
|
||||
///
|
||||
fn efi_boot_record_create(
|
||||
boot_index: u16,
|
||||
boot_label: &str,
|
||||
uki_path: &str,
|
||||
maybe_kernel_cmd: &Option<String>,
|
||||
) -> Result<(), ExecCommandError> {
|
||||
let (efi_partno, efi_parent_dev) = get_efi_part_info()?;
|
||||
|
||||
//let local_date = time_format::strftime_local("%Y-%m-%d", time_format::now().unwrap()).unwrap();
|
||||
let string_boot_index = boot_index.to_string();
|
||||
|
||||
let mut efibootmgr_args: Vec<&str> = vec![
|
||||
"--create",
|
||||
"--index",
|
||||
&string_boot_index,
|
||||
"--disk",
|
||||
&efi_parent_dev,
|
||||
"--part",
|
||||
&efi_partno,
|
||||
"--label",
|
||||
boot_label,
|
||||
"--loader",
|
||||
uki_path,
|
||||
];
|
||||
if let Some(kernel_cmd) = maybe_kernel_cmd {
|
||||
efibootmgr_args.push("--unicode");
|
||||
efibootmgr_args.push(kernel_cmd);
|
||||
}
|
||||
exec_command("efibootmgr", &efibootmgr_args)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Deletes all existing boot records and create a default
|
||||
///
|
||||
pub fn init_efi_boot_record(maybe_kernel_cmd: &Option<String>) -> Result<(), ExecCommandError> {
|
||||
// 1 delete all bootnums
|
||||
delete_all_efi_bootnums()?;
|
||||
// 2 create defaul
|
||||
efi_boot_record_create(0, BOOT_MENU_LABEL, BOOT_UKI_IMAGE_NAME, maybe_kernel_cmd)?;
|
||||
efi_boot_record_create(
|
||||
1,
|
||||
BOOT_MENU_LABEL_BACK,
|
||||
BOOT_UKI_IMAGE_NAME_BACK,
|
||||
maybe_kernel_cmd,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// List installed kernels by inspecting /usr/lib/modules directory
|
||||
/// Result is a sorted vector of string
|
||||
///
|
||||
fn list_installed_kernels() -> Result<Vec<String>, ExecCommandError> {
|
||||
use regex_lite::Regex;
|
||||
|
||||
let re = Regex::new(r#"^[0-9]+\.[0-9]+\.[0-9]+-[0-9]-kira-lts"#).unwrap();
|
||||
let mut kernel_dirs: Vec<String> = Vec::new();
|
||||
|
||||
// Oh boy we roll
|
||||
// finding first dir in /usr/lib/modules that matches common kernel name
|
||||
for r_d_entry in fs::read_dir("/usr/lib/modules")? {
|
||||
let d_entry = r_d_entry?;
|
||||
if d_entry.file_type()?.is_dir() {
|
||||
let maybe_file_name = d_entry.file_name().to_str().map(|s| s.to_string());
|
||||
if let Some(file_name) = maybe_file_name {
|
||||
if re.is_match(&file_name) {
|
||||
kernel_dirs.push(file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kernel_dirs.sort();
|
||||
Ok(kernel_dirs)
|
||||
}
|
||||
|
||||
pub fn init_efi_boot_partition_content() -> Result<(), ExecCommandError> {
|
||||
let kernel_dirs = list_installed_kernels()?;
|
||||
// check if kernel even exist lol
|
||||
if let Some(kernel_dir) = kernel_dirs.last() {
|
||||
let kernel_img_path = format!("/usr/lib/modules/{}/vmlinuz", kernel_dir);
|
||||
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_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);
|
||||
fs::copy(&kernel_img_path, UKI_IMAGE_BACK_NAME)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ExecCommandError::Other(
|
||||
"Cannot find kernel files under /usr/lib/modules dir!".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Ok. Keep it simple kira.
|
||||
/// Lets put new kernel as kira-linux-lts.efi to EFI part.
|
||||
/// Should we save old kernel? Somehow.
|
||||
/// lets rename kira-linux-lts.efi to kira-linux-lts-back.efi
|
||||
/// Lets do not do much else.
|
||||
/// sudo cp /usr/lib/modules/6.18.46-1-kira-lts/vmlinuz /beefi/EFI/kira-linux-lts.efi
|
||||
///
|
||||
pub fn boot_update() -> Result<(), ExecCommandError> {
|
||||
// find vmlinuz path in filesystem
|
||||
let kernel_dirs = list_installed_kernels()?;
|
||||
|
||||
// check if kernel even exist lol
|
||||
if let Some(kernel_dir) = kernel_dirs.last() {
|
||||
let kernel_img_path = format!("/usr/lib/modules/{}/vmlinuz", kernel_dir);
|
||||
// rename old kernel to
|
||||
println!(
|
||||
"Renaming old kernel {} to {}",
|
||||
UKI_IMAGE_NAME, UKI_IMAGE_BACK_NAME
|
||||
);
|
||||
fs::rename(UKI_IMAGE_NAME, UKI_IMAGE_BACK_NAME)?;
|
||||
// copy new kernel image
|
||||
println!(
|
||||
"Copy new kernel from {} to {}",
|
||||
kernel_img_path, UKI_IMAGE_NAME
|
||||
);
|
||||
fs::copy(&kernel_img_path, UKI_IMAGE_NAME)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ExecCommandError::Other(
|
||||
"Cannot find kernel files under /usr/lib/modules dir!".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
+70
-83
@@ -14,30 +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};
|
||||
use signal_hook::{consts::SIGINT, iterator::Signals};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
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_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),
|
||||
}
|
||||
|
||||
@@ -53,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)
|
||||
@@ -94,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),
|
||||
}
|
||||
}
|
||||
@@ -106,43 +75,61 @@ 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)] // 'multiple = false' enforces exclusivity
|
||||
struct HiveUpMode {
|
||||
/// Check for updates, prints number of updates available
|
||||
#[arg(long)]
|
||||
check_updates: 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,
|
||||
}
|
||||
|
||||
/// Check for available updates, prints number of updates available
|
||||
#[arg(long)]
|
||||
updates_available: 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,
|
||||
}
|
||||
|
||||
/// Perform system upgrade
|
||||
#[arg(long)]
|
||||
upgrade: bool,
|
||||
#[derive(Subcommand, Debug)]
|
||||
#[group(required = true)] // 'multiple = false' enforces exclusivity
|
||||
enum HiveUpMode {
|
||||
/// Manage system boot
|
||||
#[command(subcommand)]
|
||||
Boot(BootCommand),
|
||||
|
||||
/// Run hive-up in daemon mode
|
||||
#[arg(long)]
|
||||
daemon: bool,
|
||||
/// Intended to be used by pacman hooks
|
||||
#[command(subcommand)]
|
||||
Pac(Pac),
|
||||
}
|
||||
|
||||
/// Update program fot Kira Linux :3
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(author, version, about)]
|
||||
struct Cli {
|
||||
/// hive-up operation mode
|
||||
#[command(flatten)]
|
||||
#[command(subcommand)]
|
||||
mode: HiveUpMode,
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -153,36 +140,36 @@ fn main() -> Result<(), HiveUpError> {
|
||||
// read config
|
||||
let bzz_config = hive_config::read_config()?;
|
||||
|
||||
// Check CMD flags
|
||||
if args.mode.check_updates {
|
||||
let up_num = hive_intercom::client_check_for_updates()?;
|
||||
println!("Updates awailable: {}", up_num);
|
||||
} else if args.mode.updates_available {
|
||||
let up_num = hive_intercom::client_updates_available()?;
|
||||
println!("Updates awailable: {}", up_num);
|
||||
} else if args.mode.upgrade {
|
||||
let mut bzz_db = hive_db::read_db()?;
|
||||
if bzz_db.update_on_reboot {
|
||||
println!("Starting full system upgrade");
|
||||
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()),
|
||||
match args.mode {
|
||||
HiveUpMode::Boot(boot_submode) => match boot_submode {
|
||||
BootCommand::Update => {
|
||||
println!("Updating boot...");
|
||||
hive_system::boot_update()?;
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
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());
|
||||
hive_system::init_efi_boot_record(&kernel_cmd)?;
|
||||
println!("Init EFI boot menu...");
|
||||
hive_system::init_efi_boot_partition_content()?;
|
||||
}
|
||||
},
|
||||
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()?
|
||||
}
|
||||
} else if args.mode.daemon {
|
||||
daemon::run(bzz_config, term_flag.clone(), reload_flag.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user