Browse Source

Merge pull request #301 from oleorhagen/testfmt

Add a formatter, and format all code files
2.4.x
oleorhagen 4 years ago
committed by GitHub
parent
commit
5fd6880f05
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 47
      .gitlab-ci.yml
  2. 62
      configs/beaglebone_black_base_config
  3. 16
      configs/images/raspberrypi_raspbian_config
  4. 17
      configs/mender_convert_config
  5. 170
      configs/raspberrypi_config
  6. 20
      configs/rockpro64_config
  7. 70
      mender-convert
  8. 56
      modules/cliparser.sh
  9. 5
      modules/config.sh
  10. 106
      modules/deb.sh
  11. 108
      modules/decompressinput.sh
  12. 265
      modules/disk.sh
  13. 3
      modules/git.sh
  14. 45
      modules/log.sh
  15. 420
      modules/probe.sh
  16. 24
      modules/run.sh
  17. 32
      modules/testscfg.sh
  18. 22
      modules/zip.sh
  19. 46
      scripts/bootstrap-rootfs-overlay-demo-server.sh
  20. 46
      scripts/bootstrap-rootfs-overlay-hosted-server.sh
  21. 58
      scripts/bootstrap-rootfs-overlay-production-server.sh

47
.gitlab-ci.yml

@ -52,6 +52,53 @@ build:
paths: paths:
- image.tar - image.tar
test:format:
stage: test
needs: []
image: alpine:3.13
before_script:
- apk update
- apk upgrade
- apk add --update bash git shfmt
- shfmt -version
script:
- /bin/bash
- SCRIPTS=$(find modules configs scripts -type f
-not -name "*.md"
-not -wholename "scripts/test/*")
# shfmt
## Language=Bash
# -ln bash
## Indent=4 spaces
# -i 4
## List files who differ in formatting
# -l
## Redirect operators should be followed by a space
# -sr
## Indent switch statements
# -ci
## Keep column alignment padding
# -kp
## Binary operators like &&, || may start a new line
# -bn
## Overwrite the source files
# -w
- |
shfmt \
-ln bash \
-i 4 \
-l \
-sr \
-ci \
-kp \
-bn \
-w \
${SCRIPTS}
# Print diff
- git diff HEAD
# Actual test: exits with non zero status if diff
- git diff-index --quiet HEAD
.template_convert_raspbian: &convert_raspbian .template_convert_raspbian: &convert_raspbian
stage: convert stage: convert
needs: needs:

62
configs/beaglebone_black_base_config

@ -20,51 +20,51 @@ MENDER_IGNORE_UBOOT_BROKEN_UEFI=1
MENDER_IGNORE_MISSING_EFI_STUB=1 MENDER_IGNORE_MISSING_EFI_STUB=1
function beaglebone_fix_broken_uefi_uboot() { function beaglebone_fix_broken_uefi_uboot() {
log_warn "Attempting to work around broken UEFI support in U-Boot by forcing a newer U-Boot version." log_warn "Attempting to work around broken UEFI support in U-Boot by forcing a newer U-Boot version."
mkdir -p work/bbb/binaries mkdir -p work/bbb/binaries
run_and_log_cmd "wget -q ${BEAGLEBONE_BLACK_BINARIES_URL} -P work/bbb/binaries" run_and_log_cmd "wget -q ${BEAGLEBONE_BLACK_BINARIES_URL} -P work/bbb/binaries"
run_and_log_cmd "tar xzvf work/bbb/binaries/${BEAGLEBONE_BLACK_BINARIES} -C work/bbb/binaries" run_and_log_cmd "tar xzvf work/bbb/binaries/${BEAGLEBONE_BLACK_BINARIES} -C work/bbb/binaries"
# Place u-boot and MLO into rootfs/boot # Place u-boot and MLO into rootfs/boot
run_and_log_cmd "sudo mkdir -p work/rootfs/boot" run_and_log_cmd "sudo mkdir -p work/rootfs/boot"
run_and_log_cmd "sudo cp work/bbb/binaries/MLO work/boot/" run_and_log_cmd "sudo cp work/bbb/binaries/MLO work/boot/"
run_and_log_cmd "sudo cp work/bbb/binaries/u-boot.img work/boot/" run_and_log_cmd "sudo cp work/bbb/binaries/u-boot.img work/boot/"
run_and_log_cmd "sudo install -m 755 work/bbb/binaries/fw_printenv work/rootfs/sbin/fw_printenv" run_and_log_cmd "sudo install -m 755 work/bbb/binaries/fw_printenv work/rootfs/sbin/fw_printenv"
run_and_log_cmd "sudo ln -fs /sbin/fw_printenv work/rootfs/sbin/fw_setenv" run_and_log_cmd "sudo ln -fs /sbin/fw_printenv work/rootfs/sbin/fw_setenv"
} }
function beaglebone_fix_broken_uefi_kernel() { function beaglebone_fix_broken_uefi_kernel() {
log_warn "Attempting to work around kernel without EFI stub by using a newer kernel." log_warn "Attempting to work around kernel without EFI stub by using a newer kernel."
mkdir -p work/bbb/kernel mkdir -p work/bbb/kernel
run_and_log_cmd "wget -q $BEAGLEBONE_EFI_COMPATIBLE_KERNEL_URL -P work/bbb/kernel" run_and_log_cmd "wget -q $BEAGLEBONE_EFI_COMPATIBLE_KERNEL_URL -P work/bbb/kernel"
mkdir -p work/bbb/kernel/extract mkdir -p work/bbb/kernel/extract
run_and_log_cmd "tar xJf work/bbb/kernel/$BEAGLEBONE_EFI_COMPATIBLE_KERNEL -C work/bbb/kernel/extract" run_and_log_cmd "tar xJf work/bbb/kernel/$BEAGLEBONE_EFI_COMPATIBLE_KERNEL -C work/bbb/kernel/extract"
run_and_log_cmd "cp -r work/bbb/kernel/extract/* work/rootfs/" run_and_log_cmd "cp -r work/bbb/kernel/extract/* work/rootfs/"
run_and_log_cmd "ln -sf vmlinuz-$BEAGLEBONE_EFI_COMPATIBLE_KERNEL_VERSION work/rootfs/boot/kernel" run_and_log_cmd "ln -sf vmlinuz-$BEAGLEBONE_EFI_COMPATIBLE_KERNEL_VERSION work/rootfs/boot/kernel"
run_and_log_cmd "ln -sf initrd.img-$BEAGLEBONE_EFI_COMPATIBLE_KERNEL_VERSION work/rootfs/boot/initrd" run_and_log_cmd "ln -sf initrd.img-$BEAGLEBONE_EFI_COMPATIBLE_KERNEL_VERSION work/rootfs/boot/initrd"
} }
function beaglebone_fix_broken_uefi() { function beaglebone_fix_broken_uefi() {
if ! is_uboot_with_uefi_support work/boot-gap.bin; then if ! is_uboot_with_uefi_support work/boot-gap.bin; then
beaglebone_fix_broken_uefi_uboot beaglebone_fix_broken_uefi_uboot
fi fi
if ! is_efi_compatible_kernel work/rootfs/boot/$kernel_imagetype; then if ! is_efi_compatible_kernel work/rootfs/boot/$kernel_imagetype; then
beaglebone_fix_broken_uefi_kernel beaglebone_fix_broken_uefi_kernel
fi fi
} }
PLATFORM_MODIFY_HOOKS+=(beaglebone_fix_broken_uefi) PLATFORM_MODIFY_HOOKS+=(beaglebone_fix_broken_uefi)
function disable_udisks2_service() { function disable_udisks2_service() {
# Mask udisks2.service, otherwise it will mount the inactive part and we # Mask udisks2.service, otherwise it will mount the inactive part and we
# might write an update while it is mounted which often result in # might write an update while it is mounted which often result in
# corruptions. # corruptions.
# #
# TODO: Find a way to only blacklist mmcblk0pX devices instead of masking # TODO: Find a way to only blacklist mmcblk0pX devices instead of masking
# the service. # the service.
run_and_log_cmd "sudo ln -sf /dev/null work/rootfs/etc/systemd/system/udisks2.service" run_and_log_cmd "sudo ln -sf /dev/null work/rootfs/etc/systemd/system/udisks2.service"
} }
PLATFORM_MODIFY_HOOKS+=(disable_udisks2_service) PLATFORM_MODIFY_HOOKS+=(disable_udisks2_service)

16
configs/images/raspberrypi_raspbian_config

@ -17,11 +17,11 @@ MENDER_COMPRESS_DISK_IMAGE=lzma
# Resize the data partition to fill the remaining space, using parted, with systemd # Resize the data partition to fill the remaining space, using parted, with systemd
# #
function grow_data_partition() { function grow_data_partition() {
log_info "Adding systemd init script to run parted and resize the data partition on boot" log_info "Adding systemd init script to run parted and resize the data partition on boot"
log_info "to fill all the available space on the storage media" log_info "to fill all the available space on the storage media"
run_and_log_cmd "sudo mkdir -p work/rpi/etc/systemd/system/" run_and_log_cmd "sudo mkdir -p work/rpi/etc/systemd/system/"
run_and_log_cmd "sudo mkdir -p work/rootfs/etc/systemd/system/data.mount.wants/" run_and_log_cmd "sudo mkdir -p work/rootfs/etc/systemd/system/data.mount.wants/"
cat <<-EOF > work/rpi/etc/systemd/system/mender-grow-data.service cat <<- EOF > work/rpi/etc/systemd/system/mender-grow-data.service
[Unit] [Unit]
Description=Mender service to grow data partition size Description=Mender service to grow data partition size
DefaultDependencies=no DefaultDependencies=no
@ -38,10 +38,10 @@ function grow_data_partition() {
WantedBy=data.mount WantedBy=data.mount
EOF EOF
# Install # Install
run_and_log_cmd "cp work/rpi/etc/systemd/system/mender-grow-data.service \ run_and_log_cmd "cp work/rpi/etc/systemd/system/mender-grow-data.service \
work/rootfs/etc/systemd/system/" work/rootfs/etc/systemd/system/"
run_and_log_cmd "ln -sf work/rootfs/etc/systemd/system/mender-grow-data.service \ run_and_log_cmd "ln -sf work/rootfs/etc/systemd/system/mender-grow-data.service \
work/rootfs/etc/systemd/system/data.mount.wants/" work/rootfs/etc/systemd/system/data.mount.wants/"
} }

17
configs/mender_convert_config

@ -32,7 +32,6 @@ MENDER_ARTIFACT_COMPRESSION="gzip"
# this. # this.
MENDER_ENABLE_SYSTEMD=y MENDER_ENABLE_SYSTEMD=y
# Custom mkfs options for creating the rootfs partition # Custom mkfs options for creating the rootfs partition
MENDER_ROOT_PART_MKFS_OPTS="" MENDER_ROOT_PART_MKFS_OPTS=""
@ -232,16 +231,16 @@ source configs/mender_grub_config
# You might want to override this to e.g provide state-scripts or providing # You might want to override this to e.g provide state-scripts or providing
# a private key to sign your artifact. # a private key to sign your artifact.
mender_create_artifact() { mender_create_artifact() {
local -r device_types="${1}" local -r device_types="${1}"
local -r artifact_name="${2}" local -r artifact_name="${2}"
local -r image_name="${3}" local -r image_name="${3}"
local -r all_device_types="$(for device_type in $device_types; do echo " --device-type $device_type"; done)" local -r all_device_types="$(for device_type in $device_types; do echo " --device-type $device_type"; done)"
mender_artifact=deploy/${image_name}.mender mender_artifact=deploy/${image_name}.mender
log_info "Writing Mender artifact to: ${mender_artifact}" log_info "Writing Mender artifact to: ${mender_artifact}"
log_info "This can take up to 20 minutes depending on which compression method is used" log_info "This can take up to 20 minutes depending on which compression method is used"
run_and_log_cmd "mender-artifact --compression ${MENDER_ARTIFACT_COMPRESSION} \ run_and_log_cmd "mender-artifact --compression ${MENDER_ARTIFACT_COMPRESSION} \
write rootfs-image \ write rootfs-image \
--file work/rootfs.img \ --file work/rootfs.img \
--output-path ${mender_artifact} \ --output-path ${mender_artifact} \

170
configs/raspberrypi_config

@ -14,89 +14,89 @@ RASPBERRYPI_BINARIES="${RASPBERRYPI_CONFIG}-2019.01.tar.gz"
RASPBERRYPI_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/uboot/raspberrypi/${RASPBERRYPI_BINARIES}" RASPBERRYPI_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/uboot/raspberrypi/${RASPBERRYPI_BINARIES}"
function platform_modify() { function platform_modify() {
mkdir -p work/rpi/binaries mkdir -p work/rpi/binaries
run_and_log_cmd "wget -q ${RASPBERRYPI_BINARIES_URL} -P work/rpi/binaries" run_and_log_cmd "wget -q ${RASPBERRYPI_BINARIES_URL} -P work/rpi/binaries"
run_and_log_cmd "tar xzvf work/rpi/binaries/${RASPBERRYPI_BINARIES} -C work/rpi/binaries" run_and_log_cmd "tar xzvf work/rpi/binaries/${RASPBERRYPI_BINARIES} -C work/rpi/binaries"
# By default, we modify cmdline.txt. # By default, we modify cmdline.txt.
# #
# In Ubuntu, the file is called btcmd.txt; if this file exists, use it instead # In Ubuntu, the file is called btcmd.txt; if this file exists, use it instead
CMDLINE="cmdline.txt" CMDLINE="cmdline.txt"
if [ -f work/boot/btcmd.txt ]; then if [ -f work/boot/btcmd.txt ]; then
CMDLINE="btcmd.txt" CMDLINE="btcmd.txt"
fi fi
# Make a copy of Linux kernel arguments and modify. # Make a copy of Linux kernel arguments and modify.
run_and_log_cmd "cp work/boot/$CMDLINE work/rpi/$CMDLINE" run_and_log_cmd "cp work/boot/$CMDLINE work/rpi/$CMDLINE"
# Set a dynamic rootfs part (required for Mender A/B update strategy) # Set a dynamic rootfs part (required for Mender A/B update strategy)
run_and_log_cmd "sed -i 's/\b[ ]root=[^ ]*/ root=\${mender_kernel_root}/' work/rpi/$CMDLINE" run_and_log_cmd "sed -i 's/\b[ ]root=[^ ]*/ root=\${mender_kernel_root}/' work/rpi/$CMDLINE"
# Root filesystem can not be resized when the disk is partition according # Root filesystem can not be resized when the disk is partition according
# to Mender layout, where the rootfs partition is the not last one which # to Mender layout, where the rootfs partition is the not last one which
# is a requirement to be able to do an "online" resize. # is a requirement to be able to do an "online" resize.
# #
# This disables resize of rootfs on boot but applies the changes to # This disables resize of rootfs on boot but applies the changes to
# cmdline.txt that are performed in the init_resize.sh script. # cmdline.txt that are performed in the init_resize.sh script.
# #
# Extracted from /usr/lib/raspi-config/init_resize.sh # Extracted from /usr/lib/raspi-config/init_resize.sh
run_and_log_cmd "sed -i 's| init=/usr/lib/raspi-config/init_resize\.sh||' work/rpi/$CMDLINE" run_and_log_cmd "sed -i 's| init=/usr/lib/raspi-config/init_resize\.sh||' work/rpi/$CMDLINE"
run_and_log_cmd "sed -i 's| sdhci\.debug_quirks2=4||' work/rpi/$CMDLINE" run_and_log_cmd "sed -i 's| sdhci\.debug_quirks2=4||' work/rpi/$CMDLINE"
if ! grep -q splash work/rpi/$CMDLINE; then if ! grep -q splash work/rpi/$CMDLINE; then
run_and_log_cmd "sed -i 's/ quiet//g' work/rpi/$CMDLINE" run_and_log_cmd "sed -i 's/ quiet//g' work/rpi/$CMDLINE"
fi fi
# Update Linux kernel command arguments with our custom configuration # Update Linux kernel command arguments with our custom configuration
run_and_log_cmd "sudo cp work/rpi/$CMDLINE work/boot/" run_and_log_cmd "sudo cp work/rpi/$CMDLINE work/boot/"
# Mask udisks2.service, otherwise it will mount the inactive part and we # Mask udisks2.service, otherwise it will mount the inactive part and we
# might write an update while it is mounted which often result in # might write an update while it is mounted which often result in
# corruptions. # corruptions.
# #
# TODO: Find a way to only blacklist mmcblk0pX devices instead of masking # TODO: Find a way to only blacklist mmcblk0pX devices instead of masking
# the service. # the service.
run_and_log_cmd "sudo ln -sf /dev/null work/rootfs/etc/systemd/system/udisks2.service" run_and_log_cmd "sudo ln -sf /dev/null work/rootfs/etc/systemd/system/udisks2.service"
# Ubuntu Server images actually use U-boot by default on RPi3 and the # Ubuntu Server images actually use U-boot by default on RPi3 and the
# layout is slightly different on the boot partition. That is why we need # layout is slightly different on the boot partition. That is why we need
# additional logic here to determine what we are converting. # additional logic here to determine what we are converting.
if [ -e work/boot/uboot_rpi_4_32b.bin ] && [ -e work/boot/vmlinuz ]; then if [ -e work/boot/uboot_rpi_4_32b.bin ] && [ -e work/boot/vmlinuz ]; then
RASPBERRYPI_KERNEL_IMAGE="vmlinuz" RASPBERRYPI_KERNEL_IMAGE="vmlinuz"
RASPBERRYPI_BOOTLOADER_IMAGE="uboot_rpi_4_32b.bin" RASPBERRYPI_BOOTLOADER_IMAGE="uboot_rpi_4_32b.bin"
elif [ -e work/boot/uboot.bin ] && [ -e work/boot/vmlinuz ]; then elif [ -e work/boot/uboot.bin ] && [ -e work/boot/vmlinuz ]; then
RASPBERRYPI_KERNEL_IMAGE="vmlinuz" RASPBERRYPI_KERNEL_IMAGE="vmlinuz"
RASPBERRYPI_BOOTLOADER_IMAGE="uboot.bin" RASPBERRYPI_BOOTLOADER_IMAGE="uboot.bin"
else else
RASPBERRYPI_BOOTLOADER_IMAGE="${RASPBERRYPI_KERNEL_IMAGE}" RASPBERRYPI_BOOTLOADER_IMAGE="${RASPBERRYPI_KERNEL_IMAGE}"
fi fi
# Extract Linux kernel and install to /boot directory on rootfs if it doesn't already exist. # Extract Linux kernel and install to /boot directory on rootfs if it doesn't already exist.
# If it already exists, the input image is likely already converted so we just want to use # If it already exists, the input image is likely already converted so we just want to use
# the existing kernel image. # the existing kernel image.
if [ ! -f "work/rootfs/boot/${MENDER_KERNEL_IMAGETYPE}" ]; then if [ ! -f "work/rootfs/boot/${MENDER_KERNEL_IMAGETYPE}" ]; then
run_and_log_cmd "sudo cp work/boot/${RASPBERRYPI_KERNEL_IMAGE} work/rootfs/boot/${MENDER_KERNEL_IMAGETYPE}" run_and_log_cmd "sudo cp work/boot/${RASPBERRYPI_KERNEL_IMAGE} work/rootfs/boot/${MENDER_KERNEL_IMAGETYPE}"
fi fi
# Replace kernel with U-boot and add boot script # Replace kernel with U-boot and add boot script
run_and_log_cmd "sudo mkdir -p work/rootfs/uboot" run_and_log_cmd "sudo mkdir -p work/rootfs/uboot"
run_and_log_cmd "sudo cp work/rpi/binaries/u-boot.bin work/boot/${RASPBERRYPI_BOOTLOADER_IMAGE}" run_and_log_cmd "sudo cp work/rpi/binaries/u-boot.bin work/boot/${RASPBERRYPI_BOOTLOADER_IMAGE}"
run_and_log_cmd "sudo cp work/rpi/binaries/boot.scr work/boot" run_and_log_cmd "sudo cp work/rpi/binaries/boot.scr work/boot"
run_and_log_cmd "sudo cp work/rpi/binaries/fw_env.config work/rootfs/etc/" run_and_log_cmd "sudo cp work/rpi/binaries/fw_env.config work/rootfs/etc/"
run_and_log_cmd "sudo cp work/rpi/binaries/uboot-git-log.txt work/boot" run_and_log_cmd "sudo cp work/rpi/binaries/uboot-git-log.txt work/boot"
# Raspberry Pi applications expect to find this on the device and in some # Raspberry Pi applications expect to find this on the device and in some
# cases parse the options to determine the functionality. # cases parse the options to determine the functionality.
run_and_log_cmd "sudo ln -fs /uboot/config.txt work/rootfs/boot/config.txt" run_and_log_cmd "sudo ln -fs /uboot/config.txt work/rootfs/boot/config.txt"
run_and_log_cmd "sudo ln -fs /uboot/overlays work/rootfs/boot/overlays" run_and_log_cmd "sudo ln -fs /uboot/overlays work/rootfs/boot/overlays"
run_and_log_cmd "sudo ln -fs /uboot/$CMDLINE work/rootfs/boot/$CMDLINE" run_and_log_cmd "sudo ln -fs /uboot/$CMDLINE work/rootfs/boot/$CMDLINE"
run_and_log_cmd "sudo install -m 755 work/rpi/binaries/fw_printenv work/rootfs/sbin/fw_printenv" run_and_log_cmd "sudo install -m 755 work/rpi/binaries/fw_printenv work/rootfs/sbin/fw_printenv"
run_and_log_cmd "sudo ln -fs /sbin/fw_printenv work/rootfs/sbin/fw_setenv" run_and_log_cmd "sudo ln -fs /sbin/fw_printenv work/rootfs/sbin/fw_setenv"
# Remove original 'resize2fs_once' script and its symbolic link. # Remove original 'resize2fs_once' script and its symbolic link.
if [ -L work/rootfs/etc/rc3.d/S01resize2fs_once ]; then if [ -L work/rootfs/etc/rc3.d/S01resize2fs_once ]; then
run_and_log_cmd "sudo unlink work/rootfs/etc/rc3.d/S01resize2fs_once" run_and_log_cmd "sudo unlink work/rootfs/etc/rc3.d/S01resize2fs_once"
fi fi
run_and_log_cmd "sudo rm -f work/rootfs/etc/init.d/resize2fs_once" run_and_log_cmd "sudo rm -f work/rootfs/etc/init.d/resize2fs_once"
} }

20
configs/rockpro64_config

@ -11,22 +11,22 @@ ROCKPRO64_BINARIES="${ROCKPRO64_CONFIG}-2017.09.tar.gz"
ROCKPRO64_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/uboot/rockpro64/${ROCKPRO64_BINARIES}" ROCKPRO64_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/uboot/rockpro64/${ROCKPRO64_BINARIES}"
function platform_modify() { function platform_modify() {
mkdir -p work/rockpro64 mkdir -p work/rockpro64
run_and_log_cmd "wget -Nq ${ROCKPRO64_BINARIES_URL} -P work/rockpro64" run_and_log_cmd "wget -Nq ${ROCKPRO64_BINARIES_URL} -P work/rockpro64"
run_and_log_cmd "tar xzvf work/rockpro64/${ROCKPRO64_BINARIES} -C work/rockpro64" run_and_log_cmd "tar xzvf work/rockpro64/${ROCKPRO64_BINARIES} -C work/rockpro64"
run_and_log_cmd "sudo cp work/rockpro64/boot.scr work/boot" run_and_log_cmd "sudo cp work/rockpro64/boot.scr work/boot"
run_and_log_cmd "sudo cp work/rockpro64/fw_env.config work/rootfs/etc/" run_and_log_cmd "sudo cp work/rockpro64/fw_env.config work/rootfs/etc/"
# It is not possible to resize rootfs part when using Mender. so disable # It is not possible to resize rootfs part when using Mender. so disable
# the service # the service
run_and_log_cmd "sudo touch work/rootfs/root/.no_rootfs_resize" run_and_log_cmd "sudo touch work/rootfs/root/.no_rootfs_resize"
} }
function platform_package() { function platform_package() {
log_info "Embedding bootloader in disk image" log_info "Embedding bootloader in disk image"
run_and_log_cmd "dd if=work/rockpro64/rksd_loader.img of=${img_path} \ run_and_log_cmd "dd if=work/rockpro64/rksd_loader.img of=${img_path} \
seek=64 conv=notrunc status=none" seek=64 conv=notrunc status=none"
} }

70
mender-convert

@ -38,7 +38,7 @@ MENDER_CONVERT_VERSION="${MENDER_CONVERT_VERSION:-}" # Required env variable
############################################################################### ###############################################################################
function show_help() { function show_help() {
cat << EOF cat << EOF
mender-convert mender-convert
A tool that takes an existing embedded image (Debian, Ubuntu, Raspbian, etc) A tool that takes an existing embedded image (Debian, Ubuntu, Raspbian, etc)
@ -61,21 +61,21 @@ EOF
} }
function show_version() { function show_version() {
echo "Version: ${MENDER_CONVERT_VERSION}" echo "Version: ${MENDER_CONVERT_VERSION}"
} }
function trap_exit() { function trap_exit() {
EXIT_CODE=$? EXIT_CODE=$?
if [[ ${EXIT_CODE} -ne 0 && ${EXIT_CODE} -ne ${FATAL_EXIT_CODE} ]]; then if [[ ${EXIT_CODE} -ne 0 && ${EXIT_CODE} -ne ${FATAL_EXIT_CODE} ]]; then
log_error "mender-convert failed" log_error "mender-convert failed"
[ -e ${MENDER_CONVERT_LOG_FILE} ] && tac ${MENDER_CONVERT_LOG_FILE} | sed '/DEBUG/q' | tac | sed 's/Running/When running/' [ -e ${MENDER_CONVERT_LOG_FILE} ] && tac ${MENDER_CONVERT_LOG_FILE} | sed '/DEBUG/q' | tac | sed 's/Running/When running/'
log_error "mender-convert exit code: ${EXIT_CODE}" log_error "mender-convert exit code: ${EXIT_CODE}"
fi fi
sudo rm -rf work/* sudo rm -rf work/*
} }
function trap_term() { function trap_term() {
echo "Program interrupted by user" echo "Program interrupted by user"
} }
trap trap_term INT TERM trap trap_term INT TERM
@ -83,40 +83,40 @@ trap trap_exit EXIT
source modules/git.sh source modules/git.sh
if [ -z "$MENDER_CONVERT_VERSION" ];then if [ -z "$MENDER_CONVERT_VERSION" ]; then
MENDER_CONVERT_VERSION=$(git_mender_convert_version) MENDER_CONVERT_VERSION=$(git_mender_convert_version)
fi fi
# We only handle a selection of the arguments here, the rest are passed on # We only handle a selection of the arguments here, the rest are passed on
# to the sub-scripts. # to the sub-scripts.
while (("$#")); do while (("$#")); do
case "$1" in case "$1" in
-h | --help) -h | --help)
show_help show_help
exit 0 exit 0
;; ;;
-v | --version) -v | --version)
show_version show_version
exit 0 exit 0
;; ;;
*) *)
break break
;; ;;
esac esac
done done
mender_convert_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) mender_convert_dir=$( cd "$( dirname "${BASH_SOURCE[0]}")" && pwd)
if [ "${mender_convert_dir}" != "${PWD}" ]; then if [ "${mender_convert_dir}" != "${PWD}" ]; then
echo "You must execute mender-convert from the root directory: ${mender_convert_dir}" echo "You must execute mender-convert from the root directory: ${mender_convert_dir}"
exit 1 exit 1
fi fi
if [ -z "${MENDER_ARTIFACT_NAME}" ]; then if [ -z "${MENDER_ARTIFACT_NAME}" ]; then
echo "Sorry, it seems that you have not defined MENDER_ARTIFACT_NAME" echo "Sorry, it seems that you have not defined MENDER_ARTIFACT_NAME"
echo "You can do this with the following command:" echo "You can do this with the following command:"
echo "" echo ""
echo -e "\tMENDER_ARTIFACT_NAME=\"release-1\" ./mender-convert" echo -e "\tMENDER_ARTIFACT_NAME=\"release-1\" ./mender-convert"
exit 1 exit 1
fi fi
testscfg_init testscfg_init
@ -125,8 +125,8 @@ parse_cli_options "$@"
compression_type=$(compression_type "${disk_image}") compression_type=$(compression_type "${disk_image}")
if [[ ${compression_type} != "none" ]]; then if [[ ${compression_type} != "none" ]]; then
uncompressed_disk_image=$(decompress_image "${disk_image}" "./work") uncompressed_disk_image=$(decompress_image "${disk_image}" "./work")
append_extraargs="--disk-image ${uncompressed_disk_image}" append_extraargs="--disk-image ${uncompressed_disk_image}"
fi fi
echo "MENDER_COMPRESS_DISK_IMAGE=${compression_type}" > ${ocfile} echo "MENDER_COMPRESS_DISK_IMAGE=${compression_type}" > ${ocfile}
prepend_extraargs="--config ${ocfile}" prepend_extraargs="--config ${ocfile}"

56
modules/cliparser.sh

@ -13,35 +13,35 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
function parse_cli_options () { function parse_cli_options() {
while (( "$#" )); do while (("$#")); do
case "$1" in case "$1" in
-o | --overlay) -o | --overlay)
overlays+=("${2}") overlays+=("${2}")
shift 2 shift 2
;; ;;
-c | --config) -c | --config)
configs+=("${2}") configs+=("${2}")
shift 2 shift 2
;; ;;
-d | --disk-image) -d | --disk-image)
disk_image="${2}" disk_image="${2}"
shift 2 shift 2
;; ;;
*) *)
log_fatal "Sorry but the provided option is not supported: $1" log_fatal "Sorry but the provided option is not supported: $1"
;; ;;
esac esac
done done
if [ -z "${disk_image}" ]; then if [ -z "${disk_image}" ]; then
log_warn "Sorry, but '--disk-image' is a mandatory option" log_warn "Sorry, but '--disk-image' is a mandatory option"
log_warn "See ./mender-convert --help for more information" log_warn "See ./mender-convert --help for more information"
exit 1 exit 1
fi fi
if [ ! -e ${disk_image} ]; then if [ ! -e ${disk_image} ]; then
log_fatal "File not found: ${disk_image}" log_fatal "File not found: ${disk_image}"
fi fi
} }

5
modules/config.sh

@ -17,11 +17,10 @@
# Read in the array of config files to process # Read in the array of config files to process
read -a configs <<< "${@}" read -a configs <<< "${@}"
for config in "${configs[@]}"; do for config in "${configs[@]}"; do
log_info "Using configuration file: ${config}" log_info "Using configuration file: ${config}"
source "${config}" source "${config}"
done done
# Fine grained partition variables override device/number variables where applicable # Fine grained partition variables override device/number variables where applicable
disk_override_partition_variable "MENDER_BOOT_PART_NUMBER" "${MENDER_BOOT_PART}" disk_override_partition_variable "MENDER_BOOT_PART_NUMBER" "${MENDER_BOOT_PART}"
disk_override_partition_variable "MENDER_ROOTFS_PART_A_NUMBER" "${MENDER_ROOTFS_PART_A}" disk_override_partition_variable "MENDER_ROOTFS_PART_A_NUMBER" "${MENDER_ROOTFS_PART_A}"

106
modules/deb.sh

@ -26,32 +26,32 @@ source modules/log.sh
# #
# @return - Filename of the downloaded package # @return - Filename of the downloaded package
# #
function deb_from_repo_dist_get () { function deb_from_repo_dist_get() {
if [[ $# -lt 5 || $# -gt 7 ]]; then if [[ $# -lt 5 || $# -gt 7 ]]; then
log_fatal "deb_from_repo_dist_get() requires 5 arguments" log_fatal "deb_from_repo_dist_get() requires 5 arguments"
fi fi
local -r download_dir="${1}" local -r download_dir="${1}"
local -r repo_url="${2}" local -r repo_url="${2}"
local -r architecture="${3}" local -r architecture="${3}"
local -r distribution="${4}" local -r distribution="${4}"
local -r package="${5}" local -r package="${5}"
local -r component="${6:-main}" local -r component="${6:-main}"
# Fetch and parse the packages list of the given distribution to find the latest version # Fetch and parse the packages list of the given distribution to find the latest version
local -r packages_url="${repo_url}/dists/${distribution}/${component}/binary-${architecture}/Packages" local -r packages_url="${repo_url}/dists/${distribution}/${component}/binary-${architecture}/Packages"
run_and_log_cmd "wget -Nq ${packages_url} -P /tmp" run_and_log_cmd "wget -Nq ${packages_url} -P /tmp"
local -r deb_package_path=$(grep Filename /tmp/Packages | grep ${package}_ | grep ${architecture} | tail -n1 | sed 's/Filename: //') local -r deb_package_path=$(grep Filename /tmp/Packages | grep ${package}_ | grep ${architecture} | tail -n1 | sed 's/Filename: //')
if [ -z "${deb_package_path}" ]; then if [ -z "${deb_package_path}" ]; then
log_fatal "Couldn't find package ${package} in ${packages_url}" log_fatal "Couldn't find package ${package} in ${packages_url}"
fi fi
local -r filename=$(basename $deb_package_path) local -r filename=$(basename $deb_package_path)
run_and_log_cmd "wget -Nq ${repo_url}/${deb_package_path} -P ${download_dir}" run_and_log_cmd "wget -Nq ${repo_url}/${deb_package_path} -P ${download_dir}"
rm -f /tmp/Packages rm -f /tmp/Packages
log_info "Successfully downloaded ${filename}" log_info "Successfully downloaded ${filename}"
echo ${filename} echo ${filename}
} }
# Download a deb package direcrly from the pool of an APT repository # Download a deb package direcrly from the pool of an APT repository
@ -65,26 +65,26 @@ function deb_from_repo_dist_get () {
# #
# @return - Filename of the downloaded package # @return - Filename of the downloaded package
# #
function deb_from_repo_pool_get () { function deb_from_repo_pool_get() {
if [[ $# -ne 5 ]]; then if [[ $# -ne 5 ]]; then
log_fatal "deb_from_repo_pool_get() requires 5 arguments" log_fatal "deb_from_repo_pool_get() requires 5 arguments"
fi fi
local -r download_dir="${1}" local -r download_dir="${1}"
local -r repo_url="${2}" local -r repo_url="${2}"
local -r architecture="${3}" local -r architecture="${3}"
local -r package="${4}" local -r package="${4}"
local -r version="${5}" local -r version="${5}"
local -r component="${6:-main}" local -r component="${6:-main}"
local -r initial="$(echo $package | head -c 1)" local -r initial="$(echo $package | head -c 1)"
local -r deb_package_path="pool/${component}/${initial}/${package}/${package}_${version}_${architecture}.deb" local -r deb_package_path="pool/${component}/${initial}/${package}/${package}_${version}_${architecture}.deb"
local -r filename=$(basename $deb_package_path) local -r filename=$(basename $deb_package_path)
run_and_log_cmd "wget -Nq ${repo_url}/${deb_package_path} -P ${download_dir}" run_and_log_cmd "wget -Nq ${repo_url}/${deb_package_path} -P ${download_dir}"
rm -f /tmp/Packages rm -f /tmp/Packages
log_info "Successfully downloaded ${filename}" log_info "Successfully downloaded ${filename}"
echo ${filename} echo ${filename}
} }
# Extract the binary files of a deb package into a directory # Extract the binary files of a deb package into a directory
@ -92,21 +92,21 @@ function deb_from_repo_pool_get () {
# $1 - Deb package # $1 - Deb package
# $2 - Dest directory # $2 - Dest directory
# #
function deb_extract_package () { function deb_extract_package() {
if [[ $# -ne 2 ]]; then if [[ $# -ne 2 ]]; then
log_fatal "deb_extract_package() requires 2 arguments" log_fatal "deb_extract_package() requires 2 arguments"
fi fi
local -r deb_package="$(pwd)/${1}" local -r deb_package="$(pwd)/${1}"
local -r dest_dir="$(pwd)/${2}" local -r dest_dir="$(pwd)/${2}"
local -r extract_dir=$(mktemp -d) local -r extract_dir=$(mktemp -d)
cd ${extract_dir} cd ${extract_dir}
run_and_log_cmd "ar -xv ${deb_package}" run_and_log_cmd "ar -xv ${deb_package}"
mkdir -p files mkdir -p files
run_and_log_cmd "sudo tar xJf data.tar.xz -C files" run_and_log_cmd "sudo tar xJf data.tar.xz -C files"
cd - > /dev/null 2>&1 cd - > /dev/null 2>&1
run_and_log_cmd "sudo rsync --archive --keep-dirlinks --verbose ${extract_dir}/files/ ${dest_dir}" run_and_log_cmd "sudo rsync --archive --keep-dirlinks --verbose ${extract_dir}/files/ ${dest_dir}"
log_info "Successfully installed $(basename ${filename})" log_info "Successfully installed $(basename ${filename})"
} }

108
modules/decompressinput.sh

@ -22,28 +22,28 @@ source modules/log.sh
# #
# @return - The MENDER_COMPRESS_IMAGE compression type # @return - The MENDER_COMPRESS_IMAGE compression type
# #
function compression_type () { function compression_type() {
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
log_fatal "compression_type() requires one argument" log_fatal "compression_type() requires one argument"
fi fi
local -r disk_image="${1}" local -r disk_image="${1}"
case "${disk_image}" in case "${disk_image}" in
*.img | *.sdimg | *.wic | *.rpi-sdimg) *.img | *.sdimg | *.wic | *.rpi-sdimg)
echo "none" echo "none"
;; ;;
*.gz) *.gz)
echo "gzip" echo "gzip"
;; ;;
*.zip) *.zip)
echo "zip" echo "zip"
;; ;;
*.xz ) *.xz)
echo "lzma" echo "lzma"
;; ;;
* ) *)
log_fatal "Unsupported compression type: ${disk_image}. Please uncompress the image yourself." log_fatal "Unsupported compression type: ${disk_image}. Please uncompress the image yourself."
;; ;;
esac esac
} }
# Decompresses the given input image # Decompresses the given input image
@ -53,36 +53,36 @@ function compression_type () {
# #
# @return - Name of the uncompressed image # @return - Name of the uncompressed image
# #
function decompress_image () { function decompress_image() {
if [[ $# -ne 2 ]]; then if [[ $# -ne 2 ]]; then
log_fatal "decompress_image() requires an image argument and an output directory" log_fatal "decompress_image() requires an image argument and an output directory"
fi fi
local -r input_image="${1}" local -r input_image="${1}"
local -r output_dir="${2}" local -r output_dir="${2}"
local disk_image="${output_dir}/$(basename ${input_image})" local disk_image="${output_dir}/$(basename ${input_image})"
case "$(compression_type ${disk_image})" in case "$(compression_type ${disk_image})" in
none ) none)
: :
;; ;;
gzip ) gzip)
log_info "Decompressing ${disk_image}..." log_info "Decompressing ${disk_image}..."
disk_image=${disk_image%.gz} disk_image=${disk_image%.gz}
zcat "${input_image}" > "${disk_image}" zcat "${input_image}" > "${disk_image}"
;; ;;
zip ) zip)
log_info "Decompressing ${disk_image}..." log_info "Decompressing ${disk_image}..."
filename="$(zip_get_imgname ${input_image})" filename="$(zip_get_imgname ${input_image})"
unzip "${input_image}" -d "${output_dir}" &>/dev/null unzip "${input_image}" -d "${output_dir}" &> /dev/null
disk_image="$(dirname ${disk_image})/${filename}" disk_image="$(dirname ${disk_image})/${filename}"
;; ;;
lzma ) lzma)
log_info "Decompressing ${disk_image}..." log_info "Decompressing ${disk_image}..."
disk_image=${disk_image%.xz} disk_image=${disk_image%.xz}
xzcat "${input_image}" > "${disk_image}" xzcat "${input_image}" > "${disk_image}"
;; ;;
* ) *)
log_fatal "Unsupported input image format: ${input_image}. We support: '.img', '.gz', '.zip', '.xz'." log_fatal "Unsupported input image format: ${input_image}. We support: '.img', '.gz', '.zip', '.xz'."
;; ;;
esac esac
echo "${disk_image}" echo "${disk_image}"
} }

265
modules/disk.sh

@ -37,7 +37,7 @@
# FLAGS partition flags # FLAGS partition flags
# SCHEME partition table type (dos, gpt, ...) # SCHEME partition table type (dos, gpt, ...)
disk_get_part_value() { disk_get_part_value() {
echo "$(partx -o ${3} -g -r --nr ${2} ${1})" echo "$(partx -o ${3} -g -r --nr ${2} ${1})"
} }
# Prints the partition numbers of all the partitions # Prints the partition numbers of all the partitions
@ -48,11 +48,10 @@ disk_get_part_value() {
# #
# $1 - path to disk image # $1 - path to disk image
disk_get_part_nums() { disk_get_part_nums() {
partx --show $1 | tail -n +2 | partx --show $1 | tail -n +2 \
while read line | while read line; do
do echo $line | awk '{printf "%d\n", $1}'
echo $line | awk '{printf "%d\n", $1}' done
done
} }
# Extract a file system image from a disk image # Extract a file system image from a disk image
@ -62,21 +61,21 @@ disk_get_part_nums() {
# $3 - size (in 512 blocks) # $3 - size (in 512 blocks)
# $4 - path to output file # $4 - path to output file
disk_extract_part() { disk_extract_part() {
run_and_log_cmd "dd if=$1 of=$4 skip=$2 bs=512 count=$3 conv=sparse status=none" run_and_log_cmd "dd if=$1 of=$4 skip=$2 bs=512 count=$3 conv=sparse status=none"
} }
# Convert MiB to number of 512 sectors # Convert MiB to number of 512 sectors
# #
# $1 - MiB value # $1 - MiB value
disk_mb_to_sectors() { disk_mb_to_sectors() {
echo "$(( (${1} * 1024 * 1024) / 512 ))" echo "$(((${1} * 1024 * 1024) / 512))"
} }
# Convert 512 sectors to MiB # Convert 512 sectors to MiB
# #
# $1 - number of 512 sectors # $1 - number of 512 sectors
disk_sectors_to_mb() { disk_sectors_to_mb() {
echo "$(( (${1} * 512) / 1024 / 1024 ))" echo "$(((${1} * 512) / 1024 / 1024))"
} }
# Align value (result is number of 512 sectors) # Align value (result is number of 512 sectors)
@ -84,14 +83,14 @@ disk_sectors_to_mb() {
# $1 - value to align (number of 512 sectors) # $1 - value to align (number of 512 sectors)
# $2 - alignment in bytes # $2 - alignment in bytes
disk_align_sectors() { disk_align_sectors() {
local size_in_bytes=$(( ${1} * 512)) local size_in_bytes=$((${1} * 512))
local reminder=$(( ${size_in_bytes} % ${2} )) local reminder=$((${size_in_bytes} % ${2}))
if [ $reminder -ne 0 ]; then if [ $reminder -ne 0 ]; then
size_in_bytes=$(( $size_in_bytes - $reminder + ${2} )) size_in_bytes=$(($size_in_bytes - $reminder + ${2}))
fi fi
echo "$(( $size_in_bytes / 512 ))" echo "$(($size_in_bytes / 512))"
} }
# Write file at offset of another file # Write file at offset of another file
@ -100,7 +99,7 @@ disk_align_sectors() {
# $2 - destination file # $2 - destination file
# $3 - offset in number of 512 sectors # $3 - offset in number of 512 sectors
disk_write_at_offset() { disk_write_at_offset() {
run_and_log_cmd "dd if=${1} of=${2} seek=${3} conv=notrunc status=none" run_and_log_cmd "dd if=${1} of=${2} seek=${3} conv=notrunc status=none"
} }
# Create file system image from directory content # Create file system image from directory content
@ -110,144 +109,138 @@ disk_write_at_offset() {
# $3 - image size in sectors # $3 - image size in sectors
# $4 - file system type, e.g ext4, xfs, ... # $4 - file system type, e.g ext4, xfs, ...
disk_create_file_system_from_folder() { disk_create_file_system_from_folder() {
log_info "Creating a file-system image from: ${1}" log_info "Creating a file-system image from: ${1}"
run_and_log_cmd "dd if=/dev/zero of=${2} seek=${3} count=0 bs=512 status=none" run_and_log_cmd "dd if=/dev/zero of=${2} seek=${3} count=0 bs=512 status=none"
case ${1} in case ${1} in
*data/ ) EXTRA_OPTS="${MENDER_DATA_PART_MKFS_OPTS}";; *data/) EXTRA_OPTS="${MENDER_DATA_PART_MKFS_OPTS}" ;;
*rootfs/ ) EXTRA_OPTS="${MENDER_ROOT_PART_MKFS_OPTS}";; *rootfs/) EXTRA_OPTS="${MENDER_ROOT_PART_MKFS_OPTS}" ;;
* ) EXTRA_OPTS="";; *) EXTRA_OPTS="" ;;
esac esac
case "$4" in case "$4" in
"ext4") "ext4")
MKFS_EXT4="/usr/bin/mkfs.ext4" MKFS_EXT4="/usr/bin/mkfs.ext4"
if [ ! -f ${MKFS_EXT4} ]; then if [ ! -f ${MKFS_EXT4} ]; then
MKFS_EXT4="/sbin/mkfs.ext4" MKFS_EXT4="/sbin/mkfs.ext4"
fi fi
run_and_log_cmd "${MKFS_EXT4} -q -F ${2} ${EXTRA_OPTS}" run_and_log_cmd "${MKFS_EXT4} -q -F ${2} ${EXTRA_OPTS}"
;; ;;
"xfs") "xfs")
MKFS_XFS="/usr/bin/mkfs.xfs" MKFS_XFS="/usr/bin/mkfs.xfs"
if [ ! -f ${MKFS_XFS} ]; then if [ ! -f ${MKFS_XFS} ]; then
MKFS_XFS="/sbin/mkfs.xfs" MKFS_XFS="/sbin/mkfs.xfs"
fi fi
run_and_log_cmd "${MKFS_XFS} -q -f ${2} ${EXTRA_OPTS}" run_and_log_cmd "${MKFS_XFS} -q -f ${2} ${EXTRA_OPTS}"
;; ;;
*) *)
log_fatal "Unknown file system type specified: ${4}" log_fatal "Unknown file system type specified: ${4}"
;; ;;
esac esac
run_and_log_cmd "mkdir -p work/output" run_and_log_cmd "mkdir -p work/output"
run_and_log_cmd "sudo mount ${2} work/output" run_and_log_cmd "sudo mount ${2} work/output"
run_and_log_cmd "sudo rsync --archive --delete ${1} work/output/" run_and_log_cmd "sudo rsync --archive --delete ${1} work/output/"
run_and_log_cmd "sudo umount work/output" run_and_log_cmd "sudo umount work/output"
} }
# Print path to the boot partition filesystem image # Print path to the boot partition filesystem image
# #
disk_boot_part() { disk_boot_part() {
# Why this little dance you might wonder. # Why this little dance you might wonder.
# #
# Some disk images do not have a boot partition, but our integration does # Some disk images do not have a boot partition, but our integration does
# require one and this is why there is a difference here. # require one and this is why there is a difference here.
# #
# If input image did not have a boot part it will be generated and be called: # If input image did not have a boot part it will be generated and be called:
# #
# work/boot-generated.vfat # work/boot-generated.vfat
# #
# This is mostly done to make it obvious that we have created an empty vfat file. # This is mostly done to make it obvious that we have created an empty vfat file.
# #
# But if the disk image already had a boot part, we assume that it is the first # But if the disk image already had a boot part, we assume that it is the first
# partition that was extracted. # partition that was extracted.
# #
# We also need to adjust the part number of the rootfs part depending on if # We also need to adjust the part number of the rootfs part depending on if
# boot part was extracted or generated. # boot part was extracted or generated.
boot_part="work/boot-generated.vfat" boot_part="work/boot-generated.vfat"
if [ ! -f ${boot_part} ]; then if [ ! -f ${boot_part} ]; then
boot_part="work/part-1.fs" boot_part="work/part-1.fs"
fi fi
echo "${boot_part}" echo "${boot_part}"
} }
# Print path to the root partition filesystem image # Print path to the root partition filesystem image
# #
disk_root_part() { disk_root_part() {
boot_part="work/boot-generated.vfat" boot_part="work/boot-generated.vfat"
if [ ! -f ${boot_part} ]; then if [ ! -f ${boot_part} ]; then
root_part="work/part-2.fs" root_part="work/part-2.fs"
else else
root_part="work/part-1.fs" root_part="work/part-1.fs"
fi fi
echo "${root_part}" echo "${root_part}"
} }
# Check if supplied argument is valid partuuid device path. # Check if supplied argument is valid partuuid device path.
# Supports both dos and gpt paths # Supports both dos and gpt paths
# #
# $1 - partuuid device path # $1 - partuuid device path
disk_is_valid_partuuid_device() { disk_is_valid_partuuid_device() {
disk_is_valid_partuuid_gpt_device "$1" || disk_is_valid_partuuid_dos_device "$1" disk_is_valid_partuuid_gpt_device "$1" || disk_is_valid_partuuid_dos_device "$1"
} }
# Check if supplied argument is valid gpt partuuid device path. # Check if supplied argument is valid gpt partuuid device path.
# #
# Example: /dev/disk/by-partuuid/26445670-f37c-408b-be2c-3ef419866620 # Example: /dev/disk/by-partuuid/26445670-f37c-408b-be2c-3ef419866620
# #
# $1 - gpt partuuid device path # $1 - gpt partuuid device path
disk_is_valid_partuuid_gpt_device() { disk_is_valid_partuuid_gpt_device() {
echo "${1}" | grep -qE '^/dev/disk/by-partuuid/([0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12})$' echo "${1}" | grep -qE '^/dev/disk/by-partuuid/([0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12})$'
} }
# Check if supplied argument is valid dos partuuid device path. # Check if supplied argument is valid dos partuuid device path.
# #
# Example: /dev/disk/by-partuuid/26445670-01 # Example: /dev/disk/by-partuuid/26445670-01
# #
# $1 - dos partuuid device path # $1 - dos partuuid device path
disk_is_valid_partuuid_dos_device() { disk_is_valid_partuuid_dos_device() {
echo "${1}" | grep -qE '^/dev/disk/by-partuuid/[0-9a-f]{8}-[0-9a-f]{2}$' echo "${1}" | grep -qE '^/dev/disk/by-partuuid/[0-9a-f]{8}-[0-9a-f]{2}$'
} }
# Get partuuid from supplied device path. # Get partuuid from supplied device path.
# Supports both dos and gpt paths # Supports both dos and gpt paths
# #
# $1 - partuuid device path # $1 - partuuid device path
disk_get_partuuid_from_device() { disk_get_partuuid_from_device() {
if ! disk_is_valid_partuuid_device "${1}"; then if ! disk_is_valid_partuuid_device "${1}"; then
log_fatal "Invalid partuuid device: '${1}'" log_fatal "Invalid partuuid device: '${1}'"
fi fi
echo "${1}" | sed "s:/dev/disk/by-partuuid/::" echo "${1}" | sed "s:/dev/disk/by-partuuid/::"
} }
# Get dos disk identifier from supplied device path. # Get dos disk identifier from supplied device path.
# #
# $1 - dos compatible partuuid device path # $1 - dos compatible partuuid device path
disk_get_partuuid_dos_diskid_from_device() { disk_get_partuuid_dos_diskid_from_device() {
if ! disk_is_valid_partuuid_dos_device "${1}"; then if ! disk_is_valid_partuuid_dos_device "${1}"; then
log_fatal "Invalid dos partuuid device: '${1}'" log_fatal "Invalid dos partuuid device: '${1}'"
fi fi
partuuid=$(disk_get_partuuid_from_device "${1}") partuuid=$(disk_get_partuuid_from_device "${1}")
echo "$partuuid" | cut -d- -f1 echo "$partuuid" | cut -d- -f1
} }
# Get dos partuuid number from supplied device path. # Get dos partuuid number from supplied device path.
# #
# $1 - dos compatible partuuid device path # $1 - dos compatible partuuid device path
disk_get_partuuid_dos_part_number() { disk_get_partuuid_dos_part_number() {
if ! disk_is_valid_partuuid_dos_device "${1}"; then if ! disk_is_valid_partuuid_dos_device "${1}"; then
log_fatal "Invalid dos partuuid device: '${1}'" log_fatal "Invalid dos partuuid device: '${1}'"
fi fi
partuuid=$(disk_get_partuuid_from_device "${1}") partuuid=$(disk_get_partuuid_from_device "${1}")
echo "$partuuid" | cut -d- -f2 echo "$partuuid" | cut -d- -f2
} }
# Get correct device path for current configuration. # Get correct device path for current configuration.
@ -256,34 +249,33 @@ disk_get_partuuid_dos_part_number() {
# $1 - partition number to use if fine grained variable not set # $1 - partition number to use if fine grained variable not set
# $2 - fine grained device part variable name # $2 - fine grained device part variable name
disk_get_part_device() { disk_get_part_device() {
part="${!2}" part="${!2}"
if [ "${MENDER_ENABLE_PARTUUID}" == "y" ]; then if [ "${MENDER_ENABLE_PARTUUID}" == "y" ]; then
if ! disk_is_valid_partuuid_device "${part}"; then if ! disk_is_valid_partuuid_device "${part}"; then
log_fatal "Invalid partuuid device for ${2}: '${part}'" log_fatal "Invalid partuuid device for ${2}: '${part}'"
fi fi
else else
part="${MENDER_STORAGE_DEVICE_BASE}${1}" part="${MENDER_STORAGE_DEVICE_BASE}${1}"
fi fi
echo "${part}" echo "${part}"
} }
disk_boot_part_device() { disk_boot_part_device() {
disk_get_part_device "${MENDER_BOOT_PART_NUMBER}" "MENDER_BOOT_PART" disk_get_part_device "${MENDER_BOOT_PART_NUMBER}" "MENDER_BOOT_PART"
} }
disk_data_part_device() { disk_data_part_device() {
disk_get_part_device "${MENDER_DATA_PART_NUMBER}" "MENDER_DATA_PART" disk_get_part_device "${MENDER_DATA_PART_NUMBER}" "MENDER_DATA_PART"
} }
disk_root_part_a_device() { disk_root_part_a_device() {
disk_get_part_device "${MENDER_ROOTFS_PART_A_NUMBER}" "MENDER_ROOTFS_PART_A" disk_get_part_device "${MENDER_ROOTFS_PART_A_NUMBER}" "MENDER_ROOTFS_PART_A"
} }
disk_root_part_b_device() { disk_root_part_b_device() {
disk_get_part_device "${MENDER_ROOTFS_PART_B_NUMBER}" "MENDER_ROOTFS_PART_B" disk_get_part_device "${MENDER_ROOTFS_PART_B_NUMBER}" "MENDER_ROOTFS_PART_B"
} }
# Get device partition number from device path. # Get device partition number from device path.
# Unrecognized or unsupported device paths will generate an error # Unrecognized or unsupported device paths will generate an error
# #
@ -291,28 +283,28 @@ disk_root_part_b_device() {
disk_get_device_part_number() { disk_get_device_part_number() {
dev_part="unknown" dev_part="unknown"
case "$1" in case "$1" in
/dev/nvme*n*p* ) /dev/nvme*n*p*)
dev_part=$(echo $1 | cut -dp -f2) dev_part=$(echo $1 | cut -dp -f2)
;; ;;
/dev/mmcblk*p* ) /dev/mmcblk*p*)
dev_part=$(echo $1 | cut -dp -f2) dev_part=$(echo $1 | cut -dp -f2)
;; ;;
/dev/[sh]d[a-z][1-9]* ) /dev/[sh]d[a-z][1-9]*)
dev_part=${1##*d[a-z]} dev_part=${1##*d[a-z]}
;; ;;
ubi*_* ) ubi*_*)
dev_part=$(echo $1 | cut -d_ -f2) dev_part=$(echo $1 | cut -d_ -f2)
;; ;;
/dev/disk/by-partuuid/* ) /dev/disk/by-partuuid/*)
if disk_is_valid_partuuid_dos_device "$1";then if disk_is_valid_partuuid_dos_device "$1"; then
dev_part=$(disk_get_partuuid_dos_part_number "$1") dev_part=$(disk_get_partuuid_dos_part_number "$1")
dev_part=$((16#${dev_part})) dev_part=$((16#${dev_part}))
else else
log_fatal "partition number does not exist for GPT partuuid: '$1'" log_fatal "partition number does not exist for GPT partuuid: '$1'"
fi fi
;; ;;
esac esac
part=$(printf "%d" $dev_part 2>/dev/null) part=$(printf "%d" $dev_part 2> /dev/null)
if [ $? = 1 ]; then if [ $? = 1 ]; then
log_fatal "Could not determine partition number from '${1}'" log_fatal "Could not determine partition number from '${1}'"
else else
@ -327,19 +319,19 @@ disk_get_device_part_number() {
disk_get_device_base() { disk_get_device_base() {
dev_base="" dev_base=""
case "$1" in case "$1" in
/dev/nvme*n*p* ) /dev/nvme*n*p*)
dev_base=$(echo $1 | cut -dp -f1) dev_base=$(echo $1 | cut -dp -f1)
;; ;;
/dev/mmcblk*p* ) /dev/mmcblk*p*)
dev_base=$(echo $1 | cut -dp -f1) dev_base=$(echo $1 | cut -dp -f1)
;; ;;
/dev/[sh]d[a-z][1-9]* ) /dev/[sh]d[a-z][1-9]*)
dev_base=${1%%[1-9]*} dev_base=${1%%[1-9]*}
;; ;;
ubi*_* ) ubi*_*)
dev_base=$(echo $1 | cut -d_ -f1) dev_base=$(echo $1 | cut -d_ -f1)
;; ;;
/dev/disk/by-partuuid/* ) /dev/disk/by-partuuid/*)
log_fatal "device base does not exist for GPT partuuid: '$1'" log_fatal "device base does not exist for GPT partuuid: '$1'"
;; ;;
esac esac
@ -350,20 +342,19 @@ disk_get_device_base() {
fi fi
} }
# Conditionally redefine partition number/device if fine grained variable set. # Conditionally redefine partition number/device if fine grained variable set.
# #
# $1 - variable name # $1 - variable name
# $2 - variable value # $2 - variable value
disk_override_partition_variable() { disk_override_partition_variable() {
if [ "${MENDER_ENABLE_PARTUUID}" == "y" ]; then if [ "${MENDER_ENABLE_PARTUUID}" == "y" ]; then
if disk_is_valid_partuuid_dos_device "${2}";then if disk_is_valid_partuuid_dos_device "${2}"; then
eval "${1}"=$(disk_get_device_part_number "${2}") eval "${1}"=$(disk_get_device_part_number "${2}")
fi fi
else else
if [ -n "${2}" ];then if [ -n "${2}" ]; then
eval "${1}"=$(disk_get_device_part_number "${2}") eval "${1}"=$(disk_get_device_part_number "${2}")
MENDER_STORAGE_DEVICE_BASE=$(disk_get_device_base "${2}") MENDER_STORAGE_DEVICE_BASE=$(disk_get_device_base "${2}")
fi fi
fi fi
} }

3
modules/git.sh

@ -14,9 +14,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# Print the mender convert version # Print the mender convert version
# #
git_mender_convert_version() { git_mender_convert_version() {
git describe --tags --dirty --exact-match 2>/dev/null || git rev-parse --short HEAD git describe --tags --dirty --exact-match 2> /dev/null || git rev-parse --short HEAD
} }

45
modules/log.sh

@ -18,7 +18,6 @@
# from sub-directories # from sub-directories
log_file="${MENDER_CONVERT_LOG_FILE:-${PWD}/work/convert.log}" log_file="${MENDER_CONVERT_LOG_FILE:-${PWD}/work/convert.log}"
# Add some colour to the log messages # Add some colour to the log messages
YELLOW='\033[1;33m' # Warning YELLOW='\033[1;33m' # Warning
@ -28,50 +27,50 @@ NC='\033[0m' # No Color
# Log the given message at the given level. # Log the given message at the given level.
function log { function log {
local -r level="$1" local -r level="$1"
local -r message="$2" local -r message="$2"
local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S") local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local -r script_name="$(basename "$0")" local -r script_name="$(basename "$0")"
echo -e "${timestamp} [${level}] [$script_name] ${message}" >> ${log_file} echo -e "${timestamp} [${level}] [$script_name] ${message}" >> ${log_file}
>&2 echo -e "${timestamp} [${level}] [$script_name] ${message}" echo >&2 -e "${timestamp} [${level}] [$script_name] ${message}"
} }
function local_log_debug { function local_log_debug {
local -r level="DEBUG" local -r level="DEBUG"
local -r message="$1" local -r message="$1"
local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S") local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S")
local -r script_name="$(basename "$0")" local -r script_name="$(basename "$0")"
echo -e "${timestamp} [${level}] [$script_name] ${message}" >> ${log_file} echo -e "${timestamp} [${level}] [$script_name] ${message}" >> ${log_file}
} }
# Log the given message at DEBUG level. # Log the given message at DEBUG level.
function log_debug { function log_debug {
local -r message="$1" local -r message="$1"
local_log_debug "$message" local_log_debug "$message"
} }
# Log the given message at INFO level. # Log the given message at INFO level.
function log_info { function log_info {
local -r message="$1" local -r message="$1"
log "INFO" "$message" log "INFO" "$message"
} }
# Log the given message at WARN level. # Log the given message at WARN level.
function log_warn { function log_warn {
local -r message="$1" local -r message="$1"
log "${YELLOW}WARN${NC}" "$message" log "${YELLOW}WARN${NC}" "$message"
} }
# Log the given message at ERROR level. # Log the given message at ERROR level.
function log_error { function log_error {
local -r message="$1" local -r message="$1"
log "${RED}ERROR${NC}" "$message" log "${RED}ERROR${NC}" "$message"
} }
# Log the given message at FATAL level. # Log the given message at FATAL level.
FATAL_EXIT_CODE=90 FATAL_EXIT_CODE=90
function log_fatal { function log_fatal {
local -r message="$1" local -r message="$1"
log "${IRED}FATAL${NC}" "$message" log "${IRED}FATAL${NC}" "$message"
exit ${FATAL_EXIT_CODE} exit ${FATAL_EXIT_CODE}
} }

420
modules/probe.sh

@ -19,34 +19,34 @@
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_arch() { probe_arch() {
# --dereference, means to follow symlinks because 'ls' could be a symlink # --dereference, means to follow symlinks because 'ls' could be a symlink
# to busybox # to busybox
file_info="" file_info=""
for location in bin/ls usr/bin/ls; do for location in bin/ls usr/bin/ls; do
if [ -L work/rootfs/${location} ]; then if [ -L work/rootfs/${location} ]; then
location=$(readlink work/rootfs/${location}) location=$(readlink work/rootfs/${location})
fi fi
if [ -e work/rootfs/${location} ]; then if [ -e work/rootfs/${location} ]; then
file_info=$(file -b --dereference work/rootfs/${location}) file_info=$(file -b --dereference work/rootfs/${location})
break break
fi fi
done done
if [ -z "${file_info}" ]; then if [ -z "${file_info}" ]; then
log_fatal "Sorry, not able to determine target architecture" log_fatal "Sorry, not able to determine target architecture"
fi fi
target_arch="unknown" target_arch="unknown"
if grep -q x86-64 <<< "${file_info}"; then if grep -q x86-64 <<< "${file_info}"; then
target_arch="x86-64" target_arch="x86-64"
elif grep -Eq "ELF 32-bit.*ARM" <<< "${file_info}"; then elif grep -Eq "ELF 32-bit.*ARM" <<< "${file_info}"; then
target_arch="arm" target_arch="arm"
elif grep -Eq "ELF 64-bit.*aarch64" <<< "${file_info}"; then elif grep -Eq "ELF 64-bit.*aarch64" <<< "${file_info}"; then
target_arch="aarch64" target_arch="aarch64"
else else
log_fatal "Unsupported architecture: ${file_info}" log_fatal "Unsupported architecture: ${file_info}"
fi fi
echo "${target_arch}" echo "${target_arch}"
} }
# Prints GRUB EFI name depending on target architecture # Prints GRUB EFI name depending on target architecture
@ -54,23 +54,23 @@ probe_arch() {
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_grub_efi_name() { probe_grub_efi_name() {
efi_name="" efi_name=""
arch=$(probe_arch) arch=$(probe_arch)
case "${arch}" in case "${arch}" in
"x86-64") "x86-64")
efi_name="grub-efi-bootx64.efi" efi_name="grub-efi-bootx64.efi"
;; ;;
"arm") "arm")
efi_name="grub-efi-bootarm.efi" efi_name="grub-efi-bootarm.efi"
;; ;;
"aarch64") "aarch64")
efi_name="grub-efi-bootaa64.efi" efi_name="grub-efi-bootaa64.efi"
;; ;;
*) *)
log_fatal "Unknown arch: ${arch}" log_fatal "Unknown arch: ${arch}"
;; ;;
esac esac
echo "$efi_name" echo "$efi_name"
} }
# Prints Debian arch name depending on target architecture # Prints Debian arch name depending on target architecture
@ -78,23 +78,23 @@ probe_grub_efi_name() {
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_debian_arch_name() { probe_debian_arch_name() {
deb_arch="" deb_arch=""
arch=$(probe_arch) arch=$(probe_arch)
case "${arch}" in case "${arch}" in
"x86-64") "x86-64")
deb_arch="amd64" deb_arch="amd64"
;; ;;
"arm") "arm")
deb_arch="armhf" deb_arch="armhf"
;; ;;
"aarch64") "aarch64")
deb_arch="arm64" deb_arch="arm64"
;; ;;
*) *)
log_fatal "Unknown arch: ${arch}" log_fatal "Unknown arch: ${arch}"
;; ;;
esac esac
echo "${deb_arch}" echo "${deb_arch}"
} }
# Prints GRUB EFI target name depending on target architecture # Prints GRUB EFI target name depending on target architecture
@ -104,23 +104,23 @@ probe_debian_arch_name() {
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_grub_efi_target_name() { probe_grub_efi_target_name() {
efi_target_name="" efi_target_name=""
arch=$(probe_arch) arch=$(probe_arch)
case "$arch" in case "$arch" in
"x86-64") "x86-64")
efi_target_name="bootx64.efi" efi_target_name="bootx64.efi"
;; ;;
"arm") "arm")
efi_target_name="bootarm.efi" efi_target_name="bootarm.efi"
;; ;;
"aarch64") "aarch64")
efi_target_name="bootaa64.efi" efi_target_name="bootaa64.efi"
;; ;;
*) *)
log_fatal "Unknown arch: ${arch}" log_fatal "Unknown arch: ${arch}"
;; ;;
esac esac
echo "$efi_target_name" echo "$efi_target_name"
} }
# Prints path to the Linux kernel image # Prints path to the Linux kernel image
@ -128,36 +128,36 @@ probe_grub_efi_target_name() {
# $1 - directory in which the search is performed # $1 - directory in which the search is performed
# #
probe_kernel_image() { probe_kernel_image() {
kernel_image_path="" kernel_image_path=""
for image in vmlinuz zImage bzImage; do for image in vmlinuz zImage bzImage; do
# Linux kernel image type and naming varies between different platforms. # Linux kernel image type and naming varies between different platforms.
# #
# The wildcard at the end is important, because it is common to suffix the # The wildcard at the end is important, because it is common to suffix the
# Linux kernel version to the image type/name, e.g: # Linux kernel version to the image type/name, e.g:
# #
# vmlinuz-4.14-x86_64 # vmlinuz-4.14-x86_64
# vmlinuz-3.10.0-862.el7.x86_64 # vmlinuz-3.10.0-862.el7.x86_64
# vmlinuz-4.15.0-20-generic # vmlinuz-4.15.0-20-generic
# #
#Search for kernels, resolve symlinks, ignore invalid and select the latest if many #Search for kernels, resolve symlinks, ignore invalid and select the latest if many
kernels=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' ! -name '*.old' \ kernels=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' ! -name '*.old' \
-exec readlink -f {} \; | awk -F '/' '{print $NF,$0}' | sort -k1rV | uniq) -exec readlink -f {} \; | awk -F '/' '{print $NF,$0}' | sort -k1rV | uniq)
kernel_image_path=$(head -n 1 <<< "$kernels" | cut -f2- -d' ') kernel_image_path=$(head -n 1 <<< "$kernels" | cut -f2- -d' ')
n=$(wc -l <<< "$kernels") n=$(wc -l <<< "$kernels")
if [ "$n" -gt "1" ];then if [ "$n" -gt "1" ]; then
msg=$(awk '{printf " %s\n", $2}' <<< ${kernels}) msg=$(awk '{printf " %s\n", $2}' <<< ${kernels})
log_warn "Found multiple kernel images: \n\n${msg}\n" log_warn "Found multiple kernel images: \n\n${msg}\n"
log_warn "Selecting newest kernel image: \n\n ${kernel_image_path}\n" log_warn "Selecting newest kernel image: \n\n ${kernel_image_path}\n"
log_warn "Set MENDER_GRUB_KERNEL_IMAGETYPE to override selected kernel" log_warn "Set MENDER_GRUB_KERNEL_IMAGETYPE to override selected kernel"
fi fi
#kernel_image_path=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' | sort -rV | head -n 1 ) #kernel_image_path=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' | sort -rV | head -n 1 )
if [ -n "${kernel_image_path}" ]; then if [ -n "${kernel_image_path}" ]; then
break break
fi fi
done done
echo "${kernel_image_path}" echo "${kernel_image_path}"
} }
# Prints path to the initrd/initramfs image # Prints path to the initrd/initramfs image
@ -165,33 +165,33 @@ probe_kernel_image() {
# $1 - directory in which the search is performed # $1 - directory in which the search is performed
# #
probe_initrd_image() { probe_initrd_image() {
initrd_image_path="" initrd_image_path=""
for image in initramfs initrd; do for image in initramfs initrd; do
# initrd/initramfs naming varies between different platforms. # initrd/initramfs naming varies between different platforms.
# #
# The wildcard at the end is important, because it is common to suffix the # The wildcard at the end is important, because it is common to suffix the
# Linux kernel version to the image name, e.g: # Linux kernel version to the image name, e.g:
# #
# initrd.img-4.15.0-20-generic # initrd.img-4.15.0-20-generic
# #
#Search for initrd, resolve symlinks, ignore invalid and select the latest if many #Search for initrd, resolve symlinks, ignore invalid and select the latest if many
initrds=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' ! -name '*.old' \ initrds=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*' ! -name '*.old' \
-exec readlink -f {} \; | awk -F '/' '{print $NF,$0}' | sort -k1rV | uniq) -exec readlink -f {} \; | awk -F '/' '{print $NF,$0}' | sort -k1rV | uniq)
initrd_image_path=$(head -n 1 <<< "$initrds" | cut -f2- -d' ') initrd_image_path=$(head -n 1 <<< "$initrds" | cut -f2- -d' ')
n=$(wc -l <<< "$initrds") n=$(wc -l <<< "$initrds")
if [ "$n" -gt "1" ];then if [ "$n" -gt "1" ]; then
msg=$(awk '{printf " %s\n", $2}' <<< ${initrds}) msg=$(awk '{printf " %s\n", $2}' <<< ${initrds})
log_warn "Found multiple initrd images: \n\n${msg}\n" log_warn "Found multiple initrd images: \n\n${msg}\n"
log_warn "Selecting newest initrd: \n\n ${initrd_image_path}\n" log_warn "Selecting newest initrd: \n\n ${initrd_image_path}\n"
log_warn "Set MENDER_GRUB_INITRD_IMAGETYPE to override selected initrd" log_warn "Set MENDER_GRUB_INITRD_IMAGETYPE to override selected initrd"
fi fi
if [ -n "${initrd_image_path}" ]; then if [ -n "${initrd_image_path}" ]; then
break break
fi fi
done done
echo "${initrd_image_path}" echo "${initrd_image_path}"
} }
# Prints Linux kernel image name # Prints Linux kernel image name
@ -202,36 +202,36 @@ probe_initrd_image() {
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_kernel_in_boot_and_root() { probe_kernel_in_boot_and_root() {
kernel_imagetype_path="" kernel_imagetype_path=""
# Important to check rootfs/boot first, because it might be possible that # Important to check rootfs/boot first, because it might be possible that
# they are stored in both partitions, and in this case we want to find the # they are stored in both partitions, and in this case we want to find the
# image in the rootfs first and use that, to avoid copying it over from # image in the rootfs first and use that, to avoid copying it over from
# boot part when it is already there. # boot part when it is already there.
for boot in work/rootfs/boot work/boot; do for boot in work/rootfs/boot work/boot; do
kernel_imagetype_path=$(probe_kernel_image ${boot}) kernel_imagetype_path=$(probe_kernel_image ${boot})
if [ -n "${kernel_imagetype_path}" ] && [ "${boot}" == "work/boot" ]; then if [ -n "${kernel_imagetype_path}" ] && [ "${boot}" == "work/boot" ]; then
log_info "Found Linux kernel image in boot part, moving to rootfs/boot" log_info "Found Linux kernel image in boot part, moving to rootfs/boot"
sudo cp ${kernel_imagetype_path} work/rootfs/boot sudo cp ${kernel_imagetype_path} work/rootfs/boot
break; break
elif [ -n "${kernel_imagetype_path}" ]; then elif [ -n "${kernel_imagetype_path}" ]; then
break; break
fi fi
done done
if [ -z "${kernel_imagetype_path}" ]; then if [ -z "${kernel_imagetype_path}" ]; then
log_warn "Unfortunately we where not able to find the Linux kernel image." log_warn "Unfortunately we where not able to find the Linux kernel image."
log_fatal "Please specify the image name using MENDER_GRUB_KERNEL_IMAGETYPE" log_fatal "Please specify the image name using MENDER_GRUB_KERNEL_IMAGETYPE"
fi fi
log_info "Found Linux kernel image: \n\n\t${kernel_imagetype_path}\n" log_info "Found Linux kernel image: \n\n\t${kernel_imagetype_path}\n"
kernel_imagetype=$(basename ${kernel_imagetype_path}) kernel_imagetype=$(basename ${kernel_imagetype_path})
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then
check_efi_compatible_kernel ${kernel_imagetype_path} check_efi_compatible_kernel ${kernel_imagetype_path}
fi fi
echo "${kernel_imagetype}" echo "${kernel_imagetype}"
} }
# Prints initrd/initramfs image name # Prints initrd/initramfs image name
@ -242,82 +242,82 @@ probe_kernel_in_boot_and_root() {
# No input parameters and these work on the assumption that boot and root parts # No input parameters and these work on the assumption that boot and root parts
# are mounted at work/boot and work/rootfs # are mounted at work/boot and work/rootfs
probe_initrd_in_boot_and_root() { probe_initrd_in_boot_and_root() {
initrd_image_path="" initrd_image_path=""
# Important to check rootfs/boot first, because it might be possible that # Important to check rootfs/boot first, because it might be possible that
# they are stored in both partitions, and in this case we want to find the # they are stored in both partitions, and in this case we want to find the
# image in the rootfs first and use that, to avoid copying it over from # image in the rootfs first and use that, to avoid copying it over from
# boot part when it is already there. # boot part when it is already there.
for boot in work/rootfs/boot work/boot; do for boot in work/rootfs/boot work/boot; do
initrd_image_path=$(probe_initrd_image ${boot}) initrd_image_path=$(probe_initrd_image ${boot})
if [ -n "${initrd_image_path}" ] && [ "${boot}" == "work/boot" ]; then if [ -n "${initrd_image_path}" ] && [ "${boot}" == "work/boot" ]; then
sudo cp ${initrd_image_path} work/rootfs/boot sudo cp ${initrd_image_path} work/rootfs/boot
break; break
elif [ -n "${initrd_image_path}" ]; then elif [ -n "${initrd_image_path}" ]; then
break; break
fi fi
done done
if [ -n "${initrd_image_path}" ]; then if [ -n "${initrd_image_path}" ]; then
log_info "Found initramfs image: \n\n\t${initrd_image_path}\n" log_info "Found initramfs image: \n\n\t${initrd_image_path}\n"
initrd_imagetype=$(basename ${initrd_image_path}) initrd_imagetype=$(basename ${initrd_image_path})
else else
log_info "Unfortunately we where not able to find the initrd image." log_info "Unfortunately we where not able to find the initrd image."
log_info "Please specify the image name using MENDER_GRUB_INITRD_IMAGETYPE \ log_info "Please specify the image name using MENDER_GRUB_INITRD_IMAGETYPE \
(only required if your board is using this)" (only required if your board is using this)"
initrd_imagetype="" initrd_imagetype=""
fi fi
echo "${initrd_imagetype}" echo "${initrd_imagetype}"
} }
check_for_broken_uboot_uefi_support() { check_for_broken_uboot_uefi_support() {
if ! is_uboot_with_uefi_support "$@"; then if ! is_uboot_with_uefi_support "$@"; then
local log_level=log_fatal local log_level=log_fatal
if [ "$MENDER_IGNORE_UBOOT_BROKEN_UEFI" = 1 ]; then if [ "$MENDER_IGNORE_UBOOT_BROKEN_UEFI" = 1 ]; then
log_level=log_warn log_level=log_warn
fi
$log_level 'Detected a U-Boot version in the range v2018.09 - v2019.07. These U-Boot versions are known to have broken UEFI support, and therefore the MENDER_GRUB_EFI_INTEGRATION feature is unlikely to work. This only affects newly flashed devices using the partition image (extension ending in "img"). The Mender artifact should still work to upgrade an existing, working device. There are two possible workarounds for this issue: 1) Use either an older or a newer image that works, and use a Mender artifact afterwards to up/down-grade it to the version you want. 2) If the device has a non-UEFI U-Boot port in mender-convert, use that (look for a board specific file in `configs`) . If you want to ignore this error and force creation of the image, set the MENDER_IGNORE_UBOOT_BROKEN_UEFI=1 config option.'
fi fi
$log_level 'Detected a U-Boot version in the range v2018.09 - v2019.07. These U-Boot versions are known to have broken UEFI support, and therefore the MENDER_GRUB_EFI_INTEGRATION feature is unlikely to work. This only affects newly flashed devices using the partition image (extension ending in "img"). The Mender artifact should still work to upgrade an existing, working device. There are two possible workarounds for this issue: 1) Use either an older or a newer image that works, and use a Mender artifact afterwards to up/down-grade it to the version you want. 2) If the device has a non-UEFI U-Boot port in mender-convert, use that (look for a board specific file in `configs`) . If you want to ignore this error and force creation of the image, set the MENDER_IGNORE_UBOOT_BROKEN_UEFI=1 config option.'
fi
} }
is_uboot_with_uefi_support() { is_uboot_with_uefi_support() {
local path="$1" local path="$1"
# Broken UEFI support in range v2018.09 - v2019.07 (see MEN-2404) # Broken UEFI support in range v2018.09 - v2019.07 (see MEN-2404)
local regex='U-Boot 20(18\.(09|1[0-2])|19\.0[1-7])' local regex='U-Boot 20(18\.(09|1[0-2])|19\.0[1-7])'
if egrep -qr "$regex" "$path"; then if egrep -qr "$regex" "$path"; then
return 1 return 1
fi fi
return 0 return 0
} }
check_efi_compatible_kernel() { check_efi_compatible_kernel() {
if ! is_efi_compatible_kernel "$@"; then if ! is_efi_compatible_kernel "$@"; then
local log_level=log_fatal local log_level=log_fatal
if [ "$MENDER_IGNORE_MISSING_EFI_STUB" = 1 ]; then if [ "$MENDER_IGNORE_MISSING_EFI_STUB" = 1 ]; then
log_level=log_warn log_level=log_warn
fi
$log_level 'Detected a kernel which does not have an EFI stub. This kernel is not supported when booting with UEFI. Please consider using a U-Boot port if the board has one (look for a board specific file in `configs`), or find a kernel which has the CONFIG_EFI_STUB turned on. To ignore this message and proceed anyway, set the MENDER_IGNORE_MISSING_EFI_STUB=1 config option.'
fi fi
$log_level 'Detected a kernel which does not have an EFI stub. This kernel is not supported when booting with UEFI. Please consider using a U-Boot port if the board has one (look for a board specific file in `configs`), or find a kernel which has the CONFIG_EFI_STUB turned on. To ignore this message and proceed anyway, set the MENDER_IGNORE_MISSING_EFI_STUB=1 config option.'
fi
} }
is_efi_compatible_kernel() { is_efi_compatible_kernel() {
kernel_path="$1" kernel_path="$1"
case "$(probe_arch)" in case "$(probe_arch)" in
arm|aarch64) arm | aarch64)
# On ARM, as of version 2.04, GRUB can only boot kernels which have an EFI # On ARM, as of version 2.04, GRUB can only boot kernels which have an EFI
# stub in them. See MEN-2404. # stub in them. See MEN-2404.
if ! file -k $kernel_path | fgrep -q 'EFI application'; then if ! file -k $kernel_path | fgrep -q 'EFI application'; then
return 1 return 1
fi fi
;; ;;
*) *)
# Other platforms are fine. # Other platforms are fine.
: :
;; ;;
esac esac
return 0 return 0
} }

24
modules/run.sh

@ -18,16 +18,16 @@
# #
# $1 - command to run # $1 - command to run
function run_and_log_cmd() { function run_and_log_cmd() {
local -r cmd="${1}" local -r cmd="${1}"
local -r position="(${BASH_SOURCE[1]}:${BASH_LINENO[0]}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }" local -r position="(${BASH_SOURCE[1]}:${BASH_LINENO[0]}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }"
local exit_code=0 local exit_code=0
output="$({ eval ${cmd}; } 2>&1)" || exit_code=$? output="$({ eval ${cmd}; } 2>&1)" || exit_code=$?
local log_msg="Running: ${position} \n\r\n\r\t${cmd}" local log_msg="Running: ${position} \n\r\n\r\t${cmd}"
if [[ "${output}" != "" ]]; then if [[ "${output}" != "" ]]; then
log_msg="${log_msg}\n\t${output}\n" log_msg="${log_msg}\n\t${output}\n"
fi fi
log_debug "${log_msg}" log_debug "${log_msg}"
if [[ ${exit_code} -ne 0 ]]; then if [[ ${exit_code} -ne 0 ]]; then
exit ${exit_code} exit ${exit_code}
fi fi
} }

32
modules/testscfg.sh

@ -15,9 +15,9 @@
# Init tests configuration file # Init tests configuration file
# #
function testscfg_init () { function testscfg_init() {
rm -f work/testscfg.tmp rm -f work/testscfg.tmp
touch work/testscfg.tmp touch work/testscfg.tmp
} }
# Add key/value to tests configuration file # Add key/value to tests configuration file
@ -25,23 +25,23 @@ function testscfg_init () {
# $1 - key # $1 - key
# $2 - value # $2 - value
# #
function testscfg_add () { function testscfg_add() {
if [[ $# -ne 2 ]]; then if [[ $# -ne 2 ]]; then
log_fatal "testscfg_add() requires 2 arguments" log_fatal "testscfg_add() requires 2 arguments"
fi fi
local -r key="${1}" local -r key="${1}"
local -r value="${2}" local -r value="${2}"
echo "${key}=\"${value}\"" >> work/testscfg.tmp echo "${key}=\"${value}\"" >> work/testscfg.tmp
} }
# Save tests configuration file into the given location # Save tests configuration file into the given location
# #
# $1 - Filename # $1 - Filename
# #
function testscfg_save () { function testscfg_save() {
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
log_fatal "testscfg_save() requires 1 argument" log_fatal "testscfg_save() requires 1 argument"
fi fi
local -r filename="${1}" local -r filename="${1}"
cp work/testscfg.tmp ${filename} cp work/testscfg.tmp ${filename}
} }

22
modules/zip.sh

@ -20,15 +20,15 @@
# #
# @return - Name of the img contained in the archive # @return - Name of the img contained in the archive
# #
function zip_get_imgname () { function zip_get_imgname() {
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
log_fatal "zip_get_imgname requires one argument" log_fatal "zip_get_imgname requires one argument"
fi fi
local -r disk_image="${1}" local -r disk_image="${1}"
# Assert that the archive holds only one file # Assert that the archive holds only one file
nfiles="$(unzip -l ${disk_image} | awk '{nfiles=$2} END {print nfiles}')" nfiles="$(unzip -l ${disk_image} | awk '{nfiles=$2} END {print nfiles}')"
[[ "$nfiles" -ne 1 ]] && log_fatal "Zip archive has more than one file. Needs to be unzipped by a human. nfiles: $nfiles" [[ "$nfiles" -ne 1 ]] && log_fatal "Zip archive has more than one file. Needs to be unzipped by a human. nfiles: $nfiles"
local -r filename="$(unzip -lq ${disk_image} | awk 'NR==3 {filename=$NF} END {print filename}')" local -r filename="$(unzip -lq ${disk_image} | awk 'NR==3 {filename=$NF} END {print filename}')"
[[ ${filename} == *.img ]] || log_fatal "no img file found in the zip archive ${disk_image}." [[ ${filename} == *.img ]] || log_fatal "no img file found in the zip archive ${disk_image}."
echo "$(basename ${filename})" echo "$(basename ${filename})"
} }

46
scripts/bootstrap-rootfs-overlay-demo-server.sh

@ -17,39 +17,39 @@
# Exit if any command exits with a non-zero exit status. # Exit if any command exits with a non-zero exit status.
set -o errexit set -o errexit
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}")/../" && pwd)
if [ "${root_dir}" != "${PWD}" ]; then if [ "${root_dir}" != "${PWD}" ]; then
echo "You must execute $(basename $0) from the root directory: ${root_dir}" echo "You must execute $(basename $0) from the root directory: ${root_dir}"
exit 1 exit 1
fi fi
server_ip="" server_ip=""
output_dir="" output_dir=""
while (( "$#" )); do while (("$#")); do
case "$1" in case "$1" in
-o | --output-dir) -o | --output-dir)
output_dir="${2}" output_dir="${2}"
shift 2 shift 2
;; ;;
-s | --server-ip) -s | --server-ip)
server_ip="${2}" server_ip="${2}"
shift 2 shift 2
;; ;;
*) *)
echo "Sorry but the provided option is not supported: $1" echo "Sorry but the provided option is not supported: $1"
echo "Usage: $(basename $0) --output-dir <rootfs overlay dir> --server-ip <your server IP address>" echo "Usage: $(basename $0) --output-dir <rootfs overlay dir> --server-ip <your server IP address>"
exit 1 exit 1
;; ;;
esac esac
done done
if [ -z "${output_dir}" ]; then if [ -z "${output_dir}" ]; then
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option"
exit 1 exit 1
fi fi
if [ -z "${server_ip}" ]; then if [ -z "${server_ip}" ]; then
echo "Sorry, but you need to provide a server IP address using the '-s/--server-ip' option" echo "Sorry, but you need to provide a server IP address using the '-s/--server-ip' option"
exit 1 exit 1
fi fi
if [ -e ${output_dir} ]; then if [ -e ${output_dir} ]; then

46
scripts/bootstrap-rootfs-overlay-hosted-server.sh

@ -17,40 +17,40 @@
# Exit if any command exits with a non-zero exit status. # Exit if any command exits with a non-zero exit status.
set -o errexit set -o errexit
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}")/../" && pwd)
if [ "${root_dir}" != "${PWD}" ]; then if [ "${root_dir}" != "${PWD}" ]; then
echo "You must execute $(basename $0) from the root directory: ${root_dir}" echo "You must execute $(basename $0) from the root directory: ${root_dir}"
exit 1 exit 1
fi fi
tenant_token="" tenant_token=""
output_dir="" output_dir=""
while (( "$#" )); do while (("$#")); do
case "$1" in case "$1" in
-t | --tenant-token) -t | --tenant-token)
tenant_token="${2}" tenant_token="${2}"
shift 2 shift 2
;; ;;
-o | --output-dir) -o | --output-dir)
output_dir="${2}" output_dir="${2}"
shift 2 shift 2
;; ;;
*) *)
echo "Sorry but the provided option is not supported: $1" echo "Sorry but the provided option is not supported: $1"
echo "Usage: $(basename $0) --output-dir ./rootfs_overlay_demo --tenant-token <paste your token here>" echo "Usage: $(basename $0) --output-dir ./rootfs_overlay_demo --tenant-token <paste your token here>"
exit 1 exit 1
;; ;;
esac esac
done done
if [ -z "${output_dir}" ]; then if [ -z "${output_dir}" ]; then
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option"
exit 1 exit 1
fi fi
if [ -z "${tenant_token}" ]; then if [ -z "${tenant_token}" ]; then
echo "Sorry, but you need to provide a tenant token using the '-t/--tenant-token' option" echo "Sorry, but you need to provide a tenant token using the '-t/--tenant-token' option"
exit 1 exit 1
fi fi
if [ -e ${output_dir} ]; then if [ -e ${output_dir} ]; then

58
scripts/bootstrap-rootfs-overlay-production-server.sh

@ -17,44 +17,44 @@
# Exit if any command exits with a non-zero exit status. # Exit if any command exits with a non-zero exit status.
set -o errexit set -o errexit
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}")/../" && pwd)
if [ "${root_dir}" != "${PWD}" ]; then if [ "${root_dir}" != "${PWD}" ]; then
echo "You must execute $(basename $0) from the root directory: ${root_dir}" echo "You must execute $(basename $0) from the root directory: ${root_dir}"
exit 1 exit 1
fi fi
server_url="" server_url=""
output_dir="" output_dir=""
while (( "$#" )); do while (("$#")); do
case "$1" in case "$1" in
-o | --output-dir) -o | --output-dir)
output_dir="${2}" output_dir="${2}"
shift 2 shift 2
;; ;;
-s | --server-url) -s | --server-url)
server_url="${2}" server_url="${2}"
shift 2 shift 2
;; ;;
-S | --server-cert) -S | --server-cert)
server_cert="${2}" server_cert="${2}"
shift 2 shift 2
;; ;;
*) *)
echo "Sorry but the provided option is not supported: $1" echo "Sorry but the provided option is not supported: $1"
echo "Usage: $(basename $0) --output-dir ./rootfs_overlay_demo --server-url <your server URL> [--server-cert <path to your server.crt file>]" echo "Usage: $(basename $0) --output-dir ./rootfs_overlay_demo --server-url <your server URL> [--server-cert <path to your server.crt file>]"
exit 1 exit 1
;; ;;
esac esac
done done
if [ -z "${output_dir}" ]; then if [ -z "${output_dir}" ]; then
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option"
exit 1 exit 1
fi fi
if [ -z "${server_url}" ]; then if [ -z "${server_url}" ]; then
echo "Sorry, but you need to provide a server URL using the '-s/--server-url' option" echo "Sorry, but you need to provide a server URL using the '-s/--server-url' option"
exit 1 exit 1
fi fi
if [ -e ${output_dir} ]; then if [ -e ${output_dir} ]; then
@ -70,10 +70,10 @@ cat <<- EOF > ${output_dir}/etc/mender/mender.conf
EOF EOF
if [ -n "${server_cert}" ]; then if [ -n "${server_cert}" ]; then
cat <<- EOF >> ${output_dir}/etc/mender/mender.conf cat <<- EOF >> ${output_dir}/etc/mender/mender.conf
"ServerCertificate": "/etc/mender/server.crt", "ServerCertificate": "/etc/mender/server.crt",
EOF EOF
cp -f "${server_cert}" ${output_dir}/etc/mender/server.crt cp -f "${server_cert}" ${output_dir}/etc/mender/server.crt
fi fi
cat <<- EOF >> ${output_dir}/etc/mender/mender.conf cat <<- EOF >> ${output_dir}/etc/mender/mender.conf

Loading…
Cancel
Save