WizardKit/setup/build_linux
2021-03-25 23:43:10 -06:00

425 lines
13 KiB
Bash
Executable file

#!/bin/bash
#
## Wizard Kit: Live Linux Build Tool
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
# Prep
DATE="$(date +%Y-%m-%d)"
DATETIME="$(date +%Y-%m-%d_%H%M)"
ROOT_DIR="$(realpath $(dirname "$0")/..)"
BUILD_DIR="$ROOT_DIR/setup/BUILD"
LOG_DIR="$BUILD_DIR/logs"
OUT_DIR="$ROOT_DIR/setup/OUT"
PROFILE_DIR="$BUILD_DIR/archiso-profile"
REPO_DIR="$BUILD_DIR/repo"
SKEL_DIR="$PROFILE_DIR/airootfs/etc/skel"
TEMP_DIR="$BUILD_DIR/temp"
MIRRORLIST_SOURCE='https://archlinux.org/mirrorlist/?country=US&protocol=http&protocol=https&ip_version=4&use_mirror_status=on'
if command -v nano >/dev/null 2>&1; then
EDITOR=nano
elif command -v vim >/dev/null 2>&1; then
EDITOR=vim
else
EDITOR=vi
fi
if [ ! -z ${SUDO_USER+x} ]; then
REAL_USER="$SUDO_USER"
fi
function ask() {
while :; do
read -p "$1 [Y/N] " -r answer
if echo "$answer" | egrep -iq '^(y|yes|sure)$'; then
return 0
elif echo "$answer" | egrep -iq '^(n|no|nope)$'; then
return 1
fi
done
}
function cleanup() {
for d in "$TEMP_DIR" "$PROFILE_DIR"; do
if [[ -d "$d" ]]; then
if ask "Remove: ${d}?"; then
rm -Rf "$d"
fi
fi
done
mkdir -p "$BUILD_DIR" 2>/dev/null
mkdir -p "$LOG_DIR" 2>/dev/null
mkdir -p "$OUT_DIR" 2>/dev/null
mkdir -p "$TEMP_DIR" 2>/dev/null
}
function fix_kit_permissions() {
# GitHub zip archives don't preserve the correct permissions
for d in docs images scripts setup; do
find "$ROOT_DIR/$d" -type d -exec chmod 755 "{}" \;
done
}
function load_settings() {
dos2unix "$ROOT_DIR/scripts/wk/cfg/main.py"
while read line; do
if echo "$line" | egrep -q "^\w+='"; then
line="$(echo "$line" | sed -r 's/[\r\n]+//')"
eval "$line"
fi
done < "$ROOT_DIR/scripts/wk/cfg/main.py"
}
function copy_live_env() {
echo "Copying Archlinux files..."
rsync -aI "$ROOT_DIR/setup/linux/profile_base/" "$PROFILE_DIR/"
# Add items
if [[ "${1:-}" != "--minimal" ]]; then
rsync -aI "$ROOT_DIR/setup/linux/profile_gui/" "$PROFILE_DIR/"
fi
mkdir -p "$PROFILE_DIR/airootfs/usr/local/bin"
rsync -aI "$ROOT_DIR/scripts/" "$PROFILE_DIR/airootfs/usr/local/bin/"
# Update profiledef.sh to set proper permissions for executable files
for _file in $(find "$PROFILE_DIR/airootfs" -executable -type f | sed "s%$PROFILE_DIR/airootfs%%" | sort); do
sed -i "\$i\ [\"$_file\"]=\"0:0:0755\"" "$PROFILE_DIR/profiledef.sh"
done
}
function run_elevated() {
prog="$1"
shift
if command -v sudo >/dev/null 2>&1; then
if ! sudo "$prog" $*; then
echo "ERROR: Failed to run '$prog'"
if ask "Retry?"; then
sudo "$prog" $*
fi
fi
else
echo -n "Root "
if ! su -c "export REAL_USER=$USER && '$prog' $*"; then
echo "ERROR: Failed to run '$prog'"
if ask "Retry?"; then
su -c "export REAL_USER=$USER && '$prog' $*"
fi
fi
fi
}
function update_live_env() {
hostname="$(echo "${KIT_NAME_SHORT}-linux" | tr "[:upper:]" "[:lower:]")"
username="tech"
label="${KIT_NAME_SHORT}_LINUX"
# MOTD
sed -i -r "s/KIT_NAME_SHORT/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
sed -i -r "s/KIT_NAME_FULL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
sed -i -r "s/SUPPORT_URL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
# Boot config (legacy)
mkdir -p "$PROFILE_DIR/arch"
cp "$ROOT_DIR/images/Pxelinux.png" "$PROFILE_DIR/arch/pxelinux.png"
cp "$ROOT_DIR/images/Syslinux.png" "$PROFILE_DIR/arch/syslinux.png"
sed -i -r "s/__+/$KIT_NAME_FULL/" "$PROFILE_DIR/syslinux/syslinux.cfg"
mkdir -p "$TEMP_DIR" 2>/dev/null
curl -Lo "$TEMP_DIR/wimboot.zip" "http://git.ipxe.org/releases/wimboot/wimboot-latest.zip"
7z e -aoa "$TEMP_DIR/wimboot.zip" -o"$PROFILE_DIR/arch/boot" 'wimboot*/LICENSE.txt' 'wimboot*/README.txt' 'wimboot*/wimboot'
# Boot config (UEFI)
mkdir -p "$PROFILE_DIR/EFI/boot"
cp "/usr/share/refind/refind_x64.efi" "$PROFILE_DIR/EFI/boot/bootx64.efi"
cp "$ROOT_DIR/images/rEFInd.png" "$PROFILE_DIR/EFI/boot/rEFInd.png"
rsync -aI "/usr/share/refind/drivers_x64/" "$PROFILE_DIR/EFI/boot/drivers_x64/"
rsync -aI "/usr/share/refind/icons/" "$PROFILE_DIR/EFI/boot/icons/" --exclude "/usr/share/refind/icons/svg"
sed -i "s/%ARCHISO_LABEL%/${label}/" "$PROFILE_DIR/EFI/boot/refind.conf"
# Memtest86
mkdir -p "$PROFILE_DIR/EFI/memtest86/Benchmark"
mkdir -p "$TEMP_DIR/memtest86"
curl -Lo "$TEMP_DIR/memtest86/memtest86-usb.zip" "https://www.memtest86.com/downloads/memtest86-usb.zip"
7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.zip" -o"$TEMP_DIR/memtest86" "memtest86-usb.img"
7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.img" -o"$TEMP_DIR/memtest86" "MemTest86.img"
7z x -aoa "$TEMP_DIR/memtest86/MemTest86.img" -o"$TEMP_DIR/memtest86"
rm "$TEMP_DIR/memtest86/EFI/BOOT/BOOTIA32.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT/BOOTX64.efi" "$PROFILE_DIR/EFI/memtest86/memtestx64.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT"/* "$PROFILE_DIR/EFI/memtest86"/
mv "$TEMP_DIR/memtest86/help"/* "$PROFILE_DIR/EFI/memtest86"/
mv "$TEMP_DIR/memtest86/license.rtf" "$PROFILE_DIR/EFI/memtest86"/
# Hostname
echo "$hostname" > "$PROFILE_DIR/airootfs/etc/hostname"
echo "127.0.1.1 $hostname.localdomain $hostname" >> "$PROFILE_DIR/airootfs/etc/hosts"
# Live packages
cp "$ROOT_DIR/setup/linux/packages/base" "$PROFILE_DIR/packages.x86_64"
if [[ "${1:-}" != "--minimal" ]]; then
cat "$ROOT_DIR/setup/linux/packages/gui" >> "$PROFILE_DIR/packages.x86_64"
fi
echo "[custom]" >> "$PROFILE_DIR/pacman.conf"
echo "SigLevel = Optional TrustAll" >> "$PROFILE_DIR/pacman.conf"
echo "Server = file://$REPO_DIR" >> "$PROFILE_DIR/pacman.conf"
# Mirrors
mkdir -p "$PROFILE_DIR/airootfs/etc/pacman.d"
curl -Lo "$PROFILE_DIR/airootfs/etc/pacman.d/mirrorlist" "$MIRRORLIST_SOURCE"
sed -i 's/#Server/Server/g' "$PROFILE_DIR/airootfs/etc/pacman.d/mirrorlist"
# MOTD
sed -i -r "s/_+/$KIT_NAME_FULL Linux Environment/" "$PROFILE_DIR/airootfs/etc/motd"
# Oh My ZSH
git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git "$SKEL_DIR/.oh-my-zsh"
rm -Rf "$SKEL_DIR/.oh-my-zsh/.git"
curl -o "$SKEL_DIR/.oh-my-zsh/themes/lean.zsh-theme" https://raw.githubusercontent.com/miekg/lean/master/prompt_lean_setup
if [[ "${1:-}" != "--minimal" ]]; then
# Openbox theme
git clone --depth=1 https://github.com/addy-dclxvi/Openbox-Theme-Collections.git "$TEMP_DIR/ob-themes"
mkdir -p "$PROFILE_DIR/airootfs/usr/share/themes"
cp -a "$TEMP_DIR/ob-themes/Triste-Orange" "$PROFILE_DIR/airootfs/usr/share/themes/"
# Rofi
## Probably don't need the exact commit but it'll be fine
mkdir -p "$PROFILE_DIR/airootfs/usr/share/fonts/"
curl -Lo \
"$PROFILE_DIR/airootfs/usr/share/fonts/Fantasque-Sans-Mono-Nerd-Font.ttf" \
"https://github.com/adi1090x/rofi/raw/9c4093c665326bb08d6affc7e16d18d8f25c4452/fonts/Fantasque-Sans-Mono-Nerd-Font.ttf"
curl -Lo \
"$PROFILE_DIR/airootfs/usr/share/fonts/Feather.ttf" \
"https://github.com/adi1090x/rofi/raw/9c4093c665326bb08d6affc7e16d18d8f25c4452/fonts/Feather.ttf"
fi
# SSH
mkdir -p "$SKEL_DIR/.ssh"
ssh-keygen -b 4096 -C "$username@$hostname" -N "" -f "$SKEL_DIR/.ssh/id_rsa"
if ! grep -qv "^#" "$ROOT_DIR/setup/linux/authorized_keys"; then
echo "WARNING: No authorized SSH keys found." 1>&2
fi
cp "$ROOT_DIR/setup/linux/authorized_keys" "$SKEL_DIR/.ssh/authorized_keys"
# Root user
echo "root:$(echo "$ROOT_PASSWORD" | openssl passwd -6 -stdin):14871::::::" >> "$PROFILE_DIR/airootfs/etc/shadow"
# Tech user
echo "tech:$(echo "$TECH_PASSWORD" | openssl passwd -6 -stdin):14871::::::" >> "$PROFILE_DIR/airootfs/etc/shadow"
# Timezonew
ln -sf "/usr/share/zoneinfo/$LINUX_TIME_ZONE" "$PROFILE_DIR/airootfs/etc/localtime"
if [[ "${1:-}" != "--minimal" ]]; then
# VNC password
mkdir "$SKEL_DIR/.vnc"
echo "$TECH_PASSWORD" | vncpasswd -f > "$SKEL_DIR/.vnc/passwd"
# Wallpaper
mkdir -p "$PROFILE_DIR/airootfs/usr/share/wallpaper"
cp "$ROOT_DIR/images/Linux.png" "$PROFILE_DIR/airootfs/usr/share/wallpaper/burned.in"
fi
# WiFi
IFS_BAK="${IFS}"
IFS=$'\n'
mkdir -p "$PROFILE_DIR/airootfs/var/lib/iwd"
for line in $(<"$ROOT_DIR/setup/linux/known_networks"); do
if [[ "${line:0:1}" == "#" ]]; then
# Skip comments
continue
fi
w_name="${line%%:::*}"
w_pass="${line##*:::}"
w_pass="$(wpa_passphrase "${w_name}" "${w_pass}" \
| grep -E 'psk=[0-9a-z]+' \
| sed -r 's/\s+psk=//')"
echo "[Security]" > "$PROFILE_DIR/airootfs/var/lib/iwd/${w_name}.psk"
echo "PreSharedKey=${w_pass}" >> "$PROFILE_DIR/airootfs/var/lib/iwd/${w_name}.psk"
done
IFS="${IFS_BAK}"
}
function update_repo() {
if [[ "$EUID" -eq 0 ]]; then
echo "This section not meant to be run as root."
echo "Aborted."
exit 1
fi
echo "Updating custom repo..."
# Archive current files
if [[ -d "$REPO_DIR" ]]; then
mkdir -p "$BUILD_DIR/Archive" 2>/dev/null
archive="$BUILD_DIR/Archive/$(date "+%Y-%m-%d_%H%M%S")"
mv -bv "$REPO_DIR" "$archive"
fi
sleep 1s
# Build custom repo packages
mkdir -p "$REPO_DIR" 2>/dev/null
mkdir -p "$TEMP_DIR" 2>/dev/null
pushd "$TEMP_DIR" >/dev/null
while read -r p; do
echo "Building: $p"
curl -LsfO https://aur.archlinux.org/cgit/aur.git/snapshot/$p.tar.gz
tar xf $p.tar.gz
pushd $p >/dev/null
if [[ "$p" == "hfsprogs" ]]; then
sed -i 's!http://cavan.codon.org.uk/\~mjg59/diskdev_cmds!https://sources.voidlinux.org/hfsprogs-540.1.linux3!' "$TEMP_DIR/hfsprogs/PKGBUILD"
fi
makepkg -d
popd >/dev/null
mv -n $p/*zst "$REPO_DIR"/
done < "$ROOT_DIR/setup/linux/packages/aur"
popd >/dev/null
# Build custom repo database
pushd "$REPO_DIR" >/dev/null
repo-add custom.db.tar.gz *zst
popd >/dev/null
}
function install_deps() {
echo "Installing dependencies..."
packages=
while read -r line; do
packages="$packages $line"
done < "$ROOT_DIR/setup/linux/packages/dependencies"
run_elevated pacman -Syu --needed --noconfirm $packages
}
function build_linux() {
cleanup
fix_kit_permissions
install_deps
load_settings --edit
# Update repo if necessary
if ! [[ -e "${REPO_DIR}/custom.db.tar.gz" ]]; then
update_repo
fi
# Build requested version(s)
for version in "$@"; do
if [[ "$version" == "Full" ]]; then
copy_live_env
update_live_env
elif [[ "$version" == "Minimal" ]]; then
copy_live_env --minimal
update_live_env --minimal
fi
# Rerun script as root to start Archiso build process
run_elevated "$(realpath "$0")" --build-iso
# Cleanup
mv -nv "$PROFILE_DIR" "${PROFILE_DIR}.${version}"
perl-rename -v "s/(${KIT_NAME_SHORT}-Linux)-(${DATE}.*)/\1-${version}-\2/" "$OUT_DIR"/*
done
}
function build_iso() {
if [[ "$EUID" -ne 0 ]]; then
echo "This section is meant to be run as root."
echo "Aborted."
exit 1
fi
# Removing cached (and possibly outdated) custom repo packages
for package in $(cat "$ROOT_DIR/setup/linux/packages/aur"); do
for p in /var/cache/pacman/pkg/*${package}*; do
if [[ -f "${p}" ]]; then
rm "${p}"
fi
done
done
# Build ISO
prefix="${KIT_NAME_SHORT}-Linux"
label="${KIT_NAME_SHORT}_LINUX"
#mkarchiso -w "$BUILD_DIR/work" -o "$OUT_DIR" -v "$PROFILE_DIR" | tee -a "$LOG_DIR/$DATETIME.log"
mkarchiso -w /tmp/archiso-tmp -o "$OUT_DIR" -v "$PROFILE_DIR" | tee -a "$LOG_DIR/$DATETIME.log"
# Cleanup
echo "Removing temp files..."
rm "$TEMP_DIR/Linux" -Rf | tee -a "$LOG_DIR/$DATETIME.log"
#sudo umount -R "$BUILD_DIR/work" || true
#sudo rm -rf "$BUILD_DIR/work"
sudo umount -R /tmp/archiso-tmp || true
sudo rm -rf /tmp/archiso-tmp
echo "Reverting permissions..."
chown $REAL_USER:$REAL_USER "$PROFILE_DIR" -R
chown $REAL_USER:$REAL_USER "$OUT_DIR" -R
}
# Check input
case ${1:-} in
-a|--build-all)
build_linux Full Minimal
echo Done
;;
-b|--build-full)
build_linux Full
echo Done
;;
-f|--fix-perms)
fix_kit_permissions
echo Done
;;
-i|--install-deps)
install_deps
echo Done
;;
-m|--build-minimal)
build_linux Minimal
echo Done
;;
-n|--prep-minimal-env)
load_settings --edit
copy_live_env --minimal
update_live_env --minimal
echo Done
;;
-o|--build-iso)
load_settings
build_iso
echo Done
;;
-p|--prep-live-env)
load_settings --edit
copy_live_env
update_live_env
echo Done
;;
-u|--update-repo)
update_repo
echo Done
;;
*)
echo "Usage: $(basename "$0") [OPTIONS]"
echo ""
echo "Options:"
echo " -a --build-all Perform all tasks to build all isos"
echo " -b --build-full Perform all tasks to build the full iso"
echo " -m --build-minimal Perform all tasks to build the minimal iso"
echo " -h --help Show usage"
echo ""
echo "Advanced options:"
echo " -f --fix-perms Fix folder permissions"
echo " -i --install-deps Install build dependencies"
echo " -n --prep-minimal-env Prep live & airootfs folders (minimal packages)"
echo " -o --build-iso Build ISO (using current setup)"
echo " -p --prep-live-env Prep live & airootfs folders"
echo " -u --update-repo Update custom pacman repo"
;;
esac