WizardKit/Build Linux
2018-01-12 15:22:07 -07:00

371 lines
13 KiB
Bash
Executable file

#!/bin/bash
#
## Wizard Kit: Live Linux Build Tool
# Prep
DATE="$(date +%F)"
DATETIME="$(date +%F_%H%M)"
ROOT_DIR="$(realpath $(dirname "$0"))"
BUILD_DIR="$ROOT_DIR/BUILD_LINUX"
LIVE_DIR="$BUILD_DIR/live"
LOG_DIR="$BUILD_DIR/logs"
OUT_DIR="$ROOT_DIR/OUT_LINUX"
REPO_DIR="$BUILD_DIR/repo"
SKEL_DIR="$LIVE_DIR/airootfs/etc/skel"
TEMP_DIR="$BUILD_DIR/temp"
MIRRORLIST_SOURCE='https://www.archlinux.org/mirrorlist/?country=US&protocol=http&protocol=https&ip_version=4&use_mirror_status=on'
if which nano >/dev/null 2>&1; then
EDITOR=nano
elif which vim >/dev/null 2>&1; then
EDITOR=vim
else
EDITOR=vi
fi
if which sudo >/dev/null 2>&1; then
REAL_USER="$SUDO_USER"
fi
function ask() {
while :; do
read -p "$1 " -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" "$LIVE_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 .bin .cbin .kit_items .linux_items .pe_items Images; do
find "$ROOT_DIR/$d" -type d -exec chmod 755 "{}" \;
done
}
function load_settings() {
# Check if settings already loaded
## Code based on StackOverflow Q&A
## Question: https://stackoverflow.com/q/3601515
## Asked by: https://stackoverflow.com/users/260127/prosseek
## Edited by: https://stackoverflow.com/users/3924118/nbro
## Answer: https://stackoverflow.com/a/13864829
## Answer by: https://stackoverflow.com/users/1633643/lionel
## Answer edit: https://stackoverflow.com/users/-1/community
if [ ! -z ${KIT_NAME_FULL+x} ]; then
# KIT_NAME_FULL is set
return 0 # Skip loading settings from main.py
fi
# Copy settings
if [[ ! -e "$BUILD_DIR/main.py" ]] || ask "Overwrite main.py?"; then
cp -bv "$ROOT_DIR/.bin/Scripts/settings/main.py" "$BUILD_DIR/main.py"
dos2unix "$BUILD_DIR/main.py"
fi
# Edit settings
read -p "Press Enter to open settings... " -r
"$EDITOR" "$BUILD_DIR/main.py"
# Load settings
while read line; do
if echo "$line" | egrep -q "^\w+='"; then
line="$(echo "$line" | sed -r 's/[\r\n]+//')"
eval "$line"
fi
done < "$BUILD_DIR/main.py"
}
function copy_live_env() {
echo "Copying Archlinux files..."
rsync -aI /usr/share/archiso/configs/releng/ "$LIVE_DIR/"
# Remove items
rm "$LIVE_DIR/airootfs/etc/systemd/scripts/choose-mirror"
rmdir "$LIVE_DIR/airootfs/etc/systemd/scripts" --ignore-fail-on-non-empty
rm "$LIVE_DIR/airootfs/etc/systemd/system/choose-mirror.service"
rm "$LIVE_DIR/airootfs/etc/systemd/system/etc-pacman.d-gnupg.mount"
rm "$LIVE_DIR/airootfs/etc/systemd/system/pacman-init.service"
rm "$LIVE_DIR/airootfs/etc/udev/rules.d/81-dhcpcd.rules"
rmdir "$LIVE_DIR/airootfs/etc/udev/rules.d" --ignore-fail-on-non-empty
rmdir "$LIVE_DIR/airootfs/etc/udev" --ignore-fail-on-non-empty
rm "$LIVE_DIR/isolinux"/*.cfg
rm "$LIVE_DIR/syslinux"/*.cfg "$LIVE_DIR/syslinux"/*.png
# Add items
rsync -aI "$ROOT_DIR/.linux_items/include/" "$LIVE_DIR/"
mkdir -p "$LIVE_DIR/airootfs/usr/local/bin"
rsync -aI "$ROOT_DIR/.bin/Scripts/" "$LIVE_DIR/airootfs/usr/local/bin/"
cp -a "$BUILD_DIR/main.py" "$LIVE_DIR/airootfs/usr/local/bin/settings/"
}
function run_elevated() {
prog="$1"
shift
if which sudo >/dev/null 2>&1; then
sudo "$prog" $*
else
echo -n "Root "
su -c "export REAL_USER=$USER && '$prog' $*"
fi
}
function update_live_env() {
hostname="$(echo "${KIT_NAME_SHORT}-linux" | tr "[:upper:]" "[:lower:]")"
username="$(echo "${KIT_NAME_SHORT}tech" | tr "[:upper:]" "[:lower:]")"
label="${KIT_NAME_SHORT}_LINUX"
# Boot config (legacy)
mkdir -p "$LIVE_DIR/arch"
cp "$ROOT_DIR/Images/Pxelinux.png" "$LIVE_DIR/arch/pxelinux.png"
cp "$ROOT_DIR/Images/Syslinux.png" "$LIVE_DIR/arch/syslinux.png"
sed -i -r "s/_+/$KIT_NAME_FULL/" "$LIVE_DIR/syslinux/wk_head.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 "$TEMP_DIR/wimboot.zip" -o"$LIVE_DIR/arch/boot" 'wimboot*/LICENSE.txt' 'wimboot*/README.txt' 'wimboot*/wimboot'
# Boot config (UEFI)
mkdir -p "$LIVE_DIR/EFI/boot"
cp "/usr/share/refind/refind_x64.efi" "$LIVE_DIR/EFI/boot/bootx64.efi"
cp "$ROOT_DIR/Images/rEFInd.png" "$LIVE_DIR/EFI/boot/rEFInd.png"
rsync -aI "/usr/share/refind/drivers_x64/" "$LIVE_DIR/EFI/boot/drivers_x64/"
rsync -aI "/usr/share/refind/icons/" "$LIVE_DIR/EFI/boot/icons/" --exclude "/usr/share/refind/icons/svg"
sed -i "s/%ARCHISO_LABEL%/${label}/" "$LIVE_DIR/EFI/boot/refind.conf"
# Memtest86
mkdir -p "$LIVE_DIR/EFI/memtest86/Benchmark"
mkdir -p "$TEMP_DIR/memtest86"
curl -Lo "$TEMP_DIR/memtest86/memtest86.iso.tar.gz" "https://www.memtest86.com/downloads/memtest86-iso.tar.gz"
tar xvf "$TEMP_DIR/memtest86/memtest86.iso.tar.gz" -C "$TEMP_DIR/memtest86"
7z x "$TEMP_DIR/memtest86"/*.iso -o"$TEMP_DIR/memtest86"
mv "$TEMP_DIR/memtest86/EFI/BOOT/BLACKLIS.CFG" "$LIVE_DIR/EFI/memtest86/blacklist.cfg"
mv "$TEMP_DIR/memtest86/EFI/BOOT/BOOTX64.EFI" "$LIVE_DIR/EFI/memtest86/memtestx64.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT/MT86.PNG" "$LIVE_DIR/EFI/memtest86/mt86.png"
mv "$TEMP_DIR/memtest86/EFI/BOOT/UNIFONT.BIN" "$LIVE_DIR/EFI/memtest86/unifont.bin"
# build.sh
if ! grep -iq 'wizardkit additions' "$LIVE_DIR/build.sh"; then
sed -i -r 's/^(run_once make_iso)$/# wizardkit additions\n\1/' "$LIVE_DIR/build.sh"
sed -i '/# wizardkit additions/r .linux_items/build_additions.txt' "$LIVE_DIR/build.sh"
fi
# Hostname
echo "$hostname" > "$LIVE_DIR/airootfs/etc/hostname"
echo "127.0.1.1 $hostname.localdomain $hostname" >> "$LIVE_DIR/airootfs/etc/hosts"
# Live packages
sed -i -r 's/^(b43|clonezilla|gpm|grml|refind|testdisk|vim)/#\1/' "$LIVE_DIR/packages.both"
cat "$ROOT_DIR/.linux_items/packages/live" >> "$LIVE_DIR/packages.both"
echo "[custom]" >> "$LIVE_DIR/pacman.conf"
echo "SigLevel = Optional TrustAll" >> "$LIVE_DIR/pacman.conf"
echo "Server = file://$REPO_DIR" >> "$LIVE_DIR/pacman.conf"
echo "" >> "$LIVE_DIR/pacman.conf"
# Mirrors
sed -i -r 's/^(.*mirrorlist.*)$/#NOPE#\1/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "curl -o '/etc/pacman.d/mirrorlist' '$MIRRORLIST_SOURCE'" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "sed -i 's/#Server/Server/g' /etc/pacman.d/mirrorlist" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# MOTD
sed -i -r "s/_+/$KIT_NAME_FULL Linux Environment/" "$LIVE_DIR/airootfs/etc/motd"
# Oh My ZSH
git clone --depth=1 git://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
# Openbox theme
git clone --depth=1 git@github.com:addy-dclxvi/Openbox-Theme-Collections.git "$TEMP_DIR/ob-themes"
mkdir -p "$LIVE_DIR/airootfs/usr/share/themes"
cp -a "$TEMP_DIR/ob-themes/Triste-Orange" "$LIVE_DIR/airootfs/usr/share/themes/"
# Services
sed -i -r 's/^(.*pacman-init.*)$/#NOPE#\1/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
sed -i -r 's/^(.*choose-mirror.*)$/#NOPE#\1/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# SSH
mkdir -p "$SKEL_DIR/.ssh"
ssh-keygen -b 4096 -C "$username@$hostname" -N "" -f "$SKEL_DIR/.ssh/id_rsa"
echo 'rm /root/.ssh/id*' >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo 'rm /root/.zlogin' >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
sed -i -r 's/^(.*PermitRootLogin.*)$/#NOPE#\1/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# Root user
echo "echo 'root:$ROOT_PASSWORD' | chpasswd" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# Sudo
echo "echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# Tech user
echo "groupadd -r autologin" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "useradd -m -s /bin/zsh -G autologin,power,storage,wheel -U $username" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "echo '$username:$TECH_PASSWORD' | chpasswd" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# Tech user autologin
mkdir -p "$LIVE_DIR/airootfs/etc/systemd/system/getty@tty1.service.d"
echo "[Service]" > "$LIVE_DIR/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf"
echo "ExecStart=" >> "$LIVE_DIR/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf"
echo "ExecStart=-/sbin/agetty --autologin $username --noclear %I 38400 linux" >> "$LIVE_DIR/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf"
# Timezone
echo "ln -sf '/usr/share/zoneinfo/$LINUX_TIME_ZONE' '/etc/localtime'" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo 'sed -i "s/#FallbackNTP/NTP/" /etc/systemd/timesyncd.conf' >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# udevil fix
echo "mkdir /media" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
# Wallpaper
mkdir -p "$LIVE_DIR/airootfs/usr/share/wallpaper"
cp "$ROOT_DIR/Images/Linux.png" "$LIVE_DIR/airootfs/usr/share/wallpaper/burned.in"
}
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 "$BUILD_DIR/Archive" 2>/dev/null
archive="$BUILD_DIR/Archive/$(date "+%F_%H%M%S")"
mv -bv "$REPO_DIR" "$archive"
fi
sleep 1s
# Build custom repo packages
mkdir "$REPO_DIR" 2>/dev/null
mkdir "$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
makepkg -s --noconfirm
popd >/dev/null
mv -n $p/*xz "$REPO_DIR"/
done < "$ROOT_DIR/.linux_items/packages/aur"
popd >/dev/null
# Build custom repo database
pushd "$REPO_DIR" >/dev/null
repo-add custom.db.tar.gz *xz
popd >/dev/null
}
function install_deps() {
echo "Installing dependencies..."
packages=
while read -r line; do
packages="$packages $line"
done < "$ROOT_DIR/.linux_items/packages/dependencies"
run_elevated pacman -Syu --needed --noconfirm $packages
}
function build_iso() {
if [[ "$EUID" -ne 0 ]]; then
echo "This section is meant to be run as root."
echo "Aborted."
exit 1
fi
# Set permissions
echo "Setting permissions..."
chown root:root "$LIVE_DIR" -R
chmod 700 "$LIVE_DIR/airootfs/etc/skel/.ssh"
chmod 600 "$LIVE_DIR/airootfs/etc/skel/.ssh/id_rsa"
# Build ISO
prefix="${KIT_NAME_SHORT}-Linux"
label="${KIT_NAME_SHORT}_LINUX"
"$LIVE_DIR/build.sh" -N "$prefix" -V "$DATE" -L "$label" -w "$TEMP_DIR/Linux" -o "$OUT_DIR" -v | tee -a "$LOG_DIR/$DATETIME.log"
# Cleanup
echo "Removing temp files..."
rm "$TEMP_DIR/Linux" -Rf | tee -a "$LOG_DIR/$DATETIME.log"
echo "Reverting permissions..."
chown $REAL_USER:$REAL_USER "$LIVE_DIR" -R
}
function build_full() {
if [[ "$EUID" -eq 0 ]]; then
echo "This section not meant to be run as root."
echo "Aborted."
exit 1
fi
# Prep for build
cleanup
fix_kit_permissions
install_deps
load_settings
update_repo
copy_live_env
update_live_env
# Rerun script as root to start Archiso build process
run_elevated "$(realpath "$0")" --build-iso
}
# Check input
case $1 in
-b|--build-full)
build_full
;;
-f|--fix-perms)
fix_kit_permissions
;;
-i|--install-deps)
install_deps
;;
-o|--build-iso)
load_settings
build_iso
;;
-p|--prep-live-env)
load_settings
copy_live_env
update_live_env
;;
-u|--update-repo)
update_repo
;;
*)
echo "Usage: $(basename "$0") [OPTIONS]"
echo ""
echo "Options:"
echo " -b --build-full Perform all tasks and build 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 " -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