15 Commits
8 changed files with 404 additions and 263 deletions
@@ -1,43 +0,0 @@
name: "Build Release Binary"
run-name: "Build Release: ${{ inputs.tag_name }}"
on:
# Allows triggering from another workflow
workflow_call:
inputs:
tag_name:
description: 'Git tag to build (e.g., v1.0.0)'
required: true
type: string
workflow_dispatch: # Enables manual triggering
inputs:
tag_name:
description: 'Git tag to build (e.g., v1.0.0)'
required: true
type: string
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
GIT_DEFAULT_HASH: sha256
with:
# If triggered manually, use the input tag.
# If triggered by push, GITHUB_REF_NAME is the tag.
ref: ${{ inputs.tag_name || gitea.ref_name }}
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Build Release Binary
run: cargo build --release
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: nyanit-${{ inputs.tag_name || gitea.ref_name }}
path: target/release/nyanit
-40
View File
@@ -1,40 +0,0 @@
name: Create Release with Binary
on:
workflow_dispatch: # Enables manual triggering
inputs:
tag_name:
description: 'Git tag to build (e.g., v1.0.0)'
required: true
type: string
rel_description:
description: 'Release description'
required: false
type: string
jobs:
# This job calls the reusable workflow
build-binary:
uses: ./.gitea/workflows/build-release-binary.yml
with:
tag_name: "${{ inputs.tag_name }}"
create-release:
needs: build-binary # Wait for the reusable workflow to finish
runs-on: ubuntu-latest
steps:
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: nyanit-${{ inputs.tag_name }}
- name: Create Release and Attach Binary
uses: actions/release-action@main
with:
artifacts: "nyanit-${{ inputs.tag_name }}"
api_key: ${{ secrets.bzzpss_release_psszz }}
tag_name: ${{ inputs.tag_name }}
name: Release ${{ inputs.tag_name }}
body: "Automated release for ${{ inputs.tag_name }}\n${{ inputs.rel_description }}"
Generated
+91 -96
View File
@@ -2,15 +2,6 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.21" version = "0.2.21"
@@ -34,9 +25,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.13.0" version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]] [[package]]
name = "by_address" name = "by_address"
@@ -59,6 +50,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]] [[package]]
name = "compact_str" name = "compact_str"
version = "0.9.1" version = "0.9.1"
@@ -75,9 +72,9 @@ dependencies = [
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.23.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" checksum = "88490bf1b990d87eaaa7ac8aa887f629a08e7359765b4911faf63c3763347d23"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"darling_macro", "darling_macro",
@@ -85,26 +82,26 @@ dependencies = [
[[package]] [[package]]
name = "darling_core" name = "darling_core"
version = "0.23.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" checksum = "084e274f91c482280130e1e34e0b8d6e66776a060d7b6de7b84289ca778868c4"
dependencies = [ dependencies = [
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn", "syn 3.0.3",
] ]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.23.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" checksum = "68f5792fa0d41cd2325ce0ffa64f0a340eaebd4971a3a0c5e1ffd2cc488a355e"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn", "syn 3.0.3",
] ]
[[package]] [[package]]
@@ -115,9 +112,9 @@ checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
[[package]] [[package]]
name = "either" name = "either"
version = "1.16.0" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
@@ -125,12 +122,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fast-srgb8"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
[[package]] [[package]]
name = "foldhash" name = "foldhash"
version = "0.2.0" version = "0.2.0"
@@ -182,15 +173,15 @@ dependencies = [
[[package]] [[package]]
name = "instability" name = "instability"
version = "0.3.12" version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" checksum = "2bf84e73fa6f27f299dec58e13223cf70db80da872eb921d4f6138342a0eabc8"
dependencies = [ dependencies = [
"darling", "darling",
"indoc", "indoc",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 3.0.3",
] ]
[[package]] [[package]]
@@ -221,9 +212,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.186" version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]] [[package]]
name = "libm" name = "libm"
@@ -233,27 +224,33 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]] [[package]]
name = "line-clipping" name = "line-clipping"
version = "0.3.7" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" checksum = "e752191d037c44ad111a8caa762921926658402f01cc1253f7bef2020ece4f5e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "lru" name = "lru"
version = "0.18.1" version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" checksum = "5d2f2f9b4ba7e6b24d95e7e899329d35be83bcded72c8540cdd5368932d1d90a"
dependencies = [ dependencies = [
"hashbrown 0.17.1", "hashbrown 0.17.1",
] ]
[[package]] [[package]]
name = "memchr" name = "nix"
version = "2.8.3" version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
@@ -287,43 +284,53 @@ checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
[[package]] [[package]]
name = "nyanit" name = "nyanit"
version = "0.1.4" version = "0.2.1"
dependencies = [ dependencies = [
"nix",
"ratatui", "ratatui",
"ratatui-textarea", "ratatui-textarea",
"regex", "regex-lite",
"termion", "termion",
] ]
[[package]] [[package]]
name = "palette" name = "palette"
version = "0.7.6" version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64"
dependencies = [ dependencies = [
"approx", "approx",
"fast-srgb8",
"libm", "libm",
"palette_derive", "palette_derive",
"palette_math",
] ]
[[package]] [[package]]
name = "palette_derive" name = "palette_derive"
version = "0.7.6" version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be"
dependencies = [ dependencies = [
"by_address", "by_address",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.119",
]
[[package]]
name = "palette_math"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12"
dependencies = [
"libm",
] ]
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "1.13.1" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
@@ -333,18 +340,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.46" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -428,33 +435,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "regex" name = "regex-lite"
version = "1.13.0" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db"
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]] [[package]]
name = "rustversion" name = "rustversion"
@@ -470,9 +454,9 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [ dependencies = [
"serde_core", "serde_core",
"serde_derive", "serde_derive",
@@ -480,22 +464,22 @@ dependencies = [
[[package]] [[package]]
name = "serde_core" name = "serde_core"
version = "1.0.228" version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.228" version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 3.0.3",
] ]
[[package]] [[package]]
@@ -528,14 +512,25 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.119",
] ]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.118" version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -554,29 +549,29 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.18" version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "2.0.18" version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 3.0.3",
] ]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.53" version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
dependencies = [ dependencies = [
"deranged", "deranged",
"libc", "libc",
+4 -4
View File
@@ -1,19 +1,19 @@
[package] [package]
name = "nyanit" name = "nyanit"
version = "0.1.4" version = "0.2.1"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
nix = { version = "0.31", features = ["mount"] }
ratatui = { version = "0.30", default-features = false, features = ["termion"] } ratatui = { version = "0.30", default-features = false, features = ["termion"] }
ratatui-textarea = { version = "0.9", default-features = false, features = ["termion"] } ratatui-textarea = { version = "0.9", default-features = false, features = ["termion"] }
regex = "1.1" regex-lite = "0.1"
termion = "4" termion = "4"
[profile.release] [profile.release]
lto = true lto = true
debug = false debug = false
incremental = false incremental = false
codegen-units = 1 codegen-units = 1
opt-level = 2 opt-level = "s"
strip = true strip = true
+13 -4
View File
@@ -8,14 +8,23 @@ And this partition should be formated to bcachefs.
2. Nyanit checks if bcachefs is encrypted, and asks for unlock password if it is. 2. Nyanit checks if bcachefs is encrypted, and asks for unlock password if it is.
3. Then it mounts it to **/mnt/bee-root**. 3. Then it mounts it to **/mnt/real-bee**.
4. And looks for snapshots with name pattern **/mnt/bee-root/bzz_snaps/bzz-yyyy-mm-ddTHH-MM-SS** 4. Now dealing with snapshoots. Its getting complicated because we need to have then outside root subvolume
Root subvolume should be named **bee-root**
Snapshoots made by hive-up should be placed in **bee-root/bzz-snaps** - **/mnt/real-bee/bee-root/bzz-snaps**
We need to transver snapshoot if any from **/mnt/real-bee/bee-root/bzz-snaps** to **/mnt/real-bee/bzz-snaps**
Snapshoots names should match **bzz-yyyy-mm-ddTHH-MM-SS** pattern.
5. If no snapshots are found it calls **switch_root** for **/mnt/bee-root** 4. And looks for snapshots with name pattern **/mnt/real-bee/bzz-snaps/bzz-yyyy-mm-ddTHH-MM-SS**
5. If no snapshots are found it calls **switch_root** for **/mnt/real-bee/bee-root**
6. Othervise vait for F2 for few seconds. 6. Othervise vait for F2 for few seconds.
And if F2 pressed provides list of snapshoots to boot from. And if F2 pressed provides list of snapshoots to boot from.
7. After some snapshoot or just **/mnt/bee-root** is selected, Nyanit doing **switch_root** to it. 7. After some snapshoot or just **/mnt/bee-root/real-bee** is selected, Nyanit doing **switch_root** to it.
8. TO-DO
- add cleaning of old snapshoots.
- add replacing bee-root with snapshoot
+50
View File
@@ -0,0 +1,50 @@
#!/bin/sh
echo "work dir: $1"
_tools_list=(
/usr/bin/bcachefs
/usr/bin/fsck
/usr/bin/fsck.vfat
/usr/bin/switch_root
/usr/bin/blkid
)
workdir=$1
echo "Populate initdramfs tree..."
cd $workdir
mkdir -p initramfs/{dev,proc,sys,run,mnt,mnt/bee_root,tmp,etc,usr,usr/bin,usr/lib}
echo "Create /bin /lib /lib64 simlinks"
cd $workdir/initramfs
ln -s usr/lib lib64
ln -s usr/lib lib
ln -s usr/bin bin
cd $workdir/initramfs/usr
ln -s lib lib64
echo "Install NYANIT..."
cd $workdir
lddtree --bindir / --copy-to-tree $workdir/initramfs init
echo "Copy libs and binaries"
cd $workdir
lddtree --copy-to-tree $workdir/initramfs "${_tools_list[@]}"
echo "Remove setuid flag from everything..."
chmod -R a-s $workdir/initramfs
fakeroot -- sh << EOF
echo "Create console device node"
cd $workdir/initramfs
mknod -m 622 dev/console c 5 1
# Create cpio archive
echo "Create cpio archive"
cd $workdir/initramfs
find . | cpio -ov --format=newc > ../initramfs.cpio
EOF
echo "Done!"
+37 -22
View File
@@ -39,9 +39,11 @@ use nyan_system::ExecCommandError;
const BEE_CAT: &str = include_str!("bee_cat.txt"); const BEE_CAT: &str = include_str!("bee_cat.txt");
//const ROOT_PARTLABEL: &str = "bee-root"; //const ROOT_PARTLABEL: &str = "bee-root";
const ROOT_DEV: &str = "/dev/disk/by-partlabel/bee-root"; const ROOT_PARTLABEL: &str = "bee-root";
const TMP_ROOT: &str = "/mnt/bee_root"; const TMP_REAL_ROOT: &str = "/mnt/real-bee";
const TMP_ROOT_SNAPS: &str = "/mnt/bee-root/bzz_snaps"; const TMP_REAL_ROOT_SNAPS: &str = "/mnt/real-bee/bzz-snaps";
const TMP_ROOT: &str = "/mnt/real-bee/bee-root";
const TMP_ROOT_SNAPS: &str = "/mnt/real-bee/bee-root/bzz-snaps";
const SYS_INIT: &str = "/sbin/init"; const SYS_INIT: &str = "/sbin/init";
// fn bee_root_is_present() -> bool { // fn bee_root_is_present() -> bool {
@@ -74,12 +76,15 @@ enum NyanitState {
} }
/// Mounting bee-root and chiking if there any snapshots /// Mounting bee-root and chiking if there any snapshots
fn mount_and_check_snaps() -> Result<NyanitState, ExecCommandError> { fn mount_and_check_snaps(bee_root_dev: &str) -> Result<NyanitState, ExecCommandError> {
// mount bee-root // mount bee-root
nyan_system::mount_bee_root(TMP_ROOT, ROOT_DEV)?; nyan_system::mount_bee_root(bee_root_dev, TMP_REAL_ROOT)?;
// let root_list = nyan_system::list_dir(TMP_ROOT)?;
// return Err(ExecCommandError::Other(root_list));
// list snaps if any // list snaps if any
let mut snaps_list = nyan_system::list_bzzpss_snaps(TMP_ROOT_SNAPS)?; let mut snaps_list = nyan_system::list_bzzpss_snaps(TMP_REAL_ROOT_SNAPS)?;
// if any snaps detected whait for user to press F2 // if any snaps detected whait for user to press F2
if snaps_list.len() > 0 { if snaps_list.len() > 0 {
snaps_list.insert(0, TMP_ROOT.to_string()); snaps_list.insert(0, TMP_ROOT.to_string());
@@ -90,23 +95,33 @@ fn mount_and_check_snaps() -> Result<NyanitState, ExecCommandError> {
Ok(NyanitState::HandOff(TMP_ROOT.into())) Ok(NyanitState::HandOff(TMP_ROOT.into()))
} }
fn init_stage() -> Result<NyanitState, ExecCommandError> { fn init_stage() -> Result<(String, NyanitState), ExecCommandError> {
// mount sysfss // mount sysfss
nyan_system::prepare_env().map_err(|ex| format!("prepare_env error: {}", ex))?; nyan_system::prepare_env().map_err(|ex| format!("prepare_env error: {}", ex))?;
// get bee-root device name aka /dev/sda1
// trying for max 3 sec
let bee_root_dev = nyan_system::try_find_partlabel(ROOT_PARTLABEL, 3)
.ok_or_else(|| "Timed out trying to find dev by partlabel.".to_string())?;
// works until this point!!!!
// check if device is encrypted // check if device is encrypted
if nyan_system::bzzpss_dev_encrypted(ROOT_DEV).map_err(|ex| format!("Error checking if device is encrypted: {}", ex))? { if nyan_system::bzzpss_dev_encrypted(&bee_root_dev)
.map_err(|ex| format!("Error checking if device is encrypted: {}", ex))?
{
// if encrypted return EnterPassword so used get promted for pass // if encrypted return EnterPassword so used get promted for pass
return Ok(NyanitState::EnterPassword); return Ok((bee_root_dev, NyanitState::EnterPassword));
} }
// if unencrypted // if unencrypted
mount_and_check_snaps() let check_res = mount_and_check_snaps(&bee_root_dev)?;
Ok((bee_root_dev, check_res))
} }
struct NyanitTUI<'a> { struct NyanitTUI<'a> {
exit: bool, exit: bool,
state: NyanitState, state: NyanitState,
bee_root_dev: String,
list_state: ListState, list_state: ListState,
time_counter: u32, time_counter: u32,
textarea: Option<TextArea<'a>>, textarea: Option<TextArea<'a>>,
@@ -117,22 +132,23 @@ impl NyanitTUI<'_> {
Ok(Self { Ok(Self {
exit: false, exit: false,
state: NyanitState::Init, state: NyanitState::Init,
bee_root_dev: String::new(),
list_state: ListState::default().with_selected(Some(0)), list_state: ListState::default().with_selected(Some(0)),
time_counter: 0, time_counter: 0,
textarea: None, textarea: None,
}) })
} }
// pub fn bzz_unwrap<T,E>(&mut self, val: Result<T,E>) -> T {
// match val {
// Ok(v) => v,
// }
// }
/// runs the application's main loop until the user quits /// runs the application's main loop until the user quits
pub fn run(&mut self) -> io::Result<()> { pub fn run(&mut self) -> io::Result<()> {
self.state = match init_stage() { self.state = match init_stage() {
Ok(st) => st, Ok(res) => {
Err(ex) => NyanitState::Error(format!("Error while trying to bzzz-pss things: {}", ex)), self.bee_root_dev = res.0;
res.1
}
Err(ex) => {
NyanitState::Error(format!("Error while trying to bzzz-pss things:\n{}", ex))
}
}; };
// if drive unencrypted and there is no root snapshots finish boot // if drive unencrypted and there is no root snapshots finish boot
@@ -279,11 +295,12 @@ impl NyanitTUI<'_> {
// try to unlock if enter pressed // try to unlock if enter pressed
Event::Key(event::Key::Char('\n')) => { Event::Key(event::Key::Char('\n')) => {
let password = self.textarea.as_ref().unwrap().lines()[0].clone(); let password = self.textarea.as_ref().unwrap().lines()[0].clone();
match nyan_system::bcachefs_unlock(password, ROOT_DEV) { match nyan_system::bcachefs_unlock(password, &self.bee_root_dev) {
Ok(unlocked) => { Ok(unlocked) => {
if unlocked { if unlocked {
// need to check for subvolumes and stuff // need to check for subvolumes and stuff
self.state = match mount_and_check_snaps() { self.state = match mount_and_check_snaps(&self.bee_root_dev)
{
Ok(st) => { Ok(st) => {
self.time_counter = 0; self.time_counter = 0;
st st
@@ -337,10 +354,8 @@ impl NyanitTUI<'_> {
} }
} }
fn main() -> ExitCode { fn main() -> ExitCode {
nyan_system::set_env_vars_unsafe(); // nyan_system::set_env_vars_unsafe();
let mut app = NyanitTUI::new().unwrap(); let mut app = NyanitTUI::new().unwrap();
app.run().unwrap(); app.run().unwrap();
// Terminal restores automatically when `stdout` (RawTerminal) is dropped // Terminal restores automatically when `stdout` (RawTerminal) is dropped
+208 -53
View File
@@ -18,9 +18,13 @@
Functions fot system interaction Functions fot system interaction
*/ */
use nix;
use std::fs; use std::fs;
use std::process::Command; use std::process::Command;
// timeout for block deices population
const WAIT_FOR_BLK_DEVS: u64 = 5u64;
#[derive(Debug)] #[derive(Debug)]
pub struct CommandFailed { pub struct CommandFailed {
pub stderr: Vec<u8>, pub stderr: Vec<u8>,
@@ -81,6 +85,12 @@ impl From<String> for ExecCommandError {
} }
} }
impl From<&str> for ExecCommandError {
fn from(err: &str) -> Self {
ExecCommandError::Other(err.to_string())
}
}
impl std::fmt::Display for ExecCommandError { impl std::fmt::Display for ExecCommandError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
@@ -101,9 +111,7 @@ impl std::error::Error for ExecCommandError {}
/// exec given command with arguments, capturing stderr in case or failure /// exec given command with arguments, capturing stderr in case or failure
pub fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError> { pub fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError> {
// For testing shake lets assume all binaries is in /usr/bin let out = Command::new(cmd).args(args).output()?;
let ex_cmd = format!("/usr/bin/{}", cmd);
let out = Command::new(ex_cmd).args(args).output()?;
if out.status.success() { if out.status.success() {
Ok(()) Ok(())
} else { } else {
@@ -111,6 +119,63 @@ pub fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError>
} }
} }
pub fn try_find_partlabel(partlabel: &str, timeout_secs: u64) -> Option<String> {
use std::{thread, time::Duration};
let start = std::time::Instant::now();
while start.elapsed().as_secs() < timeout_secs {
if let Ok(Some(label)) = find_partlabel(partlabel) {
return Some(label);
}
thread::sleep(Duration::from_millis(100));
}
None
}
/// 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())
)))
}
}
}
// pub fn list_dir(dirname: &str) -> Result<String, ExecCommandError> {
// let res: String = fs::read_dir(dirname)?
// .filter_map(|entry| entry.ok())
// .map(|entry| entry.file_name().to_string_lossy().to_string())
// .collect::<Vec<String>>()
// .join("\n");
// Ok(res)
// }
/// exec given command with arguments, returning stdout parsed to UTF-8 string /// exec given command with arguments, returning stdout parsed to UTF-8 string
/// capturing stderr in case or failure /// capturing stderr in case or failure
// pub fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result<String, ExecCommandError> { // pub fn exec_command_out(cmd: &str, args: &Vec<&str>) -> Result<String, ExecCommandError> {
@@ -122,21 +187,6 @@ pub fn exec_command(cmd: &str, args: &Vec<&str>) -> Result<(), ExecCommandError>
// } // }
// } // }
// ls /dev/disk/by-partlabel/
// here we can find gpt part labels
// pub fn list_gpt_labeled_devs() -> Result<Vec<String>, ExecCommandError> {
// use std::os::unix::fs::FileTypeExt;
// let mut res: Vec<String> = Vec::new();
// for maybe_entry in fs::read_dir("/dev/disk/by-partlabel/")? {
// let entry = maybe_entry?;
// if entry.file_type()?.is_block_device() {
// res.push(entry.path().to_str().unwrap().to_string());
// }
// }
// Ok(res)
// }
/// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0somedev /// bcachefs unlock --file=/tmp/bzzpsspass.txt /dev/loop0somedev
/// Ok so. It is stupid, because bcacheutils far from ideal. /// Ok so. It is stupid, because bcacheutils far from ideal.
/// But if we provide wrong password from file or stdin this stuff plays stupid and asks for right password. /// But if we provide wrong password from file or stdin this stuff plays stupid and asks for right password.
@@ -149,18 +199,24 @@ pub fn bcachefs_unlock(pass: String, dev: &str) -> Result<bool, ExecCommandError
use std::process::Stdio; use std::process::Stdio;
// "-k", "session" is important as it stores key in sessyin keyring what allows // "-k", "session" is important as it stores key in sessyin keyring what allows
// system to mount filesystem after switch_root // system to mount filesystem after switch_root
let mut child = Command::new("bcachefs") let mut child = Command::new("/usr/bin/bcachefs")
.args(&vec!["unlock", "-k", "session", dev]) .args(&vec!["unlock", "-k", "session", dev])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.spawn()?; .spawn()?;
let mut c_stderr = child.stderr.take().ok_or_else(||{"Unable to get child process STDERR".to_string()})?; let mut c_stderr = child
.stderr
.take()
.ok_or_else(|| "Unable to get child process STDERR".to_string())?;
// Write password to STDIN in a limited scope // Write password to STDIN in a limited scope
{ {
let mut c_stdin = child.stdin.take().ok_or_else(||{"Unable to get child process STDIN".to_string()})?; let mut c_stdin = child
.stdin
.take()
.ok_or_else(|| "Unable to get child process STDIN".to_string())?;
// neccessery to use thread or we may be deadlocking // neccessery to use thread or we may be deadlocking
c_stdin.write_all(pass.as_bytes())?; c_stdin.write_all(pass.as_bytes())?;
let bytes_written = c_stdin.write(b"\n")?; let bytes_written = c_stdin.write(b"\n")?;
@@ -186,7 +242,7 @@ pub fn bcachefs_unlock(pass: String, dev: &str) -> Result<bool, ExecCommandError
/// Cheking if device is encripted /// Cheking if device is encripted
pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result<bool, ExecCommandError> { pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result<bool, ExecCommandError> {
match exec_command("bcachefs", &vec!["unlock", "--check", dev_name]) { match exec_command("/usr/bin/bcachefs", &vec!["unlock", "--check", dev_name]) {
Ok(_) => Ok(true), // if status OK - dev encrypted Ok(_) => Ok(true), // if status OK - dev encrypted
Err(ExecCommandError::CommandFailed(_)) => Ok(false), // if bcachefs returned error - unencrypted Err(ExecCommandError::CommandFailed(_)) => Ok(false), // if bcachefs returned error - unencrypted
Err(ex) => Err(ex), // othervice its error Err(ex) => Err(ex), // othervice its error
@@ -195,11 +251,18 @@ pub fn bzzpss_dev_encrypted(dev_name: &str) -> Result<bool, ExecCommandError> {
//const TMP_ROOT: &str = "/mnt/bee-root"; //const TMP_ROOT: &str = "/mnt/bee-root";
pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandError> { pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandError> {
use regex::Regex; use regex_lite::Regex;
use std::path::Path;
// root snapshoot in a form of bzz-yyyy-mm-ddTHH-MM-SS // 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 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(); 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)? { for maybe_entry in fs::read_dir(snaps_dir)? {
let entry = maybe_entry?; let entry = maybe_entry?;
if entry.file_type()?.is_dir() { if entry.file_type()?.is_dir() {
@@ -213,63 +276,155 @@ pub fn list_bzzpss_snaps(snaps_dir: &str) -> Result<Vec<String>, ExecCommandErro
Ok(res) Ok(res)
} }
// pulls /sys/class/block
fn wait_for_block_devices(timeout_secs: u64) -> bool {
use std::path::Path;
use std::{thread, time::Duration};
let start = std::time::Instant::now();
while start.elapsed().as_secs() < timeout_secs {
// Check if any block device exists (e.g., sda, nvme0n1, vda)
// You can refine this to check for a specific device needed for root
if Path::new("/sys/class/block")
.read_dir()
.ok()
.and_then(|mut d| d.next().is_some().then_some(true))
.unwrap_or(false)
{
// Optional: Verify specific device needed for root exists
// if Path::new("/dev/nvme0n1").exists() { return true; }
return true;
}
thread::sleep(Duration::from_millis(100));
}
false
}
// mounting process // mounting process
//# Mount essential virtual filesystems //# Mount essential virtual filesystems
// mount -t proc none /proc // mount -t proc none /proc
// mount -t sysfs none /sys // mount -t sysfs none /sys
// modprobe bcachefs // modprobe bcachefs
pub fn prepare_env() -> Result<(), ExecCommandError> { pub fn prepare_env() -> Result<(), ExecCommandError> {
use nix::mount::{MsFlags, mount};
use std::path::Path;
// Mount proc filesystem
// mount -t proc none /proc // mount -t proc none /proc
exec_command("mount", &vec!["-t", "proc", "none", "/proc"])?; let proc_mount_flags =
MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_RELATIME;
mount(
Some("proc"),
Path::new("/proc"),
Some("proc"),
proc_mount_flags,
None::<&str>,
)
.map_err(|ex| format!("Error mounting /proc: {}", ex.to_string()))?;
// mount -t sysfs none /sys // mount -t sysfs none /sys
exec_command("mount", &vec!["-t", "sysfs", "none", "/sys"])?; let sys_mount_flags =
MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_RELATIME;
mount(
Some("sysfs"),
Path::new("/sys"),
Some("sysfs"),
sys_mount_flags,
None::<&str>,
)
.map_err(|ex| format!("Error mounting /sys: {}", ex.to_string()))?;
//waiting for block devs population
if wait_for_block_devices(WAIT_FOR_BLK_DEVS) == false {
return Err("Waiting for block devices to get populated timed out.".into());
}
let dev_mount_flags = MsFlags::MS_NOSUID | MsFlags::MS_RELATIME;
mount(
Some("devtmpfs"),
"/dev",
Some("devtmpfs"),
dev_mount_flags,
Some("mode=0755"),
)
.map_err(|ex| format!("Error mounting /dev: {}", ex.to_string()))?;
//mount -t tmpfs -o nosuid,nodev,noexec,mode=0755 none /run
let run_mount_flags = MsFlags::MS_NOSUID | MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_RELATIME;
mount(
Some("run"),
"/run",
Some("tmpfs"),
run_mount_flags,
Some("mode=0755"),
)
.map_err(|ex| format!("Error mounting /run: {}", ex.to_string()))?;
// modprobe bcachefs // modprobe bcachefs
// exec_command("modprobe", &vec!["bcachefs"])?; // exec_command("modprobe", &vec!["bcachefs"])?;
// Creating dir for udev so this little shit wont hang
// fs::create_dir("/run/udev")?;
Ok(()) Ok(())
} }
/// ///
/// MUST be done before spawning any threads or async runtimes /// MUST be done before spawning any threads or async runtimes
pub fn set_env_vars_unsafe() -> () { // pub fn set_env_vars_unsafe() -> () {
use std::env; // use std::env;
// 1. Define your custom paths // // 1. Define your custom paths
let custom_bin = "/usr/bin"; // let custom_bin = "/usr/bin";
let custom_lib = "/usr/lib"; // let custom_lib = "/usr/lib";
// 2. Retrieve existing paths to append/prepend (optional but recommended) // // 2. Retrieve existing paths to append/prepend (optional but recommended)
// 3. Construct new path strings // // 3. Construct new path strings
let new_path = match env::var("PATH") { // let new_path = match env::var("PATH") {
Err(_) => custom_bin.to_string(), // Err(_) => custom_bin.to_string(),
Ok(v) => format!("{}:{}", v, custom_bin) // Ok(v) => format!("{}:{}", custom_bin, v),
}; // };
let new_ld_path = match env::var("LD_LIBRARY_PATH") { // let new_ld_path = match env::var("LD_LIBRARY_PATH") {
Err(_) => custom_lib.to_string(), // Err(_) => custom_lib.to_string(),
Ok(v) => format!("{}:{}", v, custom_lib) // Ok(v) => format!("{}:{}", custom_lib, v),
}; // };
// 4. Set environment variables (UNSAFE in Rust 2024+) // // 4. Set environment variables (UNSAFE in Rust 2024+)
// MUST be done before spawning any threads or async runtimes // // MUST be done before spawning any threads or async runtimes
unsafe { // unsafe {
env::set_var("PATH", new_path); // env::set_var("PATH", new_path);
env::set_var("LD_LIBRARY_PATH", new_ld_path); // env::set_var("LD_LIBRARY_PATH", new_ld_path);
} // }
} // }
// # Mount the real root filesystem // # Mount the real root filesystem
pub fn mount_bee_root(mount_point: &str, dev_name: &str) -> Result<(), ExecCommandError> { pub fn mount_bee_root(dev_name: &str, mount_point: &str) -> Result<(), ExecCommandError> {
exec_command("mount", &vec!["-o", "ro", dev_name, mount_point])?; use nix::mount::{MsFlags, mount};
use std::path::Path;
let root_mount_flags = MsFlags::MS_RDONLY | MsFlags::MS_RELATIME;
mount(
Some(dev_name),
Path::new(mount_point),
Some("bcachefs"),
root_mount_flags,
None::<&str>,
)
.map_err(|ex| format!("Error mounting root {} to {} :\n{}",dev_name, mount_point, ex.to_string()))?;
// exec_command("/usr/bin/mount", &vec!["-o", "ro", dev_name, mount_point])?;
Ok(()) Ok(())
} }
// finish boot // finish boot
pub fn hand_off_control(mnt_root: &str, init_path: &str) -> Result<(), ExecCommandError> { pub fn hand_off_control(mnt_root: &str, init_path: &str) -> Result<(), ExecCommandError> {
use std::env; //use std::env;
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
// 2. Change directory to the new root (Mandatory for switch_root) // 2. Change directory to the new root (Mandatory for switch_root)
env::set_current_dir(mnt_root)?; // Actually this may be a problem!
// env::set_current_dir(mnt_root)?;
// # Clean up virtual filesystems // # Clean up virtual filesystems
// !!! do not do this, switch_root handle this stuff and fail if thay not present! // !!! do not do this, switch_root handle this stuff and fail if thay not present!
@@ -281,7 +436,7 @@ pub fn hand_off_control(mnt_root: &str, init_path: &str) -> Result<(), ExecComma
// 3. Execute switch_root. // 3. Execute switch_root.
// This call replaces the current Rust process. // This call replaces the current Rust process.
// It only returns if an error occurs. // It only returns if an error occurs.
let err = Command::new("switch_root") let err = Command::new("/usr/bin/switch_root")
.arg(mnt_root) .arg(mnt_root)
.arg(init_path) .arg(init_path)
.exec(); .exec();