Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ There is also experimental support for Alpine Linux. The Alpine disk image is ab
sudo ./build_complete.sh dedede distro=alpine
```

Artix Linux is also supported. Since Artix does not use systemd, no systemd patching is required in the rootfs itself. To use it, pass `distro=artix`:
Artix Linux is also supported on both x86_64 and ARM64 devices. The rootfs bootstrap uses the local `./artix-bootstrap.sh` script (based on [`gripped/artix-bootstrap`](https://github.com/gripped/artix-bootstrap)), and ARM64 builds use Armtix repos. Since Artix does not use systemd, no systemd patching is required in the rootfs itself. To use it, pass `distro=artix`:
```bash
sudo ./build_complete.sh dedede distro=artix
```
Expand Down
174 changes: 174 additions & 0 deletions artix-bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/bin/bash
#
# Based on: https://github.com/gripped/artix-bootstrap (MIT)
# Shimboot-local wrapper with explicit ARCH option (-a) and aarch64 package matching.

set -e -u -o pipefail

PACMAN_PACKAGES=(
acl artix-mirrorlist brotli bzip2 coreutils curl e2fsprogs expat gawk gettext glibc gnupg gpgme grep icu keyutils krb5 libarchive libassuan libgcc libgpg-error libidn2 libnghttp2 libnghttp3 libngtcp2 libpsl libseccomp libssh2 libstdc++ libunistring libxml2 lz4 openssl pacman xz zlib zstd
)
BASIC_PACKAGES=(${PACMAN_PACKAGES[*]} filesystem)
DEFAULT_REPO_URL="http://mirror1.artixlinux.org/repos"

cleanup() {
! mountpoint -q "$CLEANUP_DEST/proc" || LC_ALL=C umount -R "$CLEANUP_DEST/proc"
! mountpoint -q "$CLEANUP_DEST/sys" || LC_ALL=C umount -R "$CLEANUP_DEST/sys"
! mountpoint -q "$CLEANUP_DEST/dev" || LC_ALL=C umount -R "$CLEANUP_DEST/dev"
}

stderr() { echo "$@" >&2; }
debug() { stderr "--- $@"; }
extract_href() { sed -n '/<a / s/^.*<a [^>]*href="\([^"]*\)".*$/\1/p'; }
fetch() { curl -L -s "$@"; }

fetch_file() {
local filepath=$1 status_code
shift
if [[ -e "$filepath" ]]; then
status_code=$(curl --write-out %{http_code} -L -z "$filepath" -o "$filepath" "$@")
else
status_code=$(curl --write-out %{http_code} -L -o "$filepath" "$@")
fi
[[ "$status_code" -eq 200 ]]
}

uncompress() {
local filepath=$1 dest=$2
case "$filepath" in
*.gz) tar xzf "$filepath" -C "$dest" ;;
*.xz) xz -dc "$filepath" | tar x -C "$dest" ;;
*.zst) tar --zstd -xf "$filepath" -C "$dest" ;;
*) debug "Error: unknown package format: $filepath"; return 1 ;;
esac
}

get_repo_url() { local repo_name=$1 repo_url=$2 arch=$3; echo "${repo_url%/}/$repo_name/os/$arch"; }
get_template_repo_url() { local repo_url=$1 arch=$2; echo "${repo_url%/}/\$repo/os/$arch"; }

configure_pacman() {
local dest=$1 arch=$2
cp "/etc/resolv.conf" "$dest/etc/resolv.conf"
local server
server=$(get_template_repo_url "$REPO_URL" "$arch")
mkdir -p "$dest/etc/pacman.d"
echo "Server = $server" > "$dest/etc/pacman.d/mirrorlist"
}

configure_minimal_system() {
local dest=$1
mkdir -p "$dest/dev"
sed -ie 's/^root:.*$/root:$1$GT9AUpJe$oXANVIjIzcnmOpY07iaGi\/:14657::::::/' "$dest/etc/shadow"
touch "$dest/etc/group"
echo "bootstrap" > "$dest/etc/hostname"

rm -f "$dest/etc/mtab"
echo "rootfs / rootfs rw 0 0" > "$dest/etc/mtab"
test -e "$dest/dev/null" || mknod "$dest/dev/null" c 1 3
test -e "$dest/dev/random" || mknod -m 0644 "$dest/dev/random" c 1 8
test -e "$dest/dev/urandom" || mknod -m 0644 "$dest/dev/urandom" c 1 9

sed -i 's|^#XferCommand = /usr/bin/curl -L|XferCommand = /usr/bin/curl -k -L|' "$dest/etc/pacman.conf"
sed -i 's/^DownloadUser/#DownloadUser/' "$dest/etc/pacman.conf"
sed -i "s/^[[:space:]]*\(CheckSpace\)/# \1/" "$dest/etc/pacman.conf"
sed -i "s/^[[:space:]]*SigLevel[[:space:]]*=.*$/SigLevel = Never/" "$dest/etc/pacman.conf"
}

fetch_repo_packages_list() {
local repo=$1
fetch "$repo/" | extract_href | awk -F"/" '{print $NF}' | sort -rn || {
debug "Error: cannot fetch packages list: $repo"; return 1;
}
}

install_pacman_packages() {
local pkgs=$1 dest=$2 dl=$3 system_list=$4 world_list=$5 galaxy_list=$6
for package in $pkgs; do
local esc_package regex file repo filepath
esc_package=$(echo "$package" | sed 's/\+/%2B/g')
regex="^$esc_package-([a-zA-Z\d.:%]*)-([\d.]*)-(i686|x86_64|aarch64|any)\.pkg\.tar\.(gz|xz|zst)$"
file=$(echo "$system_list" | grep -Pm1 "$regex" || true); repo=$SYSTEM_REPO
test "$file" || { file=$(echo "$world_list" | grep -Pm1 "$regex" || true); repo=$WORLD_REPO; }
test "$file" || { file=$(echo "$galaxy_list" | grep -Pm1 "$regex" || true); repo=$GALAXY_REPO; }
test "$file" || { debug "Error: cannot find package: $package"; return 1; }
filepath="$dl/$file"
[[ -f "$filepath" ]] || fetch_file "$filepath" "$repo/$file"
uncompress "$filepath" "$dest"
done
}

install_packages() {
local arch=$1 dest=$2 packages=$3
LC_ALL=C mount --types proc /proc "$dest"/proc
LC_ALL=C mount --rbind /sys "$dest"/sys
LC_ALL=C mount --make-rslave "$dest"/sys
LC_ALL=C mount --rbind /dev "$dest"/dev
LC_ALL=C mount --make-rslave "$dest"/dev
LC_ALL=C chroot "$dest" /usr/bin/pacman --noconfirm --arch "$arch" -Sy --overwrite='*' $packages
LC_ALL=C umount -R "$dest"/proc
LC_ALL=C umount -R "$dest"/sys
LC_ALL=C umount -R "$dest"/dev
}

cleanup_files() {
local dest=$1
rm -f "$dest/.BUILDINFO" "$dest/.INSTALL" "$dest/.MTREE" "$dest/.PKGINFO"
rm -f "$dest/etc/pacman.conf"
mv "$dest/etc/pacman.conf.pacnew" "$dest/etc/pacman.conf"
}

show_usage() {
stderr "Usage: $(basename "$0") [-q] [-i INIT] [-r REPO_URL] [-d DOWNLOAD_DIR] [-a ARCH] DESTDIR"
}

main() {
test $# -eq 0 && set -- "-h"
local init= arch= repo_url= download_dir= preserve_download_dir=

while getopts "qi:r:d:a:h" arg; do
case "$arg" in
i) init=$OPTARG ;;
r) repo_url=$OPTARG ;;
d) download_dir=$OPTARG; preserve_download_dir=true ;;
a) arch=$OPTARG ;;
*) show_usage; return 1 ;;
esac
done
shift $((OPTIND-1))
test $# -eq 1 || { show_usage; return 1; }

[[ -z "$init" ]] && init="openrc"
[[ -z "$arch" ]] && arch="x86_64"
[[ -z "$repo_url" ]] && repo_url="$DEFAULT_REPO_URL"

local dest=$1
SYSTEM_REPO=$(get_repo_url system "$repo_url" "$arch")
WORLD_REPO=$(get_repo_url world "$repo_url" "$arch")
GALAXY_REPO=$(get_repo_url galaxy "$repo_url" "$arch")
REPO_URL="$repo_url"
CLEANUP_DEST=$dest
trap cleanup EXIT

[[ -z "$download_dir" ]] && download_dir=$(mktemp -d)
mkdir -p "$download_dir"
[[ -z "$preserve_download_dir" ]] && trap "rm -rf '$download_dir'" KILL TERM EXIT

mkdir -p "$dest"
local system_list world_list galaxy_list
system_list=$(fetch_repo_packages_list "$SYSTEM_REPO")
world_list=$(fetch_repo_packages_list "$WORLD_REPO")
galaxy_list=$(fetch_repo_packages_list "$GALAXY_REPO")

install_pacman_packages "${BASIC_PACKAGES[*]}" "$dest" "$download_dir" "$system_list" "$world_list" "$galaxy_list"
configure_pacman "$dest" "$arch"
configure_minimal_system "$dest"
install_packages "$arch" "$dest" "base ${init} elogind-${init}"
install_packages "$arch" "$dest" "artix-keyring"
configure_pacman "$dest" "$arch"
cleanup_files "$dest"

[[ -z "$preserve_download_dir" ]] && rm -rf "$download_dir"
debug "Done!"
}

main "$@"
36 changes: 20 additions & 16 deletions build_rootfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ print_help() {
}

assert_root
assert_deps "realpath debootstrap findmnt wget pcregrep tar"
assert_deps "realpath debootstrap findmnt wget pcregrep tar curl gawk xz zstd"
assert_args "$2"
parse_args "$@"

Expand Down Expand Up @@ -99,26 +99,30 @@ elif [ "$distro" = "alpine" ]; then
chroot_script="/opt/setup_rootfs_alpine.sh"

elif [ "$distro" = "artix" ]; then
if [ "$arch" != "amd64" ]; then
print_error "artix rootfs creation currently only supports amd64."
real_arch=""
repo_url="http://mirror1.artixlinux.org/repos"
if [ "$arch" = "amd64" ]; then
real_arch="x86_64"
elif [ "$arch" = "arm64" ]; then
real_arch="aarch64"
repo_url="https://armtixlinux.org/repos"
else
print_error "Artix rootfs creation currently only supports amd64 and arm64."
exit 1
fi

print_info "downloading artix bootstrap rootfs"

bootstrap_script_url="https://gitea.artixlinux.org/artix/artix-bootstrap/raw/branch/master/artix-bootstrap.sh"
bootstrap_script="/tmp/artix-bootstrap.sh"

git clone "$bootstrap_script_url" "$bootstrap_dir"

chmod +x "$bootstrap_dir/artix-bootstrap.sh"

if [ -z "$arch" ]; then
arch="x86_64"
print_info "bootstrapping Artix rootfs using local artix-bootstrap.sh"
bootstrap_script="$(realpath -m ./artix-bootstrap.sh)"
if [ ! -x "$bootstrap_script" ]; then
print_error "Missing executable bootstrap script at $bootstrap_script"
exit 1
fi

print_info "bootstrapping Artix system in $rootfs_dir"
bash "$bootstrap_dir/artix-bootstrap.sh" "$rootfs_dir"
if ! "$bootstrap_script" -i openrc -a "$real_arch" -r "$repo_url" "$rootfs_dir"; then
print_error "Artix bootstrap failed."
print_error "Run manually for troubleshooting: $bootstrap_script -i openrc -a $real_arch -r $repo_url $rootfs_dir"
exit 1
fi

chroot_script="/opt/setup_rootfs_artix.sh"

Expand Down
38 changes: 36 additions & 2 deletions rootfs/opt/setup_rootfs_artix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ arch="${10}"

if [ "$arch" = "amd64" ]; then
real_arch="x86_64"
distro_flavor="artix"
elif [ "$arch" = "arm64" ]; then
real_arch="aarch64"
distro_flavor="armtix"
else
real_arch="$arch"
distro_flavor="artix"
fi

if [ ! "$hostname" ]; then
Expand All @@ -39,13 +44,42 @@ ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
END

cat > /etc/pacman.d/mirrorlist <<END
if [ "$distro_flavor" = "armtix" ]; then
cat > /etc/pacman.d/mirrorlist <<END
Server = https://mirrors.armtixlinux.org/armtix/\$repo/os/$real_arch
Server = https://armtixlinux.org/repos/\$repo/os/$real_arch
END
else
cat > /etc/pacman.d/mirrorlist <<END
Server = https://mirror1.artixlinux.org/\$repo/os/$real_arch
Server = https://mirror.pascalpuffke.de/artix-linux/\$repo/os/$real_arch
END
fi

pacman-key --init || true
pacman-key --populate artix archlinux || pacman-key --populate artix
populate_keyrings() {
local existing_keyrings=""
for keyring in "$@"; do
if [ -f "/usr/share/pacman/keyrings/${keyring}.gpg" ]; then
existing_keyrings="$existing_keyrings $keyring"
fi
done

if [ -n "$existing_keyrings" ]; then
# shellcheck disable=SC2086
pacman-key --populate $existing_keyrings
else
echo "warning: no expected keyring files were found under /usr/share/pacman/keyrings"
echo "warning: proceeding without pacman-key --populate"
fi
}

if [ "$distro_flavor" = "armtix" ]; then
# Armtix systems may still ship artix keyrings depending on bootstrap source.
populate_keyrings armtix archlinuxarm artix archlinux
else
populate_keyrings artix archlinux
fi
pacman -Syy --noconfirm

#add service to kill frecon
Expand Down
Loading