mirror of
https://github.com/RetroPie/RetroPie-Setup.git
synced 2025-04-02 10:51:41 -04:00
Using LZMA (xz) for compression instead LZ77 (gzip) reduces the image size by approx 30% more. Image writing utilities with compressed image support (RPI Imager, Balena Etcher) already support it and the RaspiOS or Armbian images are already distributed as `.xz` files. Changed our image compression format from `.gz` to `.xz` and thus reduce the download size for all images.
398 lines
12 KiB
Bash
398 lines
12 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# This file is part of The RetroPie Project
|
|
#
|
|
# The RetroPie Project is the legal property of its developers, whose names are
|
|
# too numerous to list here. Please refer to the COPYRIGHT.md file distributed with this source.
|
|
#
|
|
# See the LICENSE.md file at the top-level directory of this distribution and
|
|
# at https://raw.githubusercontent.com/RetroPie/RetroPie-Setup/master/LICENSE.md
|
|
#
|
|
|
|
rp_module_id="image"
|
|
rp_module_desc="Create/Manage RetroPie images"
|
|
rp_module_section=""
|
|
rp_module_flags=""
|
|
|
|
function depends_image() {
|
|
local depends=(kpartx unzip binfmt-support rsync parted squashfs-tools dosfstools e2fsprogs xz-utils)
|
|
isPlatform "x86" && depends+=(qemu-user-static)
|
|
getDepends "${depends[@]}"
|
|
}
|
|
|
|
function _get_info_image() {
|
|
local dist="$1"
|
|
local key="$2"
|
|
# don't use $md_data so this function can be used directly from builder.sh
|
|
local ini="${__mod_info[image/path]%/*}/image/dists/${dist}.ini"
|
|
[[ ! -f "$ini" ]] && fatalError "Definition file $ini does not exist"
|
|
|
|
iniConfig "=" "\"" "$ini"
|
|
iniGet "$key"
|
|
[[ -z "$ini_value" ]] && fatalError "Unable to locate key '$key' in definition file $ini"
|
|
echo "$ini_value"
|
|
}
|
|
|
|
function create_chroot_image() {
|
|
local dist="$1"
|
|
[[ -z "$dist" ]] && return 1
|
|
|
|
local chroot="$2"
|
|
[[ -z "$chroot" ]] && chroot="$md_build/$dist"
|
|
|
|
mkdir -p "$md_build"
|
|
pushd "$md_build"
|
|
|
|
mkdir -p "$chroot"
|
|
|
|
local url=$(_get_info_image "$dist" "url")
|
|
local format=$(_get_info_image "$dist" "format")
|
|
|
|
local base="raspbian-${dist}-lite"
|
|
local image="${dist}.img"
|
|
local dest="${image}.${format}"
|
|
if [[ ! -f "$image" ]]; then
|
|
case "$format" in
|
|
zip)
|
|
download "$url" "$dest"
|
|
unzip -o "$dest"
|
|
mv "$(unzip -Z -1 "$dest")" "$image"
|
|
rm "$dest"
|
|
;;
|
|
xz)
|
|
download "$url" "$dest"
|
|
xz -d -v "$dest"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# abort if there is no extracted image present
|
|
[[ ! -f "$image" ]] && return 1
|
|
|
|
# mount image
|
|
local partitions=($(kpartx -s -a -v "$image" | awk '{ print "/dev/mapper/"$3 }'))
|
|
local part_boot="${partitions[0]}"
|
|
local part_root="${partitions[1]}"
|
|
|
|
local tmp="$(mktemp -d -p "$md_build")"
|
|
mkdir -p "$tmp/boot"
|
|
|
|
mount "$part_root" "$tmp"
|
|
mount "$part_boot" "$tmp/boot"
|
|
|
|
printMsgs "console" "Creating chroot from $image ..."
|
|
rsync -aAHX --numeric-ids --delete "$tmp/" "$chroot/"
|
|
|
|
umount -l "$tmp/boot" "$tmp"
|
|
rm -rf "$tmp"
|
|
|
|
dmsetup remove "${partitions[@]}"
|
|
|
|
popd
|
|
return 0
|
|
}
|
|
|
|
function install_rp_image() {
|
|
local platform="$1"
|
|
if [[ -z "$platform" ]]; then
|
|
printMsgs "console" "Requires a platform (eg rpi3/rpi4)"
|
|
return 1
|
|
fi
|
|
|
|
local dist="$2"
|
|
if [[ -z "$dist" ]]; then
|
|
printMsgs "Requires a distribution name (eg rpios-buster/rpios-bullseye)"
|
|
return 1
|
|
fi
|
|
|
|
local chroot="$3"
|
|
[[ -z "$chroot" ]] && chroot="$md_build/$dist"
|
|
|
|
local dist_version="$(_get_info_image "$dist" "version")"
|
|
|
|
# hostname to retropie
|
|
echo "retropie" >"$chroot/etc/hostname"
|
|
sed -i "s/raspberrypi/retropie/" "$chroot/etc/hosts"
|
|
|
|
# quieter boot / disable plymouth (as without the splash parameter it
|
|
# causes all boot messages to be displayed and interferes with people
|
|
# using tty3 to make the boot even quieter)
|
|
if ! grep -q consoleblank "$chroot/boot/cmdline.txt"; then
|
|
# extra quiet as the raspbian usr/lib/raspi-config/init_resize.sh does
|
|
# sed -i 's/ quiet init=.*$//' /boot/cmdline.txt so this will remove the last quiet
|
|
# and the init line but leave ours intact
|
|
sed -i "s/quiet/quiet loglevel=3 consoleblank=0 plymouth.enable=0 quiet/" "$chroot/boot/cmdline.txt"
|
|
fi
|
|
|
|
# set default GPU mem (videocore only) and overscan_scale so ES scales to overscan settings.
|
|
iniConfig "=" "" "$chroot/boot/config.txt"
|
|
if [[ "$dist_version" -lt 11 && "platform" != "rpi4" ]]; then
|
|
iniSet "gpu_mem_256" 128
|
|
iniSet "gpu_mem_512" 256
|
|
iniSet "gpu_mem_1024" 256
|
|
fi
|
|
iniSet "overscan_scale" 1
|
|
|
|
# disable 64bit kernel
|
|
iniSet "arm_64bit" 0
|
|
|
|
[[ -z "$__chroot_branch" ]] && __chroot_branch="master"
|
|
cat > "$chroot/home/pi/install.sh" <<_EOF_
|
|
#!/bin/bash
|
|
cd
|
|
if systemctl is-enabled userconfig &>/dev/null; then
|
|
echo "pi:raspberry" | sudo chpasswd
|
|
sudo systemctl disable userconfig
|
|
sudo systemctl --quiet enable getty@tty1
|
|
fi
|
|
sudo apt-get update
|
|
sudo apt-get -y install git dialog xmlstarlet joystick
|
|
git clone -b "$__chroot_branch" https://github.com/RetroPie/RetroPie-Setup.git
|
|
cd RetroPie-Setup
|
|
modules=(
|
|
'raspbiantools apt_upgrade'
|
|
'setup basic_install'
|
|
'bluetooth depends'
|
|
'raspbiantools enable_modules'
|
|
'autostart enable'
|
|
'usbromservice'
|
|
'samba depends'
|
|
'samba install_shares'
|
|
'splashscreen default'
|
|
'splashscreen enable'
|
|
'bashwelcometweak'
|
|
'xpad'
|
|
)
|
|
for module in "\${modules[@]}"; do
|
|
sudo __platform=$platform __nodialog=1 __has_binaries=$__chroot_has_binaries ./retropie_packages.sh \$module
|
|
done
|
|
|
|
sudo rm -rf tmp
|
|
sudo apt-get clean
|
|
_EOF_
|
|
|
|
# chroot and run install script
|
|
rp_callModule image chroot "$chroot" bash /home/pi/install.sh
|
|
|
|
rm "$chroot/home/pi/install.sh"
|
|
|
|
# remove any ssh host keys that may have been generated during any ssh package upgrades
|
|
rm -f "$chroot/etc/ssh/ssh_host"*
|
|
}
|
|
|
|
function _init_chroot_image() {
|
|
local chroot="$1"
|
|
[[ -z "$chroot" ]] && return 1
|
|
|
|
# unmount on ctrl+c
|
|
trap "_trap_chroot_image '$chroot'" INT
|
|
|
|
# mount special filesystems to chroot
|
|
mkdir -p "$chroot"{/dev/pts,/proc}
|
|
mount none -t devpts "$chroot/dev/pts"
|
|
mount -t proc /proc "$chroot/proc"
|
|
|
|
# required for emulated chroot
|
|
isPlatform "x86" && cp "/usr/bin/qemu-arm-static" "$chroot/usr/bin/"
|
|
|
|
local nameserver="$__nameserver"
|
|
[[ -z "$nameserver" ]] && nameserver="$(nmcli device show | grep IP4.DNS | awk '{print $NF; exit}')"
|
|
# so we can resolve inside the chroot
|
|
echo "nameserver $nameserver" >"$chroot/etc/resolv.conf"
|
|
|
|
# move /etc/ld.so.preload out of the way to avoid warnings
|
|
mv "$chroot/etc/ld.so.preload" "$chroot/etc/ld.so.preload.bak"
|
|
}
|
|
|
|
function _deinit_chroot_image() {
|
|
local chroot="$1"
|
|
[[ -z "$chroot" ]] && return 1
|
|
|
|
trap "" INT
|
|
|
|
>"$chroot/etc/resolv.conf"
|
|
|
|
isPlatform "x86" && rm -f "$chroot/usr/bin/qemu-arm-static"
|
|
|
|
# restore /etc/ld.so.preload
|
|
mv "$chroot/etc/ld.so.preload.bak" "$chroot/etc/ld.so.preload"
|
|
|
|
umount -l "$chroot/proc" "$chroot/dev/pts"
|
|
trap INT
|
|
}
|
|
|
|
function _trap_chroot_image() {
|
|
_deinit_chroot_image "$1"
|
|
exit
|
|
}
|
|
|
|
function chroot_image() {
|
|
local chroot="$1"
|
|
[[ -z "$chroot" ]] && return 1
|
|
shift
|
|
|
|
printMsgs "console" "Chrooting to $chroot ..."
|
|
_init_chroot_image "$chroot"
|
|
HOME="/home/pi" chroot --userspec 1000:1000 "$chroot" "$@"
|
|
_deinit_chroot_image "$chroot"
|
|
}
|
|
|
|
function create_image() {
|
|
local image="$1"
|
|
[[ -z "$image" ]] && return 1
|
|
|
|
local chroot="$2"
|
|
[[ -z "$chroot" ]] && chroot="$md_build/chroot"
|
|
|
|
# make image size 300mb larger than contents of chroot
|
|
local mb_size=$(du -s --block-size 1048576 "$chroot" 2>/dev/null | cut -f1)
|
|
((mb_size+=492))
|
|
|
|
# create image
|
|
printMsgs "console" "Creating image $image ..."
|
|
dd if=/dev/zero of="$image" bs=1M count="$mb_size"
|
|
|
|
# partition
|
|
printMsgs "console" "partitioning $image ..."
|
|
parted -s "$image" -- \
|
|
mklabel msdos \
|
|
unit mib \
|
|
mkpart primary fat32 4 260 \
|
|
mkpart primary 260 -1s
|
|
|
|
# format
|
|
printMsgs "console" "Formatting $image ..."
|
|
|
|
# change to the image folder as kpartx has problems removing the
|
|
# device mapper files when using a full path to the image
|
|
local image_path="${image%/*}"
|
|
local image_name="${image##*/}"
|
|
pushd "$image_path"
|
|
|
|
local partitions=($(kpartx -s -a -v "$image_name" | awk '{ print "/dev/mapper/"$3 }'))
|
|
local part_boot="${partitions[0]}"
|
|
local part_root="${partitions[1]}"
|
|
|
|
mkfs.vfat -F 32 -n bootfs "$part_boot"
|
|
# use the mke2fs config from the chroot so we create the filesystem with supported features
|
|
# disable huge_file & 64bit as with the Raspberry Pi OS images
|
|
MKE2FS_CONFIG="$chroot/etc/mke2fs.conf" mkfs.ext4 -O ^huge_file,^64bit -L retropie "$part_root"
|
|
|
|
parted "$image_name" print
|
|
|
|
# disable ctrl+c
|
|
trap "" INT
|
|
|
|
# mount
|
|
printMsgs "console" "Mounting $image_name ..."
|
|
local tmp="$(mktemp -d -p "$md_build")"
|
|
mount "$part_root" "$tmp"
|
|
mkdir -p "$tmp/boot"
|
|
mount "$part_boot" "$tmp/boot"
|
|
|
|
# copy files
|
|
printMsgs "console" "Rsyncing chroot to $image_name ..."
|
|
rsync -aAHX --numeric-ids "$chroot/" "$tmp/"
|
|
|
|
# we need to fix up the UUIDS for /boot/cmdline.txt and /etc/fstab
|
|
local old_id="$(sed "s/.*PARTUUID=\([^-]*\).*/\1/" $tmp/boot/cmdline.txt)"
|
|
local new_id="$(blkid -s PARTUUID -o value "$part_root" | cut -c -8)"
|
|
sed -i "s/$old_id/$new_id/" "$tmp/boot/cmdline.txt"
|
|
sed -i "s/$old_id/$new_id/g" "$tmp/etc/fstab"
|
|
|
|
# unmount
|
|
umount -l "$tmp/boot" "$tmp"
|
|
rm -rf "$tmp"
|
|
|
|
kpartx -d "$image_name"
|
|
|
|
trap INT
|
|
}
|
|
|
|
# generate berryboot squashfs from filesystem
|
|
function create_bb_image() {
|
|
local image="$1"
|
|
[[ -z "$image" ]] && return 1
|
|
|
|
local chroot="$2"
|
|
[[ -z "$chroot" ]] && return 1
|
|
|
|
# replace fstab
|
|
echo "proc /proc proc defaults 0 0" >"$chroot/etc/fstab"
|
|
|
|
# remove any earlier image
|
|
rm -f "$image"
|
|
|
|
mksquashfs "$chroot" "$image" -comp lzo -e boot -e lib/modules
|
|
}
|
|
|
|
function all_image() {
|
|
local dist="$1"
|
|
local make_bb="$2"
|
|
local platforms="$(_get_info_image "$dist" "platforms")"
|
|
local platform
|
|
printMsgs "heading" "Building $platforms images based on $dist ..."
|
|
for platform in $platforms; do
|
|
platform_image "$platform" "$dist" "$make_bb"
|
|
done
|
|
combine_json_image
|
|
}
|
|
|
|
function platform_image() {
|
|
local platform="$1"
|
|
local dist="$2"
|
|
local make_bb="$3"
|
|
[[ -z "$platform" ]] && return 1
|
|
|
|
local dest="$__tmpdir/images"
|
|
mkdir -p "$dest"
|
|
|
|
printMsgs "heading" "Building $platform image based on $dist ..."
|
|
|
|
rp_callModule image create_chroot "$dist"
|
|
rp_callModule image install_rp "$platform" "$dist" "$md_build/$dist"
|
|
|
|
local dist_name="$(_get_info_image "$dist" "name")"
|
|
local file_add="$(_get_info_image "$dist" "file_${platform}")"
|
|
local image_title="$(_get_info_image "$dist" "title_${platform}")"
|
|
|
|
local image_base="retropie-${dist_name}-${__version}-${file_add}"
|
|
local image_name="${image_base}.img"
|
|
local image_file="$dest/$image_name"
|
|
|
|
rp_callModule image create "$image_file" "$md_build/$dist"
|
|
[[ "$make_bb" -eq 1 ]] && rp_callModule image create_bb "$dest/${image_base}-berryboot.img256"
|
|
|
|
printMsgs "console" "Compressing ${image_name} ..."
|
|
xz -v --compress --stdout "$image_file" > "${image_file}.xz"
|
|
|
|
printMsgs "console" "Generating JSON data for rpi-imager ..."
|
|
local template
|
|
template="$(<"$md_data/template.json")"
|
|
template="${template/IMG_PATH/$__version\/${image_name}.xz}"
|
|
template="${template/IMG_EXTRACT_SIZE/$(stat -c %s $image_file)}"
|
|
template="${template/IMG_SHA256/$(sha256sum $image_file | cut -d" " -f1)}"
|
|
template="${template/IMG_DOWNLOAD_SIZE/$(stat -c %s ${image_file}.xz)}"
|
|
template="${template/IMG_VERSION/$__version}"
|
|
template="${template/IMG_PLATFORM/$image_title}"
|
|
template="${template/IMG_DATE/$(date '+%Y-%m-%d')}"
|
|
echo "$template" >"${image_file}.json"
|
|
|
|
rm -f "$image_file"
|
|
}
|
|
|
|
function combine_json_image() {
|
|
local dest="$__tmpdir/images"
|
|
{
|
|
local template
|
|
echo -en "{\n \"os_list\": [\n"
|
|
local i=0
|
|
while read file; do
|
|
[[ "$i" -gt 0 ]] && echo -en ",\n"
|
|
template="$(<$file)"
|
|
echo -n "$template"
|
|
((i++))
|
|
done < <(find "$dest" -name "*.img.json" | sort)
|
|
echo -en "\n ]\n}\n"
|
|
} >"$dest/os_list_imagingutility.json"
|
|
}
|