pep-mklive/mkplatformfs.sh

245 lines
10 KiB
Bash
Executable File

#!/bin/sh
#-
# Copyright (c) 2017 Google
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#-
readonly PROGNAME=$(basename "$0")
readonly ARCH=$(uname -m)
readonly REQTOOLS="xbps-install xbps-reconfigure tar xz"
# This source pulls in all the functions from lib.sh. This set of
# functions makes it much easier to work with chroots and abstracts
# away all the problems with running binaries with QEMU.
# shellcheck source=./lib.sh
. ./lib.sh
# Die is a function provided in lib.sh which handles the cleanup of
# the mounts and removal of temporary directories if the running
# program exists unexpectedly.
trap 'die "Interrupted! exiting..."' INT TERM HUP
# Even though we only support really one target for most of these
# architectures this lets us refer to these quickly and easily by
# XBPS_ARCH. This makes it a lot more obvious what is happening later
# in the script, and it makes it easier to consume the contents of
# these down the road in later scripts.
usage() {
cat <<-EOH
Usage: $PROGNAME [options] <platform> <rootfs-tarball>
Generates a platform-specific ROOTFS tarball from a generic Peppermintos ROOTFS
generated by mkrootfs.sh.
Supported platforms: i686, x86_64, GCP,
rpi-armv6l, rpi-armv7l, rpi-aarch64,
pinebookpro, pinephone, rock64, rockpro64
OPTIONS
-b <system-pkg> Set an alternative base-system package (default: base-system)
-c <cachedir> Set the XBPS cache directory (default: ./xbps-cachedir-<arch>)
-C <file> Full path to the XBPS configuration file
-k <cmd> Call '<cmd> <ROOTFSPATH>' after building the ROOTFS
-n Do not compress the image, instead print out the ROOTFS directory
-o <file> Filename to write the PLATFORMFS archive to (default: automatic)
-p "<pkg> ..." Additional packages to install into the ROOTFS
-r <repo> Use this XBPS repository. May be specified multiple times
-x <num> Number of threads to use for image compression (default: dynamic)
-h Show this help and exit
-V Show version and exit
EOH
}
# ########################################
# SCRIPT EXECUTION STARTS HERE
# ########################################
BASEPKG=base-system
COMPRESSION="y"
while getopts "b:p:k:c:C:r:x:o:nhV" opt; do
case $opt in
b) BASEPKG="$OPTARG" ;;
p) EXTRA_PKGS="$OPTARG" ;;
k) POST_CMD="$OPTARG" ;;
c) XBPS_CACHEDIR="--cachedir=$OPTARG" ;;
C) XBPS_CONFFILE="-C $OPTARG" ;;
r) XBPS_REPOSITORY="--repository=$OPTARG $XBPS_REPOSITORY" ;;
x) COMPRESSOR_THREADS="$OPTARG" ;;
o) FILENAME="$OPTARG" ;;
n) COMPRESSION="n" ;;
V) version; exit 0;;
h) usage; exit 0 ;;
*) usage >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
PLATFORM="$1"
BASE_TARBALL="$2"
if [ -z "$PLATFORM" ] || [ -z "$BASE_TARBALL" ]; then
usage >&2
exit 1
fi
# This is an aweful hack since the script isn't using privesc
# mechanisms selectively. This is a TODO item.
if [ "$(id -u)" -ne 0 ]; then
die "need root perms to continue, exiting."
fi
# Before going any further, check that the tools that are needed are
# present. If we delayed this we could check for the QEMU binary, but
# its a reasonable tradeoff to just bail out now.
check_tools
# Most platforms have a base system package that includes specific
# packages for bringing up the hardware. In the case of the cloud
# platforms the base package includes the components needed to inject
# SSH keys and user accounts. The base platform packages are always
# noarch though, so we strip off the -musl extention if it was
# provided.
case "$PLATFORM" in
rpi*) PKGS="$BASEPKG rpi-base" ;;
i686*) PKGS="$BASEPKG" ;;
x86_64*) PKGS="$BASEPKG" ;;
GCP*) PKGS="$BASEPKG ${PLATFORM%-*}-base" ;;
pinebookpro*) PKGS="$BASEPKG ${PLATFORM%-*}-base" ;;
pinephone*) PKGS="$BASEPKG ${PLATFORM%-*}-base" ;;
rock64*) PKGS="$BASEPKG ${PLATFORM%-*}-base" ;;
rockpro64*) PKGS="$BASEPKG ${PLATFORM%-*}-base" ;;
*) die "$PROGNAME: invalid platform!";;
esac
# Derive the target architecture using the static map
set_target_arch_from_platform
# And likewise set the cache
set_cachedir
# Append any additional packages if they were requested
if [ -n "$EXTRA_PKGS" ] ; then
PKGS="$PKGS $EXTRA_PKGS"
fi
# We need to operate on a tempdir, if this fails to create, it is
# absolutely crucial to bail out so that we don't hose the system that
# is running the script.
ROOTFS=$(mktemp -d) || die "failed to create tempdir, exiting..."
# Now that we have a directory for the ROOTFS, we can expand the
# existing base filesystem into the directory
if [ ! -e "$BASE_TARBALL" ]; then
die "no valid base tarball given, exiting."
fi
info_msg "Expanding base tarball $BASE_TARBALL into $ROOTFS for $PLATFORM build."
tar xf "$BASE_TARBALL" --xattrs --xattrs-include='*' -C "$ROOTFS"
# This will install, but not configure, the packages specified by
# $PKGS. After this step we will do an xbps-reconfigure -f $PKGS
# under the correct architecture to ensure the system is setup
# correctly.
run_cmd_target "xbps-install -SU $XBPS_CONFFILE $XBPS_CACHEDIR $XBPS_REPOSITORY -r $ROOTFS -y $PKGS"
# Now that the packages are installed, we need to chroot in and
# reconfigure. This needs to be done as the right architecture.
# Since this is the only thing we're doing in the chroot, we clean up
# right after.
run_cmd_chroot "$ROOTFS" "xbps-reconfigure -a"
# Before final cleanup the ROOTFS needs to be checked to make sure it
# contains an initrd and if its a platform with arch 'arm*' it needs
# to also have a uInitrd. For this to work the system needs to have
# the uboot-mkimage package installed. Base system packages that do
# not provide this must provide the uInitrd pre-prepared if they are
# arm based. x86 images will have this built using native dracut
# using post unpacking steps for platforms that consume the x86
# tarballs. This check is very specific and ensures that applicable
# tooling is present before proceeding.
if [ ! -f "$ROOTFS/boot/uInitrd" ] ||
[ ! -f "$ROOTFS/boot/initrd" ] &&
[ -z "${XBPS_TARGET_ARCH##*arm*}" ] &&
[ -x "$ROOTFS/usr/bin/dracut" ] &&
[ -x "$ROOTFS/usr/bin/mkimage" ]; then
# Dracut needs to know the kernel version that will be using this
# initrd so that it can install the kernel drivers in it. Normally
# this check is quite complex, but since this is a clean rootfs and we
# just installed exactly one kernel, this check can get by with a
# really niave command to figure out the kernel version
KERNELVERSION=$(ls "$ROOTFS/usr/lib/modules/")
# Some platforms also have special arguments that need to be set
# for dracut. This allows us to kludge around issues that may
# exist on certain specific platforms we build for.
set_dracut_args_from_platform
# Now that things are setup, we can call dracut and build the initrd.
# This will pretty much step through the normal process to build
# initrd with the exception that the autoinstaller and netmenu are
# force added since no module depends on them.
info_msg "Building initrd for kernel version $KERNELVERSION"
run_cmd_chroot "$ROOTFS" "env -i /usr/bin/dracut $dracut_args /boot/initrd $KERNELVERSION"
[ $? -ne 0 ] && die "Failed to generate the initramfs"
run_cmd_chroot "$ROOTFS" "env -i /usr/bin/mkimage -A arm -O linux -T ramdisk -C gzip -a 0 -e 0 -n 'Peppermintos' -d /boot/initrd /boot/uInitrd"
fi
cleanup_chroot
# The cache isn't that useful since by the time the ROOTFS will be
# used it is likely to be out of date. Rather than shipping it around
# only for it to be out of date, we remove it now.
rm -rf "$ROOTFS/var/cache/*" 2>/dev/null
# Now we can run the POST_CMD script. This user-supplied script gets the
# $ROOTFS as a parameter.
if [ -n "$POST_CMD" ]; then
info_msg "Running user supplied command: $POST_CMD"
run_cmd $POST_CMD $ROOTFS
fi
# Compress the tarball or just print out the path?
if [ "$COMPRESSION" = "y" ]; then
# Finally we can compress the tarball, the name will include the
# platform and the date on which the tarball was built.
tarball=${FILENAME:-pep-${PLATFORM}-PLATFORMFS-$(date -u '+%Y%m%d').tar.xz}
run_cmd "tar cp --posix --xattrs --xattrs-include='*' -C $ROOTFS . | xz -T${COMPRESSOR_THREADS:-0} -9 > $tarball "
[ $? -ne 0 ] && die "Failed to compress tarball"
# Now that we have the tarball we don't need the rootfs anymore, so we
# can get rid of it.
rm -rf "$ROOTFS"
# Last thing to do before closing out is to let the user know that
# this succeeded. This also ensures that there's something visible
# that the user can look for at the end of the script, which can make
# it easier to see what's going on if something above failed.
info_msg "Successfully created $tarball ($PLATFORM)"
else
# User requested just printing out the path to the rootfs, here it comes.
info_msg "Successfully created rootfs under $ROOTFS"
fi