307 lines
9.9 KiB
Bash
Executable file
307 lines
9.9 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 "$BUILD_DIR" 2>/dev/null
|
|
mkdir "$LOG_DIR" 2>/dev/null
|
|
mkdir "$OUT_DIR" 2>/dev/null
|
|
mkdir "$TEMP_DIR" 2>/dev/null
|
|
}
|
|
|
|
function copy_archiso() {
|
|
echo "Copying Archlinux files..."
|
|
rsync -aI /usr/share/archiso/configs/releng/ "$LIVE_DIR/"
|
|
|
|
# Add items
|
|
rsync -aI "$ROOT_DIR/.linux_items/include/live/" "$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
|
|
}
|
|
|
|
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 unset
|
|
: # pass
|
|
else
|
|
# 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"
|
|
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 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_archlive() {
|
|
hostname="$(echo "${KIT_NAME_SHORT}-linux" | tr "[:upper:]" "[:lower:]")"
|
|
username="$(echo "${KIT_NAME_SHORT}tech" | tr "[:upper:]" "[:lower:]")"
|
|
|
|
# build.sh
|
|
if ! grep -iq 'customize_iso' "$LIVE_DIR/build.sh"; then
|
|
sed -ir "s!run_once make_iso\$!# customize_iso\ncp -a \"$ROOT_DIR/.linux_items/include/iso\"/* \"\${work_dir}/iso\"/\n\nrun_once make_iso!" "$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"
|
|
|
|
# Locale
|
|
echo 'sed -i "s/#FallbackNTP/NTP/" /etc/systemd/timesyncd.conf' >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
|
|
|
|
# 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 "s/WK/$KIT_NAME_SHORT/" "$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_test.zsh
|
|
|
|
# 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:$LINUX_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:$LINUX_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
|
|
sed -i -r "s#zoneinfo/UTC#$LINUX_TIME_ZONE#g" "$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_arch() {
|
|
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="$(< "$LIVE_DIR/airootfs/etc/hostname")"
|
|
label="${KIT_NAME_SHORT}_LINUX"
|
|
"$LIVE_DIR/build.sh" -N "$prefix" -V "$DATE" -L "$label" -w "$TEMP_DIR/Arch" -o "$OUT_DIR" -v | tee -a "$LOG_DIR/$DATETIME.log"
|
|
|
|
# Cleanup
|
|
echo "Removing temp files..."
|
|
rm "$TEMP_DIR/Arch" -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
|
|
install_deps
|
|
load_settings
|
|
update_repo
|
|
copy_archiso
|
|
update_archlive
|
|
# Rerun script as root to start Archiso build process
|
|
run_elevated "$(realpath "$0")" --build-arch
|
|
}
|
|
|
|
# Check input
|
|
case $1 in
|
|
--build-arch)
|
|
load_settings
|
|
build_arch
|
|
;;
|
|
|
|
--copy-archiso)
|
|
load_settings
|
|
copy_archiso
|
|
update_archlive
|
|
;;
|
|
|
|
--install-deps)
|
|
install_deps
|
|
;;
|
|
|
|
--update-repo)
|
|
update_repo
|
|
;;
|
|
|
|
*)
|
|
build_full
|
|
;;
|
|
esac
|
|
|