Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 96f801e27d | |||
| 3f7cd80a96 | |||
| 41c3f9badd | |||
| 01a0073e78 |
845
Cargo.lock
generated
845
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "init"
|
||||
version = "2.5.0"
|
||||
version = "2.5.2"
|
||||
edition = "2024"
|
||||
|
||||
[profile.release]
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@ -1,4 +1,4 @@
|
||||
from rust:1.91.0-alpine as rust
|
||||
from rust:1.93.0-alpine as rust
|
||||
|
||||
run apk add --no-cache git musl-dev libudev-zero-dev openssl-dev cryptsetup-dev lvm2-dev clang-libs clang-dev
|
||||
|
||||
@ -14,13 +14,15 @@ run apk add zstd lz4
|
||||
|
||||
workdir /system
|
||||
|
||||
env VERSION=3.23.2
|
||||
|
||||
run . /etc/os-release \
|
||||
&& wget -O- https://dl-cdn.alpinelinux.org/alpine/v${VERSION_ID%.*}/releases/x86_64/alpine-minirootfs-${VERSION_ID}-x86_64.tar.gz |tar zxv
|
||||
&& wget -O- https://dl-cdn.alpinelinux.org/alpine/v${VERSION%.*}/releases/x86_64/alpine-minirootfs-${VERSION}-x86_64.tar.gz |tar zxv
|
||||
|
||||
run apk add --no-cache --update -p . musl libgcc coreutils \
|
||||
lvm2 lvm2-extra lvm2-dmeventd udev cryptsetup \
|
||||
iproute2 lvm2 lvm2-extra lvm2-dmeventd udev cryptsetup \
|
||||
e2fsprogs lsblk openssl openssh-server wireguard-tools-wg-quick \
|
||||
&& rm -rf usr/share/apk var/cache/apk etc/motd
|
||||
&& rm -rf usr/share/apk var/cache/apk etc/motd dev/*
|
||||
|
||||
copy etc/sshd_config etc/ssh/sshd_config
|
||||
|
||||
@ -34,6 +36,6 @@ run chroot . init-version
|
||||
run find * |cpio -H newc -oF /initrd
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
from alpine:3.22.2
|
||||
from alpine:3.23.0
|
||||
copy --from=initrd /initrd /
|
||||
entrypoint ["base64","/initrd"]
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
pub mod bootstrap;
|
||||
pub mod connect_boot;
|
||||
pub mod init;
|
||||
pub mod init_input;
|
||||
pub mod version;
|
||||
|
||||
@ -1 +0,0 @@
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use eyre::{format_err, Result};
|
||||
use log::{error, info, warn};
|
||||
use std::collections::BTreeSet as Set;
|
||||
use std::convert::Infallible;
|
||||
use std::os::unix::fs::symlink;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::{fs, process::Command};
|
||||
@ -323,13 +324,7 @@ async fn child_reaper() {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! cstr {
|
||||
($s:expr) => {
|
||||
std::ffi::CString::new($s)?.as_c_str()
|
||||
};
|
||||
}
|
||||
|
||||
async fn switch_root(root: &str) -> Result<()> {
|
||||
async fn switch_root(root: &str) -> Result<Infallible> {
|
||||
info!("killing all processes and switching root");
|
||||
dklog::LOG.close().await;
|
||||
|
||||
@ -340,7 +335,13 @@ async fn switch_root(root: &str) -> Result<()> {
|
||||
eprintln!("failed to kill processes: {e}");
|
||||
}
|
||||
|
||||
nix::unistd::execv(
|
||||
macro_rules! cstr {
|
||||
($s:expr) => {
|
||||
std::ffi::CString::new($s)?.as_c_str()
|
||||
};
|
||||
}
|
||||
|
||||
Ok(nix::unistd::execv(
|
||||
cstr!("/sbin/switch_root"),
|
||||
&[
|
||||
cstr!("switch_root"),
|
||||
@ -349,8 +350,5 @@ async fn switch_root(root: &str) -> Result<()> {
|
||||
cstr!(root),
|
||||
cstr!("/sbin/init"),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
unreachable!();
|
||||
)?)
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ pub async fn bootstrap(cfg: Config) {
|
||||
.await;
|
||||
}
|
||||
|
||||
// prepare system
|
||||
let boot_version = utils::param("version").unwrap_or("current");
|
||||
let base_dir = &format!("/bootstrap/{boot_version}");
|
||||
|
||||
|
||||
@ -56,27 +56,72 @@ pub async fn setup(devs: &[CryptDev]) {
|
||||
.await;
|
||||
}
|
||||
|
||||
static PREV_PW: Mutex<String> = Mutex::const_new(String::new());
|
||||
struct PrevPw {
|
||||
pw: String,
|
||||
reuse: bool,
|
||||
}
|
||||
|
||||
async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> {
|
||||
'open_loop: loop {
|
||||
let mut prev_pw = PREV_PW.lock().await;
|
||||
let prompt = if prev_pw.is_empty() {
|
||||
format!("crypt password for {crypt_dev}? ")
|
||||
} else {
|
||||
format!("crypt password for {crypt_dev} (enter = reuse previous)? ")
|
||||
};
|
||||
|
||||
let mut pw = input::read_password(prompt).await;
|
||||
if pw.is_empty() {
|
||||
pw = prev_pw.clone();
|
||||
impl PrevPw {
|
||||
fn is_set(&self) -> bool {
|
||||
!self.pw.is_empty()
|
||||
}
|
||||
|
||||
fn can_reuse(&self) -> bool {
|
||||
self.reuse && self.is_set()
|
||||
}
|
||||
|
||||
fn invalidate(&mut self) {
|
||||
self.pw = String::new();
|
||||
self.reuse = false;
|
||||
}
|
||||
|
||||
async fn input(&mut self, prompt: impl std::fmt::Display) -> String {
|
||||
if self.can_reuse() {
|
||||
info!("reusing password");
|
||||
self.pw.clone()
|
||||
} else if self.is_set() {
|
||||
let pw =
|
||||
input::read_password(format!("{prompt} (\"\" reuse, \"*\" auto-reuse)? ")).await;
|
||||
|
||||
match pw.as_str() {
|
||||
"" => self.pw.clone(),
|
||||
"*" => {
|
||||
self.reuse = true;
|
||||
self.pw.clone()
|
||||
}
|
||||
_ => {
|
||||
self.pw = pw.clone();
|
||||
pw
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let pw = loop {
|
||||
let pw = input::read_password(format!("{prompt}? ")).await;
|
||||
if pw.is_empty() {
|
||||
error!("empty password provided!");
|
||||
continue;
|
||||
}
|
||||
break pw;
|
||||
};
|
||||
|
||||
*prev_pw = pw.clone();
|
||||
self.pw = pw.clone();
|
||||
pw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PREV_PW: Mutex<PrevPw> = Mutex::const_new(PrevPw {
|
||||
pw: String::new(),
|
||||
reuse: false,
|
||||
});
|
||||
|
||||
async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> {
|
||||
'open_loop: loop {
|
||||
let mut prev_pw = PREV_PW.lock().await;
|
||||
|
||||
let pw = prev_pw
|
||||
.input(format!("crypt password for {crypt_dev}"))
|
||||
.await;
|
||||
|
||||
if cryptsetup(&pw, ["open", dev_path, crypt_dev]).await? {
|
||||
return Ok(());
|
||||
@ -107,17 +152,19 @@ async fn crypt_open(crypt_dev: &str, dev_path: &str) -> Result<()> {
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
// device looks initialized, don't allow format
|
||||
warn!("{dev_path} looks initialized, formatting not allowed from init");
|
||||
|
||||
prev_pw.invalidate();
|
||||
|
||||
match input::read_choice(["[r]etry", "[i]gnore"]).await {
|
||||
'r' => continue 'open_loop,
|
||||
'i' => return Ok(()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn cryptsetup<const N: usize>(pw: &str, args: [&str; N]) -> Result<bool> {
|
||||
|
||||
@ -2,6 +2,10 @@ use crate::input;
|
||||
|
||||
pub async fn run() {
|
||||
tokio::spawn(async {
|
||||
// give a bit of time for stdout
|
||||
use tokio::time::{sleep, Duration};
|
||||
sleep(Duration::from_millis(200)).await;
|
||||
|
||||
if let Err(e) = input::forward_requests_from_socket().await {
|
||||
eprintln!("failed to forwards requests from socket: {e}");
|
||||
std::process::exit(1);
|
||||
|
||||
Reference in New Issue
Block a user