Last active
February 5, 2021 09:01
-
-
Save sundbry/5c435b0d35576b9863710b48b675d363 to your computer and use it in GitHub Desktop.
Guix Rescue CD Install
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# Bare metal Guix bootstrap program from a livecd (SystemRescueCd) shell. | |
GUIX_TARBALL="https://ftp.gnu.org/gnu/guix/guix-binary-1.2.0.x86_64-linux.tar.xz" | |
BUSYBOX_BINARY="https://busybox.net/downloads/binaries/1.31.0-i686-uclibc/busybox" | |
GUIX_MAX_JOBS=4 | |
BOOT_SIZE="2M" | |
: ${SWAP_SIZE:="4096M"} | |
ROOT_AUTHORIZED_KEYS=$(cat <<EOF | |
ssh-rsa my-ssh-key-here user@host | |
EOF | |
) | |
ROOT_FS="btrfs" | |
function abort { | |
let EXIT_CODE=${2:-2} | |
echo Aborting: $1 | |
exit $EXIT_CODE | |
} | |
function verify { | |
let STATUS=$1 | |
MESSAGE=$2 | |
EXIT_CODE=$3 | |
if [ $STATUS -ne 0 ]; then | |
abort "$MESSAGE" $EXIT_CODE | |
fi | |
} | |
function select_disk { | |
INSTALL_DISK=$1 | |
if [ -z "$INSTALL_DISK" ]; then | |
echo -n "Disk to install to: " | |
read INSTALL_DISK | |
fi | |
# Format a GPT partition table | |
if [ ! -b "$INSTALL_DISK" ]; then | |
abort "$INSTALL_DISK is not a block device" 1 | |
fi | |
echo "Installing Guix to $INSTALL_DISK" | |
} | |
function partition_disk { | |
# Create a GPT partition table with a BIOS boot partition, a swap partition, and a single Btrfs data partition. | |
FDISK_SEQUENCE="g\nn\n1\n\n+${BOOT_SIZE}\nt\n4\nn\n2\n\n+${SWAP_SIZE}\nt\n2\n15\nn\n3\n\n\np\nw\n" | |
echo -e $FDISK_SEQUENCE | fdisk ${INSTALL_DISK} | |
verify $? "Partitioning failed!" | |
which kpartx > /dev/null 2>&1 | |
if [ $? -eq 0 ]; then | |
kpartx -u ${INSTALL_DISK} | |
else | |
partprobe ${INSTALL_DISK} | |
fi | |
verify $? "Failed to reload partition table!" | |
sleep 1 | |
} | |
function format_disk { | |
case $ROOT_FS in | |
btrfs) | |
mkfs.btrfs -f -L data0 ${INSTALL_DISK}3 | |
;; | |
ext4) | |
mkfs.ext4 -F -L data0 ${INSTALL_DISK}3 | |
;; | |
*) | |
abort "Unsupported ROOT_FS" | |
;; | |
esac | |
verify $? "Failed to create data partition" | |
mkswap ${INSTALL_DISK}2 | |
} | |
function close_chroot { | |
killall guix-daemon | |
rm -f /mnt/busybox /mnt/etc/ssl | |
sleep 1 | |
umount /mnt/proc /mnt/dev /mnt/tmp | |
lsof /mnt | |
umount /mnt | |
} | |
function build_chroot { | |
mkdir -p /mnt/proc /mnt/dev /mnt/etc /mnt/tmp /mnt/root/.config/guix | |
ln -sf /var/guix/profiles/per-user/root/current-guix /mnt/root/.config/guix/current | |
mount -o bind /proc /mnt/proc | |
mount -o bind /dev /mnt/dev | |
mount -o bind /tmp /mnt/tmp | |
# Install busybox | |
if [ ! -f /mnt/busybox ]; then | |
wget "$BUSYBOX_BINARY" -O /mnt/busybox | |
verify $? "Failed to download Busybox" | |
chmod 0755 /mnt/busybox | |
fi | |
# Detect if we have user namespaces enabled | |
zcat /proc/config.gz | grep CONFIG_USER_NS > /dev/null 2>&1 | |
if [ $? -ne 0 ]; then | |
abort "CONFIG_USER_NS required. Please use a newer kernel." | |
fi | |
cp -f /etc/services /mnt/etc/services | |
cp -f /etc/hosts /mnt/etc/hosts | |
cp -f /etc/resolv.conf /mnt/etc/resolv.conf | |
cat <<EOF > /mnt/etc/config.scm | |
(use-modules (gnu)) | |
(use-service-modules networking ssh) | |
(use-package-modules bootloaders certs ssh) | |
(operating-system | |
(host-name "guix") | |
(timezone "Etc/UTC") | |
(bootloader (bootloader-configuration | |
(bootloader grub-bootloader) | |
(target "${INSTALL_DISK}") | |
(terminal-outputs '(console)))) | |
(file-systems (cons (file-system | |
(mount-point "/") | |
(device "${INSTALL_DISK}3") | |
(type "${ROOT_FS}")) | |
%base-file-systems)) | |
(swap-devices (list "${INSTALL_DISK}2")) | |
(packages (cons* nss-certs openssh-sans-x %base-packages)) | |
(services | |
(append (list (service dhcp-client-service-type) | |
;(static-networking-service | |
; "enp5s0f1" | |
; "1.2.3.4" | |
; #:gateway "1.2.3.1" | |
; #:netmask "255.255.255.0" | |
; #:name-servers '("4.2.2.2" "1.1.1.1")) | |
(service openssh-service-type | |
(openssh-configuration | |
(openssh openssh-sans-x) | |
(password-authentication? #f) | |
(permit-root-login #t) | |
(authorized-keys | |
\`(("root" ,(plain-file "authorized_keys" "${ROOT_AUTHORIZED_KEYS}"))))))) | |
%base-services))) | |
EOF | |
trap close_chroot EXIT | |
} | |
function install_chroot { | |
cat <<EOF | unshare -U -p -m -f -R /mnt /busybox sh & | |
echo "Sleeping until user mapping is ready" | |
/busybox sleep 5 | |
echo "Woken up." | |
export GUIX_PROFILE=/root/.config/guix/current | |
source \$GUIX_PROFILE/etc/profile | |
/busybox touch /etc/group /etc/passwd | |
/busybox adduser -u 0 -h /root root | |
/busybox addgroup -g 0 root | |
#/busybox addgroup -g 30000 guixbuild | |
printf 'guixbuild:x:30000:guixbuilder1,guixbuilder2,guixbuilder3,guixbuilder4\n' >> /etc/group | |
for i in \$(/busybox seq 1 $GUIX_MAX_JOBS); do /busybox adduser -H -G guixbuild guixbuilder\$i ; /busybox groups guixbuilder\$i; done | |
/busybox cat /etc/passwd | |
/busybox cat /etc/group | |
set -e | |
guix-daemon --build-users-group=guixbuild --max-jobs=$GUIX_MAX_JOBS & | |
/busybox sleep 1 | |
guix archive --authorize < \$(/busybox find /gnu -name ci.guix.gnu.org.pub) | |
guix package -i nss-certs | |
/busybox ln -sf \$(/busybox readlink -f /root/.guix-profile)/etc/ssl /etc/ssl | |
/busybox ls -l /etc/ssl | |
guix pull | |
guix describe | |
guix system init -v 1 /etc/config.scm / | |
EOF | |
let process=$! | |
sleep 1 # give process time to spawn the container | |
echo "Setting uid_map, gid_map for process $process" | |
printf '0 0 65535' > /proc/$process/uid_map | |
printf '0 0 65535' > /proc/$process/gid_map | |
echo "uid_map:" | |
cat /proc/$process/uid_map | |
echo "gid_map:" | |
cat /proc/$process/gid_map | |
wait $process | |
verify $? "Failed to install system" | |
echo "Guix System Distribution installation complete! You may now reboot." | |
} | |
function install { | |
format_disk | |
mount LABEL=data0 /mnt | |
wget "$GUIX_TARBALL" -O /mnt/guix.tar.xz | |
verify $? "Failed to download Guix" | |
tar --warning=no-timestamp -xf /mnt/guix.tar.xz -C /mnt | |
verify $? "Failed to extract Guix" | |
rm -f /mnt/guix.tar.xz | |
build_chroot | |
install_chroot | |
} | |
function run_shell { | |
mount LABEL=data0 /mnt | |
build_chroot | |
echo "alias bb=/busybox" | |
exec unshare -U -p -m -f -r -R /mnt /busybox sh | |
} | |
function print_help { | |
echo "Usage: $1 <command>" | |
echo " Commands are: " | |
echo " partition <disk>" | |
echo " install <disk>" | |
echo " shell <disk>" | |
exit 1 | |
} | |
case $1 in | |
partition) | |
select_disk $2 | |
partition_disk | |
;; | |
install) | |
select_disk $2 | |
install | |
;; | |
shell) | |
select_disk $2 | |
run_shell | |
;; | |
*) | |
print_help $0 | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment