Wire live installer commit path (Sam & Codex)
Live GUI installs now write runtime handoff files under /var/run/clawdie-installer, invoke bsdinstall script through a dedicated commit helper, persist the installed handoff for first HDD boot, and point the operator at /setup after reboot. The live autologin user is restricted to a narrow sudoers rule for the commit helper and reboot only. Build: pass Tests: pass — sh -n + QML build + config-format + stubbed live-commit dry-run Real-disk / bhyve install: NOT YET TESTED
This commit is contained in:
parent
3a9954f9ec
commit
835074ab8d
8 changed files with 253 additions and 40 deletions
11
build.sh
11
build.sh
|
|
@ -295,6 +295,8 @@ configure_live_installer_session() {
|
|||
"${MOUNT_POINT}/usr/local/bin/clawdie-qml-installer"
|
||||
install -m 0755 "${LIVE_SESSION_DIR}/clawdie-live-installer-launch.sh" \
|
||||
"${MOUNT_POINT}/usr/local/bin/clawdie-live-installer-launch.sh"
|
||||
install -m 0755 "${LIVE_SESSION_DIR}/clawdie-live-commit.sh" \
|
||||
"${MOUNT_POINT}/usr/local/bin/clawdie-live-commit.sh"
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/usr/local/etc/lightdm/lightdm.conf.d"
|
||||
install -m 0644 "${LIVE_SESSION_DIR}/lightdm-live.conf" \
|
||||
|
|
@ -316,6 +318,15 @@ Session=lumina
|
|||
EOF
|
||||
chroot "$MOUNT_POINT" chown -R clawdie-installer:clawdie-installer /home/clawdie-installer
|
||||
|
||||
mkdir -p "${MOUNT_POINT}/usr/local/etc/sudoers.d"
|
||||
cat > "${MOUNT_POINT}/usr/local/etc/sudoers.d/clawdie-live-installer" <<'EOF'
|
||||
# Allow the live autologin user to run only the installer commit helper and
|
||||
# reboot from the success screen, without a password prompt.
|
||||
Defaults:clawdie-installer !requiretty
|
||||
clawdie-installer ALL=(root) NOPASSWD: /usr/local/bin/clawdie-live-commit.sh, /sbin/reboot
|
||||
EOF
|
||||
chmod 0440 "${MOUNT_POINT}/usr/local/etc/sudoers.d/clawdie-live-installer"
|
||||
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'dbus_enable="YES"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'seatd_enable="YES"'
|
||||
set_config_line "${MOUNT_POINT}/etc/rc.conf" 'lightdm_enable="YES"'
|
||||
|
|
|
|||
|
|
@ -117,16 +117,28 @@ export SETUP_IMPORT_TEST=1
|
|||
. "${SHARE}/firstboot/shell-deploy.sh"
|
||||
|
||||
# ── Load GUI config if present ───────────────────────────────────────────────
|
||||
SETUP_HANDOFF_LOADED=0
|
||||
if [ -f "/tmp/clawdie-install.conf" ]; then
|
||||
log_msg "[firstboot] Loading GUI installer configuration"
|
||||
. "/tmp/clawdie-install.conf"
|
||||
step_done "wizard"
|
||||
SETUP_HANDOFF_LOADED=1
|
||||
elif [ -f "/var/db/clawdie-installer/clawdie-handoff.sealed" ]; then
|
||||
log_msg "[firstboot] Loading installed handoff payload"
|
||||
. "/var/db/clawdie-installer/clawdie-handoff.sealed"
|
||||
step_done "wizard"
|
||||
SETUP_HANDOFF_LOADED=1
|
||||
fi
|
||||
|
||||
log_msg "[firstboot] Starting — target: ${TARGET:-baremetal}${RESUME:+, resume mode}"
|
||||
|
||||
# ── Import setup.txt/system.env from USB config partition ───────────────────
|
||||
run_step "setup-import" clawdie_setup_import_load "Load first-boot setup from USB partition"
|
||||
if [ "$SETUP_HANDOFF_LOADED" -eq 1 ]; then
|
||||
log_msg "[firstboot] Skipping setup-import (installer handoff already loaded)"
|
||||
step_done "setup-import"
|
||||
else
|
||||
run_step "setup-import" clawdie_setup_import_load "Load first-boot setup from USB partition"
|
||||
fi
|
||||
|
||||
# ── ZFS pool detection (baremetal only) ───────────────────────────────────
|
||||
# Runs early to decide boot mode: install | upgrade | maintenance
|
||||
|
|
|
|||
|
|
@ -10,6 +10,30 @@
|
|||
#include <QTextStream>
|
||||
#include <QRegularExpression>
|
||||
#include <QVariant>
|
||||
#include <QDir>
|
||||
|
||||
static QString shellEscape(const QString &value) {
|
||||
QString escaped = value;
|
||||
escaped.replace('\\', "\\\\");
|
||||
escaped.replace('"', "\\\"");
|
||||
escaped.replace('$', "\\$");
|
||||
escaped.replace('`', "\\`");
|
||||
escaped.replace('\n', " ");
|
||||
escaped.replace('\r', " ");
|
||||
return escaped;
|
||||
}
|
||||
|
||||
static void writeShellAssignment(QTextStream &out, const QString &key, const QString &value) {
|
||||
out << key << "=\"" << shellEscape(value) << "\"\n";
|
||||
}
|
||||
|
||||
static QString normalizeHostLabel(const QString &value) {
|
||||
QString label = value.toLower();
|
||||
label.remove(QRegularExpression("[^a-z0-9-]"));
|
||||
label.remove(QRegularExpression("^-+"));
|
||||
label.remove(QRegularExpression("-+$"));
|
||||
return label.isEmpty() ? QStringLiteral("clawdie") : label;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// DiskModel — lists available disks for installation target selection
|
||||
|
|
@ -165,6 +189,7 @@ signals:
|
|||
|
||||
private:
|
||||
void parseNvidiaBusId(const QString &output) {
|
||||
Q_UNUSED(output);
|
||||
// Recommend driver version based on device ID
|
||||
// For now, recommend 590 (most modern)
|
||||
// In production: parse device ID and map to version
|
||||
|
|
@ -400,21 +425,62 @@ public:
|
|||
return false;
|
||||
|
||||
if (qEnvironmentVariableIsSet("CLAWDIE_LIVE_SESSION")) {
|
||||
QFile logFile("/var/log/clawdie-firstboot.log");
|
||||
if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream log(&logFile);
|
||||
log << "[live-installer] Live GUI session bootstrapped successfully.\n";
|
||||
log << "[live-installer] Commit path is not implemented in this build yet.\n";
|
||||
log << "[live-installer] Stop here and continue with Step 2/3 implementation.\n";
|
||||
logFile.close();
|
||||
}
|
||||
const QString runtimeDir = QStringLiteral("/var/run/clawdie-installer");
|
||||
QDir().mkpath(runtimeDir);
|
||||
|
||||
QFile progressFile("/var/log/clawdie-firstboot.progress");
|
||||
if (progressFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream progress(&progressFile);
|
||||
progress << "ERROR=live-session-bootstrap-only\n";
|
||||
progressFile.close();
|
||||
const QString hostLabel = normalizeHostLabel(m_username);
|
||||
const QString handoffPath = runtimeDir + QStringLiteral("/clawdie-handoff.sealed");
|
||||
QFile handoffFile(handoffPath);
|
||||
if (!handoffFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
qWarning() << "Failed to create handoff file:" << handoffFile.errorString();
|
||||
return false;
|
||||
}
|
||||
QTextStream handoff(&handoffFile);
|
||||
handoff << "# Clawdie live installer handoff\n";
|
||||
writeShellAssignment(handoff, QStringLiteral("ASSISTANT_NAME"), m_username);
|
||||
writeShellAssignment(handoff, QStringLiteral("HOSTNAME"), hostLabel);
|
||||
writeShellAssignment(handoff, QStringLiteral("AGENT_DOMAIN"), hostLabel + QStringLiteral(".home.arpa"));
|
||||
writeShellAssignment(handoff, QStringLiteral("CLAWDIE_USER_PASSWORD"), m_password);
|
||||
handoff << "\n";
|
||||
writeShellAssignment(handoff, QStringLiteral("AGENT_GENDER"), QStringLiteral("f"));
|
||||
writeShellAssignment(handoff, QStringLiteral("TZ"), QStringLiteral("UTC"));
|
||||
writeShellAssignment(handoff, QStringLiteral("SYSTEM_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(handoff, QStringLiteral("DISPLAY_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(handoff, QStringLiteral("ASSISTANT_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(handoff, QStringLiteral("KEYMAP"), QStringLiteral("sl.kbd"));
|
||||
writeShellAssignment(handoff, QStringLiteral("FEATURE_TAILSCALE"), QStringLiteral("YES"));
|
||||
writeShellAssignment(handoff, QStringLiteral("TAILSCALE_AUTHKEY"), QStringLiteral(""));
|
||||
writeShellAssignment(handoff, QStringLiteral("FEATURE_GIT"), QStringLiteral("YES"));
|
||||
writeShellAssignment(handoff, QStringLiteral("FEATURE_GITEA"), QStringLiteral("NO"));
|
||||
writeShellAssignment(handoff, QStringLiteral("CODE_HOSTING_MODE"), QStringLiteral("git"));
|
||||
handoffFile.close();
|
||||
|
||||
const QString envPath = runtimeDir + QStringLiteral("/live-install.env");
|
||||
QFile envFile(envPath);
|
||||
if (!envFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
qWarning() << "Failed to create live install env:" << envFile.errorString();
|
||||
return false;
|
||||
}
|
||||
QTextStream env(&envFile);
|
||||
env << "# Clawdie live installer environment\n";
|
||||
writeShellAssignment(env, QStringLiteral("INSTALL_DISK"), m_selectedDisk);
|
||||
envFile.close();
|
||||
|
||||
QProcess *installProcess = new QProcess(this);
|
||||
connect(installProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, [](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
Q_UNUSED(exitStatus);
|
||||
if (exitCode != 0) {
|
||||
qWarning() << "Live installation process failed with exit code:" << exitCode;
|
||||
}
|
||||
});
|
||||
|
||||
installProcess->start(QStringLiteral("sudo"),
|
||||
QStringList() << QStringLiteral("-n")
|
||||
<< QStringLiteral("/usr/local/bin/clawdie-live-commit.sh"));
|
||||
|
||||
if (!installProcess->waitForStarted(5000))
|
||||
return false;
|
||||
|
||||
m_installationStarted = true;
|
||||
emit installationStartedChanged();
|
||||
|
|
@ -430,34 +496,39 @@ public:
|
|||
QTextStream out(&configFile);
|
||||
out << "# Clawdie GUI Installer Configuration\n";
|
||||
out << "# Generated by QML installer\n\n";
|
||||
const QString hostLabel = normalizeHostLabel(m_username);
|
||||
|
||||
out << "# User settings\n";
|
||||
out << "ASSISTANT_NAME=\"" << m_username << "\"\n";
|
||||
out << "AGENT_DOMAIN=\"" << m_username.toLower() << ".home.arpa\"\n";
|
||||
out << "CLAWDIE_USER_PASSWORD=\"" << m_password << "\"\n\n";
|
||||
writeShellAssignment(out, QStringLiteral("ASSISTANT_NAME"), m_username);
|
||||
writeShellAssignment(out, QStringLiteral("HOSTNAME"), hostLabel);
|
||||
writeShellAssignment(out, QStringLiteral("AGENT_DOMAIN"), hostLabel + QStringLiteral(".home.arpa"));
|
||||
writeShellAssignment(out, QStringLiteral("CLAWDIE_USER_PASSWORD"), m_password);
|
||||
out << "\n";
|
||||
|
||||
out << "# Installation settings\n";
|
||||
out << "INSTALL_DISK=\"" << m_selectedDisk << "\"\n";
|
||||
out << "GPU_DRIVER_VERSION=\"" << m_gpuDriverVersion << "\"\n\n";
|
||||
writeShellAssignment(out, QStringLiteral("INSTALL_DISK"), m_selectedDisk);
|
||||
writeShellAssignment(out, QStringLiteral("GPU_DRIVER_VERSION"), QString::number(m_gpuDriverVersion));
|
||||
out << "\n";
|
||||
|
||||
out << "# Feature flags\n";
|
||||
out << "FEATURE_DESKTOP=\"" << (m_installDesktop ? "YES" : "NO") << "\"\n";
|
||||
out << "FEATURE_DEVTOOLS=\"" << (m_installDevTools ? "YES" : "NO") << "\"\n";
|
||||
out << "FEATURE_NVIDIA=\"" << (m_installNvidia ? "YES" : "NO") << "\"\n";
|
||||
out << "LOCAL_LLM_PROVIDER=\"" << (m_installLLM ? "llama.cpp" : "none") << "\"\n\n";
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_DESKTOP"), m_installDesktop ? QStringLiteral("YES") : QStringLiteral("NO"));
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_DEVTOOLS"), m_installDevTools ? QStringLiteral("YES") : QStringLiteral("NO"));
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_NVIDIA"), m_installNvidia ? QStringLiteral("YES") : QStringLiteral("NO"));
|
||||
writeShellAssignment(out, QStringLiteral("LOCAL_LLM_PROVIDER"), m_installLLM ? QStringLiteral("llama.cpp") : QStringLiteral("none"));
|
||||
out << "\n";
|
||||
|
||||
out << "# Defaults from firstboot.sh\n";
|
||||
out << "AGENT_GENDER=\"f\"\n";
|
||||
out << "TZ=\"UTC\"\n";
|
||||
out << "SYSTEM_LOCALE=\"sl_SI.UTF-8\"\n";
|
||||
out << "DISPLAY_LOCALE=\"sl_SI.UTF-8\"\n";
|
||||
out << "ASSISTANT_LOCALE=\"sl_SI.UTF-8\"\n";
|
||||
out << "KEYMAP=\"sl.kbd\"\n";
|
||||
out << "FEATURE_TAILSCALE=\"YES\"\n";
|
||||
out << "TAILSCALE_AUTHKEY=\"\"\n";
|
||||
out << "FEATURE_GIT=\"YES\"\n";
|
||||
out << "FEATURE_GITEA=\"NO\"\n";
|
||||
out << "CODE_HOSTING_MODE=\"git\"\n";
|
||||
writeShellAssignment(out, QStringLiteral("AGENT_GENDER"), QStringLiteral("f"));
|
||||
writeShellAssignment(out, QStringLiteral("TZ"), QStringLiteral("UTC"));
|
||||
writeShellAssignment(out, QStringLiteral("SYSTEM_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(out, QStringLiteral("DISPLAY_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(out, QStringLiteral("ASSISTANT_LOCALE"), QStringLiteral("sl_SI.UTF-8"));
|
||||
writeShellAssignment(out, QStringLiteral("KEYMAP"), QStringLiteral("sl.kbd"));
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_TAILSCALE"), QStringLiteral("YES"));
|
||||
writeShellAssignment(out, QStringLiteral("TAILSCALE_AUTHKEY"), QStringLiteral(""));
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_GIT"), QStringLiteral("YES"));
|
||||
writeShellAssignment(out, QStringLiteral("FEATURE_GITEA"), QStringLiteral("NO"));
|
||||
writeShellAssignment(out, QStringLiteral("CODE_HOSTING_MODE"), QStringLiteral("git"));
|
||||
|
||||
configFile.close();
|
||||
|
||||
|
|
@ -474,16 +545,21 @@ public:
|
|||
|
||||
QProcess *installProcess = new QProcess(this);
|
||||
connect(installProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
this, [](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
Q_UNUSED(exitStatus);
|
||||
if (exitCode != 0) {
|
||||
qWarning() << "Installation process failed with exit code:" << exitCode;
|
||||
}
|
||||
});
|
||||
|
||||
installProcess->start("/bin/sh", QStringList() << "-c"
|
||||
<< "export $(cat /tmp/clawdie-install.conf | xargs) && "
|
||||
"sudo -p '[sudo] password: ' " + firstbootPath);
|
||||
installProcess->start(QStringLiteral("sudo"),
|
||||
QStringList() << QStringLiteral("-n")
|
||||
<< QStringLiteral("/bin/sh")
|
||||
<< QStringLiteral("-c")
|
||||
<< QStringLiteral(". /tmp/clawdie-install.conf; exec \"%1\"").arg(firstbootPath));
|
||||
|
||||
if (!installProcess->waitForStarted(5000))
|
||||
return false;
|
||||
|
||||
m_installationStarted = true;
|
||||
emit installationStartedChanged();
|
||||
|
|
|
|||
|
|
@ -70,6 +70,23 @@ ColumnLayout {
|
|||
text: tracker.success ? "Finish machine bootstrap first. Provider keys, Telegram, and browser sign-in are configured after boot." : "You may retry the installation or seek support."
|
||||
font.pixelSize: 12
|
||||
color: "#666666"
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Text {
|
||||
text: tracker.success ? "After reboot, open http://127.0.0.1:3100/setup on the Clawdie host or local console. Remote use of https://<agent-domain>/setup is only safe after TLS and PF/reverse-proxy or tailnet/LAN allowlisting are in place." : ""
|
||||
font.pixelSize: 12
|
||||
color: "#555555"
|
||||
wrapMode: Text.WordWrap
|
||||
visible: tracker.success
|
||||
}
|
||||
|
||||
Text {
|
||||
text: tracker.success ? "If no setup token is shown after boot, run 'npm run setup-token -- rotate' on the installed host and use that token at /setup. Do not expose /setup directly to the public internet before setup completes." : ""
|
||||
font.pixelSize: 12
|
||||
color: "#8a4f00"
|
||||
wrapMode: Text.WordWrap
|
||||
visible: tracker.success
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
@ -110,8 +127,7 @@ ColumnLayout {
|
|||
enabled: tracker.finished
|
||||
|
||||
onClicked: {
|
||||
// Call reboot command
|
||||
backend.runCommand("reboot", [])
|
||||
backend.runCommand("sudo", ["-n", "/sbin/reboot"])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ stop_cmd=":"
|
|||
|
||||
SHARE="/usr/local/share/clawdie-iso"
|
||||
LOG="/var/log/clawdie-firstboot.log"
|
||||
HANDOFF_FILE="/var/db/clawdie-installer/clawdie-handoff.sealed"
|
||||
|
||||
clawdie_firstboot_start()
|
||||
{
|
||||
|
|
@ -31,6 +32,8 @@ clawdie_firstboot_start()
|
|||
if [ "$RC" -eq 0 ]; then
|
||||
echo "Clawdie first-boot setup complete. Disabling service."
|
||||
sysrc -x clawdie_firstboot_enable
|
||||
rm -f "$HANDOFF_FILE"
|
||||
rmdir /var/db/clawdie-installer 2>/dev/null || true
|
||||
rm -rf "$SHARE"
|
||||
else
|
||||
echo "Clawdie first-boot setup failed (exit $RC). Check $LOG"
|
||||
|
|
|
|||
|
|
@ -38,8 +38,18 @@ set_config_line() {
|
|||
USB_SHARE="/usr/local/share/clawdie-iso"
|
||||
HDD_SHARE="/mnt/usr/local/share/clawdie-iso"
|
||||
HDD_RCD="/mnt/usr/local/etc/rc.d"
|
||||
LIVE_INSTALLER_RUNTIME_DIR="${LIVE_INSTALLER_RUNTIME_DIR:-/var/run/clawdie-installer}"
|
||||
LIVE_INSTALLER_PERSIST_DIR="/mnt/var/db/clawdie-installer"
|
||||
LIVE_INSTALLER_PERSIST_HANDOFF="${LIVE_INSTALLER_PERSIST_DIR}/clawdie-handoff.sealed"
|
||||
LIVE_INSTALLER_PROGRESS_FILE="${LIVE_INSTALLER_PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
|
||||
|
||||
set_progress() {
|
||||
[ -n "${LIVE_INSTALLER_PROGRESS_FILE:-}" ] || return 0
|
||||
echo "PROGRESS=$1" >> "$LIVE_INSTALLER_PROGRESS_FILE"
|
||||
}
|
||||
|
||||
echo "clawdie-iso: injecting firstboot payload..."
|
||||
set_progress 4
|
||||
|
||||
# Copy firstboot scripts
|
||||
mkdir -p "$HDD_SHARE"
|
||||
|
|
@ -61,6 +71,14 @@ chmod +x "${HDD_SHARE}/firstboot/maintenance-mode.sh" 2>/dev/null || true
|
|||
mkdir -p "$HDD_RCD"
|
||||
cp "${USB_SHARE}/firstboot/rc.d/clawdie-firstboot" "${HDD_RCD}/clawdie-firstboot"
|
||||
chmod +x "${HDD_RCD}/clawdie-firstboot"
|
||||
set_progress 5
|
||||
|
||||
if [ -f "${LIVE_INSTALLER_RUNTIME_DIR}/clawdie-handoff.sealed" ]; then
|
||||
mkdir -p "$LIVE_INSTALLER_PERSIST_DIR"
|
||||
cp "${LIVE_INSTALLER_RUNTIME_DIR}/clawdie-handoff.sealed" "$LIVE_INSTALLER_PERSIST_HANDOFF"
|
||||
chmod 0600 "$LIVE_INSTALLER_PERSIST_HANDOFF"
|
||||
set_progress 6
|
||||
fi
|
||||
|
||||
# Enable mac_do framework at first HDD boot with no credential grants yet.
|
||||
set_config_line /mnt/boot/loader.conf 'mac_do_load="YES"'
|
||||
|
|
@ -68,5 +86,6 @@ set_config_line /mnt/etc/sysctl.conf 'security.mac.do.rules='
|
|||
|
||||
# Enable service in rc.conf on HDD
|
||||
echo 'clawdie_firstboot_enable="YES"' >> /mnt/etc/rc.conf
|
||||
set_progress 7
|
||||
|
||||
echo "clawdie-iso: firstboot payload installed. Rebooting to HDD..."
|
||||
|
|
|
|||
75
live/installer-session/clawdie-live-commit.sh
Normal file
75
live/installer-session/clawdie-live-commit.sh
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
RUNTIME_DIR="${RUNTIME_DIR:-/var/run/clawdie-installer}"
|
||||
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
|
||||
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
|
||||
USB_SHARE="${USB_SHARE:-/usr/local/share/clawdie-iso}"
|
||||
ENV_FILE="${RUNTIME_DIR}/live-install.env"
|
||||
HANDOFF_FILE="${RUNTIME_DIR}/clawdie-handoff.sealed"
|
||||
INSTALLERCONFIG_FILE="${RUNTIME_DIR}/freebsd-installerconfig"
|
||||
INSTALLERCONFIG_TEMPLATE="${USB_SHARE}/installerconfig"
|
||||
|
||||
log_msg() {
|
||||
echo "$(date '+%H:%M:%S') [live-installer] $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
set_progress() {
|
||||
echo "PROGRESS=$1" >> "$PROGRESS_FILE"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "ERROR=$1" >> "$PROGRESS_FILE"
|
||||
log_msg "$2"
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$RUNTIME_DIR"
|
||||
: > "$LOG_FILE"
|
||||
: > "$PROGRESS_FILE"
|
||||
|
||||
[ -r "$ENV_FILE" ] || fail "missing-live-install-env" "Missing $ENV_FILE"
|
||||
[ -r "$HANDOFF_FILE" ] || fail "missing-live-handoff" "Missing $HANDOFF_FILE"
|
||||
[ -r "$INSTALLERCONFIG_TEMPLATE" ] || fail "missing-installer-template" "Missing $INSTALLERCONFIG_TEMPLATE"
|
||||
|
||||
. "$ENV_FILE"
|
||||
|
||||
[ -n "${INSTALL_DISK:-}" ] || fail "missing-install-disk" "INSTALL_DISK is required"
|
||||
case "$INSTALL_DISK" in
|
||||
*[!A-Za-z0-9._/-]*)
|
||||
fail "invalid-install-disk" "INSTALL_DISK contains unsupported characters: $INSTALL_DISK"
|
||||
;;
|
||||
esac
|
||||
|
||||
set_progress 1
|
||||
log_msg "Preparing live install for disk ${INSTALL_DISK}"
|
||||
|
||||
{
|
||||
echo 'DISTRIBUTIONS="kernel.txz base.txz"'
|
||||
echo 'export nonInteractive="YES"'
|
||||
echo 'export ZFSBOOT_POOL_NAME="clawdie"'
|
||||
echo 'export ZFSBOOT_VDEV_TYPE="stripe"'
|
||||
echo "export ZFSBOOT_DISKS=\"${INSTALL_DISK}\""
|
||||
echo 'export ZFSBOOT_FORCE_4K_SECTORS="1"'
|
||||
echo "export LIVE_INSTALLER_RUNTIME_DIR=\"${RUNTIME_DIR}\""
|
||||
echo "export LIVE_INSTALLER_PROGRESS_FILE=\"${PROGRESS_FILE}\""
|
||||
awk 'found || /^#!/ { found = 1; print }' "$INSTALLERCONFIG_TEMPLATE"
|
||||
} > "$INSTALLERCONFIG_FILE"
|
||||
chmod 0700 "$INSTALLERCONFIG_FILE"
|
||||
chmod 0600 "$HANDOFF_FILE"
|
||||
|
||||
set_progress 2
|
||||
log_msg "Generated ${INSTALLERCONFIG_FILE}"
|
||||
|
||||
set_progress 3
|
||||
log_msg "Starting scripted bsdinstall"
|
||||
|
||||
if BSDINSTALL_LOG="$LOG_FILE" bsdinstall script "$INSTALLERCONFIG_FILE" >> "$LOG_FILE" 2>&1; then
|
||||
set_progress 8
|
||||
log_msg "bsdinstall completed successfully"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
_rc=$?
|
||||
fail "bsdinstall-failed" "bsdinstall exited with status ${_rc}"
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# Live installer runtime — needed on the USB image itself
|
||||
qt6-base
|
||||
qt6-declarative
|
||||
sudo
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue