Skip to content

Instantly share code, notes, and snippets.

@sundbry
Last active February 5, 2021 09:01
Show Gist options
  • Save sundbry/5c435b0d35576b9863710b48b675d363 to your computer and use it in GitHub Desktop.
Save sundbry/5c435b0d35576b9863710b48b675d363 to your computer and use it in GitHub Desktop.
Guix Rescue CD Install
#!/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