summaryrefslogtreecommitdiff
path: root/infra/guix/bootstrap.sh
diff options
context:
space:
mode:
Diffstat (limited to 'infra/guix/bootstrap.sh')
-rw-r--r--infra/guix/bootstrap.sh86
1 files changed, 86 insertions, 0 deletions
diff --git a/infra/guix/bootstrap.sh b/infra/guix/bootstrap.sh
new file mode 100644
index 0000000..6f53dbc
--- /dev/null
+++ b/infra/guix/bootstrap.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -eu
+umask 077
+fail() { printf '%s\n' "$1" >&2; exit 1; }
+safe_directory() {
+ [ -d "$1" ] && [ ! -L "$1" ] && [ "$(stat -c %u "$1")" = 0 ] &&
+ [ -z "$(find "$1" -maxdepth 0 -perm /022 -print)" ]
+}
+[ "$#" = 0 ] || fail 'Usage: sudo ./stack-recovery/bootstrap'
+[ "$(id -u)" = 0 ] || fail 'Run bootstrap explicitly as root; restore runs as the service user.'
+[ "$(uname -sm)" = 'Linux x86_64' ] || fail 'Requires x86_64 Linux.'
+command -v flock >/dev/null || fail 'Host util-linux flock is required.'
+command -v diff >/dev/null || fail 'Host GNU diffutils is required.'
+BUNDLE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+(cd "$BUNDLE" && sha256sum --check --strict SHA256SUMS)
+[ ! -e /var/guix ] && [ ! -L /var/guix ] || fail 'Managed Guix installation found; refusing bootstrap.'
+[ ! -L /gnu ] && [ ! -L /gnu/store ] || fail 'Symlink /gnu or store; refusing bootstrap.'
+STAGE=
+INITIAL=
+trap '[ -z "$STAGE" ] || rm -rf -- "$STAGE"; [ -z "$INITIAL" ] || rm -rf -- "$INITIAL"' EXIT HUP INT TERM
+if [ ! -e /gnu ]; then
+ INITIAL=$(mktemp -d /.stack-guix.XXXXXX)
+ chmod 755 "$INITIAL"
+ mkdir -m 755 "$INITIAL/store" "$INITIAL/.stack-runtimes"
+ mv -T --no-clobber -- "$INITIAL" /gnu
+ rm -rf -- "$INITIAL"
+ INITIAL=
+fi
+safe_directory /gnu && safe_directory /gnu/.stack-runtimes || fail 'Foreign or writable /gnu ownership metadata; refusing bootstrap.'
+exec 9>/gnu/.stack-runtimes/install.lock
+flock 9
+if [ -e /gnu/store ]; then
+ safe_directory /gnu/store || fail 'Foreign or writable Guix store; refusing bootstrap.'
+else
+ [ ! -L /gnu/store ] || fail 'Symlink store; refusing bootstrap.'
+ mkdir -m 755 /gnu/store
+fi
+DIGEST=$(sha256sum "$BUNDLE/runtime.tar.gz")
+DIGEST=${DIGEST%% *}
+MARKER=/gnu/.stack-runtimes/$DIGEST
+if [ -e "$MARKER" ] || [ -L "$MARKER" ]; then
+ [ -f "$MARKER" ] && [ ! -L "$MARKER" ] && [ "$(stat -c %u "$MARKER")" = 0 ] &&
+ [ -z "$(find "$MARKER" -perm /222 -print)" ] && [ "$(cat "$MARKER")" = "$DIGEST" ] ||
+ fail 'Invalid completed-runtime marker; refusing bootstrap.'
+ printf '%s\n' 'Guix runtime already installed.'
+ exit 0
+fi
+STAGE=$(mktemp -d /gnu/.stack-stage.XXXXXX)
+tar -xzf "$BUNDLE/runtime.tar.gz" --no-same-owner -C "$STAGE"
+[ -d "$STAGE/gnu" ] && [ ! -L "$STAGE/gnu" ] &&
+ [ -d "$STAGE/gnu/store" ] && [ ! -L "$STAGE/gnu/store" ] || fail 'Runtime has no canonical Guix store.'
+set -- "$STAGE/gnu/store/"*
+[ -e "$1" ] || [ -L "$1" ] || fail 'Runtime Guix store is empty.'
+chown -hR 0:0 "$STAGE/gnu/store"
+chmod -R a-w "$STAGE/gnu/store"
+for ENTRY do
+ TARGET=/gnu/store/${ENTRY##*/}
+ if [ -e "$TARGET" ] || [ -L "$TARGET" ]; then
+ diff -qr --no-dereference -- "$ENTRY" "$TARGET" || fail 'Conflicting Guix store entry; existing data retained.'
+ [ -z "$(find "$TARGET" \( ! -user 0 -o \( ! -type l -perm /222 \) \) -print -quit)" ] ||
+ fail 'Existing Guix store entry has unsafe ownership or write permissions.'
+ else
+ mv -T --no-clobber -- "$ENTRY" "$TARGET"
+ [ ! -e "$ENTRY" ] && [ ! -L "$ENTRY" ] || fail 'Guix store entry appeared during installation; retry bootstrap.'
+ fi
+done
+printf '%s\n' "$DIGEST" > "$STAGE/complete"
+chmod 444 "$STAGE/complete"
+mv -T --no-clobber -- "$STAGE/complete" "$MARKER"
+[ ! -e "$STAGE/complete" ] || fail 'Runtime marker appeared during installation; retry bootstrap.'
+printf '%s\n' 'Guix runtime installed. Run restore as the service user.'