initial commit
This commit is contained in:
commit
ddc990b522
13 changed files with 1679 additions and 0 deletions
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# sorry but I don't need my network config public
|
||||||
|
setup/network.toml
|
||||||
|
# also other config contains like access tokens so just hide everything
|
||||||
|
setup/
|
||||||
|
|
||||||
|
# rust/cargo
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# git
|
||||||
|
*.orig
|
||||||
|
|
||||||
|
# emacs
|
||||||
|
*~
|
||||||
|
\#*#
|
||||||
|
.#*#
|
||||||
|
|
||||||
|
# intellij
|
||||||
|
/.idea/
|
||||||
|
*.ipr
|
||||||
|
*.iml
|
653
Cargo.lock
generated
Normal file
653
Cargo.lock
generated
Normal file
|
@ -0,0 +1,653 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attohttpc"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2"
|
||||||
|
dependencies = [
|
||||||
|
"flate2",
|
||||||
|
"http",
|
||||||
|
"log",
|
||||||
|
"native-tls",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "basic-toml"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.141"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mkalpiimg"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"attohttpc",
|
||||||
|
"basic-toml",
|
||||||
|
"serde",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.17.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.49"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.84"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.159"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.159"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.0",
|
||||||
|
"windows_aarch64_msvc 0.48.0",
|
||||||
|
"windows_i686_gnu 0.48.0",
|
||||||
|
"windows_i686_msvc 0.48.0",
|
||||||
|
"windows_x86_64_gnu 0.48.0",
|
||||||
|
"windows_x86_64_gnullvm 0.48.0",
|
||||||
|
"windows_x86_64_msvc 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "mkalpiimg"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
attohttpc = "0.24"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
tempfile = "3.4"
|
||||||
|
toml = { version = "0.1", package = "basic-toml" }
|
277
LICENSE
Normal file
277
LICENSE
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
Eclipse Public License - v 2.0
|
||||||
|
|
||||||
|
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
|
||||||
|
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
|
||||||
|
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
|
||||||
|
|
||||||
|
1. DEFINITIONS
|
||||||
|
|
||||||
|
"Contribution" means:
|
||||||
|
|
||||||
|
a) in the case of the initial Contributor, the initial content
|
||||||
|
Distributed under this Agreement, and
|
||||||
|
|
||||||
|
b) in the case of each subsequent Contributor:
|
||||||
|
i) changes to the Program, and
|
||||||
|
ii) additions to the Program;
|
||||||
|
where such changes and/or additions to the Program originate from
|
||||||
|
and are Distributed by that particular Contributor. A Contribution
|
||||||
|
"originates" from a Contributor if it was added to the Program by
|
||||||
|
such Contributor itself or anyone acting on such Contributor's behalf.
|
||||||
|
Contributions do not include changes or additions to the Program that
|
||||||
|
are not Modified Works.
|
||||||
|
|
||||||
|
"Contributor" means any person or entity that Distributes the Program.
|
||||||
|
|
||||||
|
"Licensed Patents" mean patent claims licensable by a Contributor which
|
||||||
|
are necessarily infringed by the use or sale of its Contribution alone
|
||||||
|
or when combined with the Program.
|
||||||
|
|
||||||
|
"Program" means the Contributions Distributed in accordance with this
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
"Recipient" means anyone who receives the Program under this Agreement
|
||||||
|
or any Secondary License (as applicable), including Contributors.
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source Code or other
|
||||||
|
form, that is based on (or derived from) the Program and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship.
|
||||||
|
|
||||||
|
"Modified Works" shall mean any work in Source Code or other form that
|
||||||
|
results from an addition to, deletion from, or modification of the
|
||||||
|
contents of the Program, including, for purposes of clarity any new file
|
||||||
|
in Source Code form that contains any contents of the Program. Modified
|
||||||
|
Works shall not include works that contain only declarations,
|
||||||
|
interfaces, types, classes, structures, or files of the Program solely
|
||||||
|
in each case in order to link to, bind by name, or subclass the Program
|
||||||
|
or Modified Works thereof.
|
||||||
|
|
||||||
|
"Distribute" means the acts of a) distributing or b) making available
|
||||||
|
in any manner that enables the transfer of a copy.
|
||||||
|
|
||||||
|
"Source Code" means the form of a Program preferred for making
|
||||||
|
modifications, including but not limited to software source code,
|
||||||
|
documentation source, and configuration files.
|
||||||
|
|
||||||
|
"Secondary License" means either the GNU General Public License,
|
||||||
|
Version 2.0, or any later versions of that license, including any
|
||||||
|
exceptions or additional permissions as identified by the initial
|
||||||
|
Contributor.
|
||||||
|
|
||||||
|
2. GRANT OF RIGHTS
|
||||||
|
|
||||||
|
a) Subject to the terms of this Agreement, each Contributor hereby
|
||||||
|
grants Recipient a non-exclusive, worldwide, royalty-free copyright
|
||||||
|
license to reproduce, prepare Derivative Works of, publicly display,
|
||||||
|
publicly perform, Distribute and sublicense the Contribution of such
|
||||||
|
Contributor, if any, and such Derivative Works.
|
||||||
|
|
||||||
|
b) Subject to the terms of this Agreement, each Contributor hereby
|
||||||
|
grants Recipient a non-exclusive, worldwide, royalty-free patent
|
||||||
|
license under Licensed Patents to make, use, sell, offer to sell,
|
||||||
|
import and otherwise transfer the Contribution of such Contributor,
|
||||||
|
if any, in Source Code or other form. This patent license shall
|
||||||
|
apply to the combination of the Contribution and the Program if, at
|
||||||
|
the time the Contribution is added by the Contributor, such addition
|
||||||
|
of the Contribution causes such combination to be covered by the
|
||||||
|
Licensed Patents. The patent license shall not apply to any other
|
||||||
|
combinations which include the Contribution. No hardware per se is
|
||||||
|
licensed hereunder.
|
||||||
|
|
||||||
|
c) Recipient understands that although each Contributor grants the
|
||||||
|
licenses to its Contributions set forth herein, no assurances are
|
||||||
|
provided by any Contributor that the Program does not infringe the
|
||||||
|
patent or other intellectual property rights of any other entity.
|
||||||
|
Each Contributor disclaims any liability to Recipient for claims
|
||||||
|
brought by any other entity based on infringement of intellectual
|
||||||
|
property rights or otherwise. As a condition to exercising the
|
||||||
|
rights and licenses granted hereunder, each Recipient hereby
|
||||||
|
assumes sole responsibility to secure any other intellectual
|
||||||
|
property rights needed, if any. For example, if a third party
|
||||||
|
patent license is required to allow Recipient to Distribute the
|
||||||
|
Program, it is Recipient's responsibility to acquire that license
|
||||||
|
before distributing the Program.
|
||||||
|
|
||||||
|
d) Each Contributor represents that to its knowledge it has
|
||||||
|
sufficient copyright rights in its Contribution, if any, to grant
|
||||||
|
the copyright license set forth in this Agreement.
|
||||||
|
|
||||||
|
e) Notwithstanding the terms of any Secondary License, no
|
||||||
|
Contributor makes additional grants to any Recipient (other than
|
||||||
|
those set forth in this Agreement) as a result of such Recipient's
|
||||||
|
receipt of the Program under the terms of a Secondary License
|
||||||
|
(if permitted under the terms of Section 3).
|
||||||
|
|
||||||
|
3. REQUIREMENTS
|
||||||
|
|
||||||
|
3.1 If a Contributor Distributes the Program in any form, then:
|
||||||
|
|
||||||
|
a) the Program must also be made available as Source Code, in
|
||||||
|
accordance with section 3.2, and the Contributor must accompany
|
||||||
|
the Program with a statement that the Source Code for the Program
|
||||||
|
is available under this Agreement, and informs Recipients how to
|
||||||
|
obtain it in a reasonable manner on or through a medium customarily
|
||||||
|
used for software exchange; and
|
||||||
|
|
||||||
|
b) the Contributor may Distribute the Program under a license
|
||||||
|
different than this Agreement, provided that such license:
|
||||||
|
i) effectively disclaims on behalf of all other Contributors all
|
||||||
|
warranties and conditions, express and implied, including
|
||||||
|
warranties or conditions of title and non-infringement, and
|
||||||
|
implied warranties or conditions of merchantability and fitness
|
||||||
|
for a particular purpose;
|
||||||
|
|
||||||
|
ii) effectively excludes on behalf of all other Contributors all
|
||||||
|
liability for damages, including direct, indirect, special,
|
||||||
|
incidental and consequential damages, such as lost profits;
|
||||||
|
|
||||||
|
iii) does not attempt to limit or alter the recipients' rights
|
||||||
|
in the Source Code under section 3.2; and
|
||||||
|
|
||||||
|
iv) requires any subsequent distribution of the Program by any
|
||||||
|
party to be under a license that satisfies the requirements
|
||||||
|
of this section 3.
|
||||||
|
|
||||||
|
3.2 When the Program is Distributed as Source Code:
|
||||||
|
|
||||||
|
a) it must be made available under this Agreement, or if the
|
||||||
|
Program (i) is combined with other material in a separate file or
|
||||||
|
files made available under a Secondary License, and (ii) the initial
|
||||||
|
Contributor attached to the Source Code the notice described in
|
||||||
|
Exhibit A of this Agreement, then the Program may be made available
|
||||||
|
under the terms of such Secondary Licenses, and
|
||||||
|
|
||||||
|
b) a copy of this Agreement must be included with each copy of
|
||||||
|
the Program.
|
||||||
|
|
||||||
|
3.3 Contributors may not remove or alter any copyright, patent,
|
||||||
|
trademark, attribution notices, disclaimers of warranty, or limitations
|
||||||
|
of liability ("notices") contained within the Program from any copy of
|
||||||
|
the Program which they Distribute, provided that Contributors may add
|
||||||
|
their own appropriate notices.
|
||||||
|
|
||||||
|
4. COMMERCIAL DISTRIBUTION
|
||||||
|
|
||||||
|
Commercial distributors of software may accept certain responsibilities
|
||||||
|
with respect to end users, business partners and the like. While this
|
||||||
|
license is intended to facilitate the commercial use of the Program,
|
||||||
|
the Contributor who includes the Program in a commercial product
|
||||||
|
offering should do so in a manner which does not create potential
|
||||||
|
liability for other Contributors. Therefore, if a Contributor includes
|
||||||
|
the Program in a commercial product offering, such Contributor
|
||||||
|
("Commercial Contributor") hereby agrees to defend and indemnify every
|
||||||
|
other Contributor ("Indemnified Contributor") against any losses,
|
||||||
|
damages and costs (collectively "Losses") arising from claims, lawsuits
|
||||||
|
and other legal actions brought by a third party against the Indemnified
|
||||||
|
Contributor to the extent caused by the acts or omissions of such
|
||||||
|
Commercial Contributor in connection with its distribution of the Program
|
||||||
|
in a commercial product offering. The obligations in this section do not
|
||||||
|
apply to any claims or Losses relating to any actual or alleged
|
||||||
|
intellectual property infringement. In order to qualify, an Indemnified
|
||||||
|
Contributor must: a) promptly notify the Commercial Contributor in
|
||||||
|
writing of such claim, and b) allow the Commercial Contributor to control,
|
||||||
|
and cooperate with the Commercial Contributor in, the defense and any
|
||||||
|
related settlement negotiations. The Indemnified Contributor may
|
||||||
|
participate in any such claim at its own expense.
|
||||||
|
|
||||||
|
For example, a Contributor might include the Program in a commercial
|
||||||
|
product offering, Product X. That Contributor is then a Commercial
|
||||||
|
Contributor. If that Commercial Contributor then makes performance
|
||||||
|
claims, or offers warranties related to Product X, those performance
|
||||||
|
claims and warranties are such Commercial Contributor's responsibility
|
||||||
|
alone. Under this section, the Commercial Contributor would have to
|
||||||
|
defend claims against the other Contributors related to those performance
|
||||||
|
claims and warranties, and if a court requires any other Contributor to
|
||||||
|
pay any damages as a result, the Commercial Contributor must pay
|
||||||
|
those damages.
|
||||||
|
|
||||||
|
5. NO WARRANTY
|
||||||
|
|
||||||
|
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
|
||||||
|
PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
|
||||||
|
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
||||||
|
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
|
||||||
|
TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. Each Recipient is solely responsible for determining the
|
||||||
|
appropriateness of using and distributing the Program and assumes all
|
||||||
|
risks associated with its exercise of rights under this Agreement,
|
||||||
|
including but not limited to the risks and costs of program errors,
|
||||||
|
compliance with applicable laws, damage to or loss of data, programs
|
||||||
|
or equipment, and unavailability or interruption of operations.
|
||||||
|
|
||||||
|
6. DISCLAIMER OF LIABILITY
|
||||||
|
|
||||||
|
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
|
||||||
|
PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
|
||||||
|
SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
|
||||||
|
PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
|
||||||
|
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
7. GENERAL
|
||||||
|
|
||||||
|
If any provision of this Agreement is invalid or unenforceable under
|
||||||
|
applicable law, it shall not affect the validity or enforceability of
|
||||||
|
the remainder of the terms of this Agreement, and without further
|
||||||
|
action by the parties hereto, such provision shall be reformed to the
|
||||||
|
minimum extent necessary to make such provision valid and enforceable.
|
||||||
|
|
||||||
|
If Recipient institutes patent litigation against any entity
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that the
|
||||||
|
Program itself (excluding combinations of the Program with other software
|
||||||
|
or hardware) infringes such Recipient's patent(s), then such Recipient's
|
||||||
|
rights granted under Section 2(b) shall terminate as of the date such
|
||||||
|
litigation is filed.
|
||||||
|
|
||||||
|
All Recipient's rights under this Agreement shall terminate if it
|
||||||
|
fails to comply with any of the material terms or conditions of this
|
||||||
|
Agreement and does not cure such failure in a reasonable period of
|
||||||
|
time after becoming aware of such noncompliance. If all Recipient's
|
||||||
|
rights under this Agreement terminate, Recipient agrees to cease use
|
||||||
|
and distribution of the Program as soon as reasonably practicable.
|
||||||
|
However, Recipient's obligations under this Agreement and any licenses
|
||||||
|
granted by Recipient relating to the Program shall continue and survive.
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute copies of this Agreement,
|
||||||
|
but in order to avoid inconsistency the Agreement is copyrighted and
|
||||||
|
may only be modified in the following manner. The Agreement Steward
|
||||||
|
reserves the right to publish new versions (including revisions) of
|
||||||
|
this Agreement from time to time. No one other than the Agreement
|
||||||
|
Steward has the right to modify this Agreement. The Eclipse Foundation
|
||||||
|
is the initial Agreement Steward. The Eclipse Foundation may assign the
|
||||||
|
responsibility to serve as the Agreement Steward to a suitable separate
|
||||||
|
entity. Each new version of the Agreement will be given a distinguishing
|
||||||
|
version number. The Program (including Contributions) may always be
|
||||||
|
Distributed subject to the version of the Agreement under which it was
|
||||||
|
received. In addition, after a new version of the Agreement is published,
|
||||||
|
Contributor may elect to Distribute the Program (including its
|
||||||
|
Contributions) under the new version.
|
||||||
|
|
||||||
|
Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
|
||||||
|
receives no rights or licenses to the intellectual property of any
|
||||||
|
Contributor under this Agreement, whether expressly, by implication,
|
||||||
|
estoppel or otherwise. All rights in the Program not expressly granted
|
||||||
|
under this Agreement are reserved. Nothing in this Agreement is intended
|
||||||
|
to be enforceable by any entity that is not a Contributor or Recipient.
|
||||||
|
No third-party beneficiary rights are created under this Agreement.
|
||||||
|
|
||||||
|
Exhibit A - Form of Secondary Licenses Notice
|
||||||
|
|
||||||
|
"This Source Code may also be made available under the following
|
||||||
|
Secondary Licenses when the conditions for such availability set forth
|
||||||
|
in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
|
||||||
|
version(s), and exceptions or additional permissions here}."
|
||||||
|
|
||||||
|
Simply including a copy of this Agreement, including this Exhibit A
|
||||||
|
is not sufficient to license the Source Code under Secondary Licenses.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to
|
||||||
|
look for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
35
rustfmt.toml
Normal file
35
rustfmt.toml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
edition = "2021"
|
||||||
|
max_width = 140
|
||||||
|
newline_style = "Unix"
|
||||||
|
unstable_features = true
|
||||||
|
|
||||||
|
# always use tabs.
|
||||||
|
hard_tabs = true
|
||||||
|
tab_spaces = 4
|
||||||
|
|
||||||
|
# commas inbetween but not after
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
trailing_comma = "Never"
|
||||||
|
|
||||||
|
# fix my imports for me
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
#group_imports = "One"
|
||||||
|
|
||||||
|
# format everything
|
||||||
|
format_code_in_doc_comments = true
|
||||||
|
format_macro_matchers = true
|
||||||
|
|
||||||
|
# don't keep outdated syntax
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
use_try_shorthand = true
|
||||||
|
|
||||||
|
# condense Struct { _, _ } to Struct { .. }
|
||||||
|
condense_wildcard_suffixes = true
|
||||||
|
|
||||||
|
# prefer foo(Bar { \n }) over foo(\nBar { \n }\n)
|
||||||
|
overflow_delimited_expr = true
|
||||||
|
|
||||||
|
# I wish there was a way to allow 0..n but not a + 1..b + 2
|
||||||
|
# However, the later looks so terible that I use spaces everywhere
|
||||||
|
# https://github.com/rust-lang/rustfmt/issues/3367
|
||||||
|
spaces_around_ranges = true
|
23
src/main.rs
Normal file
23
src/main.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
mod setup;
|
||||||
|
mod steps;
|
||||||
|
|
||||||
|
use crate::steps::{install_autostart, set_passwords};
|
||||||
|
use setup::Setup;
|
||||||
|
use steps::{init_first_boot, init_network, init_os, install_packages, prepare_img};
|
||||||
|
|
||||||
|
const IMAGE_SIZE_GB: u64 = 2;
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let setup = Setup::load()?;
|
||||||
|
|
||||||
|
let img = prepare_img()?;
|
||||||
|
init_os(&setup, &img)?;
|
||||||
|
init_network(&img, &setup)?;
|
||||||
|
install_packages(&img, &setup)?;
|
||||||
|
install_autostart(&img, &setup)?;
|
||||||
|
init_first_boot(&img)?;
|
||||||
|
set_passwords(&img, &setup)?;
|
||||||
|
|
||||||
|
eprintln!("SUCCESS");
|
||||||
|
Ok(())
|
||||||
|
}
|
47
src/steps/init_first_boot.rs
Normal file
47
src/steps/init_first_boot.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
use super::{run_chroot, Image};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
pub fn init_first_boot(img: &Image) -> anyhow::Result<()> {
|
||||||
|
eprintln!("Preparing first boot script ...");
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
img.root.0.join("usr").join("local").join("bin").join("first-boot"),
|
||||||
|
r#"#!/bin/sh
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
cat <<PARTED | sudo parted ---pretend-input-tty /dev/mmcblk0
|
||||||
|
unit %
|
||||||
|
resizepart 2
|
||||||
|
Yes
|
||||||
|
100%
|
||||||
|
PARTED
|
||||||
|
|
||||||
|
partprobe
|
||||||
|
resize2fs /dev/mmcblk0p2
|
||||||
|
|
||||||
|
rc-update add zram-init boot
|
||||||
|
|
||||||
|
rc-update del first-boot
|
||||||
|
rm /etc/init.d/first-boot /usr/local/bin/first-boot
|
||||||
|
|
||||||
|
reboot
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
fs::write(
|
||||||
|
img.root.0.join("etc").join("init.d").join("first-boot"),
|
||||||
|
r#"#!/sbin/openrc-run
|
||||||
|
command="/usr/local/bin/first-boot"
|
||||||
|
command_background=false
|
||||||
|
depend() {
|
||||||
|
after modules
|
||||||
|
need localmount
|
||||||
|
}"#
|
||||||
|
)?;
|
||||||
|
run_chroot(
|
||||||
|
img,
|
||||||
|
"root",
|
||||||
|
"chmod +x /etc/init.d/first-boot /usr/local/bin/first-boot; rc-update add first-boot"
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
111
src/steps/init_network.rs
Normal file
111
src/steps/init_network.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use super::{run_chroot, Image};
|
||||||
|
use crate::setup::{network::WifiSecurity, Setup};
|
||||||
|
use anyhow::Context as _;
|
||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::Write as _
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init_network(img: &Image, setup: &Setup) -> anyhow::Result<()> {
|
||||||
|
eprintln!("Preparing network ...");
|
||||||
|
|
||||||
|
let mut interfaces = File::create(img.root.0.join("etc").join("network").join("interfaces"))?;
|
||||||
|
for (name, ty) in [("lo", "loopback"), ("eth0", "dhcp")] {
|
||||||
|
writeln!(interfaces, "auto {name}")?;
|
||||||
|
writeln!(interfaces, "iface {name} inet {ty}")?;
|
||||||
|
writeln!(interfaces)?;
|
||||||
|
}
|
||||||
|
writeln!(interfaces, "hostname {}", setup.os.host.hostname)?;
|
||||||
|
fs::write(
|
||||||
|
img.root.0.join("etc").join("resolv.conf"),
|
||||||
|
r#"nameserver 1.0.0.1
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
nameserver 2606:4700:4700::1001
|
||||||
|
nameserver 2606:4700:4700::1111
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", "networking", "default"])?;
|
||||||
|
|
||||||
|
if setup.network.tailscale {
|
||||||
|
run_chroot(img, "root", "apk add tailscale; rc-update add tailscale default")?;
|
||||||
|
fs::write(
|
||||||
|
img.root.0.join("usr").join("local").join("bin").join("tailscale-up"),
|
||||||
|
r#"#!/bin/sh
|
||||||
|
for i in 0 1 2 3 4; do
|
||||||
|
ping -c 2 -W 1 1.1.1.1 && break
|
||||||
|
if [ "$i" == "4" ]; then exit 1; fi
|
||||||
|
echo "Waiting for network ..."
|
||||||
|
sleep 2s
|
||||||
|
done
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Connecting to tailscale ..."
|
||||||
|
timeout -v 2m tailscale up
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
fs::write(
|
||||||
|
img.root.0.join("etc").join("init.d").join("tailscale-up"),
|
||||||
|
r#"#!/sbin/openrc-run
|
||||||
|
command="/usr/local/bin/tailscale-up"
|
||||||
|
command_background=false
|
||||||
|
depend() {
|
||||||
|
after ntpd
|
||||||
|
need tailscale
|
||||||
|
}"#
|
||||||
|
)?;
|
||||||
|
run_chroot(
|
||||||
|
img,
|
||||||
|
"root",
|
||||||
|
"chmod +x /usr/local/bin/tailscale-up /etc/init.d/tailscale-up; rc-update add tailscale-up default"
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setup.network.wifi.is_empty() {
|
||||||
|
run_chroot(img, "root", "echo 'brcmfmac' >> /etc/modules")?;
|
||||||
|
run_chroot(img, "root", ["apk", "add", "iw", "iwd", "wireless-tools", "wireless-regdb"])?;
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", "iwd", "default"])?;
|
||||||
|
|
||||||
|
let iwd = img.root.0.join("etc").join("iwd");
|
||||||
|
fs::create_dir_all(&iwd).context("Unable to create /etc/iwd directory")?;
|
||||||
|
fs::write(
|
||||||
|
iwd.join("main.conf"),
|
||||||
|
r#"# main iwd configuration file
|
||||||
|
|
||||||
|
[General]
|
||||||
|
EnableNetworkConfiguration=true
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
EnableIPv6=true
|
||||||
|
NameResolvingService=none
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
.context("Unable to write /etc/iwd/main.conf")?;
|
||||||
|
|
||||||
|
let iwd = img.root.0.join("var").join("lib").join("iwd");
|
||||||
|
fs::create_dir_all(&iwd).context("Unable to create /var/lib/iwd directory")?;
|
||||||
|
for wifi in &setup.network.wifi {
|
||||||
|
let ssid = &wifi.ssid;
|
||||||
|
match &wifi.security {
|
||||||
|
WifiSecurity::None => {
|
||||||
|
fs::write(iwd.join(format!("{ssid}.open")), "\n")?;
|
||||||
|
},
|
||||||
|
WifiSecurity::WpaPsk { password } => {
|
||||||
|
fs::write(iwd.join(format!("{ssid}.psk")), format!("[Security]\nPassphrase={password}\n"))?;
|
||||||
|
},
|
||||||
|
WifiSecurity::WpaEap { identity, password } => {
|
||||||
|
let mut file = File::create(iwd.join(format!("{ssid}.8021x")))?;
|
||||||
|
writeln!(file, "[Security]")?;
|
||||||
|
writeln!(file, "EAP-Method=PWD")?;
|
||||||
|
writeln!(file, "EAP-Identity={identity}")?;
|
||||||
|
writeln!(file, "EAP-Password={password}")?;
|
||||||
|
writeln!(file)?;
|
||||||
|
writeln!(file, "[Settings]")?;
|
||||||
|
writeln!(file, "AutoConnect=true")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
189
src/steps/init_os.rs
Normal file
189
src/steps/init_os.rs
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
use super::{download, run, run_chroot, tempfile, Image};
|
||||||
|
use crate::setup::Setup;
|
||||||
|
use anyhow::Context as _;
|
||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::Write as _,
|
||||||
|
path::Path
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init_os(setup: &Setup, img: &Image) -> anyhow::Result<()> {
|
||||||
|
eprintln!("Preparing operating system ...");
|
||||||
|
|
||||||
|
// write raspberry pi config
|
||||||
|
fs::write(img.boot.0.join("cmdline.txt"), &setup.os.rpi.cmdline)?;
|
||||||
|
let mut config = File::create(img.boot.0.join("config.txt"))?;
|
||||||
|
writeln!(
|
||||||
|
config,
|
||||||
|
r#"# Do not modify this file. Create and/or modify usercfg.txt instead.
|
||||||
|
[pi3]
|
||||||
|
kernel=vmlinuz-rpi
|
||||||
|
initramfs initramfs-rpi
|
||||||
|
[pi3+]
|
||||||
|
kernel=vmlinuz-rpi
|
||||||
|
initramfs initramfs-rpi
|
||||||
|
[pi4]
|
||||||
|
enable_gic=1
|
||||||
|
kernel=vmlinuz-rpi4
|
||||||
|
initramfs initramfs-rpi4
|
||||||
|
[all]"#
|
||||||
|
)?;
|
||||||
|
if setup.os.alpine.arch.is64bit() {
|
||||||
|
writeln!(config, "arm_64bit=1")?;
|
||||||
|
}
|
||||||
|
writeln!(config, "include usercfg.txt")?;
|
||||||
|
drop(config);
|
||||||
|
fs::write(img.boot.0.join("usercfg.txt"), &setup.os.rpi.usercfg)?;
|
||||||
|
|
||||||
|
// write initial apk config
|
||||||
|
let etc = img.root.0.join("etc");
|
||||||
|
let etc_apk = etc.join("apk");
|
||||||
|
let etc_apk_keys = etc_apk.join("keys");
|
||||||
|
fs::create_dir_all(&etc_apk_keys).context("Failed to create /etc/apk/keys directory")?;
|
||||||
|
let mut repositories = File::create(etc_apk.join("repositories"))?;
|
||||||
|
for repo in ["main", "community"] {
|
||||||
|
writeln!(repositories, "{}/{}/{repo}", setup.os.alpine.mirror, setup.os.alpine.branch)?;
|
||||||
|
}
|
||||||
|
for repo in &setup.os.alpine.extra_repos {
|
||||||
|
writeln!(repositories, "{repo}")?;
|
||||||
|
}
|
||||||
|
drop(repositories);
|
||||||
|
|
||||||
|
// download apk keys
|
||||||
|
let keys = tempfile()?;
|
||||||
|
download(
|
||||||
|
keys.path(),
|
||||||
|
&format!(
|
||||||
|
"https://gitlab.alpinelinux.org/alpine/aports/-/archive/{branch}/aports-{branch}.tar.bz2?path=main/alpine-keys",
|
||||||
|
branch = setup.os.alpine.branch.git_branch()
|
||||||
|
)
|
||||||
|
)?;
|
||||||
|
run(&[
|
||||||
|
"tar",
|
||||||
|
"xfj",
|
||||||
|
keys.path().to_str().unwrap(),
|
||||||
|
"-C",
|
||||||
|
etc_apk_keys.to_str().unwrap(),
|
||||||
|
"--strip-components=3",
|
||||||
|
"--wildcards",
|
||||||
|
"*/alpine-devel@lists.alpinelinux.org-*.rsa.pub"
|
||||||
|
])?;
|
||||||
|
drop(keys);
|
||||||
|
|
||||||
|
// copy additional keys
|
||||||
|
for key in &setup.os.alpine.extra_keys {
|
||||||
|
let key = Path::new(key);
|
||||||
|
let name = key.file_name().unwrap();
|
||||||
|
fs::copy(Path::new("setup").join(key), etc_apk_keys.join(name))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bootstrap alpine
|
||||||
|
run(&[
|
||||||
|
"apk",
|
||||||
|
"add",
|
||||||
|
"--root",
|
||||||
|
&img.root,
|
||||||
|
"--update-cache",
|
||||||
|
"--initdb",
|
||||||
|
"--arch",
|
||||||
|
setup.os.alpine.arch.to_str(),
|
||||||
|
"agetty",
|
||||||
|
"alpine-base",
|
||||||
|
"alpine-sdk",
|
||||||
|
"ca-certificates",
|
||||||
|
"elogind",
|
||||||
|
"eudev",
|
||||||
|
"haveged",
|
||||||
|
"linux-rpi",
|
||||||
|
"linux-rpi4",
|
||||||
|
"openssh",
|
||||||
|
"parted",
|
||||||
|
"raspberrypi-bootloader",
|
||||||
|
"sudo",
|
||||||
|
"tzdata",
|
||||||
|
"udev-init-scripts",
|
||||||
|
"util-linux-login",
|
||||||
|
"zram-init"
|
||||||
|
])?;
|
||||||
|
run(&[
|
||||||
|
"sed",
|
||||||
|
"-E",
|
||||||
|
"-e",
|
||||||
|
"s,getty(.*)$,agetty --noclear\\1 linux,",
|
||||||
|
"-i",
|
||||||
|
etc.join("inittab").to_str().unwrap()
|
||||||
|
])?;
|
||||||
|
for service in ["udev", "udev-postmount", "udev-settle", "udev-trigger"] {
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", service, "sysinit"])?;
|
||||||
|
}
|
||||||
|
for service in ["modules", "syslog", "swclock"] {
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", service, "boot"])?;
|
||||||
|
}
|
||||||
|
for service in ["elogind", "haveged", "ntpd", "sshd"] {
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", service, "default"])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure fstab
|
||||||
|
fs::write(
|
||||||
|
etc.join("fstab"),
|
||||||
|
r#"# <device> <dir> <type> <options> <dump> <fsck>
|
||||||
|
/dev/mmcblk0p1 /boot vfat defaults 0 2
|
||||||
|
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// something is broken with abuild's functions.sh, so let's set CBUILD ourselves
|
||||||
|
let profile_d = etc.join("profile.d");
|
||||||
|
fs::create_dir_all(&profile_d)?;
|
||||||
|
fs::write(
|
||||||
|
profile_d.join("cbuild.sh"),
|
||||||
|
&format!("export CBUILD={}", setup.os.alpine.arch.cbuild())
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// set up the locale
|
||||||
|
run_chroot(img, "root", ["setup-hostname", &setup.os.host.hostname])?;
|
||||||
|
run_chroot(img, "root", ["setup-timezone", "-z", &setup.os.host.timezone])?;
|
||||||
|
if let Some(variant) = setup.os.host.keymap_variant.as_deref() {
|
||||||
|
run_chroot(img, "root", ["setup-keymap", &setup.os.host.keymap, variant])?;
|
||||||
|
} else {
|
||||||
|
run_chroot(img, "root", ["setup-keymap", &setup.os.host.keymap])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up a user that we can use to install packages
|
||||||
|
run_chroot(img, "root", ["adduser", "-D", "mkalpiimg"])?;
|
||||||
|
run_chroot(img, "root", ["adduser", "mkalpiimg", "abuild"])?;
|
||||||
|
run_chroot(img, "root", "echo mkalpiimg:mkalpiimg | chpasswd")?;
|
||||||
|
fs::write(etc.join("sudoers.d").join("mkalpiimg"), "%abuild ALL=(ALL) NOPASSWD: ALL")?;
|
||||||
|
fs::create_dir_all(img.root.0.join("var").join("cache").join("distfiles"))?;
|
||||||
|
run_chroot(img, "root", "chgrp abuild /var/cache/distfiles; chmod 775 /var/cache/distfiles")?;
|
||||||
|
run_chroot(img, "mkalpiimg", ["abuild-keygen", "-a", "-n", "-b", "4096"])?;
|
||||||
|
run_chroot(img, "root", "cp /home/mkalpiimg/.abuild/*.rsa.pub /etc/apk/keys/")?;
|
||||||
|
|
||||||
|
// avoid a bug with cargo in qemu: https://github.com/rust-lang/cargo/issues/10583
|
||||||
|
let cargo = img.root.0.join("home").join("mkalpiimg").join(".cargo");
|
||||||
|
fs::create_dir_all(&cargo)?;
|
||||||
|
fs::write(cargo.join("config.toml"), "[net]\ngit-fetch-with-cli = true\n")?;
|
||||||
|
|
||||||
|
// set up the other users as requested
|
||||||
|
fs::write(etc.join("sudoers.d").join("wheel"), "%wheel ALL=(ALL:ALL) ALL")?;
|
||||||
|
for user in &setup.os.user {
|
||||||
|
run_chroot(img, "root", ["adduser", "-s", "/bin/ash", "-D", &user.name])?;
|
||||||
|
if user.sudo {
|
||||||
|
run_chroot(img, "root", ["adduser", &user.name, "wheel"])?;
|
||||||
|
}
|
||||||
|
for grp in &user.groups {
|
||||||
|
run_chroot(img, "root", ["adduser", &user.name, grp])?;
|
||||||
|
}
|
||||||
|
let ssh = img.root.0.join("home").join(&user.name).join(".ssh");
|
||||||
|
fs::create_dir_all(&ssh)?;
|
||||||
|
let mut keys = File::create(ssh.join("authorized_keys"))?;
|
||||||
|
for key in &user.authorized_keys {
|
||||||
|
writeln!(keys, "{key}")?;
|
||||||
|
}
|
||||||
|
drop(keys);
|
||||||
|
run_chroot(img, "root", ["chown", "-R", &user.name, &format!("/home/{}/.ssh", user.name)])?;
|
||||||
|
run_chroot(img, &user.name, "chmod 700 ~/.ssh; chmod 600 ~/.ssh/*")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
52
src/steps/install_packages.rs
Normal file
52
src/steps/install_packages.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use super::{run_chroot, Image};
|
||||||
|
use crate::setup::Setup;
|
||||||
|
|
||||||
|
pub fn install_packages(img: &Image, setup: &Setup) -> anyhow::Result<()> {
|
||||||
|
eprintln!("Installing packages ...");
|
||||||
|
|
||||||
|
for pkg in &setup.packages.install {
|
||||||
|
run_chroot(img, "root", ["apk", "add", pkg])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for service in &setup.packages.autostart {
|
||||||
|
run_chroot(img, "root", ["rc-update", "add", service, "default"])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install_autostart(img: &Image, setup: &Setup) -> anyhow::Result<()> {
|
||||||
|
// TODO make the kiosk optional maybe?
|
||||||
|
let kiosk = &setup.autostart.kiosk;
|
||||||
|
eprintln!("Installing kiosk ...");
|
||||||
|
run_chroot(img, "root", [
|
||||||
|
"apk",
|
||||||
|
"add",
|
||||||
|
"cage",
|
||||||
|
"firefox-esr",
|
||||||
|
"font-noto",
|
||||||
|
"mesa-dri-gallium",
|
||||||
|
"polkit",
|
||||||
|
"polkit-elogind"
|
||||||
|
])?;
|
||||||
|
run_chroot(img, "root", [
|
||||||
|
"sed",
|
||||||
|
"-E",
|
||||||
|
"-i",
|
||||||
|
"-e",
|
||||||
|
&format!("/tty1/s,agetty,agetty --autologin {},", kiosk.user),
|
||||||
|
"/etc/inittab"
|
||||||
|
])?;
|
||||||
|
run_chroot(img, &kiosk.user, "[ -e ~/.profile ] || echo '#!/bin/busybox ash' >~/.profile")?;
|
||||||
|
run_chroot(
|
||||||
|
img,
|
||||||
|
&kiosk.user,
|
||||||
|
format!(
|
||||||
|
r#"echo 'if [ "$(tty)" == "/dev/tty1" ]; then dbus-run-session cage firefox-esr --kiosk "{}"; fi' >>~/.profile"#,
|
||||||
|
kiosk.page
|
||||||
|
)
|
||||||
|
.as_str()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
183
src/steps/mod.rs
Normal file
183
src/steps/mod.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
use anyhow::{anyhow, bail, Context as _};
|
||||||
|
use std::{
|
||||||
|
fmt::Write as _,
|
||||||
|
fs::File,
|
||||||
|
io::{self, BufWriter},
|
||||||
|
ops::Deref,
|
||||||
|
os::unix::process::ExitStatusExt as _,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::Command
|
||||||
|
};
|
||||||
|
use tempfile::{NamedTempFile, TempDir};
|
||||||
|
|
||||||
|
fn tempfile() -> io::Result<NamedTempFile> {
|
||||||
|
NamedTempFile::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(cmd: &[&str]) -> anyhow::Result<()> {
|
||||||
|
let display = format!("`\"{}\"`", cmd.join("\" \""));
|
||||||
|
eprintln!(" -> Running {display} ...");
|
||||||
|
|
||||||
|
let status = match Command::new(cmd[0]).args(cmd.iter().skip(1)).status() {
|
||||||
|
Ok(status) => status,
|
||||||
|
Err(err) => bail!("Failed to run `\"{}\"`: {err}", cmd.join("\" \""))
|
||||||
|
};
|
||||||
|
if !status.success() {
|
||||||
|
bail!(
|
||||||
|
"Failed to run `\"{}\"`: Process returned exit code {}",
|
||||||
|
cmd.join("\" \""),
|
||||||
|
status.into_raw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_output(cmd: &[&str]) -> anyhow::Result<String> {
|
||||||
|
let display = format!("`\"{}\"`", cmd.join("\" \""));
|
||||||
|
eprintln!(" -> Running {display} ...");
|
||||||
|
|
||||||
|
let output = match Command::new(cmd[0]).args(cmd.iter().skip(1)).output() {
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(err) => bail!("Failed to run {display}: {err}")
|
||||||
|
};
|
||||||
|
if !output.status.success() {
|
||||||
|
bail!("Failed to run {display}: Process returned exit code {}", output.status.into_raw());
|
||||||
|
}
|
||||||
|
String::from_utf8(output.stdout).context("The output of {display} contained invalid characters")
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! run_parted {
|
||||||
|
($path:expr, $($arg:expr),+) => {
|
||||||
|
run(&["parted", "-s", $path.to_str().unwrap(), $($arg,)+])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ChrootCmd {
|
||||||
|
fn into_shell_cmd(self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> ChrootCmd for [&str; N] {
|
||||||
|
fn into_shell_cmd(self) -> String {
|
||||||
|
(&self[..]).into_shell_cmd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChrootCmd for &[&str] {
|
||||||
|
fn into_shell_cmd(self) -> String {
|
||||||
|
let mut cmd = String::new();
|
||||||
|
for arg in self {
|
||||||
|
write!(cmd, "'{}' ", arg.replace('\'', "'\"'\"'")).unwrap();
|
||||||
|
}
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChrootCmd for &str {
|
||||||
|
fn into_shell_cmd(self) -> String {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_chroot(img: &Image, user: &str, cmd: impl ChrootCmd) -> anyhow::Result<()> {
|
||||||
|
let cmd = format!(". /etc/profile; set -euo pipefail; {}", cmd.into_shell_cmd());
|
||||||
|
run(&[
|
||||||
|
"chroot",
|
||||||
|
&img.root,
|
||||||
|
"/usr/bin/env",
|
||||||
|
"-i",
|
||||||
|
"sudo",
|
||||||
|
"-u",
|
||||||
|
user,
|
||||||
|
"-i",
|
||||||
|
"-n",
|
||||||
|
"ash",
|
||||||
|
"-c",
|
||||||
|
&cmd
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn download(out: &Path, url: &str) -> anyhow::Result<()> {
|
||||||
|
eprintln!(" -> Downloading {url} ...");
|
||||||
|
attohttpc::get(url).send()?.write_to(BufWriter::new(File::create(out)?))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Image {
|
||||||
|
path: PathBuf,
|
||||||
|
boot: Mount,
|
||||||
|
dev: Mount,
|
||||||
|
root: Mount,
|
||||||
|
device: LoopDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Image {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
eprintln!("Cleaning up ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LoopDevice(String);
|
||||||
|
|
||||||
|
impl LoopDevice {
|
||||||
|
fn part(&self, num: usize) -> String {
|
||||||
|
format!("{}p{num}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for LoopDevice {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for LoopDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let res = run(&["udisksctl", "loop-delete", "--no-user-interaction", "-b", self]);
|
||||||
|
if let Err(err) = res {
|
||||||
|
eprintln!("Failed to free loop device {}: {err}", self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mount(PathBuf);
|
||||||
|
|
||||||
|
impl Mount {
|
||||||
|
fn create(device: &str) -> anyhow::Result<Self> {
|
||||||
|
let path = TempDir::new()?.into_path();
|
||||||
|
run(&["mount", device, &path.to_string_lossy()])?;
|
||||||
|
Ok(Self(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Mount {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0.to_str().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Mount {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let res = run(&["umount", self]);
|
||||||
|
if let Err(err) = res {
|
||||||
|
eprintln!("Failed to unmount {}: {err}", self.0.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod init_first_boot;
|
||||||
|
mod init_network;
|
||||||
|
mod init_os;
|
||||||
|
mod install_packages;
|
||||||
|
mod prepare_img;
|
||||||
|
mod set_passwords;
|
||||||
|
|
||||||
|
pub use init_first_boot::init_first_boot;
|
||||||
|
pub use init_network::init_network;
|
||||||
|
pub use init_os::init_os;
|
||||||
|
pub use install_packages::{install_autostart, install_packages};
|
||||||
|
pub use prepare_img::prepare_img;
|
||||||
|
pub use set_passwords::set_passwords;
|
57
src/steps/prepare_img.rs
Normal file
57
src/steps/prepare_img.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use super::{run, run_output, Image, LoopDevice, Mount};
|
||||||
|
use crate::IMAGE_SIZE_GB;
|
||||||
|
use anyhow::{anyhow, Context as _};
|
||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
path::PathBuf
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn prepare_img() -> anyhow::Result<Image> {
|
||||||
|
eprintln!("Preparing empty image ...");
|
||||||
|
|
||||||
|
// let's create a file with the correct size
|
||||||
|
let path = PathBuf::from("alpi.img");
|
||||||
|
let file = File::create(&path).context("Failed to create alpi.img")?;
|
||||||
|
file.set_len(IMAGE_SIZE_GB * 1024 * 1024 * 1024)?;
|
||||||
|
drop(file);
|
||||||
|
|
||||||
|
// lets get the thing partitioned
|
||||||
|
let size = format!("{IMAGE_SIZE_GB}G");
|
||||||
|
run_parted!(path, "mktable", "msdos")?;
|
||||||
|
run_parted!(path, "mkpart", "primary", "fat32", "0G", "128M")?;
|
||||||
|
run_parted!(path, "mkpart", "primary", "ext4", "128M", &size)?;
|
||||||
|
|
||||||
|
// create a loopback device
|
||||||
|
let output = run_output(&["udisksctl", "loop-setup", "--no-user-interaction", "-f", path.to_str().unwrap()])?;
|
||||||
|
print!("{output}");
|
||||||
|
let idx = output.find("/dev/loop").ok_or_else(|| anyhow!("Unable to identify loop device"))?;
|
||||||
|
let mut end = idx + "/dev/loop".len();
|
||||||
|
while (output.as_bytes()[end] as char).is_ascii_digit() {
|
||||||
|
end += 1;
|
||||||
|
}
|
||||||
|
let device = LoopDevice(output[idx .. end].to_owned());
|
||||||
|
|
||||||
|
// TODO: Somehow create the file systems without root
|
||||||
|
run(&["mkfs.fat", "-n", "ALPI-BOOT", "-F", "32", &device.part(1)])?;
|
||||||
|
run(&["mkfs.ext4", "-q", "-F", "-L", "ALPI", "-O", "^has_journal", &device.part(2)])?;
|
||||||
|
run_parted!(path, "p")?;
|
||||||
|
|
||||||
|
// mount everything
|
||||||
|
let root = Mount::create(&device.part(2))?;
|
||||||
|
let boot = root.0.join("boot");
|
||||||
|
fs::create_dir_all(&boot)?;
|
||||||
|
run(&["mount", &device.part(1), boot.to_str().unwrap()])?;
|
||||||
|
let boot = Mount(boot);
|
||||||
|
let dev = root.0.join("dev");
|
||||||
|
fs::create_dir_all(&dev)?;
|
||||||
|
run(&["mount", "udev", dev.to_str().unwrap(), "-t", "devtmpfs", "-o", "mode=0755,nosuid"])?;
|
||||||
|
let dev = Mount(dev);
|
||||||
|
|
||||||
|
Ok(Image {
|
||||||
|
path,
|
||||||
|
device,
|
||||||
|
boot,
|
||||||
|
dev,
|
||||||
|
root
|
||||||
|
})
|
||||||
|
}
|
21
src/steps/set_passwords.rs
Normal file
21
src/steps/set_passwords.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use super::{run_chroot, Image};
|
||||||
|
use crate::setup::Setup;
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
|
pub fn set_passwords(img: &Image, setup: &Setup) -> anyhow::Result<()> {
|
||||||
|
eprintln!("Setting user passwords ...");
|
||||||
|
|
||||||
|
// the password is insecure by design, so we'll lock it for security
|
||||||
|
run_chroot(img, "root", ["passwd", "-l", "mkalpiimg"])?;
|
||||||
|
|
||||||
|
for user in &setup.os.user {
|
||||||
|
if let Some(password) = &user.password {
|
||||||
|
if password.contains('\'') {
|
||||||
|
bail!("Sorry I won't set passwords containing `'`");
|
||||||
|
}
|
||||||
|
run_chroot(img, "root", format!("echo '{}:{password}' | chpasswd", user.name).as_str())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue