You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
13 KiB
364 lines
13 KiB
#! /usr/bin/env bash
|
|
#
|
|
# Copyright 2021 Northern.tech AS
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# Default that can be overridden by providing this method in a
|
|
# configuration file passed with '--config'
|
|
function platform_modify() {
|
|
true
|
|
}
|
|
PLATFORM_MODIFY_HOOKS=(platform_modify)
|
|
|
|
function user_local_modify() {
|
|
true
|
|
}
|
|
USER_LOCAL_MODIFY_HOOKS=(user_local_modify)
|
|
|
|
function overlay_modify() {
|
|
true
|
|
}
|
|
OVERLAY_MODIFY_HOOKS=(overlay_modify)
|
|
|
|
function trap_exit() {
|
|
echo "mender-convert-modify has finished. Cleaning up..."
|
|
sudo umount -f work/boot
|
|
sudo umount -f work/rootfs
|
|
}
|
|
|
|
function trap_term() {
|
|
true
|
|
}
|
|
|
|
trap trap_term INT TERM
|
|
trap trap_exit EXIT
|
|
|
|
echo "Running $(basename $0): $@"
|
|
|
|
source modules/bootstrap.sh
|
|
source modules/disk.sh
|
|
source modules/probe.sh
|
|
source modules/deb.sh
|
|
source modules/testscfg.sh
|
|
|
|
# The mender_convert_config is always used and provides all the defaults
|
|
declare -a configs=("configs/mender_convert_config")
|
|
|
|
while (("$#")); do
|
|
case "$1" in
|
|
-o | --overlay)
|
|
overlays+=("${2}")
|
|
shift 2
|
|
;;
|
|
-c | --config)
|
|
configs+=("${2}")
|
|
shift 2
|
|
;;
|
|
-d | --disk-image)
|
|
disk_image="${2}"
|
|
shift 2
|
|
;;
|
|
*)
|
|
log_fatal "Sorry, but the provided option is not supported: $1"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Note the use of %q formatting here. This is a bash feature to add
|
|
# proper quoting to the strings so that spaces and special characters
|
|
# will be treated properly. Primarily for supporting spaces in
|
|
# pathnames and avoid splitting those into multiple parameters.
|
|
source modules/config.sh $(printf "%q " "${configs[@]}")
|
|
|
|
boot_part=$(disk_boot_part)
|
|
root_part=$(disk_root_part)
|
|
|
|
# Sysfs device paths
|
|
boot_part_device=$(disk_boot_part_device)
|
|
data_part_device=$(disk_data_part_device)
|
|
root_part_a_device=$(disk_root_part_a_device)
|
|
root_part_b_device=$(disk_root_part_b_device)
|
|
|
|
# Create mount points
|
|
mkdir -p work/boot
|
|
mkdir -p work/rootfs
|
|
|
|
sudo mount ${boot_part} work/boot
|
|
sudo mount ${root_part} work/rootfs
|
|
|
|
log_info "Installing Mender client and related files"
|
|
|
|
if [ "${MENDER_CLIENT_INSTALL}" = "y" ]; then
|
|
log_info "Installing Mender client version ${MENDER_CLIENT_VERSION}"
|
|
deb_get_and_install_pacakge mender-client "${MENDER_CLIENT_VERSION}"
|
|
|
|
# Save installed client version for tests in Yocto variable format
|
|
testscfg_add "PREFERRED_VERSION_mender-client" "$(echo ${DEB_NAME} | sed -r 's/.*_([0-9]+\.[0-9]+\.[0-9]+).*/\1/')"
|
|
fi
|
|
|
|
if [ "${MENDER_ENABLE_SYSTEMD}" == "y" ]; then
|
|
run_and_log_cmd "sudo ln -sf /lib/systemd/system/mender-client.service \
|
|
work/rootfs/etc/systemd/system/multi-user.target.wants/mender-client.service"
|
|
fi
|
|
|
|
if [ "${MENDER_ADDON_CONNECT_INSTALL}" = "y" ]; then
|
|
log_info "Installing Mender Connect addon"
|
|
deb_get_and_install_pacakge mender-connect "${MENDER_ADDON_CONNECT_VERSION}"
|
|
|
|
run_and_log_cmd "sudo ln -sf /lib/systemd/system/mender-connect.service \
|
|
work/rootfs/etc/systemd/system/multi-user.target.wants/mender-connect.service"
|
|
fi
|
|
|
|
if [ "${MENDER_ADDON_CONFIGURE_INSTALL}" = "y" ]; then
|
|
log_info "Installing Mender Configure addon"
|
|
deb_get_and_install_pacakge mender-configure "${MENDER_ADDON_CONFIGURE_VERSION}" "true"
|
|
fi
|
|
|
|
# Do this unconditionally even if not installing add-ons. The reason is that if
|
|
# the Debian package is installed later, this folder has to preexist. It is part
|
|
# of the rootfs setup, independently of the software.
|
|
log_info "Creating state folder in the data partition for Mender add-ons"
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/var/lib"
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/data/mender-configure"
|
|
run_and_log_cmd "sudo ln -sf /data/mender-configure work/rootfs/var/lib"
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/data/mender-monitor"
|
|
run_and_log_cmd "sudo ln -sf /data/mender-monitor work/rootfs/var/lib"
|
|
|
|
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then
|
|
# Check for known U-Boot problems in all files on the boot partition.
|
|
check_for_broken_uboot_uefi_support work/boot
|
|
|
|
run_and_log_cmd "wget -Nq '${MENDER_GRUBENV_URL}' -P work/"
|
|
run_and_log_cmd "tar xzvf work/${MENDER_GRUBENV_VERSION}.tar.gz -C work/"
|
|
|
|
if [ -z "${MENDER_GRUB_KERNEL_IMAGETYPE}" ]; then
|
|
kernel_imagetype=$(probe_kernel_in_boot_and_root)
|
|
else
|
|
kernel_imagetype="${MENDER_GRUB_KERNEL_IMAGETYPE}"
|
|
fi
|
|
|
|
if [ -z "${MENDER_GRUB_INITRD_IMAGETYPE}" ]; then
|
|
initrd_imagetype=$(probe_initrd_in_boot_and_root)
|
|
else
|
|
initrd_imagetype="${MENDER_GRUB_INITRD_IMAGETYPE}"
|
|
fi
|
|
|
|
cat <<- EOF > work/grub-mender-grubenv-${MENDER_GRUBENV_VERSION}/mender_grubenv_defines
|
|
mender_rootfsa_part=${MENDER_ROOTFS_PART_A_NUMBER}
|
|
mender_rootfsb_part=${MENDER_ROOTFS_PART_B_NUMBER}
|
|
mender_grub_storage_device=${MENDER_GRUB_STORAGE_DEVICE}
|
|
kernel_imagetype=kernel
|
|
initrd_imagetype=initrd
|
|
EOF
|
|
|
|
run_and_log_cmd "sudo ln -s ${kernel_imagetype} work/rootfs/boot/kernel"
|
|
if [ "${initrd_imagetype}" != "" ]; then
|
|
run_and_log_cmd "sudo ln -s ${initrd_imagetype} work/rootfs/boot/initrd"
|
|
fi
|
|
|
|
# For partuuid support grub.cfg expects dedicated variables to be added
|
|
if [ "${MENDER_ENABLE_PARTUUID}" == "y" ]; then
|
|
rootfsa_partuuid=$(disk_get_partuuid_from_device "${root_part_a_device}")
|
|
rootfsb_partuuid=$(disk_get_partuuid_from_device "${root_part_b_device}")
|
|
log_info "Using root partition A partuuid in grubenv: $rootfsa_partuuid"
|
|
log_info "Using root partition B partuuid in grubenv: $rootfsb_partuuid"
|
|
cat <<- EOF >> work/grub-mender-grubenv-${MENDER_GRUBENV_VERSION}/mender_grubenv_defines
|
|
mender_rootfsa_uuid=${rootfsa_partuuid}
|
|
mender_rootfsb_uuid=${rootfsb_partuuid}
|
|
EOF
|
|
else
|
|
cat <<- EOF >> work/grub-mender-grubenv-${MENDER_GRUBENV_VERSION}/mender_grubenv_defines
|
|
mender_kernel_root_base=${MENDER_STORAGE_DEVICE_BASE}
|
|
EOF
|
|
fi
|
|
|
|
if [ -n "${MENDER_GRUB_KERNEL_BOOT_ARGS}" ]; then
|
|
cat <<- EOF > work/grub-mender-grubenv-${MENDER_GRUBENV_VERSION}/11_bootargs_grub.cfg
|
|
set bootargs="${MENDER_GRUB_KERNEL_BOOT_ARGS}"
|
|
EOF
|
|
fi
|
|
|
|
cd work/grub-mender-grubenv-${MENDER_GRUBENV_VERSION}
|
|
run_and_log_cmd "make 2>&1"
|
|
run_and_log_cmd "sudo make DESTDIR=../ BOOT_DIR=boot install-boot-files"
|
|
run_and_log_cmd "sudo make DESTDIR=../rootfs install-tools"
|
|
cd - > /dev/null 2>&1
|
|
|
|
# Remove conflicting boot files. These files do not necessarily effect the
|
|
# functionality, but lets get rid of them to avoid confusion.
|
|
#
|
|
# There is no Mender integration for EFI boot or systemd-boot.
|
|
sudo rm -rf work/boot/loader work/rootfs/boot/loader
|
|
sudo rm -rf work/boot/EFI/Linux
|
|
sudo rm -rf work/boot/EFI/systemd
|
|
sudo rm -rf work/boot/NvVars
|
|
for empty_dir in $(
|
|
cd work/boot
|
|
find . -maxdepth 1 -type d -empty
|
|
); do
|
|
sudo rmdir work/boot/$empty_dir
|
|
done
|
|
|
|
log_info "Installing GRUB"
|
|
|
|
arch=$(probe_arch)
|
|
efi_name=$(probe_grub_efi_name)
|
|
efi_target_name=$(probe_grub_efi_target_name)
|
|
|
|
log_info "GRUB EFI: ${efi_target_name}"
|
|
|
|
run_and_log_cmd "wget -Nq ${MENDER_GRUB_BINARY_STORAGE_URL}/${arch}/${efi_name} -P work/"
|
|
run_and_log_cmd "wget -Nq ${MENDER_GRUB_BINARY_STORAGE_URL}/${arch}/grub-editenv -P work/"
|
|
|
|
run_and_log_cmd "sudo install -m 751 work/grub-editenv work/rootfs/usr/bin/"
|
|
|
|
run_and_log_cmd "sudo mkdir -p work/boot/EFI/BOOT"
|
|
run_and_log_cmd "sudo cp work/${efi_name} -P work/boot/EFI/BOOT/${efi_target_name}"
|
|
fi
|
|
|
|
# Copy dtb directory to the boot partition for use by the bootloader.
|
|
if [ -d work/rootfs/boot/dtbs ]; then
|
|
# Look for the first directory that has dtb files. First check the base
|
|
# folder, then any subfolders in versioned order.
|
|
for candidate in work/rootfs/boot/dtbs $(find work/rootfs/boot/dtbs/ -maxdepth 1 -type d | sort -V -r); do
|
|
if [ $(find $candidate -maxdepth 1 -name '*.dtb' | wc -l) -gt 0 ]; then
|
|
run_and_log_cmd "sudo cp -r $candidate work/boot/dtb"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/data/mender"
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/var/lib"
|
|
run_and_log_cmd "sudo ln -sf /data/mender work/rootfs/var/lib"
|
|
|
|
log_info "Using root device A in mender.conf: $root_part_a_device"
|
|
log_info "Using root device B in mender.conf: $root_part_b_device"
|
|
|
|
cat <<- EOF > work/mender.conf.data
|
|
{
|
|
"RootfsPartA": "${root_part_a_device}",
|
|
"RootfsPartB": "${root_part_b_device}"
|
|
}
|
|
EOF
|
|
|
|
run_and_log_cmd "sudo cp work/mender.conf.data work/rootfs/data/mender/mender.conf"
|
|
run_and_log_cmd "sudo chmod 600 work/rootfs/data/mender/mender.conf"
|
|
|
|
if [ -f resources/mender.conf ]; then
|
|
log_info "Installing the local mender.conf file"
|
|
run_and_log_cmd "mkdir -p work/rootfs/etc/mender"
|
|
run_and_log_cmd "cp resources/mender.conf work/rootfs/etc/mender"
|
|
run_and_log_cmd "sudo chmod 600 work/rootfs/etc/mender/mender.conf"
|
|
else
|
|
log_warn "No mender.conf file found in resources. Have you remembered to run the bootstrap script?"
|
|
fi
|
|
|
|
if [ -z "${MENDER_DEVICE_TYPE}" ]; then
|
|
# Observed systems who do not have this file, e.g images generated with mkosi
|
|
if [ -f work/rootfs/etc/hostname ]; then
|
|
device_type=$(cat work/rootfs/etc/hostname)
|
|
else
|
|
device_type="default"
|
|
fi
|
|
else
|
|
device_type="${MENDER_DEVICE_TYPE}"
|
|
fi
|
|
|
|
run_and_log_cmd "echo 'device_type=${device_type}' > work/device_type"
|
|
run_and_log_cmd "sudo install -m 0444 work/device_type work/rootfs/data/mender/"
|
|
|
|
if [ "${MENDER_CLIENT_INSTALL}" = "y" ]; then
|
|
run_and_log_cmd "echo 'artifact_name=${MENDER_ARTIFACT_NAME}' \
|
|
| sudo tee work/rootfs/etc/mender/artifact_info"
|
|
fi
|
|
|
|
log_info "Creating state scripts version file."
|
|
case "${MENDER_CLIENT_VERSION}" in
|
|
1*) VERSION_STRING='2' ;;
|
|
*) VERSION_STRING='3' ;;
|
|
esac
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/etc/mender/scripts/"
|
|
run_and_log_cmd "echo -n ${VERSION_STRING} | sudo tee work/rootfs/etc/mender/scripts/version"
|
|
|
|
log_info "Installing a custom /etc/fstab (see ${MENDER_CONVERT_LOG_FILE} for more info)"
|
|
|
|
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then
|
|
boot_part_mountpoint="/boot/efi"
|
|
else
|
|
boot_part_mountpoint="/uboot"
|
|
fi
|
|
|
|
run_and_log_cmd "sudo mkdir -p work/rootfs/${boot_part_mountpoint}"
|
|
|
|
if [ "${MENDER_DATA_PART_GROWFS}" == "y" ]; then
|
|
MENDER_DATA_PART_FSTAB_OPTS="${MENDER_DATA_PART_FSTAB_OPTS},x-systemd.growfs"
|
|
fi
|
|
|
|
if echo ${MENDER_ROOT_PART_FSTAB_OPTS} | tr ',' '\n' | egrep -q "^ro$"; then
|
|
if ! echo "${MENDER_ROOT_PART_MKFS_OPTS}" | fgrep -q -- "^64bit"; then
|
|
log_warn "EXT4 64bits feature is known to create unstable checksums on read-only file systems, add \"-O ^64bit\" to MENDER_ROOT_PART_MKFS_OPTS to remove it"
|
|
fi
|
|
if ! echo "${MENDER_ROOT_PART_MKFS_OPTS}" | fgrep -q -- "^has_journal"; then
|
|
log_warn "EXT4 journal feature is known to create unstable checksums on read-only file systems, add \"-O ^has_journal\" to MENDER_ROOT_PART_MKFS_OPTS to remove it"
|
|
fi
|
|
fi
|
|
|
|
log_info "Using boot partition device in fstab: $boot_part_device"
|
|
log_info "Using data partition device in fstab: $data_part_device"
|
|
|
|
sudo bash -c "cat <<- EOF > work/rootfs/etc/fstab
|
|
# stock fstab - you probably want to override this with a machine specific one
|
|
/dev/root / auto ${MENDER_ROOT_PART_FSTAB_OPTS} 1 ${MENDER_ROOT_PART_FS_PASSNO}
|
|
proc /proc proc defaults 0 0
|
|
|
|
${boot_part_device} ${boot_part_mountpoint} auto defaults,sync 0 0
|
|
${data_part_device} /data auto ${MENDER_DATA_PART_FSTAB_OPTS} 0 0
|
|
EOF"
|
|
|
|
#
|
|
# Make sure to re-label rootfs when selinux is in enforcing mode
|
|
# e.g. CentOS8 after conversion cannot start login shell due selinux
|
|
# inspired by: https://forums.centos.org/viewtopic.php?t=48714
|
|
#
|
|
if [ -f work/rootfs/etc/selinux/config ]; then
|
|
grep -r 'SELINUX=Enforcing' work/rootfs/etc/selinux/config || true
|
|
if [ $? -eq 0 ]; then
|
|
log_info "Selinux is in enforcing mode. Enable autorelabel"
|
|
touch work/rootfs/.autorelabel
|
|
fi
|
|
fi
|
|
|
|
log_info "Performing platform specific modifications (if any)"
|
|
for hook in "${PLATFORM_MODIFY_HOOKS[@]}"; do
|
|
log_info "Running hook: $hook"
|
|
eval $hook
|
|
done
|
|
|
|
log_info "Performing user/local specific modifications (if any)"
|
|
for hook in "${USER_LOCAL_MODIFY_HOOKS[@]}"; do
|
|
log_info "Running hook: $hook"
|
|
eval $hook
|
|
done
|
|
|
|
for overlay in "${overlays[@]}"; do
|
|
log_info "Applying rootfs overlay: ${overlay}"
|
|
run_and_log_cmd "sudo rsync --archive --keep-dirlinks --verbose ${overlay}/ work/rootfs/"
|
|
done
|
|
|
|
log_info "Performing overlay specific modifications (if any)"
|
|
for hook in "${OVERLAY_MODIFY_HOOKS[@]}"; do
|
|
log_info "Running hook: $hook"
|
|
eval $hook
|
|
done
|
|
|