Skip to content

Instantly share code, notes, and snippets.

@PhrozenByte
Created February 22, 2025 00:00
Show Gist options
  • Save PhrozenByte/95933c32227c3b8e596c6e2267b60b2d to your computer and use it in GitHub Desktop.
Save PhrozenByte/95933c32227c3b8e596c6e2267b60b2d to your computer and use it in GitHub Desktop.
Creates a live ISO of Arch Linux with GNOME.
#!/bin/bash
# mkarchiso-gnome
# Creates a live ISO of Arch Linux with GNOME
#
# This script was created to ease creating live ISOs of Arch Linux with GNOME
# installed. It's highly customized to my personal preferences, thus it's
# likely not very useful as-is for most people, but it could be a good
# starting point for others to create their own custom live ISO.
#
# More about `mkarchiso`: https://wiki.archlinux.org/title/Archiso
#
# Copyright (C) 2025 Daniel Rudolf (<https://www.daniel-rudolf.de>)
# License: The MIT License <http://opensource.org/licenses/MIT>
#
# SPDX-License-Identifier: MIT
set -eu -o pipefail
export LC_ALL=C
APP_NAME="$(basename "${BASH_SOURCE[0]}")"
if [ -z "${1:-}" ]; then
echo "Usage" >&2
echo " $APP_NAME OUTPUT_DIR" >&2
exit 1
fi
[ "$(id -u)" != 0 ] || { echo "You must not run \`$APP_NAME\` as root, but as \`sudo\`-able user" >&2; exit 1; }
[ -x "$(which git)" ] || { echo "Missing script dependency: git" >&2; exit 1; }
[ -x "$(which pacman)" ] || { echo "Missing script dependency: pacman" >&2; exit 1; }
[ -x "$(which makepkg)" ] || { echo "Missing script dependency: makepkg" >&2; exit 1; }
[ -x "$(which mkarchiso)" ] || { echo "Missing script dependency: mkarchiso" >&2; exit 1; }
# helper
quote() {
local QUOTED=
for ARG in "$@"; do
[ "$(printf '%q' "$ARG")" == "$ARG" ] \
&& QUOTED+=" $ARG" \
|| QUOTED+=" ${ARG@Q}"
done
echo "${QUOTED:1}"
}
cmd() {
echo + "$(quote "$@")" >&2
"$@"
}
ctee() {
local APPEND=
[ "$1" != "-a" ] || { APPEND="y"; shift; }
local FILE="$1"
shift
if [ "$APPEND" == "y" ]; then
echo + "$(quote "$@") >> $(quote "$FILE")" >&2
"$@" >> "$FILE"
else
echo + "$(quote "$@") > $(quote "$FILE")" >&2
"$@" > "$FILE"
fi
}
# system setup
# make sure that mkarchiso's chroot has internet access in case systemd-resolved isn't used on the host
# this will be gone after a reboot and will break if the user switches to a different network
echo + "[ -e /run/systemd/resolve/ ]" >&2
if [ ! -e /run/systemd/resolve/ ]; then
cmd sudo mkdir -p /run/systemd/resolve/
cmd sudo cp /etc/resolv.conf /run/systemd/resolve/stub-resolv.conf
fi
# prepare build
OUTPUT_DIR="$1"
BUILD_DIR="$(mktemp -d -t "$APP_NAME.XXXXXXXXXX")"
cmd cd "$BUILD_DIR"
cmd cp -R /usr/share/archiso/configs/releng/ ./archiso
# change ISO identity
cmd sed -i \
-e 's#^iso_name="\(.*\)"$#iso_name="\1-gnome"#g' \
-e 's#^iso_label="\(.*\)"$#iso_label="\1_GNOME"#g' \
-e 's#^iso_publisher="\(.*\)"$#iso_publisher="Daniel Rudolf <https://www.daniel-rudolf.de>"#g' \
-e 's#^iso_application="\(.*\)"$#iso_application="\1 (GNOME)"#g' \
./archiso/profiledef.sh
# increase live cow filesystem to 2G (Arch default: 256M)
cmd sed -i \
-e 's/^options \(.*\)$/options \1 cow_spacesize=2G/g' \
./archiso/efiboot/loader/entries/01-archiso-x86_64-linux.conf \
./archiso/efiboot/loader/entries/02-archiso-x86_64-speech-linux.conf
cmd sed -i \
-e '/^menuentry "Arch Linux/,/^}$/{s/^\( *linux .*\)$/\1 cow_spacesize=2G/g}' \
./archiso/grub/grub.cfg \
./archiso/grub/loopback.cfg
cmd sed -i \
-e 's/^APPEND \(.*\)$/APPEND \1 cow_spacesize=2G/g' \
./archiso/syslinux/archiso_sys-linux.cfg
# change default keymap
ctee ./archiso/airootfs/etc/vconsole.conf \
printf '%s\n' "KEYMAP=de-latin1" "XKBLAYOUT=de"
# change default locale
ctee ./archiso/airootfs/etc/locale.gen \
printf '%s\n' "de_DE.UTF-8 UTF-8" "en_US.UTF-8 UTF-8"
ctee ./archiso/airootfs/etc/locale.conf \
printf '%s\n' "LANG=de_DE.UTF-8"
ctee ./archiso/airootfs/etc/pacman.d/hooks/locale-gen.hook \
printf '%s\n' \
"# remove from airootfs!" \
"[Trigger]" \
"Operation = Install" \
"Operation = Upgrade" \
"Type = Package" \
"Target = glibc" \
"" \
"[Action]" \
"Description = Updating locales..." \
"When = PostTransaction" \
"Depends = glibc" \
"Exec = /usr/bin/locale-gen"
# change default timezone
cmd ln -sf /usr/share/zoneinfo/Europe/Berlin \
./archiso/airootfs/etc/localtime
# add the unprivileged 'archiso' user (w/o password),
# and add the user to the 'wheel' group
# also add sudo and enable it for users in the 'wheel' group
ctee -a ./archiso/airootfs/etc/passwd \
printf '%s\n' "archiso:x:1000:1000::/home/archiso:/usr/bin/bash"
ctee -a ./archiso/airootfs/etc/shadow \
printf '%s\n' "archiso::14871::::::"
ctee ./archiso/airootfs/etc/group \
printf '%s\n' \
"root:x:0:root" \
"wheel:x:998:archiso" \
"archiso:x:1000:"
ctee ./archiso/airootfs/etc/gshadow \
printf '%s\n' \
"root:!::" \
"wheel:!*::archiso" \
"archiso:!::"
cmd sed -i \
-e '/^file_permissions=($/,/^)$/{s#^)$# \["/etc/gshadow"\]="0:0:400"\n)#g}' \
./archiso/profiledef.sh
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' "sudo"
cmd mkdir -p ./archiso/airootfs/etc/sudoers.d/
ctee ./archiso/airootfs/etc/sudoers.d/wheel \
printf '%s\n' "%wheel ALL=(ALL:ALL) ALL"
# enable autologin for the 'archiso' user (both for GDM and agetty on tty3)
cmd mv ./archiso/airootfs/etc/systemd/system/[email protected]/ \
./archiso/airootfs/etc/systemd/system/[email protected]/
cmd sed -i \
-e 's/--autologin root/--autologin archiso/g' \
./archiso/airootfs/etc/systemd/system/[email protected]/autologin.conf
cmd mkdir -p ./archiso/airootfs/etc/gdm/
ctee ./archiso/airootfs/etc/gdm/custom.conf \
printf '%s\n' \
"[daemon]" \
"AutomaticLoginEnable=True" \
"AutomaticLogin=archiso"
# update Pacman config
# TODO: should rather be done for the pacman.cfg of the image,
# however, we don't have a default config to work with yet
#cmd sed -i \
# -e 's/#UseSyslog/UseSyslog/g' \
# -e 's/#Color/Color/g' \
# -e 's/#VerbosePkgLists/VerbosePkgLists/g' \
# ./archiso/pacman.conf
# add local Pacman repository
cmd mkdir -p ./repo/
ctee -a ./archiso/pacman.conf \
printf '%s\n' \
"" \
"[custom]" \
"SigLevel = Optional TrustAll" \
"Server = file://$BUILD_DIR/repo"
# build and add yay
cmd git clone https://aur.archlinux.org/yay.git
cmd makepkg -D ./yay --noconfirm -sr
echo + "YAY_PKG=\"\$(find ./yay/ -name 'yay-*-*.pkg.tar.zst' -printf '%f\n')\"" >&2
YAY_PKG="$(find ./yay/ -name 'yay-*-*.pkg.tar.zst' -printf '%f\n')"
cmd mv "./yay/$YAY_PKG" "./repo/$YAY_PKG"
cmd repo-add ./repo/custom.db.tar.zst "./repo/$YAY_PKG"
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' "yay"
ctee ./archiso/airootfs/etc/pacman.d/hooks/yay-setup.hook \
printf '%s\n' \
"# remove from airootfs!" \
"[Trigger]" \
"Operation = Install" \
"Operation = Upgrade" \
"Type = Package" \
"Target = yay" \
"" \
"[Action]" \
"Description = Setting up yay..." \
"When = PostTransaction" \
"Depends = yay" \
"Depends = sudo" \
"Exec = /usr/bin/sudo -u archiso -- /usr/bin/yay -Y --gendb"
# add tools required for package building
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"base-devel" \
"git"
# add and enable NetworkManager
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' "networkmanager"
cmd mkdir -p ./archiso/airootfs/etc/systemd/system/multi-user.target.wants/
cmd ln -sf /usr/lib/systemd/system/NetworkManager.service \
./archiso/airootfs/etc/systemd/system/multi-user.target.wants/NetworkManager.service
cmd mkdir -p ./archiso/airootfs/etc/systemd/system/bluetooth.target.wants/
cmd ln -sf /usr/lib/systemd/system/bluetooth.service \
./archiso/airootfs/etc/systemd/system/bluetooth.target.wants/bluetooth.service
# add GNOME Shell and enable GDM as display manager
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"gdm" \
"gnome-shell" \
"gnome-menus" \
"gnome-backgrounds" \
"noto-fonts" \
"gnome-control-center" \
"gnome-tweaks" \
"nautilus"
cmd ln -sf /usr/lib/systemd/system/gdm.service \
./archiso/airootfs/etc/systemd/system/display-manager.service
# build and add gnome-shell-extension-dash-to-dock
cmd git clone https://aur.archlinux.org/gnome-shell-extension-dash-to-dock.git
cmd makepkg -D ./gnome-shell-extension-dash-to-dock --noconfirm -sr
echo + "DTD_PKG=\"\$(find ./gnome-shell-extension-dash-to-dock/ -name 'gnome-shell-extension-dash-to-dock-*-*.pkg.tar.zst' -printf '%f\n')\"" >&2
DTD_PKG="$(find ./gnome-shell-extension-dash-to-dock/ -name 'gnome-shell-extension-dash-to-dock-*-*.pkg.tar.zst' -printf '%f\n')"
cmd mv "./gnome-shell-extension-dash-to-dock/$DTD_PKG" "./repo/$DTD_PKG"
cmd repo-add ./repo/custom.db.tar.zst "./repo/$DTD_PKG"
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' "gnome-shell-extension-dash-to-dock"
# enable the 'Dash to Dock' GNOME extension by default
cmd mkdir -p ./archiso/airootfs/etc/dconf/profile/
ctee ./archiso/airootfs/etc/dconf/profile/user \
printf '%s\n' \
"user-db:user" \
"system-db:local"
cmd mkdir -p ./archiso/airootfs/etc/dconf/db/local.d/
ctee ./archiso/airootfs/etc/dconf/db/local.d/00-extensions \
printf '%s\n' \
"[org/gnome/shell]" \
"enabled-extensions=['[email protected]']"
ctee ./archiso/airootfs/etc/pacman.d/hooks/dconf-update.hook \
printf '%s\n' \
"# remove from airootfs!" \
"[Trigger]" \
"Operation = Install" \
"Operation = Upgrade" \
"Type = Package" \
"Target = dconf" \
"" \
"[Action]" \
"Description = Updating dconf database..." \
"When = PostTransaction" \
"Depends = dconf" \
"Exec = /usr/bin/dconf update"
# add GNOME tools
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"gnome-disk-utility" \
"gnome-system-monitor" \
"baobab" \
"gnome-console" \
"gnome-text-editor" \
"meld" \
"evince" \
"loupe" \
"file-roller" \
"gnome-calculator" \
"gnome-connections"
# add GNOME Software and Flatpak
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"gnome-software" \
"flatpak" \
"xdg-desktop-portal-gnome"
# add Firefox and VLC media player
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"firefox" \
"vlc"
# add WireGuard
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"wireguard-tools" \
"openresolv"
# add misc command line tools
ctee -a ./archiso/packages.x86_64 \
printf '%s\n' \
"bash-completion" \
"htop" \
"iotop" \
"iftop" \
"nethogs"
# misc setup
cmd mkdir -p ./archiso/airootfs/usr/bin/
cmd ln -sf vim ./archiso/airootfs/usr/bin/vi
# run `mkarchiso`
cmd sudo mkarchiso -v -o "$OUTPUT_DIR" ./archiso/
# cleanup after successful build
cmd sudo rm -rf "$BUILD_DIR"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment