Initial commit

This commit is contained in:
Eric Renfro 2024-08-01 15:21:25 -04:00
commit 1abc5b8b59
Signed by: psi-jack
SSH key fingerprint: SHA256:1TKB8Z257L8EHK8GWNxKgMhD8a+FAR+f+j3nnlcuNVM
2 changed files with 490 additions and 0 deletions

43
README.md Normal file
View file

@ -0,0 +1,43 @@
# Gentoo Installation Helper Script
Used to provide good defaults to Gentoo to install with or without encryption, hibernation support, and with BtrFS subvolumes.
```
Usage: gentoo-install.sh <disk> [<options>...]
Positional Arguments:
<drive> Disk device used for system
Options:
-h, --help Help on this tool.
-e, --encryption Enable LUKS encryption.
-c, --compression Enable BtrFS compression.
-s, --swap Enable Swap/Hibernation support.
-d, --debug Enable DEBUG mode for testing.
--stage <stage> Installation using stagefile <stage>, for stage3 or stage4
--clean Cleanup disk for clean slate
```
## Initial Setup
This installation script is intended to work on a clean disk to provision all partitions
as appropriate to the generalized setup defined.
## Installation
Run gentoo-install.sh with appropriate parameters. An example of this for NVME-based SSD, and Encryption with Hibernation:
```
sudo ./gentoo-install.sh /dev/nvme0n1 -e -s
```
This will start the provisioning setup, with the full expectations that the system is ready to go as-is, as it will format. You will get one prompt before it actually starts.
## Stage Installation
After the preparation phase, it completes and allows you time to verify what's happened and
go over any issues you may or may not see, before you continue on to stage installation.
The Stage installation, using `--stage <stage>` allows you to setup stage3 or stage4 based on
what you provide for <stage>, which can be a url or a file to an appropriate stagefile.

447
gentoo-install.sh Normal file
View file

@ -0,0 +1,447 @@
#!/bin/bash
if [[ "$(id -u)" -ne 0 ]]; then
echo "ERROR: This needs to be run as root"
exit 250
fi
declare -rA SUBVOLS_DEFAULT=(
["@home"]="home"
["@root"]="root"
["@srv"]="srv"
["@opt"]="opt"
["@local"]="usr/local"
["@cache"]="var/cache"
["@repos"]="/var/db/repos"
["@containers"]="var/lib/containers"
["@libvirt"]="var/lib/libvirt/images"
["@machines"]="var/lib/machines"
["@portables"]="var/lib/portables"
["@log"]="var/log"
["@spool"]="var/spool"
["@www"]="var/www"
["@snapshots"]=".snapshots"
)
gunction show_help() {
echo "Usage: $0 <disk> [<options>...]"
echo ""
echo "Positional Arguments:"
echo "<drive> Disk device used for system"
echo ""
echo "Options:"
echo "-h, --help Help on this tool."
echo "-e, --encryption Enable LUKS encryption."
echo "-c, --compression Enable BtrFS compression."
echo "-s, --swap Enable Swap/Hibernation support."
echo "-d, --debug Enable DEBUG mode for testing."
echo ""
echo "--stage <stage> Installation using stagefile <stage>, for stage3 or stage4"
echo "--clean Cleanup disk for clean slate"
exit 0
}
function prepare_disk() {
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
if [[ -b "$RootDisk" ]]; then
if [[ -b "$EFIPart" || -b "$RootPart" ]]; then
echo "FATAL: Disk already provisioned. Clean required to continue."
exit 250
fi
if [[ "$ENCRYPTION" ]]; then
parted "$RootDisk" --script --align optimal -- "$RootDisk" \
mklabel gpt \
mkpart primary 1MiB 100MiB \
mkpart primary 100MiB 2048MiB \
mkpart primary 2148MiB -2048s \
set 1 esp
#mkfs.vfat -F 32 -n "EFI" "$RootPart"
#mkfs.ext4 -L "Boot" -m 0 "$EFIPart"
#mkfs.btrfs -L "System" "$RootPart"
else
parted "$RootDisk" --script --align optimal -- "$RootDisk" \
mklabel gpt \
mkpart primary 1MiB 100MiB \
mkpart primary 100MiB -2048s \
set 1 esp
#mkfs.vfat -F 32 -n "EFI" "$RootPart"
#mkfs.btrfs -L "System" "$RootPart"
fi
}
function create_luks() {
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
${cmd} cryptsetup --cipher aes-xts-plain64 --hash sha512 --use-random --verify-passphrase luksFormat "$RootPart"
${cmd} cryptsetup luksOpen "$RootPart" luksvol
}
function prepare_format() {
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
echo "Formatting EFI: $EFIPart"
${cmd} mkfs.fat -F32 -n "EFI" "$EFIPart"
if [[ "$BootPart" != "@boot" ]]; then
echo "Formatting Boot: $BootPart"
${cmd} mkfs.ext4 -FF -L "Boot" "$BootPart"
fi
if [[ "$ENCRYPTION" ]]; then
echo "Formatting Root: /dev/mapper/luksvol"
${cmd} mkfs.btrfs -L "System" /dev/mapper/luksvol
else
echo "Formatting Root: $RootPart"
${cmd} mkfs.btrfs -L "System" "$RootPart"
fi
}
function create_subvolumes() {
local -a subvols=("@")
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
if [[ "$BootPart" == "@boot" ]]; then
subvols+=("@boot")
fi
subvols+=("@swap")
subvols+=("${!SUBVOLS_DEFAULT[@]}")
mkdir -p /mnt/btrfs
if [[ "$ENCRYPTION" ]]; then
${cmd} mount "/dev/mapper/luksvol" /mnt/btrfs
else
${cmd} mount "$RootPart" /mnt/btrfs
fi
for subvol in "${subvols[@]}"
do
${cmd} btrfs subvolume create /mnt/btrfs/"$subvol"
done
${cmd} umount /mnt/btrfs
}
function get_hibernate_size() {
free --giga | awk '/^Mem:/{print $2}'
}
function prepare_target() {
local subvol
local rootmount
local compopt
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
${cmd} mkdir /mnt/gentoo
if [[ "$ENCRYPTION" ]]; then
rootmount="/dev/mapper/luksvol"
else
rootmount="$RootPart"
fi
if [[ "$COMPRESSION" ]]; then
compopt=",compress=zstd:3"
${cmd} mount -o noatime,space_cache=v2${compopt},ssd,subvol=@ "$rootmount" /mnt/gentoo
for subvol in "${!SUBVOLS_DEFAULT[@]}"
do
${cmd} mkdir -p /mnt/gentoo/"${SUBVOLS_DEFAULT[$subvol]}"
done
${cmd} mkdir -p /mnt/gentoo/boot
if [[ "$BootPart" == "@boot" ]]; then
${cmd} mount -o noatime,space_cache=v2,ssd,subvol=@boot "$rootmount" /mnt/gentoo/boot
else
${cmd} mount "$BootPart" /tamnt/gentooget/boot
fi
for subvol in "${!SUBVOLS_DEFAULT[@]}"
do
${cmd} mount -o noatime,space_cache=v2,ssd,subvol="$subvol" "$rootmount" /mnt/gentoo/"${SUBVOLS_DEFAULT[$subvol]}"
done
${cmd} mkdir -p /mnt/gentoo/efi
${cmd} mount "$EFIPart" /mnt/gentoo/efi
${cmd} mkdir -p /mnt/gentoo/swap
${cmd} mount -o noatime,ssd,subvol=@swap "$rootmount" /mnt/gentoo/swap
if [[ "$SWAP" ]]; then
#${cmd} mkdir -p /mnt/gentoo/swap
#${cmd} mount -o noatime,ssd,subvol=@swap "$rootmount" /mnt/gentoo/swap
${cmd} btrfs filesystem mkswapfile --size "$(get_hibernate_size)g" --uuid clear /mnt/gentoo/swap/hibernate.swp
fi
}
function stage_step() {
local UUID PART_ENTRY_UUID
local SwapUUID SwapOffset
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
if [[ "$DEBUG" ]]; then
echo "genfstab -U /mnt/gentoo >> /mnt/gentoo/etc/fstab"
else
genfstab -U /mnt/gentoo >> /mnt/gentoo/etc/fstab
fi
if [[ "$ENCRYPTION" ]]; then
eval "$(blkid -p --output export "$RootPart" | grep UUID)"
if [[ "$DEBUG" ]]; then
echo "echo \"luksvol UUID=$UUID none luks\" >> /mnt/gentoo/etc/crypttab"
else
echo "luksvol UUID=$UUID none luks" >> /mnt/gentoo/etc/crypttab
fi
fi
if [[ "$SWAP" ]]; then
if [[ "$DEBUG" ]]; then
echo "echo \"/swap/hibernate.swp none swap defaults 0 0\" >> /mnt/gentoo/etc/fstab"
else
echo "/swap/hibernate.swp none swap defaults 0 0" >> /mnt/gentoo/etc/fstab
fi
SwapUUID=$(grep btrfs /mnt/gentoo/etc/fstab | head -n1 | cut -f1)
SwapOffset=$(btrfs inspect-internal map-swapfile -r /mnt/gentoo/swap/hibernate.swp)
${cmd} sed -i "s/^#GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"resume=${SwapUUID} resume_offset=${SwapOffset}\"/g" /mnt/gentoo/etc/default/grub
fi
}
function show_options() {
echo "System Disk: $RootDisk"
echo "Root Partition: $RootPart"
echo "Boot Partition: $BootPart"
echo "EFI Partition: $EFIPart"
if [[ "$INSTALL_MODE" == "stage" ]]; then
echo "Install Mode: Stage"
echo "STAGE File: $INSTALL_STAGE"
elif [[ "$INSTALL_MODE" == "clean" ]]; then
echo "Install Mode: Clean"
else
echo "Install Mode: Normal"
fi
if [[ "$ENCRYPTION" ]]; then
echo "Encryption: Enabled"
else
echo "Encryption: Disabled"
fi
if [[ "$COMPRESSION" ]]; then
echo "Compression: Enabled"
else
echo "Compression: Disabled"
fi
if [[ "$SWAP" ]]; then
echo "Swap: Enabled"
else
echo "Swap: Disabled"
fi
if [[ "$DEBUG" ]]; then
echo "Debug: Enabled"
else
echo "Debug: Disabled"
fi
echo
}
function install_prep() {
show_options
read -rsn1 -p"Preparation: To proceed, press enter to continue." proceed
echo
if [[ "$proceed" != "" ]]; then
echo "Aborting."
exit 1
fi
echo "Creating Partitions on ${RootDisk}..."
prepare_disk
if [[ "$ENCRYPTION" ]]; then
echo
echo "Initiallizing LUKSv2 on ${RootPart}:"
create_luks
fi
echo
echo "Formatting Filesystems..."
prepare_format
echo
echo "Preparing Subvolumes..."
create_subvolumes
echo
echo "Preparing Installation Target..."
prepare_target
echo
echo "Installation is ready and mounted in /mnt/gentoo for stage3 or stage4 install"
echo "Please verify all went well, and re-run this script with --stage <stagefile>"
echo "as appropriate, to continue."
}
function install_stage() {
show_options
read -rsn1 -p"Stage-Installation: To proceed, press enter to continue." proceed
echo
if [[ "$proceed" != "" ]]; then
echo "Aborting."
exit 1
fi
echo
echo "Running Stage-Mode Installation Steps..."
stage_step
}
function install_cleanup() {
show_options
echo "!!!WARNING!!! This is about to destructively wipe ${RootDisk}!"
read -rsn -p"Enter YES to continue." proceed
echo
if [[ "${proceed,,}" != "yes" ]]; then
echo "Aborting."
exit 1
fi
if [[ "$DEBUG" ]]; then
local cmd="echo"
else
local cmd=""
fi
for subvol in "${!SUBVOLS_DEFAULT[@]}"
do
${cmd} umount /mnt/gentoo/"${SUBVOLS_DEFAULT[$subvol]}"
done
${cmd} umount /mnt/gentoo/efi
${cmd} umount /mnt/gentoo/boot
${cmd} umount /mnt/gentoo/swap
${cmd} umount /mnt/gentoo
if [[ "$ENCRYPTION" ]]; then
${cmd} cryptsetup luksClose luksvol
fi
${cmd} dd if=/dev/zero of="${RootDisk}" bs=1024 count=10
}
declare -a POSITIONAL_ARGS=()
declare INSTALL_MODE="normal"
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
;;
-e|--encryption)
ENCRYPTION=true
shift
;;
-c|--compression)
COMPRESSION=true
shift
;;
-s|--swap)
SWAP=true
shift
;;
-d|--debug)
DEBUG=true
shift
;;
--stage)
INSTALL_MODE=stage
INSTALL_STAGE=$1
shift 2
;;
--clean)
INSTALL_MODE=clean
shift
;;
*)
POSITIONAL_ARGS+=("$1") # save positional arg
shift
;;
esac
done
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
RootDisk="$1"
if [[ ! -b "$RootDisk" ]]; then
echo "ERROR: Invalid parameters. See --help for help"
exit 3
elif
if [[ "$ENCRYPTION" ]]; then
diskdev="${RootDisk##*/}"
if [[ "$diskdev" =~ ^nvme.* ]]; then
RootPart="${RootDisk}p3"
BootPart="${RootDisk}p2"
EFIPart="${RootDisk}p1"
else
RootPart="${RootDisk}3"
BootPart="${RootDisk}2"
EFIPart="${RootDisk}1"
fi
else
BootPart="@boot"
if [[ "$diskdev" =~ ^nvme.* ]]; then
RootPart="${RootDisk}p2"
EFIPart="${RootDisk}p1"
else
RootPart="${RootDisk}2"
EFIPart="${RootDisk}1"
fi
fi
case "$INSTALL_MODE" in
normal) install_prep;;
stage) install_stage;;
clean) install_cleanup;;
*)
echo "Error, unknown installation mode detected."
exit 3
;;
esac
fi