Browse Source
This brings the rewrite of mender-convert into master, which will become mender-convert 2.0.0. This is essentially a merge with `-s theirs`. I also manually checked there were no omitted changes from the existing master. Changelog: None Signed-off-by: Kristian Amlie <kristian.amlie@northern.tech>2.0.x
Kristian Amlie
5 years ago
65 changed files with 2561 additions and 3467 deletions
@ -1,3 +1,3 @@ |
|||
input/ |
|||
output/ |
|||
device-image-shell/output |
|||
deploy |
|||
input |
|||
work |
|||
|
@ -1,5 +1,7 @@ |
|||
input/ |
|||
output/ |
|||
device-image-shell/output |
|||
mendertesting/ |
|||
integration/ |
|||
deploy |
|||
input |
|||
work |
|||
rootfs_overlay_demo/* |
|||
mender_local_config |
|||
*.xml |
|||
*.html |
|||
|
@ -0,0 +1,5 @@ |
|||
[submodule "tests/mender-image-tests"] |
|||
path = tests/mender-image-tests |
|||
url = https://github.com/mendersoftware/mender-image-tests |
|||
branch = master |
|||
ignore = all |
@ -1,27 +0,0 @@ |
|||
language: minimal |
|||
|
|||
# Disable git shallow clone. We need full history for validating copyright year of each file. |
|||
git: |
|||
depth: false |
|||
|
|||
dist: trusty |
|||
|
|||
before_script: |
|||
- git clone git://github.com/mendersoftware/mendertesting |
|||
|
|||
# Rename the branch we're on, so that it's not in the way for the |
|||
# subsequent fetch. It's ok if this fails, it just means we're not on any |
|||
# branch. |
|||
- git branch -m temp-branch || true |
|||
# Git trick: Fetch directly into our local branches instead of remote |
|||
# branches. |
|||
- git fetch origin 'refs/heads/*:refs/heads/*' |
|||
# Get last remaining tags, if any. |
|||
- git fetch --tags origin |
|||
|
|||
script: |
|||
# Check commit compliance. |
|||
- mendertesting/check_commits.sh |
|||
# Check licenses |
|||
- mendertesting/check_license.sh |
|||
- ./docker-build |
@ -1,44 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
embedded_rootfs_dir=$3 |
|||
uboot_backup_dir=${embedded_rootfs_dir}/opt/backup/uboot |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
[ ! -d "${embedded_rootfs_dir}" ] && \ |
|||
{ log "Error: embedded content not mounted."; exit 1; } |
|||
[[ ! -f $uboot_backup_dir/MLO || ! -f $uboot_backup_dir/u-boot.img ]] && \ |
|||
{ log "Error: cannot find U-Boot related files."; exit 1; } |
|||
|
|||
cat <<- 'EOF' | sudo tee --append ${output_dir}/uEnv.txt 2>&1 >/dev/null |
|||
loadaddr=0x82000000 |
|||
fdtaddr=0x88000000 |
|||
rdaddr=0x88080000 |
|||
|
|||
initrd_high=0xffffffff |
|||
fdt_high=0xffffffff |
|||
|
|||
loadximage=echo debug: [/boot/vmlinuz-${uname_r}] ... ; load mmc 0:2 ${loadaddr} /boot/vmlinuz-${uname_r} |
|||
loadxfdt=echo debug: [/boot/dtbs/${uname_r}/${fdtfile}] ... ;load mmc 0:2 ${fdtaddr} /boot/dtbs/${uname_r}/${fdtfile} |
|||
loadxrd=echo debug: [/boot/initrd.img-${uname_r}] ... ; load mmc 0:2 ${rdaddr} /boot/initrd.img-${uname_r}; setenv rdsize ${filesize} |
|||
loaduEnvtxt=load mmc 0:2 ${loadaddr} /boot/uEnv.txt ; env import -t ${loadaddr} ${filesize}; |
|||
check_dtb=if test -n ${dtb}; then setenv fdtfile ${dtb};fi; |
|||
loadall=run loaduEnvtxt; run check_dtb; run loadximage; run loadxrd; run loadxfdt; |
|||
|
|||
mmcargs=setenv bootargs console=tty0 console=${console} ${optargs} ${cape_disable} ${cape_enable} root=/dev/mmcblk0p2 rootfstype=${mmcrootfstype} ${cmdline} |
|||
|
|||
uenvcmd=run loadall; run mmcargs; echo debug: [${bootargs}] ... ; echo debug: [bootz ${loadaddr} ${rdaddr}:${rdsize} ${fdtaddr}] ... ; bootz ${loadaddr} ${rdaddr}:${rdsize} ${fdtaddr}; |
|||
EOF |
|||
|
|||
mcopy -o -i ${output_dir}/boot.vfat -s ${output_dir}/uEnv.txt ::uEnv.txt |
|||
mcopy -o -i ${output_dir}/boot.vfat -s ${uboot_backup_dir}/MLO ::MLO |
|||
mcopy -o -i ${output_dir}/boot.vfat -s ${uboot_backup_dir}/u-boot.img ::u-boot.img |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=/dev/mapper/${boot_mapping} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -0,0 +1,40 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-bbb.sh |
|||
# |
|||
|
|||
# There are reported issues with GRUB bootloader integration, fallback to U-boot. |
|||
MENDER_GRUB_EFI_INTEGRATION=n |
|||
|
|||
# We will write a modified bootloader |
|||
MENDER_COPY_BOOT_GAP=n |
|||
|
|||
# 4MB alignment |
|||
MENDER_PARTITION_ALIGNMENT="4194304" |
|||
|
|||
BEAGLEBONE_BLACK_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/beaglebone/${BEAGLEBONE_BLACK_BINARIES}" |
|||
|
|||
function platform_modify() { |
|||
mkdir -p work/bbb/binaries |
|||
|
|||
run_and_log_cmd "wget -q ${BEAGLEBONE_BLACK_BINARIES_URL} -P work/bbb/binaries" |
|||
run_and_log_cmd "tar xvf work/bbb/binaries/${BEAGLEBONE_BLACK_BINARIES} -C work/bbb/binaries" |
|||
|
|||
# Mask udisks2.service, otherwise it will mount the inactive part and we |
|||
# might write an update while it is mounted which often result in |
|||
# corruptions. |
|||
# |
|||
# TODO: Find a way to only blacklist mmcblk0pX devices instead of masking |
|||
# the service. |
|||
run_and_log_cmd "sudo ln -sf /dev/null work/rootfs/etc/systemd/system/udisks2.service" |
|||
|
|||
# Place u-boot and MLO into 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/u-boot.img work/boot/" |
|||
run_and_log_cmd "sudo cp work/bbb/binaries/fw_env.config work/rootfs/etc/" |
|||
run_and_log_cmd "sudo cp work/bbb/binaries/uboot-git-log.txt 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 ln -fs /sbin/fw_printenv work/rootfs/sbin/fw_setenv" |
|||
} |
@ -0,0 +1,9 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-bbb.sh |
|||
# |
|||
BEAGLEBONE_BLACK_BINARIES="beaglebone-black-integration-debian-emmc-2018.07.004.tar" |
|||
source configs/beaglebone_black_base_config |
|||
MENDER_STORAGE_TOTAL_SIZE_MB="3648" |
|||
MENDER_DEVICE_TYPE="beaglebone-emmc" |
|||
MENDER_STORAGE_DEVICE="/dev/mmcblk1p" |
@ -0,0 +1,8 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-bbb.sh |
|||
# |
|||
BEAGLEBONE_BLACK_BINARIES="beaglebone-black-integration-debian-sdcard-2018.07.004.tar" |
|||
source configs/beaglebone_black_base_config |
|||
MENDER_DEVICE_TYPE="beaglebone-sdcard" |
|||
MENDER_STORAGE_DEVICE="/dev/mmcblk0p" |
@ -0,0 +1,14 @@ |
|||
# Real life SD cards typically have less than they advertise. First off, they |
|||
# often use a base of 1000 instead of 1024, and even then they are often smaller |
|||
# than advertised. The number below is based on a conservative target of 3.9GB |
|||
# (that's mathematical GB, base 1000), converted to MiB, rounding down. |
|||
MENDER_STORAGE_TOTAL_SIZE_MB=3719 |
|||
|
|||
# Use all there is, which gets us almost, but not quite, to 500MiB free space |
|||
# (about 480MiB at the time of writing). |
|||
IMAGE_ROOTFS_SIZE=-1 |
|||
IMAGE_ROOTFS_EXTRA_SPACE=0 |
|||
IMAGE_OVERHEAD_FACTOR=1.0 |
|||
|
|||
# Best compression there is! |
|||
MENDER_COMPRESS_DISK_IMAGE=lzma |
@ -0,0 +1,194 @@ |
|||
# This is the default configuration used by mender-convert. You can override |
|||
# any option specified here by providing your own configuration file using the |
|||
# '--config' argument. |
|||
# |
|||
# NOTE! This file will always be sourced. |
|||
|
|||
# Compress generated disk image |
|||
# |
|||
# This is useful when you have large disk images, compressing them |
|||
# makes it easier to transfer them between e.g an build server and a local |
|||
# machine, and obviously saves space. |
|||
# |
|||
# Possible values are: |
|||
# 'none' - No compression |
|||
# 'gzip' - Compress with gzip |
|||
# 'lzma' - Compress with xz (LZMA) |
|||
MENDER_COMPRESS_DISK_IMAGE=gzip |
|||
|
|||
# Compression algorithm for Mender Artifact |
|||
# |
|||
# Supported values are: lzma, gzip (default), none |
|||
# |
|||
# LZMA will produce a smaller Mender Artifact (2-3x) but will significantly |
|||
# increase time spent generating the Mender Artifact (10x) |
|||
MENDER_ARTIFACT_COMPRESSION="gzip" |
|||
|
|||
# Enable Mender systemd server |
|||
# |
|||
# You want this enabled if you want the Mender client to operate in managed mode |
|||
# and connect to a server. If you are not interested connecting to a server |
|||
# and will only be running standalone mode updates, then you can safely disable |
|||
# this. |
|||
MENDER_ENABLE_SYSTEMD=y |
|||
|
|||
# Set the fstab options for mounting the data partition |
|||
MENDER_DATA_PART_FSTAB_OPTS="defaults" |
|||
|
|||
# The file system will be grown to occupy the full block device. If the file |
|||
# system is already at maximum size, no action will be performed. |
|||
# |
|||
# This feature is utilizing x−systemd.growfs and will only work on systemd 242 |
|||
# and newer and nothing will be done if an older systemd version is used. |
|||
MENDER_DATA_PART_GROWFS=y |
|||
|
|||
# The name of the image or update that will be built. This is what the device |
|||
# will report that it is running, and different updates must have different |
|||
# names. |
|||
# |
|||
# This variable must be defined or the build will fail, but you should not |
|||
# set it in a configuration file and instead it should be an input to the |
|||
# mender-convert tool, e.g |
|||
# |
|||
# MENDER_ARTIFACT_NAME="release-1" ./mender-convert |
|||
# |
|||
#MENDER_ARTIFACT_NAME="" |
|||
|
|||
# A string that defines the type of device this image will be installed on and |
|||
# this value is used for compatibility checks between Mender Artifact and |
|||
# what the device is reporting. |
|||
# |
|||
# You can define multiple types by providing a space separated string of device |
|||
# types. |
|||
# |
|||
# It defaults to the content of '/etc/hostname', which is extracted from the |
|||
# input disk image |
|||
MENDER_DEVICE_TYPE="" |
|||
|
|||
# Total size of the physical storage medium that mender partitioned images |
|||
# will be written to, expressed in MiB. The size of rootfs partition will be |
|||
# calculated automatically by subtracting the sizes of boot |
|||
# (see MENDER_BOOT_PART_SIZE_MB) and data partitions |
|||
# (see MENDER_DATA_PART_SIZE_MB). |
|||
# |
|||
MENDER_STORAGE_TOTAL_SIZE_MB="8192" |
|||
|
|||
# The size of the boot partition in the generated .biosimg, .sdimg or .uefiimg |
|||
# file. |
|||
MENDER_BOOT_PART_SIZE_MB="40" |
|||
|
|||
# The size of the persistent data partition in the generated .biosimg, .sdimg |
|||
# or .uefiimg file. |
|||
# |
|||
# You rarely need to increase this number as this partition will be expanded |
|||
# on first boot to occupy the renaming free blocks on the physical storage. |
|||
MENDER_DATA_PART_SIZE_MB="128" |
|||
|
|||
# Alignment of partitions used when building partitioned images, expressed in |
|||
# bytes |
|||
# |
|||
# Default is 8MB |
|||
MENDER_PARTITION_ALIGNMENT="8388608" |
|||
|
|||
# Mender client version |
|||
# |
|||
# This is used to fetch the correct binaries |
|||
MENDER_CLIENT_VERSION="master" |
|||
|
|||
# File storage, containing binary files, do not modify this unless you know |
|||
# what you are doing. |
|||
MENDER_STORAGE_URL="https://d1b0l86ne08fsf.cloudfront.net" |
|||
|
|||
# Mender GitHub organization URL prefix |
|||
MENDER_GITHUB_ORG="https://github.com/mendersoftware" |
|||
|
|||
# Device file corresponding to the root filesystem partitions, without index. |
|||
MENDER_STORAGE_DEVICE=/dev/mmcblk0p |
|||
|
|||
# Partition index of boot partition |
|||
MENDER_BOOT_PART_INDEX="1" |
|||
|
|||
# Partition index of root filesystem A |
|||
MENDER_ROOTFS_PART_A_INDEX="2" |
|||
|
|||
# Partition index of root filesystem B |
|||
MENDER_ROOTFS_PART_B_INDEX="3" |
|||
|
|||
# Partition index of persistent data partition |
|||
MENDER_DATA_PART_INDEX="4" |
|||
|
|||
# Basename of DTB that should be loaded by the bootloader. |
|||
MENDER_KERNEL_DEVICETREE=kernel.dtb |
|||
|
|||
# Generate bmap index files |
|||
# |
|||
# https://github.com/intel/bmap-tools |
|||
MENDER_USE_BMAP="n" |
|||
|
|||
# Copy the boot gap, which is the area from sector 1 until first parition, |
|||
# this is done because some images might contain the bootloader embedded here |
|||
# and we need to copy the bootloader to the output image. |
|||
# |
|||
# In most cases you would like this enabled. |
|||
MENDER_COPY_BOOT_GAP="y" |
|||
|
|||
# The size of each of the two rootfs filesystems, in KiB. If this is 0, |
|||
# mender-convert will use the size of the filesystem content as a basis. If the |
|||
# value is -1, mender-convert will use the maximum size that will fit inside the |
|||
# created partition. The size is further modified by IMAGE_ROOTFS_EXTRA_SPACE |
|||
# and IMAGE_OVERHEAD_FACTOR. |
|||
# |
|||
# This variable directly mirrors the variable from the Yocto Project, which is |
|||
# why it is missing a "MENDER_" prefix. |
|||
IMAGE_ROOTFS_SIZE="0" |
|||
|
|||
# The amount of extra free space requested on the rootfs, in KiB. This is added |
|||
# to the value of IMAGE_ROOTFS_SIZE. The size is further modified by |
|||
# IMAGE_OVERHEAD_FACTOR. |
|||
# |
|||
# Note that due to reserved space for the root user on the filesystem, "df" may |
|||
# report a significantly lower number than requested. A more accurate number can |
|||
# be fetched using for example "dumpe2fs" and looking for the "Free blocks" |
|||
# field, but even this value is usually going to be lower than requested due to |
|||
# meta data on the filesystem. |
|||
# |
|||
# This variable directly mirrors the variable from the Yocto Project, which is |
|||
# why it is missing a "MENDER_" prefix. |
|||
IMAGE_ROOTFS_EXTRA_SPACE="0" |
|||
|
|||
# This factor is multiplied by the used space value for the generated rootfs, |
|||
# and if the result is larger than IMAGE_ROOTFS_SIZE + IMAGE_ROOTFS_EXTRA_SPACE, |
|||
# it will be used as the size of the rootfs instead of the other two variables. |
|||
# |
|||
# The actual free space will usually be lower than requested. See comment for |
|||
# IMAGE_ROOTFS_EXTRA_SPACE. |
|||
# |
|||
# This variable directly mirrors the variable from the Yocto Project, which is |
|||
# why it is missing a "MENDER_" prefix. |
|||
IMAGE_OVERHEAD_FACTOR="1.5" |
|||
|
|||
source configs/mender_grub_config |
|||
|
|||
# Function to create Mender Artifact |
|||
# |
|||
# This function is defined here, to allow it to be overridden which can be |
|||
# achieved by providing this function in a custom configuration file which will |
|||
# take precedence of this one. |
|||
# |
|||
# You might want to override this to e.g provide state-scripts or providing |
|||
# a private key to sign your artifact. |
|||
mender_create_artifact() { |
|||
local -r device_type="${1}" |
|||
local -r artifact_name="${2}" |
|||
|
|||
mender_artifact=deploy/${device_type}-${artifact_name}.mender |
|||
log_info "Writing Mender artifact to: ${mender_artifact}" |
|||
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} \ |
|||
write rootfs-image \ |
|||
--file work/rootfs.img \ |
|||
--output-path ${mender_artifact} \ |
|||
--artifact-name ${artifact_name} \ |
|||
--device-type ${device_type}" |
|||
} |
@ -0,0 +1,35 @@ |
|||
# Use U-boot -> GRUB -> EFI boot-loader integration |
|||
# |
|||
# Only disable this if you know what you are doing |
|||
MENDER_GRUB_EFI_INTEGRATION=y |
|||
|
|||
# Specific Linux kernel boot arguments |
|||
# |
|||
# Typically you would read the content of /proc/cmdline on a "golden image" |
|||
# add the appropriate arguments here. |
|||
# |
|||
# This will override the defaults set by by grub-mender-grubenv, if not an |
|||
# empty string |
|||
MENDER_GRUB_KERNEL_BOOT_ARGS="" |
|||
|
|||
# grub-mender-grubenv is the Mender integration for the GRUB bootloader |
|||
MENDER_GRUBENV_VERSION="1.3.0" |
|||
MENDER_GRUBENV_URL="${MENDER_GITHUB_ORG}/grub-mender-grubenv/archive/${MENDER_GRUBENV_VERSION}.tar.gz" |
|||
|
|||
# Name of the storage device containing root filesystem partitions in GRUB |
|||
# format. |
|||
MENDER_GRUB_STORAGE_DEVICE=hd0 |
|||
|
|||
# Type of kernel (bzImage or zImage) |
|||
# |
|||
# mender-convert will try to determinate this value on its own, only set this |
|||
# if was not possible to auto-detect |
|||
MENDER_GRUB_KERNEL_IMAGETYPE="" |
|||
|
|||
# Type of initrd image |
|||
# |
|||
# mender-convert will try to determinate this value on its own, only set this |
|||
# if was not possible to auto-detect |
|||
MENDER_GRUB_INITRD_IMAGETYPE="" |
|||
|
|||
MENDER_GRUB_BINARY_STORAGE_URL="${MENDER_STORAGE_URL}/mender-convert/grub-efi" |
@ -0,0 +1,19 @@ |
|||
# This configuration can be used to run on a qemux86-64 machine. |
|||
# |
|||
# This has been tested on images generated with the following command: |
|||
# |
|||
# mkosi -d ubuntu -r bionic -t gpt_ext4 -b --checksum --password password -o image.raw |
|||
# |
|||
# Converted with the following command: |
|||
# |
|||
# MENDER_ARTIFACT_NAME=release-1 ./mender-convert --disk-image input/image.raw --overlay rootfs_overlay_demo --config configs/qemux86-64_config |
|||
# |
|||
# and qemu is executed with the following command: |
|||
# |
|||
# qemu-system-x86_64 -enable-kvm -m 512 -smp 2 -bios /usr/share/ovmf/x64/OVMF_CODE.fd -drive format=raw,file=qemux86_64-release-1.sdimg |
|||
|
|||
MENDER_STORAGE_DEVICE=/dev/sda |
|||
MENDER_DEVICE_TYPE="qemux86_64" |
|||
|
|||
# Nothing to copy |
|||
MENDER_COPY_BOOT_GAP="n" |
@ -0,0 +1,8 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-rpi.sh |
|||
RASPBERRYPI_BINARIES="raspberrypi0w-integration-2019.01.tar.gz" |
|||
RASPBERRYPI_KERNEL_IMAGE="kernel.img" |
|||
MENDER_KERNEL_IMAGETYPE=zImage |
|||
|
|||
source configs/raspberrypi_config |
@ -0,0 +1,8 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-rpi.shraspberrypi-integration-scripts.tar.gz |
|||
RASPBERRYPI_BINARIES="raspberrypi3-integration-2019.01.tar.gz" |
|||
RASPBERRYPI_KERNEL_IMAGE="kernel7.img" |
|||
MENDER_KERNEL_IMAGETYPE="zImage" |
|||
|
|||
source configs/raspberrypi_config |
@ -0,0 +1,8 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://github.com/drewmoseley/mender-convert-integration-scripts/blob/master/build-uboot-rpi.shraspberrypi-integration-scripts.tar.gz |
|||
RASPBERRYPI_BINARIES="raspberrypi4-integration-2019.01.tar.gz" |
|||
RASPBERRYPI_KERNEL_IMAGE="kernel7l.img" |
|||
MENDER_KERNEL_IMAGETYPE="zImage" |
|||
|
|||
source configs/raspberrypi_config |
@ -0,0 +1,83 @@ |
|||
# Raspberry Pi does not support GRUB bootloader integration, fallback to U-boot. |
|||
MENDER_GRUB_EFI_INTEGRATION=n |
|||
|
|||
# Nothing to copy |
|||
MENDER_COPY_BOOT_GAP=n |
|||
|
|||
# 4MB alignment |
|||
MENDER_PARTITION_ALIGNMENT="4194304" |
|||
|
|||
RASPBERRYPI_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/raspberrypi/${RASPBERRYPI_BINARIES}" |
|||
|
|||
function platform_modify() { |
|||
mkdir -p work/rpi/binaries |
|||
|
|||
run_and_log_cmd "wget -q ${RASPBERRYPI_BINARIES_URL} -P work/rpi/binaries" |
|||
run_and_log_cmd "tar xvf work/rpi/binaries/${RASPBERRYPI_BINARIES} -C work/rpi/binaries" |
|||
|
|||
# Make a copy of Linux kernel arguments and modify. |
|||
run_and_log_cmd "cp work/boot/cmdline.txt work/rpi/cmdline.txt" |
|||
|
|||
# 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.txt" |
|||
|
|||
# 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 |
|||
# is a requirement to be able to do an "online" resize. |
|||
# |
|||
# This disables resize of rootfs on boot but applies the changes to |
|||
# cmdline.txt that are performed in the init_resize.sh script. |
|||
# |
|||
# 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.txt" |
|||
run_and_log_cmd "sed -i 's| sdhci\.debug_quirks2=4||' work/rpi/cmdline.txt" |
|||
if ! grep -q splash work/rpi/cmdline.txt; then |
|||
run_and_log_cmd "sed -i 's/ quiet//g' work/rpi/cmdline.txt" |
|||
fi |
|||
|
|||
# Update Linux kernel command arguments with our custom configuration |
|||
run_and_log_cmd "sudo cp work/rpi/cmdline.txt work/boot/" |
|||
|
|||
# Mask udisks2.service, otherwise it will mount the inactive part and we |
|||
# might write an update while it is mounted which often result in |
|||
# corruptions. |
|||
# |
|||
# TODO: Find a way to only blacklist mmcblk0pX devices instead of masking |
|||
# the 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 |
|||
# layout is slightly different on the boot partition. That is why we need |
|||
# additional logic here to determinant what we are converting. |
|||
if [ -e work/boot/uboot.bin ] && [ -e work/boot/vmlinuz ]; then |
|||
RASPBERRYPI_KERNEL_IMAGE="vmlinuz" |
|||
RASPBERRYPI_BOOTLOADER_IMAGE="uboot.bin" |
|||
else |
|||
RASPBERRYPI_BOOTLOADER_IMAGE="${RASPBERRYPI_KERNEL_IMAGE}" |
|||
fi |
|||
|
|||
# Extract Linux kernel and install to /boot directory on rootfs |
|||
run_and_log_cmd "sudo cp work/boot/${RASPBERRYPI_KERNEL_IMAGE} work/rootfs/boot/${MENDER_KERNEL_IMAGETYPE}" |
|||
|
|||
# Replace kernel with U-boot and add boot script |
|||
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/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/uboot-git-log.txt work/boot" |
|||
|
|||
# Raspberry Pi applications expect to find this on the device and in some |
|||
# cases parse the options to determinate functionality. |
|||
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/cmdline.txt work/rootfs/boot/cmdline.txt" |
|||
|
|||
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" |
|||
|
|||
# Remove original 'resize2fs_once' script and its symbolic link. |
|||
if [ -L work/rootfs/etc/rc3.d/S01resize2fs_once ]; then |
|||
run_and_log_cmd "sudo unlink work/rootfs/etc/rc3.d/S01resize2fs_once" |
|||
fi |
|||
run_and_log_cmd "sudo rm -f work/rootfs/etc/init.d/resize2fs_once" |
|||
} |
@ -0,0 +1,28 @@ |
|||
# ROCKPro64 do not support GRUB bootloader integration, fallback to U-boot. |
|||
MENDER_GRUB_EFI_INTEGRATION=n |
|||
|
|||
# We will write a modified bootloader |
|||
MENDER_COPY_BOOT_GAP=n |
|||
|
|||
ROCKPRO64_BINARIES_URL="${MENDER_STORAGE_URL}/mender-convert/armbian/rockpro64/${ROCKPRO64_BINARIES}" |
|||
|
|||
function platform_modify() { |
|||
mkdir -p work/rockpro64 |
|||
|
|||
run_and_log_cmd "wget -Nq ${ROCKPRO64_BINARIES_URL} -P work/rockpro64" |
|||
run_and_log_cmd "tar xvf 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/fw_env.config work/rootfs/etc/" |
|||
|
|||
# It is not possible to resize rootfs part when using Mender. so disable |
|||
# the service |
|||
run_and_log_cmd "sudo touch work/rootfs/root/.no_rootfs_resize" |
|||
} |
|||
|
|||
function platform_package() { |
|||
log_info "Embedding bootloader in disk image" |
|||
run_and_log_cmd "dd if=work/rockpro64/rksd_loader.img of=${sdimg_path} \ |
|||
seek=64 conv=notrunc status=none" |
|||
} |
@ -0,0 +1,8 @@ |
|||
MENDER_STORAGE_DEVICE=/dev/mmcblk1p |
|||
|
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://d1b0l86ne08fsf.cloudfront.net/mender-convert/armbian/rockpro64/integration-scripts.tar.gz |
|||
ROCKPRO64_BINARIES="emmc-boot-integration-2017.09.tar.gz" |
|||
|
|||
source configs/rockpro64_config |
@ -0,0 +1,6 @@ |
|||
# Binaries generated with the following script: |
|||
# |
|||
# https://d1b0l86ne08fsf.cloudfront.net/mender-convert/armbian/rockpro64/integration-scripts.tar.gz |
|||
ROCKPRO64_BINARIES="sd-boot-integration-2017.09.tar.gz" |
|||
|
|||
source configs/rockpro64_config |
@ -1,22 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
rootfs_mapping=$2 |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f ${output_dir}/rootfs.img ] && \ |
|||
{ log "Error: extracted rootfs partition not found. Aborting."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/rootfs.img of=/dev/mapper/${rootfs_mapping} bs=8M conv=sparse >> "$build_log" 2>&1 |
|||
sync |
|||
|
|||
sudo e2fsck -y -f /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
sudo resize2fs /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
# Check Linux ext4 file system just in case. |
|||
sudo fsck.ext4 -fp /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
# Make sure the rootfs partition's label follows Mender naming convention. |
|||
sudo tune2fs -L "primary" /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,366 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
set -e |
|||
|
|||
show_help() { |
|||
cat << EOF |
|||
|
|||
Mender executables, service and configuration files installer. |
|||
|
|||
Usage: $0 [options] |
|||
|
|||
Options: [-m|--mender-disk-image | -g|--mender-client | -a|--artifact-name | |
|||
-d|--device-type | -n|--demo | -p|--demo-host-ip | -u| --server-url | |
|||
-c|--server-cert -t| --tenant-token -k|--keep -h|--help] |
|||
|
|||
--mender-disk-image - Mender raw disk image |
|||
--mender-client - Mender client binary file |
|||
--artifact-name - artifact info |
|||
--device-type - target device type identification |
|||
--demo - Configure image using demo parameters |
|||
--demo-host-ip - Mender demo server IP address |
|||
--server-url - Mender production server url |
|||
--server-cert - Mender server certificate |
|||
--tenant-token - Mender tenant token |
|||
--keep - Keep intermediate files in output directory |
|||
--help - Show help and exit |
|||
|
|||
For examples, see: ./mender-convert --help |
|||
|
|||
EOF |
|||
exit 1 |
|||
} |
|||
|
|||
jq_inplace() { |
|||
jq_args="$1" |
|||
dest_file="$2" |
|||
sudo sh -c -e "jq \"${jq_args}\" ${dest_file} > ${dest_file}.tmp && mv ${dest_file}.tmp ${dest_file}" |
|||
} |
|||
|
|||
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
output_dir=${tool_dir}/output |
|||
|
|||
meta_mender_repo="https://raw.githubusercontent.com/mendersoftware/meta-mender" |
|||
meta_mender_revision="thud" |
|||
|
|||
mender_dir=$output_dir/mender |
|||
device_type= |
|||
artifact_name= |
|||
# Mender demo server IP address. |
|||
demo_host_ip= |
|||
# Mender production server url passed as CLI option. |
|||
server_url= |
|||
# Mender production certificate. |
|||
server_cert= |
|||
# Mender tenant token passed as CLI option. |
|||
tenant_token= |
|||
# Mender tenant token. |
|||
mender_tenant_token="dummy" |
|||
# Mender state-script format version |
|||
mender_state_scripts_version="3" |
|||
|
|||
declare -a mender_disk_mappings |
|||
|
|||
append_rootfs_configuration() { |
|||
local conffile=$1 |
|||
|
|||
local rootfsparta="/dev/mmcblk0p2" |
|||
local rootfspartb="/dev/mmcblk0p3" |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
rootfsparta="/dev/hda2" |
|||
rootfspartb="/dev/hda3" |
|||
elif [ "$device_type" == "rockpro64" ]; then |
|||
rootfsparta="/dev/mmcblk1p2" |
|||
rootfspartb="/dev/mmcblk1p3" |
|||
fi |
|||
|
|||
jq_inplace '.RootfsPartA = \"'$rootfsparta'\" | .RootfsPartB = \"'$rootfspartb'\"' ${conffile} |
|||
} |
|||
|
|||
create_client_files() { |
|||
cat <<- EOF > $mender_dir/device_type |
|||
device_type=${device_type} |
|||
EOF |
|||
|
|||
case "$device_type" in |
|||
"beaglebone" | "qemux86_64") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk0 0x800000 0x20000 |
|||
/dev/mmcblk0 0x1000000 0x20000 |
|||
EOF |
|||
;; |
|||
"raspberrypi3"|"raspberrypi0w") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk0 0x400000 0x4000 |
|||
/dev/mmcblk0 0x800000 0x4000 |
|||
EOF |
|||
;; |
|||
"rockpro64") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk1 0x400000 0x8000 |
|||
/dev/mmcblk1 0x800000 0x8000 |
|||
EOF |
|||
;; |
|||
|
|||
esac |
|||
} |
|||
|
|||
get_mender_files_from_upstream() { |
|||
|
|||
mkdir -p $mender_dir |
|||
|
|||
log "\tDownloading demo server certificate." |
|||
|
|||
wget -q -O $mender_dir/server.demo.crt \ |
|||
$meta_mender_repo/$meta_mender_revision/meta-mender-demo/recipes-mender/mender/files/server.crt |
|||
} |
|||
|
|||
install_files() { |
|||
local primary_dir=$1 |
|||
local data_dir=$2 |
|||
|
|||
sysconfdir="etc/mender" |
|||
bindir="usr/bin" |
|||
localstatedir="var/lib/mender" |
|||
dataconfdir="mender" |
|||
databootdir="u-boot" |
|||
|
|||
log "\tInstalling files." |
|||
|
|||
# Prepare 'data' partition |
|||
sudo install -d -m 755 ${data_dir}/${dataconfdir} |
|||
sudo install -d -m 755 ${data_dir}/${databootdir} |
|||
|
|||
sudo install -d -m 755 ${primary_dir}/${sysconfdir}/scripts/ |
|||
echo -n "${mender_state_scripts_version}" | sudo tee ${primary_dir}/${sysconfdir}/scripts/version |
|||
|
|||
sudo install -m 0444 ${mender_dir}/device_type ${data_dir}/${dataconfdir} |
|||
sudo install -m 0644 ${mender_dir}/fw_env.config ${data_dir}/${databootdir} |
|||
|
|||
sudo ln -sf /data/${databootdir}/fw_env.config ${primary_dir}/etc/fw_env.config |
|||
|
|||
# Create mount-points |
|||
# |
|||
# Note that only one of /boot/efi or /uboot will be used depending on what |
|||
# type of Mender integration is used (GRUB or U-boot). I do not see any |
|||
# problems with keeping an empty directory to reduce complexity of creating |
|||
# this directory structure. |
|||
sudo install -d -m 755 ${primary_dir}/data |
|||
sudo install -d -m 755 ${primary_dir}/boot/efi |
|||
sudo install -d -m 755 ${primary_dir}/uboot |
|||
|
|||
case "$device_type" in |
|||
"qemux86_64") |
|||
sudo install -d ${primary_dir}/lib64 |
|||
sudo ln -sf /lib/ld-linux-x86-64.so.2 ${primary_dir}/lib64/ld-linux-x86-64.so.2 |
|||
;; |
|||
esac |
|||
|
|||
sudo ln -sf /data/${dataconfdir} ${primary_dir}/${localstatedir} |
|||
|
|||
# Call mender make install target |
|||
( cd $GOPATH/src/github.com/mendersoftware/mender && \ |
|||
sudo make install prefix=$primary_dir ) |
|||
|
|||
# If specified, replace Mender client binary |
|||
if [ -n "${mender_client}" ]; then |
|||
sudo install -m 0755 ${mender_client} ${primary_dir}/${bindir}/mender |
|||
fi |
|||
|
|||
# Enable menderd service starting on boot. |
|||
if [ -z "${standalone_operation}" ]; then |
|||
# Enable menderd service starting on boot. |
|||
sudo ln -sf /lib/systemd/system/mender.service \ |
|||
${primary_dir}/etc/systemd/system/multi-user.target.wants/mender.service |
|||
fi |
|||
|
|||
# By default production settings configuration is installed |
|||
if [ -n "${demo}" ] && [ ${demo} -eq 1 ]; then |
|||
sudo install -m 0644 ${primary_dir}/${sysconfdir}/mender.conf.demo ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# If specified, replace server URL |
|||
if [ -n "${server_url}" ]; then |
|||
jq_inplace '.ServerURL = \"'${server_url}'\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# Set tenant token |
|||
if [ -n "${tenant_token}" ]; then |
|||
jq_inplace '.TenantToken = \"'${tenant_token}'\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# Append RootfsPartA/B to mender.conf |
|||
append_rootfs_configuration ${primary_dir}/${sysconfdir}/mender.conf |
|||
|
|||
# Set artifact name |
|||
if [ -n "${artifact_name}" ]; then |
|||
sudo sh -c -e "echo artifact_name=${artifact_name} > ${primary_dir}/${sysconfdir}/artifact_info"; |
|||
fi |
|||
|
|||
# Set demo server and install demo certificate |
|||
if [ -n "${demo_host_ip}" ]; then |
|||
sudo sh -c -e "echo '$demo_host_ip docker.mender.io s3.docker.mender.io' >> $primary_dir/etc/hosts"; |
|||
jq_inplace '.ServerURL = \"https://docker.mender.io\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
sudo install -m 0444 ${mender_dir}/server.demo.crt ${primary_dir}/${sysconfdir}/server.crt |
|||
fi |
|||
|
|||
# Install provided |
|||
if [ -n "${server_cert}" ]; then |
|||
sudo install -m 0444 ${server_cert} ${primary_dir}/${sysconfdir}/server.crt |
|||
fi |
|||
|
|||
if [ -e "${primary_dir}/${sysconfdir}/server.crt" ]; then |
|||
jq_inplace '.ServerCertificate = \"/'${sysconfdir}'/server.crt\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
} |
|||
|
|||
do_install_mender() { |
|||
if [ -z "${mender_disk_image}" ]; then |
|||
log "Mender raw disk image not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${device_type}" ]; then |
|||
log "Target device type name not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${artifact_name}" ]; then |
|||
log "Artifact info not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${server_url}" ] && [ -z "${demo_host_ip}" ] && \ |
|||
[ -z "${tenant_token}" ]; then |
|||
log "No Mender server configuration was provided, it will only be possible to update using standalone mode." |
|||
standalone_operation="true" |
|||
fi |
|||
|
|||
if [ -n "${server_url}" ] && [ -n "${demo_host_ip}" ]; then |
|||
log "Incompatible server type choice. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
[ ! -f $mender_disk_image ] && \ |
|||
{ log "$mender_disk_image - file not found. Aborting."; exit 1; } |
|||
|
|||
test -n "$(go version)" || \ |
|||
{ log "go binary not found in PATH. Aborting."; exit 1; } |
|||
|
|||
test -n "$GOPATH" || \ |
|||
{ log "GOPATH not set. Aborting."; exit 1; } |
|||
|
|||
test -d $GOPATH/src/github.com/mendersoftware/mender || \ |
|||
{ log "mender source not found in \$GOPATH/src/github.com/mendersoftware/mender. Aborting."; exit 1; } |
|||
|
|||
# Mount rootfs partition A. |
|||
create_device_maps $mender_disk_image mender_disk_mappings |
|||
|
|||
# Change current directory to 'output' directory. |
|||
cd $output_dir |
|||
|
|||
primary=${mender_disk_mappings[1]} |
|||
data=${mender_disk_mappings[3]} |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
data=${mender_disk_mappings[4]} |
|||
fi |
|||
|
|||
map_primary=/dev/mapper/"$primary" |
|||
map_data=/dev/mapper/"$data" |
|||
path_primary=$output_dir/sdimg/primary |
|||
path_data=$output_dir/sdimg/data |
|||
mkdir -p ${path_primary} ${path_data} |
|||
|
|||
sudo mount ${map_primary} ${path_primary} |
|||
sudo mount ${map_data} ${path_data} |
|||
|
|||
# Get Mender client related files. |
|||
get_mender_files_from_upstream |
|||
|
|||
# Create all necessary client's files. |
|||
create_client_files |
|||
|
|||
# Create all required paths and install files. |
|||
install_files ${path_primary} ${path_data} |
|||
|
|||
# Back to working directory. |
|||
cd $tool_dir && sync |
|||
|
|||
# Clean stuff. |
|||
detach_device_maps ${mender_disk_mappings[@]} |
|||
rm -rf $output_dir/sdimg |
|||
[[ $keep -eq 0 ]] && { rm -rf $mender_dir; } |
|||
|
|||
log "\tDone." |
|||
} |
|||
|
|||
PARAMS="" |
|||
|
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-m | --mender-disk-image) |
|||
mender_disk_image=$2 |
|||
shift 2 |
|||
;; |
|||
-g | --mender-client) |
|||
mender_client=$2 |
|||
shift 2 |
|||
;; |
|||
-d | --device-type) |
|||
device_type=$2 |
|||
shift 2 |
|||
;; |
|||
-a | --artifact-name) |
|||
artifact_name=$2 |
|||
shift 2 |
|||
;; |
|||
-n | --demo) |
|||
demo="1" |
|||
shift 1 |
|||
;; |
|||
-i | --demo-host-ip) |
|||
demo_host_ip=$2 |
|||
shift 2 |
|||
;; |
|||
-c | --server-cert) |
|||
server_cert=$2 |
|||
shift 2 |
|||
;; |
|||
-u | --server-url) |
|||
server_url=$2 |
|||
shift 2 |
|||
;; |
|||
-t | --tenant-token) |
|||
tenant_token=$2 |
|||
shift 2 |
|||
;; |
|||
-k | --keep) |
|||
keep="1" |
|||
shift 1 |
|||
;; |
|||
-h | --help) |
|||
show_help |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
-*) |
|||
log "Error: unsupported option $1" |
|||
exit 1 |
|||
;; |
|||
*) |
|||
PARAMS="$PARAMS $1" |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
eval set -- "$PARAMS" |
|||
|
|||
# Some commands expect elevated privileges. |
|||
sudo true |
|||
|
|||
do_install_mender |
@ -1,389 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
show_help() { |
|||
cat << EOF |
|||
|
|||
Tool adding GRUB specific files to Mender compliant image file. |
|||
|
|||
Usage: $0 [options] |
|||
|
|||
Options: [-m|--mender-disk-image | -b|--bootloader-toolchain | |
|||
-k|--keep | -d|--device-type] |
|||
|
|||
--mender-disk-image - Mender raw disk image |
|||
--bootloader-toolchain - GNU Arm Embedded Toolchain |
|||
--device-type - target device type identification |
|||
--keep - prevent deleting GRUB workspace |
|||
|
|||
Note: supported device types are: beaglebone, raspberrypi3 |
|||
|
|||
Examples: |
|||
|
|||
./mender-convert install-bootloader-to-mender-disk-image |
|||
--mender-disk-image <mender_image_path> |
|||
--device-type <beaglebone | raspberrypi3> |
|||
--bootloader-toolchain arm-linux-gnueabihf |
|||
|
|||
Note: toolchain naming convention is arch-vendor-(os-)abi |
|||
|
|||
arch is for architecture: arm, mips, x86, i686... |
|||
vendor is tool chain supplier: apple, Codesourcery, Linux, |
|||
os is for operating system: linux, none (bare metal) |
|||
abi is for application binary interface convention: eabi, gnueabi, gnueabihf |
|||
|
|||
EOF |
|||
} |
|||
|
|||
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
output_dir=${tool_dir}/output |
|||
integration_dir=${tool_dir}/integration |
|||
grub_dir=$output_dir/grub |
|||
grubenv_dir=$output_dir/grubenv |
|||
mender_disk_image= |
|||
bootloader_toolchain= |
|||
device_type= |
|||
keep=0 |
|||
efi_boot=EFI/BOOT |
|||
EFI_STUB_VER="4.12.0" |
|||
build_log=$output_dir/build.log |
|||
|
|||
declare -a mender_disk_mappings |
|||
|
|||
version() { |
|||
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }' |
|||
} |
|||
|
|||
get_kernel_version() { |
|||
local search_path=$1/boot |
|||
local resultvar=$2 |
|||
|
|||
[ ! -d "$search_path" ] && { return 1; } |
|||
|
|||
kernel_image=$(ls -1 $search_path | grep -E "^vmlinuz") |
|||
|
|||
local myresult=${kernel_image#*-} |
|||
eval $resultvar="'$myresult'" |
|||
return 0 |
|||
} |
|||
|
|||
build_env_lock_boot_files() { |
|||
log "\tBuilding boot scripts and tools." |
|||
local grubenv_repo_vc_dir=$grubenv_dir/.git |
|||
local grubenv_build_dir=$grubenv_dir/build |
|||
|
|||
mkdir -p $grubenv_dir |
|||
|
|||
if [ ! -d $grubenv_repo_vc_dir ]; then |
|||
git clone https://github.com/mendersoftware/grub-mender-grubenv.git $grubenv_dir >> "$build_log" 2>&1 |
|||
fi |
|||
cd $grubenv_dir |
|||
|
|||
mkdir -p $grubenv_build_dir |
|||
|
|||
# Remove old defines & settings. |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
# Prepare configuration file. |
|||
cp mender_grubenv_defines.example mender_grubenv_defines |
|||
|
|||
local kernel_imagetype=kernel |
|||
local kernel_devicetree=dtb |
|||
|
|||
sed -i '/^kernel_imagetype/s/=.*$/='${kernel_imagetype}'/' mender_grubenv_defines |
|||
sed -i '/^kernel_devicetree/s/=.*$/='${kernel_devicetree//\//\\/}'/' mender_grubenv_defines |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
local root_base=/dev/hda |
|||
sed -i '/^mender_kernel_root_base/s/=.*$/='${root_base//\//\\/}'/' mender_grubenv_defines |
|||
fi |
|||
|
|||
make --quiet >> "$build_log" 2>&1 |
|||
rc=$? |
|||
[[ $rc -eq 0 ]] && { make --quiet DESTDIR=$grubenv_build_dir install >> "$build_log" 2>&1; } |
|||
rc=$? |
|||
[[ $rc -ne 0 ]] && { log "\tError: building process failed. Aborting."; } |
|||
|
|||
cd ${output_dir} |
|||
return $rc |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - linux kernel version |
|||
build_grub_efi() { |
|||
if [ "$device_type" == "rockpro64" ]; then |
|||
return 0 |
|||
fi |
|||
|
|||
log "\tBuilding GRUB efi file." |
|||
|
|||
local grub_build_dir=$grub_dir/build |
|||
local grub_arm_dir=$grub_build_dir/arm |
|||
local host=$(uname -m) |
|||
local grub_host_dir=$grub_build_dir/$host |
|||
local grub_repo_vc_dir=$grub_dir/.git |
|||
|
|||
local version=$(echo $1 | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') |
|||
|
|||
# Build grub modules for arm platform and executables for the host. |
|||
if [ ! -d $grub_repo_vc_dir ]; then |
|||
git clone git://git.savannah.gnu.org/grub.git $grub_dir >> "$build_log" 2>&1 |
|||
fi |
|||
|
|||
cd $grub_dir |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
if [ $(version $version) -lt $(version $EFI_STUB_VER) ]; then |
|||
# To avoid error message: "plain image kernel not supported - rebuild |
|||
# with CONFIG_(U)EFI_STUB enabled" - use a specific commit. |
|||
git checkout 9b37229f0 >> "$build_log" 2>&1 |
|||
else |
|||
git checkout 72e80c025 >> "$build_log" 2>&1 |
|||
fi |
|||
|
|||
mkdir -p $grub_arm_dir |
|||
mkdir -p $grub_host_dir |
|||
|
|||
local cores=$(nproc) |
|||
|
|||
# First build host tools. |
|||
./autogen.sh >> "$build_log" 2>&1 |
|||
./configure --quiet CC=gcc --target=${host} --with-platform=efi --prefix=$grub_host_dir >> "$build_log" 2>&1 |
|||
make --quiet -j$cores >> "$build_log" 2>&1 |
|||
make --quiet install >> "$build_log" 2>&1 |
|||
|
|||
local format=${host}-efi |
|||
grub_name=bootx64.efi |
|||
local modules_path=$grub_host_dir/lib/grub/$format/ |
|||
|
|||
if [ "$device_type" == "beaglebone" ]; then |
|||
# Clean workspace. |
|||
make --quiet clean >> "$build_log" 2>&1 |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
# Now build ARM modules. |
|||
./configure --quiet --host=$bootloader_toolchain --with-platform=efi \ |
|||
--prefix=$grub_arm_dir CFLAGS="-Os -march=armv7-a" \ |
|||
CCASFLAGS="-march=armv7-a" --disable-werror >> "$build_log" 2>&1 |
|||
make --quiet -j$cores >> "$build_log" 2>&1 |
|||
make --quiet install >> "$build_log" 2>&1 |
|||
|
|||
format=arm-efi |
|||
grub_name=grub-arm.efi |
|||
modules_path=$grub_arm_dir/lib/grub/$format/ |
|||
fi |
|||
|
|||
# Build GRUB EFI image. |
|||
${grub_host_dir}/bin/grub-mkimage -v -p /$efi_boot -o $grub_name --format=$format \ |
|||
-d $modules_path boot linux ext2 fat serial part_msdos part_gpt normal \ |
|||
efi_gop iso9660 configfile search loadenv test cat echo gcry_sha256 halt \ |
|||
hashsum loadenv reboot >> "$build_log" 2>&1 |
|||
|
|||
rc=$? |
|||
[[ $rc -ne 0 ]] && { log "\tBuilding grub.efi failed. Aborting."; } \ |
|||
|| { log "\tBuilding grub.efi succeeded."; } |
|||
|
|||
cd ${output_dir} |
|||
return $rc |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - boot partition mountpoint |
|||
set_uenv() { |
|||
local boot_dir=$1 |
|||
# Erase/create uEnv.txt file. |
|||
sudo install -b -m 644 /dev/null $boot_dir/uEnv.txt |
|||
|
|||
# Fill uEnv.txt file. |
|||
cat <<- 'EOF' | sudo tee $boot_dir/uEnv.txt 2>&1 >/dev/null |
|||
bootdir= |
|||
grubfile=EFI/BOOT/grub-arm.efi |
|||
grubaddr=0x80007fc0 |
|||
loadgrub=fatload mmc 0:1 ${grubaddr} ${grubfile} |
|||
grubstart=bootefi ${grubaddr} |
|||
uenvcmd=mmc rescan; run loadgrub; run grubstart; |
|||
EOF |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - boot partition mountpoint |
|||
# $2 - primary partition mountpoint |
|||
# $3 - linux kernel version |
|||
install_files() { |
|||
log "\tInstalling GRUB files." |
|||
local boot_dir=$1 |
|||
local rootfs_dir=$2 |
|||
local linux_version=$3 |
|||
|
|||
if [ "$device_type" == "rockpro64" ]; then |
|||
cp $integration_dir/rockpro64/boot.scr ${boot_dir}/ |
|||
|
|||
# It is not possible to resize rootfs part when using Mender. so disable |
|||
# the service |
|||
touch ${rootfs_dir}/root/.no_rootfs_resize |
|||
return 0 |
|||
fi |
|||
|
|||
local grub_build_dir=$grub_dir/build |
|||
local grub_arm_dir=$grub_build_dir/arm |
|||
local grub_host_dir=$grub_build_dir/$(uname -m) |
|||
|
|||
local grubenv_build_dir=$grubenv_dir/build |
|||
local grubenv_efi_boot_dir=$grubenv_build_dir/boot/efi/EFI/BOOT/ |
|||
|
|||
local efi_boot_dir=$boot_dir/$efi_boot |
|||
|
|||
# Make sure env, lock, lock.sha256sum files exists in working directory. |
|||
[[ ! -d $grubenv_efi_boot_dir/mender_grubenv1 || \ |
|||
! -d $grubenv_efi_boot_dir/mender_grubenv2 ]] && \ |
|||
{ log "Error: cannot find mender grub related files."; return 1; } |
|||
|
|||
sudo install -d -m 755 $efi_boot_dir |
|||
|
|||
cd $grubenv_efi_boot_dir && find . -type f -exec sudo install -Dm 644 "{}" "$efi_boot_dir/{}" \; |
|||
cd ${output_dir} |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
sudo install -m 0755 ${grub_host_dir}/bin/grub-editenv $rootfs_dir/usr/bin |
|||
else |
|||
sudo install -m 0755 ${grub_arm_dir}/bin/grub-editenv $rootfs_dir/usr/bin |
|||
fi |
|||
|
|||
sudo install -m 0644 ${grub_dir}/${grub_name} $efi_boot_dir |
|||
|
|||
sudo install -m 0755 $grubenv_build_dir/usr/bin/fw_printenv $rootfs_dir/sbin/fw_printenv |
|||
sudo install -m 0755 $grubenv_build_dir/usr/bin/fw_setenv $rootfs_dir/sbin/fw_setenv |
|||
|
|||
# Replace U-Boot default printenv/setenv commands. |
|||
sudo ln -fs /sbin/fw_printenv $rootfs_dir/usr/bin/fw_printenv |
|||
sudo ln -fs /sbin/fw_setenv $rootfs_dir/usr/bin/fw_setenv |
|||
|
|||
#Create links for grub |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
# Copy kernel image to fit the grubenv defines. |
|||
sudo cp $boot_dir/bzImage $rootfs_dir/boot/kernel |
|||
elif [ "$device_type" == "beaglebone" ]; then |
|||
#Replace U-Boot default images for Debian 9.5 |
|||
if [ `grep -s '9.5' $rootfs_dir/etc/debian_version | wc -l` -eq 1 ]; then |
|||
sudo cp ${tool_dir}/files/uboot_debian_9.4/MLO ${boot_dir}/MLO |
|||
sudo cp ${tool_dir}/files/uboot_debian_9.4/u-boot.img ${boot_dir}/u-boot.img |
|||
fi |
|||
# Make links to kernel and device tree files. |
|||
sudo ln -sf /boot/dtbs/$linux_version/am335x-boneblack.dtb $rootfs_dir/boot/dtb |
|||
sudo ln -sf /boot/vmlinuz-$linux_version $rootfs_dir/boot/kernel |
|||
set_uenv $boot_dir |
|||
fi |
|||
} |
|||
|
|||
do_install_bootloader() { |
|||
if [ -z "${mender_disk_image}" ]; then |
|||
log "Mender raw disk image not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${bootloader_toolchain}" ]; then |
|||
log "ARM GCC toolchain not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${device_type}" ]; then |
|||
log "Target device type name not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if ! [ -x "$(command -v ${bootloader_toolchain}-gcc)" ]; then |
|||
log "Error: ARM GCC not found in PATH. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
[ ! -f $mender_disk_image ] && \ |
|||
{ log "$mender_disk_image - file not found. Aborting."; exit 1; } |
|||
|
|||
# Map & mount Mender compliant image. |
|||
create_device_maps $mender_disk_image mender_disk_mappings |
|||
|
|||
# Change current directory to 'output' directory. |
|||
cd $output_dir |
|||
|
|||
boot=${mender_disk_mappings[0]} |
|||
primary=${mender_disk_mappings[1]} |
|||
map_boot=/dev/mapper/"$boot" |
|||
map_primary=/dev/mapper/"$primary" |
|||
path_boot=$output_dir/sdimg/boot |
|||
path_primary=$output_dir/sdimg/primary |
|||
mkdir -p ${path_boot} ${path_primary} |
|||
|
|||
sudo mount ${map_boot} ${path_boot} |
|||
sudo mount ${map_primary} ${path_primary} |
|||
|
|||
get_kernel_version ${path_primary} kernel_version |
|||
log "\tFound kernel version: $kernel_version" |
|||
|
|||
build_env_lock_boot_files |
|||
rc=$? |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
[[ $rc -eq 0 ]] && { build_grub_efi ${EFI_STUB_VER}; } |
|||
else |
|||
[[ $rc -eq 0 ]] && { build_grub_efi ${kernel_version}; } |
|||
fi |
|||
rc=$? |
|||
[[ $rc -eq 0 ]] && { install_files ${path_boot} ${path_primary} ${kernel_version}; } |
|||
rc=$? |
|||
|
|||
# Back to working directory. |
|||
cd $tool_dir && sync |
|||
|
|||
detach_device_maps ${mender_disk_mappings[@]} |
|||
# Clean files. |
|||
rm -rf $output_dir/sdimg |
|||
|
|||
[[ $keep -eq 0 ]] && { rm -rf $grubenv_dir $grub_dir; } |
|||
[[ $rc -ne 0 ]] && { exit 1; } || { log "\tDone."; } |
|||
} |
|||
|
|||
PARAMS="" |
|||
|
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-m | --mender-disk-image) |
|||
mender_disk_image=$2 |
|||
shift 2 |
|||
;; |
|||
-b | --bootloader-toolchain) |
|||
bootloader_toolchain=$2 |
|||
shift 2 |
|||
;; |
|||
-d | --device-type) |
|||
device_type=$2 |
|||
shift 2 |
|||
;; |
|||
-k | --keep) |
|||
keep=1 |
|||
shift 1 |
|||
;; |
|||
-h | --help) |
|||
show_help |
|||
exit 0 |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
-*) |
|||
log "Error: unsupported option $1" |
|||
exit 1 |
|||
;; |
|||
*) |
|||
PARAMS="$PARAMS $1" |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
eval set -- "$PARAMS" |
|||
|
|||
# Some commands expect elevated privileges. |
|||
sudo true |
|||
|
|||
do_install_bootloader |
@ -1 +0,0 @@ |
|||
output/ |
@ -1,13 +0,0 @@ |
|||
FROM ubuntu:18.04 |
|||
|
|||
ARG MENDER_ARTIFACT_VERSION=3.2.0 |
|||
|
|||
RUN apt-get update && apt-get install -y \ |
|||
wget \ |
|||
qemu-user-static |
|||
|
|||
RUN wget -q -O /usr/bin/mender-artifact https://d1b0l86ne08fsf.cloudfront.net/mender-artifact/$MENDER_ARTIFACT_VERSION/mender-artifact \ |
|||
&& chmod +x /usr/bin/mender-artifact |
|||
|
|||
COPY docker-entrypoint.sh /usr/local/bin/ |
|||
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] |
@ -1,64 +0,0 @@ |
|||
Device Image Shell |
|||
================== |
|||
|
|||
This directory contains a tool that takes the root file system of your device as input and emulates a shell session on your device. |
|||
Any commands you run (e.g. apt update, apt upgrade) will behave as if you were logged into your actual device! |
|||
|
|||
The purpose of the tool is to create a new root file system image and Mender Artifact that can be deployed to a fleet of devices in the field. |
|||
|
|||
|
|||
## Docker environment |
|||
|
|||
To ensure dependencies are correctly set up and it is portable, a docker environment is used. |
|||
|
|||
You need to [install Docker Engine](https://docs.docker.com/install) to use this tool. |
|||
|
|||
|
|||
### Build the device-image-shell container image |
|||
|
|||
To build a container based on Ubuntu 18.04 with the required dependencies, copy this directory to your workstation and change the current directory to it. |
|||
|
|||
Then run |
|||
|
|||
```bash |
|||
./docker-build |
|||
``` |
|||
|
|||
This will create a container image `device-image-shell`. |
|||
|
|||
|
|||
### Use the device-image-shell container image |
|||
|
|||
The also assumes your device is based on the ARM architecture, which is the most common (e.g. Raspberry Pi, BeagleBoard, etc.). |
|||
|
|||
You need a root file system image (usually with .ext4 extension) for your device as a starting point, such as one output by [mender-convert](https://github.com/mendersoftware/mender-convert). Make sure to have `qemu-user-static` installed on a host machine. |
|||
|
|||
You can now enter a shell in your device root file system image by running `docker-device-image-shell` with the desired arguments: |
|||
|
|||
1. path to your existing root file system image |
|||
2. desired name for the generated Mender Artifact |
|||
3. device type, which Mender uses to ensure compatibility between devices and software |
|||
|
|||
For example, if you are using a Raspberry Pi 3, you can run: |
|||
|
|||
```bash |
|||
./docker-device-image-shell ../output/2018-11-13-raspbian-stretch-lite.ext4 2018-11-13-raspbian-stretch-lite-aptupgrade raspberrypi3 |
|||
``` |
|||
|
|||
You should now see a shell prompt. You are in an emulated environment, so any commands run here will behave as if you ran them on your device! In addition, any changes you make will be preserved in the output root file system image and Mender Artifact. |
|||
|
|||
For example, to update to the latest packages run: |
|||
|
|||
```bash |
|||
apt update |
|||
apt upgrade |
|||
``` |
|||
|
|||
When you are done, press `Ctrl+D` or run the `exit` command. Generating the Mender Artifact will take a few more minutes, depending on the size of the input image and resources available on your workstation. |
|||
|
|||
After it finishes you can find your new `.ext4` and `.mender` files in the `output/` directory. For devices where Mender is installed, you can use the Mender Artifact (`.mender` file) to deploy the changes you made in the shell to all your devices! |
|||
|
|||
|
|||
### Use caution |
|||
|
|||
Please note that since this tool is using an emulated environment (based on `qemu`) and you are not properly logged in to your device, some things may not work as expected. Look for any relevant errors in commands you run and make sure to test your changes before deploying to production devices! |
@ -1,7 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
DOCKER_IMAGE_NAME=device-image-shell |
|||
|
|||
docker build . -t ${DOCKER_IMAGE_NAME} |
@ -1,58 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
DOCKER_IMAGE_NAME=device-image-shell |
|||
OUTPUT_DIR="$(pwd)/output" |
|||
|
|||
show_usage() { |
|||
echo "Usage:" |
|||
echo "$0 <rootfs input file> <output Artifact name> <device type>" |
|||
} |
|||
|
|||
if [ "$#" -ne 3 ]; then |
|||
echo "ERROR: 3 parameters required." |
|||
show_usage |
|||
exit 1 |
|||
fi |
|||
|
|||
ROOTFS_INPUT_FILE=$1 |
|||
ARTIFACT_NAME=$2 |
|||
DEVICE_TYPE=$3 |
|||
|
|||
if [ ! -f "$ROOTFS_INPUT_FILE" ]; then |
|||
echo "ERROR: File passed as first argument is not accessible." |
|||
echo "Got ROOTFS_INPUT_FILE=\"$ROOTFS_INPUT_FILE\"" |
|||
show_usage |
|||
exit 1 |
|||
fi |
|||
|
|||
|
|||
mkdir -p $OUTPUT_DIR |
|||
|
|||
ROOTFS_INPUT_FILE_NAME="$(basename -- $ROOTFS_INPUT_FILE)" |
|||
ROOTFS_INPUT_FILE_EXTENSION="${ROOTFS_INPUT_FILE_NAME##*.}" |
|||
|
|||
ROOTFS_OUTPUT_FILE_NAME="$ARTIFACT_NAME.$ROOTFS_INPUT_FILE_EXTENSION" |
|||
|
|||
echo "Copying rootfs input file..." |
|||
rsync -h --progress $ROOTFS_INPUT_FILE $OUTPUT_DIR/$ROOTFS_OUTPUT_FILE_NAME |
|||
|
|||
docker run \ |
|||
-ti \ |
|||
--privileged=true \ |
|||
--mount type=bind,source=$OUTPUT_DIR,target=/root_images \ |
|||
$DOCKER_IMAGE_NAME $ROOTFS_OUTPUT_FILE_NAME $ARTIFACT_NAME $DEVICE_TYPE |
|||
|
|||
|
|||
# Output Artifact gets root owner and group, change to current logged in |
|||
CURRENT_USER=$(id -u -n) |
|||
CURRENT_GROUP=$(id -g -n) |
|||
|
|||
echo "Changing ownership of Mender Artifact (may ask you to authenticate)" |
|||
sudo chown $CURRENT_USER:$CURRENT_GROUP $OUTPUT_DIR/$ARTIFACT_NAME.mender |
|||
|
|||
echo "Image generation complete!" |
|||
/bin/echo -e "The new root file system is at:\n\t$OUTPUT_DIR/$ROOTFS_OUTPUT_FILE_NAME" |
|||
/bin/echo -e "The new Mender Artifact you can upload to your Mender server to deploy to your devices is at:\ |
|||
\n\t$OUTPUT_DIR/$ARTIFACT_NAME.mender" |
@ -1,38 +0,0 @@ |
|||
#!/bin/sh |
|||
set -e |
|||
|
|||
ROOTFS_OUTPUT_FILE_NAME=$1 |
|||
ARTIFACT_NAME=$2 |
|||
DEVICE_TYPE=$3 |
|||
|
|||
mkdir /root_system |
|||
|
|||
mount /root_images/$ROOTFS_OUTPUT_FILE_NAME /root_system |
|||
|
|||
if [ -f /root_system/usr/bin/qemu-arm-static ]; then |
|||
echo "WARNING: /usr/bin/qemu-arm-static already exists in image. Using this but may be of incompatible version." |
|||
QEMU_STATIC_COPIED=false |
|||
else |
|||
# trick to make chroot into ARM image work |
|||
cp /usr/bin/qemu-arm-static /root_system/usr/bin |
|||
QEMU_STATIC_COPIED=true |
|||
fi |
|||
|
|||
echo "Entering emulated shell in device image. All commands are run as the root user of the device image." |
|||
echo "Make changes (e.g. apt update, apt upgrade, wget ...) and press Ctrl-D when done." |
|||
|
|||
# Using bash for command completion support and other conveniences |
|||
chroot /root_system /bin/bash |
|||
|
|||
# Mender Artifact name must also be present inside |
|||
echo artifact_name=$ARTIFACT_NAME > /root_system/etc/mender/artifact_info |
|||
|
|||
if [ "$QEMU_STATIC_COPIED" = true ]; then |
|||
rm /root_system/usr/bin/qemu-arm-static |
|||
fi |
|||
|
|||
umount /root_system |
|||
|
|||
echo "Creating Mender Artifact. This may take 10-20 minutes (using LZMA)..." |
|||
mender-artifact --compression lzma write rootfs-image -t $DEVICE_TYPE -n $ARTIFACT_NAME -f /root_images/$ROOTFS_OUTPUT_FILE_NAME -o /root_images/$ARTIFACT_NAME.mender |
|||
sync |
@ -1,21 +1,21 @@ |
|||
#!/bin/sh |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
set -e |
|||
|
|||
if [ -z "$IMAGE_NAME" ]; then |
|||
IMAGE_NAME=mender-convert |
|||
fi |
|||
IMAGE_NAME=${IMAGE_NAME:-mender-convert} |
|||
|
|||
MENDER_CLIENT_VERSION="2.1.1" |
|||
|
|||
DOCKER_ARGS="--build-arg mender_client_version=${MENDER_CLIENT_VERSION}" |
|||
|
|||
if [ "$1" = "arm64" ]; then |
|||
DOCKER_ARGS="${DOCKER_ARGS} --build-arg toolchain_host=aarch64-linux-gnu" |
|||
DOCKER_ARGS="${DOCKER_ARGS} --build-arg go_flags=GOARCH=arm64" |
|||
else |
|||
DOCKER_ARGS="${DOCKER_ARGS} --build-arg toolchain_host=arm-buildroot-linux-gnueabihf" |
|||
DOCKER_ARGS="${DOCKER_ARGS} --build-arg go_flags=\"GOARM=6 GOARCH=arm\"" |
|||
fi |
|||
|
|||
eval docker build . -t ${IMAGE_NAME} ${DOCKER_ARGS} |
|||
eval docker build . -t ${IMAGE_NAME} "$@" |
|||
|
@ -1,16 +1,30 @@ |
|||
#!/bin/sh |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
set -e |
|||
|
|||
IMAGE_NAME=mender-convert |
|||
IMAGE_NAME=${IMAGE_NAME:-mender-convert} |
|||
|
|||
MENDER_CONVERT_DIR="$(pwd)" |
|||
mkdir -p output |
|||
|
|||
docker run \ |
|||
--mount type=bind,source="$MENDER_CONVERT_DIR,target=/mender-convert" \ |
|||
-v $MENDER_CONVERT_DIR:/mender-convert \ |
|||
--privileged=true \ |
|||
--cap-add=SYS_MODULE \ |
|||
-v /dev:/dev \ |
|||
-v /lib/modules:/lib/modules:ro \ |
|||
--env MENDER_ARTIFACT_NAME=${MENDER_ARTIFACT_NAME} \ |
|||
$IMAGE_NAME "$@" |
|||
|
@ -1,112 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
reboot_pi () { |
|||
umount /uboot |
|||
sync |
|||
echo b > /proc/sysrq-trigger |
|||
sleep 5 |
|||
exit 0 |
|||
} |
|||
|
|||
check_commands () { |
|||
if ! command -v whiptail > /dev/null; then |
|||
FAIL_REASON="whiptail not found" |
|||
sleep 5 |
|||
return 1 |
|||
fi |
|||
for COMMAND in grep cut sed parted fdisk; do |
|||
if ! command -v $COMMAND > /dev/null; then |
|||
FAIL_REASON="$COMMAND not found" |
|||
return 1 |
|||
fi |
|||
done |
|||
return 0 |
|||
} |
|||
|
|||
get_variables () { |
|||
# /sys/block/mmcblk0/mmcblk0p4/ |
|||
ROOT_PART_NAME="mmcblk0p4" |
|||
ROOT_DEV_NAME="mmcblk0" |
|||
ROOT_DEV="/dev/${ROOT_DEV_NAME}" |
|||
ROOT_PART_NUM=`cat /sys/block/${ROOT_DEV_NAME}/${ROOT_PART_NAME}/partition` |
|||
|
|||
BOOT_PART_DEV=`cat /proc/mounts | grep " /uboot " | cut -d " " -f 1` |
|||
BOOT_PART_NAME=`echo $BOOT_PART_DEV | cut -d "/" -f 3` |
|||
BOOT_DEV_NAME=`echo /sys/block/*/${BOOT_PART_NAME} | cut -d "/" -f 4` |
|||
BOOT_PART_NUM=`cat /sys/block/${BOOT_DEV_NAME}/${BOOT_PART_NAME}/partition` |
|||
|
|||
ROOT_DEV_SIZE=`cat /sys/block/${ROOT_DEV_NAME}/size` |
|||
TARGET_END=`expr $ROOT_DEV_SIZE - 1` |
|||
|
|||
PARTITION_TABLE=`parted -m $ROOT_DEV unit s print | tr -d 's'` |
|||
|
|||
LAST_PART_NUM=`echo "$PARTITION_TABLE" | tail -n 1 | cut -d ":" -f 1` |
|||
|
|||
ROOT_PART_LINE=`echo "$PARTITION_TABLE" | grep -e "^${ROOT_PART_NUM}:"` |
|||
ROOT_PART_START=`echo $ROOT_PART_LINE | cut -d ":" -f 2` |
|||
ROOT_PART_END=`echo $ROOT_PART_LINE | cut -d ":" -f 3` |
|||
} |
|||
|
|||
check_variables () { |
|||
if [ $ROOT_PART_NUM -ne $LAST_PART_NUM ]; then |
|||
FAIL_REASON="Data partition should be last partition" |
|||
return 1 |
|||
fi |
|||
|
|||
if [ $ROOT_PART_END -gt $TARGET_END ]; then |
|||
FAIL_REASON="Data partition runs past the end of device" |
|||
return 1 |
|||
fi |
|||
|
|||
if [ ! -b $ROOT_DEV ] || [ ! -b $ROOT_PART_DEV ] || [ ! -b $BOOT_PART_DEV ] ; then |
|||
FAIL_REASON="Could not determine partitions" |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
main () { |
|||
get_variables |
|||
|
|||
if ! check_variables; then |
|||
return 1 |
|||
fi |
|||
|
|||
if [ $ROOT_PART_END -eq $TARGET_END ]; then |
|||
reboot_pi |
|||
fi |
|||
|
|||
if ! parted -m $ROOT_DEV u s resizepart $ROOT_PART_NUM $TARGET_END; then |
|||
FAIL_REASON="Data partition resize failed" |
|||
return 1 |
|||
fi |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
mount -t proc proc /proc |
|||
mount -t sysfs sys /sys |
|||
|
|||
mount /uboot |
|||
sed -i 's| init=/usr/lib/raspi-config/init_resize.sh||' /uboot/cmdline.txt |
|||
sed -i 's| sdhci\.debug_quirks2=4||' ${output_dir}/cmdline.txt |
|||
if ! grep -q splash /uboot/cmdline.txt; then |
|||
sed -i "s/ quiet//g" /uboot/cmdline.txt |
|||
fi |
|||
mount /uboot -o remount,ro |
|||
sync |
|||
|
|||
echo 1 > /proc/sys/kernel/sysrq |
|||
|
|||
if ! check_commands; then |
|||
reboot_pi |
|||
fi |
|||
|
|||
if main; then |
|||
whiptail --infobox "Resized data partition. Rebooting in 5 seconds..." 20 60 |
|||
sleep 5 |
|||
else |
|||
sleep 5 |
|||
whiptail --msgbox "Could not expand filesystem, please try raspi-config.\n${FAIL_REASON}" 20 60 |
|||
fi |
|||
|
|||
reboot_pi |
@ -1,13 +0,0 @@ |
|||
[Unit] |
|||
Description=Expand data partition file system |
|||
After=mender.service |
|||
|
|||
[Service] |
|||
Type=simple |
|||
User=root |
|||
Group=root |
|||
ExecStart=/bin/sh -c 'sleep 1 ; /usr/sbin/resizefs.sh start' |
|||
RemainAfterExit=true |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
@ -1,42 +0,0 @@ |
|||
#!/bin/sh |
|||
### BEGIN INIT INFO |
|||
# Provides: resizefs |
|||
# Required-Start: |
|||
# Required-Stop: |
|||
# Default-Start: 3 |
|||
# Default-Stop: |
|||
# Short-Description: Resize the data filesystem to fill partition |
|||
# Description: |
|||
### END INIT INFO |
|||
|
|||
. /lib/lsb/init-functions |
|||
|
|||
case "$1" in |
|||
start) |
|||
log_daemon_msg "Starting resizefs service (once)" |
|||
DISK=$(lsblk -f | sed -n '2{p;q}') |
|||
DISK_DEV="/dev/$DISK" |
|||
DISK_SIZE=$(blockdev --getsize $DISK_DEV) |
|||
DATA_PART_DEV=$(findmnt /data -o source -n) |
|||
DATA_PART=$(basename $DATA_PART_DEV) |
|||
DATA_PART_START=$(parted -m $DISK_DEV unit s print | tr -d 's' | tail -n 1 | cut -d ":" -f 2) |
|||
DATA_PART_SIZE=$(blockdev --getsize $DATA_PART_DEV) |
|||
FREE_SPACE=`expr $DISK_SIZE - $DATA_PART_START - $DATA_PART_SIZE` |
|||
|
|||
if [ $FREE_SPACE -eq 0 ]; then |
|||
log_daemon_msg "Data partition already resized, aborting" |
|||
else |
|||
resize2fs $DATA_PART_DEV |
|||
FSSIZEMEG=`expr $FREE_SPACE + $DATA_PART_SIZE` |
|||
FSSIZEMEG=`expr $FSSIZEMEG / 2 / 1024`"M" |
|||
log_daemon_msg "Resizing $DATA_PART finished, new size is $FSSIZEMEG" |
|||
fi |
|||
|
|||
systemctl --no-reload disable resizefs.service |
|||
log_end_msg $? |
|||
;; |
|||
*) |
|||
echo "Usage: $0 start" >&2 |
|||
exit 3 |
|||
;; |
|||
esac |
Binary file not shown.
Binary file not shown.
@ -1,31 +0,0 @@ |
|||
MENDER_BOOT_PART="/dev/mmcblk0p1" |
|||
MENDER_BOOT_PART_DEFAULT="/dev/mmcblk0p1" |
|||
MENDER_BOOT_PART_FSTYPE="auto" |
|||
MENDER_BOOT_PART_FSTYPE_DEFAULT="auto" |
|||
MENDER_BOOT_PART_MOUNT_LOCATION="" |
|||
MENDER_BOOT_PART_SIZE_MB="16" |
|||
MENDER_BOOT_PART_SIZE_MB_DEFAULT="16" |
|||
MENDER_DATA_PART_DEFAULT="/dev/mmcblk0p4" |
|||
MENDER_DATA_PART_FSTYPE="auto" |
|||
MENDER_DATA_PART_FSTYPE_DEFAULT="auto" |
|||
MENDER_DATA_PART_SIZE_MB="128" |
|||
MENDER_DATA_PART_SIZE_MB_DEFAULT="128" |
|||
MENDER_DEVICE_TYPE="vexpress-qemu" |
|||
MENDER_DEVICE_TYPES_COMPATIBLE="vexpress-qemu" |
|||
MENDER_DEVICE_TYPES_COMPATIBLE_DEFAULT="vexpress-qemu" |
|||
MENDER_DEVICE_TYPE_DEFAULT="vexpress-qemu" |
|||
MENDER_PARTITIONING_OVERHEAD_KB="32768" |
|||
MENDER_PARTITION_ALIGNMENT="" |
|||
MENDER_ROOTFS_PART_A="/dev/mmcblk0p2" |
|||
MENDER_ROOTFS_PART_B="/dev/mmcblk0p3" |
|||
MENDER_STORAGE_DEVICE="/dev/mmcblk0" |
|||
MENDER_STORAGE_TOTAL_SIZE_MB="" |
|||
MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET="" |
|||
MENDER_CALC_ROOTFS_SIZE="" |
|||
MENDER_ARTIFACT_NAME="release-1" |
|||
MENDER_MACHINE="vexpress-qemu" |
|||
HOST_ARCH="arm" |
|||
IMAGE_FSTYPES=" tar.bz2 ext4 mender mender.bmap sdimg sdimg.bmap" |
|||
ARTIFACTIMG_FSTYPE="ext4" |
|||
DISTRO_FEATURES="" |
|||
DEPLOY_DIR_IMAGE="" |
@ -0,0 +1,109 @@ |
|||
#! /usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
echo "Running $(basename $0): $@" |
|||
|
|||
source modules/bootstrap.sh |
|||
source modules/disk.sh |
|||
|
|||
# The mender_convert_config is always used and provides all the defaults |
|||
declare -a configs=("configs/mender_convert_config") |
|||
|
|||
disk_image="" |
|||
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 |
|||
|
|||
if [ -z "${disk_image}" ]; then |
|||
log_warn "Sorry, but '--disk-image' is a mandatory option" |
|||
log_warn "See ./mender-convert --help for more information" |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ ! -e ${disk_image} ]; then |
|||
log_fatal "File not found: ${disk_image}" |
|||
fi |
|||
|
|||
# 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[@]}") |
|||
|
|||
MKFS_VFAT="/usr/bin/mkfs.vfat" |
|||
if [ ! -f ${MKFS_VFAT} ]; then |
|||
MKFS_VFAT="/sbin/mkfs.vfat" |
|||
fi |
|||
|
|||
declare -i nr_of_parts=$(disk_get_nr_of_parts ${disk_image}) |
|||
|
|||
log_info "Validating disk image" |
|||
|
|||
if [ ${nr_of_parts} -eq 0 ]; then |
|||
log_fatal "Sorry, but could not find any valid partitions for: ${disk_image}" |
|||
fi |
|||
|
|||
log_info "Disk parsed successfully" |
|||
log_info "NUMBER OF PARTS: ${nr_of_parts} TYPE: $(disk_get_part_value ${disk_image} 1 SCHEME)" |
|||
|
|||
for ((n=1;n<=${nr_of_parts};n++)); do |
|||
part_dst_file="work/part-${n}.fs" |
|||
|
|||
if [ "$(disk_get_part_value ${disk_image} ${n} TYPE)" == "0x8e" ]; then |
|||
log_fatal "Detected an LVM volume group on disk. Unfortunately this is not yet supported" |
|||
fi |
|||
|
|||
log_info "PART ${n}: SIZE: $(disk_get_part_value ${disk_image} ${n} SIZE) TYPE: $(disk_get_part_value ${disk_image} ${n} TYPE)" |
|||
log_info "PART ${n}: extracting to ${part_dst_file}" |
|||
|
|||
disk_extract_part "${disk_image}" $(disk_get_part_value ${disk_image} ${n} START) \ |
|||
$(disk_get_part_value ${disk_image} ${n} SECTORS) ${part_dst_file} |
|||
done |
|||
|
|||
# Some disk images will not have an boot partition for us to extract, |
|||
# but we do require it be present and hence we might need to generate |
|||
# a filesystem image here. |
|||
if [ ${nr_of_parts} -eq 1 ]; then |
|||
log_info "Generating boot partition (required, does not exist in original image)" |
|||
run_and_log_cmd "dd if=/dev/zero of=work/boot-generated.vfat count=${MENDER_BOOT_PART_SIZE_MB} bs=1M status=none" |
|||
run_and_log_cmd "${MKFS_VFAT} work/boot-generated.vfat" |
|||
fi |
|||
|
|||
# Extract boot gap, that is the area from sector 1 until first part, and |
|||
# this is done because some images might contain the bootloader embedded here |
|||
# and we might need to keep this area intact when we generate our custom |
|||
# image. |
|||
if [ "${MENDER_COPY_BOOT_GAP}" == "y" ]; then |
|||
log_info "Extracting boot gap to work/boot-gap.bin" |
|||
disk_extract_part "${disk_image}" \ |
|||
1 $(( $(disk_get_part_value ${disk_image} 1 START) - 1)) work/boot-gap.bin |
|||
fi |
@ -1,888 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
# Partition alignment value in bytes. |
|||
declare -i partition_alignment |
|||
# Boot partition storage offset in bytes. |
|||
declare -i vfat_storage_offset |
|||
|
|||
PART_ALIGN_4MB=4194304 |
|||
PART_ALIGN_8MB=8388608 |
|||
|
|||
# Default 'data' partition size in MiB. |
|||
declare -i data_part_size_mb |
|||
# Default total storage size in MiB. |
|||
declare -i storage_total_size_mb |
|||
|
|||
DATA_PART_SIZE_MB=128 |
|||
STORAGE_TOTAL_SIZE_MB=8000 |
|||
|
|||
# Number of required heads in a final image. |
|||
declare -i -r heads=255 |
|||
# Number of required sectors in a final image. |
|||
declare -i -r sectors=63 |
|||
|
|||
declare -a mender_partitions_regular=('boot' 'primary' 'secondary' 'data') |
|||
declare -a mender_partitions_extended=('boot' 'primary' 'secondary' 'n/a' 'data' 'swap') |
|||
declare -a raw_disk_partitions=('boot' 'rootfs') |
|||
|
|||
declare -A raw_disk_sizes |
|||
declare -A mender_disk_sizes |
|||
|
|||
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
files_dir=${tool_dir}/files |
|||
output_dir=${tool_dir}/output |
|||
integration_dir=${tool_dir}/integration |
|||
build_log=${output_dir}/build.log |
|||
|
|||
embedded_base_dir=$output_dir/embedded |
|||
sdimg_base_dir=$output_dir/sdimg |
|||
|
|||
embedded_boot_dir=$embedded_base_dir/boot |
|||
embedded_rootfs_dir=$embedded_base_dir/rootfs |
|||
sdimg_boot_dir=$sdimg_base_dir/boot |
|||
sdimg_primary_dir=$sdimg_base_dir/primary |
|||
sdimg_secondary_dir=$sdimg_base_dir/secondary |
|||
sdimg_data_dir=$sdimg_base_dir/data |
|||
|
|||
logsetup() { |
|||
[ ! -f $build_log ] && { touch $build_log; } |
|||
echo -n "" > $build_log |
|||
exec > >(tee -a $build_log) |
|||
exec 2>&1 |
|||
} |
|||
|
|||
log() { |
|||
echo -e "$*" |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 -relative file path |
|||
get_path() { |
|||
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" |
|||
} |
|||
|
|||
get_part_number_from_device() { |
|||
case "$1" in |
|||
/dev/*[0-9]p[1-9]) |
|||
echo ${1##*[0-9]p} |
|||
;; |
|||
/dev/[sh]d[a-z][1-9]) |
|||
echo ${1##*d[a-z]} |
|||
;; |
|||
ubi[0-9]_[0-9]) |
|||
echo ${1##*[0-9]_} |
|||
;; |
|||
[a-z]*\.sdimg[1-9]) |
|||
echo ${1##*\.sdimg} |
|||
;; |
|||
/dev/mapper/*[0-9]p[1-9]) |
|||
echo ${1##*[0-9]p} |
|||
;; |
|||
*) |
|||
log "Could not determine partition number from $1" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw disk image |
|||
# $2 - boot partition start offset (in sectors) |
|||
# $3 - boot partition size (in sectors) |
|||
create_single_disk_partition_table() { |
|||
local device=$1 |
|||
local bootstart=$2 |
|||
local stopsector=$(( $3 - 1 )) |
|||
|
|||
sed -e 's/\s*\([\+0-9a-zA-Z]*\).*/\1/' << EOF | sudo fdisk $device &> /dev/null |
|||
d # delete partition |
|||
n # new partition |
|||
p # primary partition |
|||
1 # partion number 1 |
|||
${bootstart} |
|||
+${stopsector} |
|||
a # set boot flag |
|||
w # write the partition table |
|||
q # and we're done |
|||
EOF |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw disk image |
|||
# $2 - root filesystem partition start offset (in sectors) |
|||
# $3 - root filesystem partition size (in sectors) |
|||
create_double_disk_partition_table() { |
|||
local device=$1 |
|||
local rootfsstart=$2 |
|||
local rootfsstop=$(( $3 - 1 )) |
|||
|
|||
sed -e 's/\s*\([\+0-9a-zA-Z]*\).*/\1/' << EOF | sudo fdisk $device &> /dev/null |
|||
d # delete partition |
|||
2 |
|||
n |
|||
p |
|||
2 |
|||
${rootfsstart} |
|||
+${rootfsstop} |
|||
w # write the partition table |
|||
q # and we're done |
|||
EOF |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw_disk image path |
|||
# |
|||
# Calculates following values: |
|||
# |
|||
# $2 - number of partitions |
|||
# $3 - array of partitions' sizes for raw disk |
|||
# |
|||
get_raw_disk_sizes() { |
|||
local limage=$1 |
|||
local rvar_count=$2 |
|||
shift 2 |
|||
local rvar_array=($@) |
|||
|
|||
local lsubname=${limage:0:10} |
|||
local lfdisk="$(fdisk -u -l ${limage})" |
|||
local lparts=($(echo "${lfdisk}" | grep "^${lsubname}" | cut -d' ' -f1)) |
|||
local lcount=${#lparts[@]} |
|||
|
|||
if [[ $lcount -gt 3 ]]; then |
|||
log "\tError: invalid/unsupported raw disk image. Aborting." |
|||
return 1 |
|||
fi |
|||
|
|||
local lsectorsize=($(echo "${lfdisk}" | grep '^Sector' | cut -d' ' -f4)) |
|||
|
|||
local idx_start=2 |
|||
local idx_size=4 |
|||
|
|||
local lfirstpartinfo="$(echo "${lfdisk}" | grep "^${lparts[0]}")" |
|||
|
|||
if [[ $lcount -gt 1 ]]; then |
|||
local lsecondpartinfo="$(echo "${lfdisk}" | grep "^${lparts[1]}")" |
|||
eval $rvar_array[prootfs_start]="'$(echo "${lsecondpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_start})'" |
|||
eval $rvar_array[prootfs_size]="'$(echo "${lsecondpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_size})'" |
|||
fi |
|||
|
|||
if [[ $lcount -gt 2 ]]; then |
|||
local lthirdpartinfo="$(echo "${lfdisk}" | grep "^${lparts[2]}")" |
|||
eval $rvar_array[pswap_start]="'$(echo "${lthirdpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_start})'" |
|||
eval $rvar_array[pswap_size]="'$(echo "${lthirdpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_size})'" |
|||
fi |
|||
|
|||
# Check is first partition is marked as bootable. |
|||
if [[ "$lfirstpartinfo" =~ .*\*.* ]]; then |
|||
((idx_start+=1)) |
|||
((idx_size+=1)) |
|||
fi |
|||
|
|||
eval $rvar_array[pboot_start]="'$(echo "${lfirstpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_start})'" |
|||
eval $rvar_array[pboot_size]="'$(echo "${lfirstpartinfo}" | tr -s ' ' | cut -d' ' -f${idx_size})'" |
|||
eval $rvar_array[sector_size]="'$lsectorsize'" |
|||
|
|||
eval $rvar_count="'$lcount'" |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
# Takes the following argument |
|||
# $1 - device type |
|||
# |
|||
# Calculates the following arguments: |
|||
# $2 - partition alignment |
|||
# $3 - vfat storage offset |
|||
|
|||
set_mender_disk_alignment() { |
|||
local rvar_partition_alignment=$2 |
|||
local rvar_vfat_storage_offset=$3 |
|||
|
|||
case "$1" in |
|||
"beaglebone" | "qemux86_64") |
|||
local lvar_partition_alignment=${PART_ALIGN_8MB} |
|||
local lvar_vfat_storage_offset=$lvar_partition_alignment |
|||
;; |
|||
"raspberrypi3" | "raspberrypi0w" | "rockpro64") |
|||
local lvar_partition_alignment=${PART_ALIGN_4MB} |
|||
local lvar_uboot_env_size=$(( $lvar_partition_alignment * 2 )) |
|||
local lvar_vfat_storage_offset=$(( $lvar_partition_alignment + $lvar_uboot_env_size )) |
|||
;; |
|||
*) |
|||
log "Error: unsupported device type $1" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
|
|||
eval $rvar_partition_alignment="'$lvar_partition_alignment'" |
|||
eval $rvar_vfat_storage_offset="'$lvar_vfat_storage_offset'" |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - Mender disk image path |
|||
# |
|||
# Calculates following values: |
|||
# |
|||
# $2 - number of partitions |
|||
# $3 - size of the sector (in bytes) |
|||
# $4 - rootfs A partition start offset (in sectors) |
|||
# $5 - rootfs A partition size (in sectors) |
|||
# $6 - rootfs B partition start offset (in sectors) |
|||
# $7 - rootfs B partition size (in sectors) |
|||
get_mender_disk_sizes() { |
|||
local limage=$1 |
|||
local rvar_count=$2 |
|||
local rvar_sectorsize=$3 |
|||
local rvar_rootfs_a_start=$4 |
|||
local rvar_rootfs_a_size=$5 |
|||
local rvar_rootfs_b_start=$6 |
|||
local rvar_rootfs_b_size=$7 |
|||
|
|||
local lsubname=${limage:0:10} |
|||
local lfdisk="$(fdisk -u -l ${limage})" |
|||
|
|||
local lparts=($(echo "${lfdisk}" | grep "^${lsubname}" | cut -d' ' -f1)) |
|||
local lcount=${#lparts[@]} |
|||
|
|||
if [[ $lcount -ne 4 ]] && [[ $lcount -ne 6 ]]; then |
|||
log "Error: invalid Mender disk image. Aborting." |
|||
return 1 |
|||
else |
|||
local lsectorsize=($(echo "${lfdisk}" | grep '^Sector' | cut -d' ' -f4)) |
|||
|
|||
local lrootfs_a_info="$(echo "${lfdisk}" | grep "^${lparts[1]}")" |
|||
local lrootfs_b_info="$(echo "${lfdisk}" | grep "^${lparts[2]}")" |
|||
|
|||
idx_start=2 |
|||
idx_size=4 |
|||
|
|||
local lrootfs_a_start=($(echo "${lrootfs_a_info}" | tr -s ' ' | cut -d' ' -f${idx_start})) |
|||
local lrootfs_a_size=($(echo "${lrootfs_a_info}" | tr -s ' ' | cut -d' ' -f${idx_size})) |
|||
local lrootfs_b_start=($(echo "${lrootfs_b_info}" | tr -s ' ' | cut -d' ' -f${idx_start})) |
|||
local lrootfs_b_size=($(echo "${lrootfs_b_info}" | tr -s ' ' | cut -d' ' -f${idx_size})) |
|||
|
|||
eval $rvar_count="'$lcount'" |
|||
eval $rvar_sectorsize="'$lsectorsize'" |
|||
eval $rvar_rootfs_a_start="'$lrootfs_a_start'" |
|||
eval $rvar_rootfs_a_size="'$lrootfs_a_size'" |
|||
eval $rvar_rootfs_b_start="'$lrootfs_b_start'" |
|||
eval $rvar_rootfs_b_size="'$lrootfs_b_size'" |
|||
|
|||
return 0 |
|||
fi |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - size variable to be aligned in sectors |
|||
# $2 - size of the sector |
|||
# |
|||
align_partition_size() { |
|||
# Final size is aligned with reference to 'partition_alignment' variable. |
|||
local rvar_size=$1 |
|||
local -n ref=$1 |
|||
|
|||
local size_in_bytes=$(( $ref * $2 )) |
|||
local reminder=$(( ${size_in_bytes} % ${partition_alignment} )) |
|||
|
|||
if [ $reminder -ne 0 ]; then |
|||
size_in_bytes=$(( $size_in_bytes - $reminder + ${partition_alignment} )) |
|||
fi |
|||
|
|||
local lsize=$(( $size_in_bytes / $2 )) |
|||
|
|||
eval $rvar_size="'$lsize'" |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - number of partition of the raw disk image |
|||
# $2 - mender image partition alignment |
|||
# $3 - mender image's boot partition offset |
|||
# $4 - data partition size (in MB) |
|||
# $5 - array of partitions' sizes for raw image |
|||
# |
|||
# Returns: |
|||
# |
|||
# $6 - array of partitions' sizes for Mender image |
|||
# |
|||
set_mender_disk_sizes() { |
|||
local count=$1 |
|||
local alignment=$2 |
|||
local offset=$3 |
|||
local datasize_mb=$4 |
|||
local _raw_sizes=$(declare -p $5) |
|||
eval "declare -A raw_sizes="${_raw_sizes#*=} |
|||
shift 5 |
|||
local rvar_array=($@) |
|||
|
|||
local sector_size=${raw_sizes[sector_size]} |
|||
local datasize=$(( ($datasize_mb * 1024 * 1024) / $sector_size )) |
|||
|
|||
local bootstart= |
|||
local bootsize= |
|||
local rootfsstart= |
|||
local rootfssize= |
|||
local bootflag= |
|||
|
|||
if [[ $count -eq 1 ]]; then |
|||
# Default size of the boot partition: 16MiB. |
|||
bootsize=$(( (${alignment} * 2) / ${sector_size} )) |
|||
# Root filesystem size is determined by the size of the single partition. |
|||
rootfssize=${raw_sizes[pboot_size]} |
|||
else |
|||
bootsize=${raw_sizes[pboot_size]} |
|||
rootfssize=${raw_sizes[prootfs_size]} |
|||
fi |
|||
|
|||
# Boot partition storage offset is defined from the top down. |
|||
bootstart=$(( ${offset} / ${sector_size} )) |
|||
|
|||
align_partition_size bootsize $sector_size |
|||
align_partition_size rootfssize $sector_size |
|||
align_partition_size datasize $sector_size |
|||
|
|||
eval $rvar_array[pboot_start]="'$bootstart'" |
|||
eval $rvar_array[pboot_size]="'$bootsize'" |
|||
eval $rvar_array[prootfs_size]="'$rootfssize'" |
|||
eval $rvar_array[pdata_size]="'$datasize'" |
|||
|
|||
if [[ $count -eq 3 ]]; then |
|||
# Add space for Swap partition. |
|||
local swapsize=${raw_sizes[pswap_size]} |
|||
align_partition_size swapsize $sector_size |
|||
eval $rvar_array[pswap_size]="'$swapsize'" |
|||
fi |
|||
|
|||
eval $rvar_array[sector_size]="'$sector_size'" |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - partition alignment |
|||
# $2 - array of partitions' sizes for Mender image |
|||
# |
|||
# Returns: |
|||
# |
|||
# #3 - number of partitions of the Mender disk image |
|||
# $4 - final Mender disk image size (in bytes) |
|||
# |
|||
calculate_mender_disk_size() { |
|||
local _mender_sizes=$(declare -p $2) |
|||
eval "declare -A mender_sizes="${_mender_sizes#*=} |
|||
local sector_size=${mender_sizes[sector_size]} |
|||
local rvar_counts=$3 |
|||
local rvar_sdimgsize=$4 |
|||
|
|||
local sdimgsize=$(( (${mender_sizes[pboot_start]} + ${mender_sizes[pboot_size]} + \ |
|||
2 * ${mender_sizes[prootfs_size]} + \ |
|||
${mender_sizes[pdata_size]}) * $sector_size )) |
|||
|
|||
eval $rvar_counts="'4'" |
|||
|
|||
if [ -v mender_sizes[pswap_size] ]; then |
|||
log "\tSwap partition found." |
|||
# Add size of the swap partition to the total size. |
|||
sdimgsize=$(( $sdimgsize + (${mender_sizes[pswap_size]} * $sector_size) )) |
|||
# Add alignment used as swap partition offset. |
|||
sdimgsize=$(( $sdimgsize + 2 * ${1} )) |
|||
eval $rvar_counts="'6'" |
|||
fi |
|||
|
|||
eval $rvar_sdimgsize="'$sdimgsize'" |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - number of partition of the Mender image |
|||
# $2 - calculated total size of the Mender image in bytes |
|||
# $3 - expected total size of the Mender image in mb |
|||
# $4 - array of partitions' sizes for Mender image |
|||
# |
|||
# Returns: |
|||
# |
|||
# Size of the rootfs partition updated and adjusted to total storage size |
|||
# |
|||
mender_image_size_to_total_storage_size() { |
|||
local count=$1 |
|||
local rvar_image_size=$2 |
|||
local -n image_size_bytes=$2 |
|||
local storage_size_mb=$3 |
|||
|
|||
local _mender_sizes=$(declare -p $4) |
|||
eval "declare -A mender_sizes="${_mender_sizes#*=} |
|||
|
|||
shift 3 |
|||
local rvar_array=($@) |
|||
|
|||
local image_size_mb=$(( (($image_size_bytes / 1024) / 1024) )) |
|||
|
|||
log "\tAdjust Mender disk image size to the total storage size (${storage_size_mb}MB)." |
|||
|
|||
if [ $image_size_mb -gt $storage_size_mb ]; then |
|||
log "\tDefined total storage size of ${3}MB is too small." |
|||
log "\tMinimal required storage is ${image_size_mb}MB. Aborting." |
|||
return 1 |
|||
elif [ $image_size_mb -eq $storage_size_mb ]; then |
|||
# Simply continue. |
|||
log "\tCalculated Mender image size exactly fits the defined total storage." |
|||
return 0 |
|||
fi |
|||
|
|||
# Get spare space for rootfs a/b partitions (in sectors). |
|||
local sector_size=${mender_sizes[sector_size]} |
|||
local image_size_s=$(( $image_size_bytes / $sector_size )) |
|||
local storage_size_bytes=$(( ($storage_size_mb * 1024 * 1024) )) |
|||
local storage_size_s=$(( $storage_size_bytes / $sector_size )) |
|||
local rootfs_overplus_bytes=0 |
|||
|
|||
local spare_storage_bytes=$(( $storage_size_bytes - $image_size_bytes )) |
|||
|
|||
if [ $(($spare_storage_bytes % 2)) -ne 0 ]; then |
|||
log "\tAdditional space for rootfs partitions not divisible by 2.\ |
|||
\n\tFinal image will be smaller than ${storage_size_mb}MB" |
|||
fi |
|||
rootfs_overplus_bytes=$(( $spare_storage_bytes / 2 )) |
|||
|
|||
local reminder=$(( ${rootfs_overplus_bytes} % ${partition_alignment} )) |
|||
if [ $reminder -ne 0 ]; then |
|||
log "\tAdditional space for rootfs partitions not aligned.\ |
|||
\n\tFinal image will be smaller than ${storage_size_mb}MB" |
|||
fi |
|||
rootfs_overplus_bytes=$(($rootfs_overplus_bytes - $reminder)) |
|||
rootfs_overplus_s=$(( $rootfs_overplus_bytes / $sector_size )) |
|||
|
|||
local prootfs_size=${mender_sizes[prootfs_size]} |
|||
prootfs_size=$(( $prootfs_size + $rootfs_overplus_s )) |
|||
|
|||
image_size_bytes=$(( $image_size_bytes + 2 * $rootfs_overplus_bytes )) |
|||
|
|||
eval $rvar_array[prootfs_size]="'$prootfs_size'" |
|||
eval $rvar_image_size="'$image_size_bytes'" |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw disk image path |
|||
# $2 - raw disk image size |
|||
create_mender_disk() { |
|||
local lfile=$1 |
|||
local lsize=$2 |
|||
|
|||
# Generates a sparse image |
|||
dd if=/dev/zero of=${lfile} seek=${lsize} bs=1 count=0 >> "$build_log" 2>&1 |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - Mender disk image path |
|||
# $2 - Mender disk image size |
|||
# $3 - partition alignment |
|||
# $4 - array of partitions' sizes for Mender image |
|||
# |
|||
format_mender_disk() { |
|||
local lfile=$1 |
|||
local lsize=$2 |
|||
local rc=0 |
|||
|
|||
local _mender_sizes=$(declare -p $4) |
|||
eval "declare -A mender_sizes="${_mender_sizes#*=} |
|||
|
|||
local sector_size=${mender_sizes[sector_size]} |
|||
local alignment=$(($3 / ${sector_size})) |
|||
|
|||
cylinders=$(( ${lsize} / ${heads} / ${sectors} / ${sector_size} )) |
|||
|
|||
pboot_start=${mender_sizes[pboot_start]} |
|||
pboot_size=${mender_sizes[pboot_size]} |
|||
pboot_end=$((${pboot_start} + ${pboot_size} - 1)) |
|||
|
|||
prootfs_size=${mender_sizes[prootfs_size]} |
|||
|
|||
prootfsa_start=$((${pboot_end} + 1)) |
|||
prootfsa_end=$((${prootfsa_start} + ${prootfs_size} - 1)) |
|||
|
|||
prootfsb_start=$((${prootfsa_end} + 1)) |
|||
prootfsb_end=$((${prootfsb_start} + ${prootfs_size} - 1)) |
|||
|
|||
pdata_start=$((${prootfsb_end} + 1)) |
|||
pdata_size=${mender_sizes[pdata_size]} |
|||
pdata_end=$((${pdata_start} + ${pdata_size} - 1)) |
|||
|
|||
if [ -v mender_sizes[pswap_size] ]; then |
|||
local pextended_start=$((${prootfsb_end} + 1)) |
|||
|
|||
pdata_start=$(($pextended_start + ${alignment})) |
|||
pdata_end=$((${pdata_start} + ${pdata_size} - 1)) |
|||
|
|||
local pswap_start=$((${pdata_end} + ${alignment} + 1)) |
|||
local pswap_size=${mender_sizes[pswap_size]} |
|||
local pswap_end=$((${pswap_start} + ${pswap_size} - 1)) |
|||
fi |
|||
|
|||
sed -e 's/\s*\([\+0-9a-zA-Z]*\).*/\1/' << EOF | sudo fdisk ${lfile} &> /dev/null |
|||
o # clear the in memory partition table |
|||
x |
|||
h |
|||
${heads} |
|||
s |
|||
${sectors} |
|||
c |
|||
${cylinders} |
|||
r |
|||
w # write the partition table |
|||
q # and we're done |
|||
EOF |
|||
|
|||
# Create partition table |
|||
sudo parted -s ${lfile} mklabel msdos || rc=$? |
|||
sudo parted -s ${lfile} unit s mkpart primary fat32 ${pboot_start} ${pboot_end} || rc=$? |
|||
sudo parted -s ${lfile} set 1 boot on || rc=$? |
|||
sudo parted -s ${lfile} -- unit s mkpart primary ext4 ${prootfsa_start} ${prootfsa_end} || rc=$? |
|||
sudo parted -s ${lfile} -- unit s mkpart primary ext4 ${prootfsb_start} ${prootfsb_end} || rc=$? |
|||
|
|||
if [ -v mender_sizes[pswap_size] ]; then |
|||
log "\tAdding swap partition." |
|||
sudo parted -s ${lfile} -- unit s mkpart extended ${pextended_start} 100% || rc=$? |
|||
sudo parted -s ${lfile} -- unit s mkpart logical ext4 ${pdata_start} ${pdata_end} || rc=$? |
|||
sudo parted -s ${lfile} -- unit s mkpart logical linux-swap ${pswap_start} ${pswap_end} || rc=$? |
|||
else |
|||
sudo parted -s ${lfile} -- unit s mkpart primary ext4 ${pdata_start} ${pdata_end} || rc=$? |
|||
fi |
|||
|
|||
[[ $rc -eq 0 ]] && { log "\tChanges in partition table applied."; } |
|||
|
|||
return $rc |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw disk file |
|||
# |
|||
verify_mender_disk() { |
|||
local lfile=$1 |
|||
local lcounts=$2 |
|||
|
|||
local limage=$(basename $lfile) |
|||
local partitions=($(fdisk -l -u ${limage} | cut -d' ' -f1 | grep 'sdimg[1-9]\{1\}$')) |
|||
|
|||
local no_of_parts=${#partitions[@]} |
|||
|
|||
[[ $no_of_parts -eq $lcounts ]] || \ |
|||
{ log "Error: incorrect number of partitions: $no_of_parts. Aborting."; return 1; } |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - raw disk image |
|||
# $2 - partition mappings holder |
|||
create_device_maps() { |
|||
local -n mappings=$2 |
|||
|
|||
if [[ -n "$1" ]]; then |
|||
loopdevice=$(sudo losetup --show -f $1) |
|||
mapfile -t mappings < <( sudo kpartx -s -v -a $loopdevice | grep 'loop' | cut -d' ' -f3 ) |
|||
[[ ${#mappings[@]} -eq 0 ]] \ |
|||
&& { log "Error: partition mappings failed. Aborting."; exit 1; } |
|||
else |
|||
log "Error: no device passed. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
sudo partprobe /dev/${mappings[0]%p*} |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - partition mappings holder |
|||
detach_device_maps() { |
|||
local mappings=($@) |
|||
|
|||
[ ${#mappings[@]} -eq 0 ] && { log "\tPartition mappings cleaned."; return; } |
|||
|
|||
local mapper=${mappings[0]%p*} |
|||
|
|||
for mapping in ${mappings[@]} |
|||
do |
|||
map_dev=/dev/mapper/"$mapping" |
|||
is_mounted=`grep ${map_dev} /proc/self/mounts | wc -l` |
|||
if [ ${is_mounted} -ne 0 ]; then |
|||
sudo umount -l $map_dev |
|||
fi |
|||
done |
|||
|
|||
sudo kpartx -d /dev/$mapper & |
|||
sudo losetup -d /dev/$mapper & |
|||
wait && sync |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - partition mappings holder |
|||
# |
|||
make_mender_disk_filesystem() { |
|||
local mappings=($@) |
|||
local counts=${#mappings[@]} |
|||
|
|||
if [ $counts -eq 4 ]; then |
|||
local labels=(${mender_partitions_regular[@]}) |
|||
elif [ $counts -eq 6 ]; then |
|||
local labels=(${mender_partitions_extended[@]}) |
|||
fi |
|||
|
|||
for mapping in ${mappings[@]} |
|||
do |
|||
map_dev=/dev/mapper/"$mapping" |
|||
part_no=$(get_part_number_from_device $map_dev) |
|||
label=${labels[${part_no} - 1]} |
|||
|
|||
case ${part_no} in |
|||
1) |
|||
log "\tCreating MS-DOS filesystem for '$label' partition." |
|||
sudo mkfs.vfat -n ${label} $map_dev >> "$build_log" 2>&1 |
|||
;; |
|||
2|3) |
|||
log "\tCreating ext4 filesystem for '$label' partition." |
|||
sudo mkfs.ext4 -L ${label} $map_dev >> "$build_log" 2>&1 |
|||
;; |
|||
4) |
|||
if [ $counts -eq 4 ]; then |
|||
log "\tCreating ext4 filesystem for '$label' partition." |
|||
sudo mkfs.ext4 -L ${label} $map_dev >> "$build_log" 2>&1 |
|||
else |
|||
continue |
|||
fi |
|||
;; |
|||
5) |
|||
log "\tCreating ext4 filesystem for '$label' partition." |
|||
sudo mkfs.ext4 -L ${label} $map_dev >> "$build_log" 2>&1 |
|||
;; |
|||
6) |
|||
log "\tCreating swap area for '$label' partition." |
|||
sudo mkswap -L ${label} $map_dev >> "$build_log" 2>&1 |
|||
;; |
|||
*) |
|||
break |
|||
;; |
|||
esac |
|||
done |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - partition mappings holder |
|||
mount_raw_disk() { |
|||
local mappings=($@) |
|||
|
|||
if [ ${#mappings[@]} -eq 1 ]; then |
|||
local path=$embedded_rootfs_dir |
|||
mkdir -p $path |
|||
sudo mount /dev/mapper/"${mappings[0]}" $path |
|||
return |
|||
fi |
|||
|
|||
for mapping in ${mappings[@]} |
|||
do |
|||
local part_no=${mapping#*p*p} |
|||
local path=$embedded_base_dir/${raw_disk_partitions[${part_no} - 1]} |
|||
mkdir -p $path |
|||
sudo mount /dev/mapper/"${mapping}" $path 2>&1 >/dev/null |
|||
done |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - partition mappings holder |
|||
mount_mender_disk() { |
|||
local mappings=($@) |
|||
local counts=${#mappings[@]} |
|||
|
|||
if [ $counts -eq 4 ]; then |
|||
local labels=(${mender_partitions_regular[@]}) |
|||
elif [ $counts -eq 6 ]; then |
|||
local labels=(${mender_partitions_extended[@]}) |
|||
fi |
|||
|
|||
for mapping in ${mappings[@]} |
|||
do |
|||
local part_no=${mapping#*p*p} |
|||
local path=$sdimg_base_dir/${labels[${part_no} - 1]} |
|||
mkdir -p $path |
|||
|
|||
case ${part_no} in |
|||
1|2|3) |
|||
sudo mount /dev/mapper/"${mapping}" $path 2>&1 >/dev/null |
|||
;; |
|||
4) |
|||
if [ $counts -eq 4 ]; then |
|||
sudo mount /dev/mapper/"${mapping}" $path 2>&1 >/dev/null |
|||
else |
|||
# Skip extended partition. |
|||
continue |
|||
fi |
|||
;; |
|||
5) |
|||
sudo mount /dev/mapper/"${mapping}" $path 2>&1 >/dev/null |
|||
;; |
|||
6) |
|||
# Skip swap partition. |
|||
continue |
|||
;; |
|||
*) |
|||
break |
|||
;; |
|||
esac |
|||
|
|||
done |
|||
} |
|||
|
|||
# Takes following arguments |
|||
# |
|||
# $1 - device type |
|||
set_fstab() { |
|||
local mountpoint= |
|||
local blk_device= |
|||
local data_id=4 |
|||
local device_type=$1 |
|||
local sysconfdir="$sdimg_primary_dir/etc" |
|||
|
|||
[ ! -d "${sysconfdir}" ] && { log "Error: cannot find rootfs config dir."; exit 1; } |
|||
|
|||
# Erase/create the fstab file. |
|||
sudo install -b -m 644 /dev/null ${sysconfdir}/fstab |
|||
|
|||
case "$device_type" in |
|||
"beaglebone") |
|||
mountpoint="/boot/efi" |
|||
blk_device=mmcblk0p |
|||
;; |
|||
"raspberrypi3"|"raspberrypi0w") |
|||
mountpoint="/uboot" |
|||
blk_device=mmcblk0p |
|||
;; |
|||
"rockpro64") |
|||
mountpoint="/uboot" |
|||
blk_device=mmcblk1p |
|||
;; |
|||
"qemux86_64") |
|||
mountpoint="/boot/efi" |
|||
blk_device=hda |
|||
data_id=5 |
|||
;; |
|||
*) |
|||
log "Error: unsupported device type $device_type" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
|
|||
# Add Mender specific entries to fstab. |
|||
sudo bash -c "cat <<- EOF > ${sysconfdir}/fstab |
|||
# stock fstab - you probably want to override this with a machine specific one |
|||
|
|||
/dev/root / auto defaults 1 1 |
|||
proc /proc proc defaults 0 0 |
|||
devpts /dev/pts devpts mode=0620,gid=5 0 0 |
|||
tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 |
|||
tmpfs /var/volatile tmpfs defaults 0 0 |
|||
|
|||
# uncomment this if your device has a SD/MMC/Transflash slot |
|||
#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0 |
|||
|
|||
# Where the U-Boot environment resides; for devices with SD card support ONLY! |
|||
/dev/${blk_device}1 $mountpoint auto defaults,sync 0 0 |
|||
/dev/${blk_device}${data_id} /data auto defaults 0 0 |
|||
EOF" |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
# Add entry referring to swap partition. |
|||
sudo tee -a ${sysconfdir}/fstab <<< "/dev/hda6 swap swap defaults 0 0" 2>&1 >/dev/null |
|||
fi |
|||
|
|||
log "\tDone." |
|||
} |
|||
|
|||
# Takes following arguments |
|||
# |
|||
# $1 - path to source raw disk image |
|||
# $2 - sector start (in 512 blocks) |
|||
# $3 - size (in 512 blocks) |
|||
|
|||
extract_file_from_image() { |
|||
log "\tStoring data in $4." |
|||
local cmd="dd if=$1 of=${output_dir}/$4 skip=$2 bs=512 count=$3 conv=sparse" |
|||
$(${cmd}>> "$build_log" 2>&1) |
|||
} |
|||
|
|||
# Takes following arguments |
|||
# |
|||
# $1 - device type |
|||
# $2 - partition alignment in bytes |
|||
# $3 - total size in bytes |
|||
# $4 - array of partitions' sizes for Mender image |
|||
# |
|||
create_test_config_file() { |
|||
local device_type=$1 |
|||
local alignment=$2 |
|||
local mender_image_size_mb=$(( (($3 / 1024) / 1024) )) |
|||
local _mender_sizes=$(declare -p $4) |
|||
eval "declare -A mender_sizes="${_mender_sizes#*=} |
|||
local sector_size=${mender_sizes[sector_size]} |
|||
|
|||
local boot_offset=$(( (${mender_sizes[pboot_start]} * $sector_size) )) |
|||
local boot_size_mb=$(( (((${mender_sizes[pboot_size]} * $sector_size) / 1024) / 1024) )) |
|||
local rootfs_size_mb=$(( (((${mender_sizes[prootfs_size]} * $sector_size) / 1024) / 1024) )) |
|||
local data_size_mb=$(( (((${mender_sizes[pdata_size]} * $sector_size) / 1024) / 1024) )) |
|||
|
|||
cp ${files_dir}/variables.template ${output_dir}/${device_type}_variables.cfg |
|||
|
|||
sed -i '/^MENDER_BOOT_PART_SIZE_MB/s/=.*$/="'${boot_size_mb}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_DATA_PART_SIZE_MB/s/=.*$/="'${data_size_mb}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_DEVICE_TYPE/s/=.*$/="'${device_type}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_PARTITION_ALIGNMENT/s/=.*$/="'${alignment}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_STORAGE_TOTAL_SIZE_MB/s/=.*$/="'${mender_image_size_mb}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET/s/=.*$/="'${boot_offset}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_CALC_ROOTFS_SIZE/s/=.*$/="'${rootfs_size_mb}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^MENDER_MACHINE/s/=.*$/="'${device_type}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
sed -i '/^DEPLOY_DIR_IMAGE/s/=.*$/="'${output_dir//\//\\/}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
} |
|||
|
|||
# Takes following arguments |
|||
# |
|||
# $1 - device type |
|||
# $2 - parameter name to change |
|||
# $3 - parameter value |
|||
update_test_config_file() { |
|||
local device_type=$1 |
|||
|
|||
[ ! -f "${output_dir}/${device_type}_variables.cfg" ] && \ |
|||
{ log "Error: test configuration file '${device_type}_variables.cfg' not found. Aborting."; return 1; } |
|||
|
|||
shift |
|||
|
|||
while test ${#} -gt 0 |
|||
do |
|||
case "$1" in |
|||
"artifact-name") |
|||
sed -i '/^MENDER_ARTIFACT_NAME/s/=.*$/="'${2}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
;; |
|||
"distro-feature") |
|||
sed -i '/^DISTRO_FEATURES/s/=.*$/="'${2}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
;; |
|||
"mount-location") |
|||
sed -i '/^MENDER_BOOT_PART_MOUNT_LOCATION/s/=.*$/="'${2}'"/' ${output_dir}/${device_type}_variables.cfg |
|||
;; |
|||
esac |
|||
shift 2 |
|||
done |
|||
|
|||
return 0 |
|||
} |
@ -0,0 +1,229 @@ |
|||
#! /usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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 |
|||
} |
|||
|
|||
function user_local_modify() { |
|||
true |
|||
} |
|||
|
|||
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 |
|||
|
|||
# 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) |
|||
|
|||
# Create mount points |
|||
mkdir -p work/boot |
|||
mkdir -p work/rootfs |
|||
|
|||
sudo mount ${boot_part} work/boot |
|||
sudo mount ${root_part} work/rootfs |
|||
|
|||
mkdir -p work/mender-deb/files |
|||
|
|||
log_info "Installing Mender client and related files" |
|||
|
|||
deb_arch=$(probe_debian_arch_name) |
|||
deb_name="mender-client_${MENDER_CLIENT_VERSION}-1_${deb_arch}.deb" |
|||
run_and_log_cmd "wget -Nq ${MENDER_STORAGE_URL}/${MENDER_CLIENT_VERSION}/dist-packages/debian/${deb_arch}/${deb_name} -P work/mender-deb" |
|||
|
|||
cd work/mender-deb |
|||
run_and_log_cmd "ar -xv ${deb_name}" |
|||
run_and_log_cmd "tar -xf data.tar.xz -C files" |
|||
cd - > /dev/null 2>&1 |
|||
|
|||
run_and_log_cmd "sudo rsync --archive --keep-dirlinks --verbose work/mender-deb/files/ work/rootfs/" |
|||
|
|||
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_GRUB_EFI_INTEGRATION}" == "y" ]; then |
|||
run_and_log_cmd "wget -Nq '${MENDER_GRUBENV_URL}' -P work/" |
|||
run_and_log_cmd "tar xvf 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 |
|||
kernel_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_INDEX} |
|||
mender_rootfsb_part=${MENDER_ROOTFS_PART_B_INDEX} |
|||
mender_kernel_root_base=${MENDER_STORAGE_DEVICE} |
|||
mender_grub_storage_device=${MENDER_GRUB_STORAGE_DEVICE} |
|||
kernel_imagetype=${kernel_imagetype} |
|||
initrd_imagetype=${initrd_imagetype} |
|||
kernel_devicetree=${MENDER_KERNEL_DEVICETREE} |
|||
EOF |
|||
|
|||
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 |
|||
sudo rm -rf work/boot/EFI/Linux |
|||
sudo rm -rf work/boot/EFI/systemd |
|||
sudo rm -rf work/boot/NvVars |
|||
|
|||
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 |
|||
|
|||
run_and_log_cmd "sudo mkdir -p work/rootfs/data/mender" |
|||
run_and_log_cmd "sudo ln -sf /data/mender work/rootfs/var/lib/mender" |
|||
|
|||
cat <<- EOF > work/mender.conf.data |
|||
{ |
|||
"RootfsPartA": "${MENDER_STORAGE_DEVICE}${MENDER_ROOTFS_PART_A_INDEX}", |
|||
"RootfsPartB": "${MENDER_STORAGE_DEVICE}${MENDER_ROOTFS_PART_B_INDEX}" |
|||
} |
|||
EOF |
|||
|
|||
run_and_log_cmd "sudo cp work/mender.conf.data work/rootfs/data/mender/mender.conf" |
|||
|
|||
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/" |
|||
run_and_log_cmd "sudo echo 'artifact_name=${MENDER_ARTIFACT_NAME}' \ |
|||
> work/rootfs/etc/mender/artifact_info" |
|||
|
|||
log_info "Installing a custom /etc/fstab (see work/convert.log 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 |
|||
|
|||
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 defaults 1 1 |
|||
proc /proc proc defaults 0 0 |
|||
|
|||
${MENDER_STORAGE_DEVICE}${MENDER_BOOT_PART_INDEX} ${boot_part_mountpoint} auto defaults,sync 0 0 |
|||
${MENDER_STORAGE_DEVICE}${MENDER_DATA_PART_INDEX} /data auto ${MENDER_DATA_PART_FSTAB_OPTS} 0 0 |
|||
EOF" |
|||
|
|||
log_info "Performing platform specific modifications (if any)" |
|||
platform_modify |
|||
|
|||
log_info "Performing user/local specific modifications (if any)" |
|||
user_local_modify |
|||
|
|||
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 |
@ -0,0 +1,311 @@ |
|||
#! /usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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_package() { |
|||
true |
|||
} |
|||
|
|||
function trap_exit() { |
|||
echo "mender-convert-package has finished. Cleaning up..." |
|||
sudo umount -f work/boot > /dev/null |
|||
sudo umount -f work/rootfs > /dev/null |
|||
} |
|||
|
|||
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 |
|||
|
|||
# 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[@]}") |
|||
|
|||
PARTED="/usr/bin/parted" |
|||
if [ ! -f ${PARTED} ]; then |
|||
PARTED="/sbin/parted" |
|||
fi |
|||
|
|||
output_dir=work |
|||
|
|||
boot_part=$(disk_boot_part) |
|||
root_part=$(disk_root_part) |
|||
|
|||
# Final output |
|||
mkdir -p deploy |
|||
|
|||
# Create mount points |
|||
mkdir -p work/boot |
|||
mkdir -p work/rootfs |
|||
|
|||
sudo mount ${boot_part} work/boot |
|||
sudo mount ${root_part} work/rootfs |
|||
|
|||
# Convert to 512 blocks |
|||
disk_image_total_sectors=$(disk_mb_to_sectors ${MENDER_STORAGE_TOTAL_SIZE_MB}) |
|||
boot_part_sectors=$(disk_mb_to_sectors ${MENDER_BOOT_PART_SIZE_MB}) |
|||
data_part_sectors=$(disk_mb_to_sectors ${MENDER_DATA_PART_SIZE_MB}) |
|||
alignment_sectors=$((${MENDER_PARTITION_ALIGNMENT} / 512)) |
|||
|
|||
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then |
|||
boot_part_start=${alignment_sectors} |
|||
overhead_sectors=$(( ${alignment_sectors} * 4 )) |
|||
else |
|||
# The two first blocks are typically reserved for U-boot environment. |
|||
boot_part_start=$(( ${alignment_sectors} * 3)) |
|||
overhead_sectors=$(( ${alignment_sectors} * 6 )) |
|||
fi |
|||
|
|||
# Validate boot-gap.bin size, ensuring it will fit between MBR and boot_part_start |
|||
if [ "${MENDER_COPY_BOOT_GAP}" == "y" ]; then |
|||
# Add one block for MBR |
|||
boot_gap_sectors=$(( $(stat --printf="%b" work/boot-gap.bin) + 1)) |
|||
if [ ${boot_gap_sectors} -ge ${boot_part_start} ]; then |
|||
log_warn "The work/boot-gap.bin file will overwrite the boot partition" |
|||
log_fatal "Please increase MENDER_PARTITION_ALIGNMENT (2x will typically solve this))" |
|||
fi |
|||
fi |
|||
|
|||
# Validate boot part size |
|||
actual_boot_size=$(du --apparent-size -s --block-size=512 ${boot_part} | cut -f 1) |
|||
if [ ${actual_boot_size} -gt ${boot_part_sectors} ]; then |
|||
log_warn "The allocated boot part size $(disk_sectors_to_mb ${boot_part_sectors}) MiB is too small." |
|||
log_warn "The actual boot part size is $(disk_sectors_to_mb ${actual_boot_size}) MiB" |
|||
log_warn "Will adjust MENDER_BOOT_PART_SIZE_MB automatically" |
|||
log_warn "Considered adjusting the configuration file to avoid this message" |
|||
boot_part_sectors=${actual_boot_size} |
|||
fi |
|||
|
|||
# Make sure that the boot part sector size is aligned to |
|||
# MENDER_PARTITION_ALIGNMENT, it is possible that the boot part is extracted |
|||
# as-is from the input image, and the input image might not have used the same |
|||
# alignment as our configuration |
|||
boot_part_sectors=$(disk_align_sectors ${boot_part_sectors} ${MENDER_PARTITION_ALIGNMENT} ) |
|||
|
|||
# Calculate rootfs size |
|||
rootfs_part_sectors=$(((${disk_image_total_sectors} - ${data_part_sectors} - \ |
|||
${boot_part_sectors} - ${overhead_sectors}) / 2)) |
|||
|
|||
# Make sure rootfs size is aligned to MENDER_PARTITION_ALIGNMENT |
|||
rootfs_part_sectors=$(disk_align_sectors ${rootfs_part_sectors} ${MENDER_PARTITION_ALIGNMENT} ) |
|||
|
|||
device_type=$(cat work/rootfs/data/mender/device_type | sed 's/[^=]*=//') |
|||
artifact_name=$(cat work/rootfs/etc/mender/artifact_info | sed 's/[^=]*=//') |
|||
|
|||
image_name="${device_type}-${artifact_name}" |
|||
|
|||
actual_rootfs_size=$(sudo du -s --block-size=512 work/rootfs | cut -f 1) |
|||
|
|||
# KiB -> 512 sectors |
|||
image_rootfs_size_sectors=$((${IMAGE_ROOTFS_SIZE} * 2)) |
|||
|
|||
if [ "${IMAGE_ROOTFS_SIZE}" -eq -1 ]; then |
|||
rootfs_image_sectors="${rootfs_part_sectors}" |
|||
elif [ "${image_rootfs_size_sectors}" -lt "${actual_rootfs_size}" ]; then |
|||
rootfs_image_sectors="${actual_rootfs_size}" |
|||
else |
|||
rootfs_image_sectors="${image_rootfs_size_sectors}" |
|||
fi |
|||
|
|||
rootfs_image_sectors=$((${rootfs_image_sectors} + ${IMAGE_ROOTFS_EXTRA_SPACE} * 2)) |
|||
|
|||
rootfs_image_sectors_overhead=$(awk -v r1="$actual_rootfs_size" "BEGIN{printf \"%.0f\", r1 * ${IMAGE_OVERHEAD_FACTOR}}") |
|||
if [ "${rootfs_image_sectors_overhead}" -gt "${rootfs_image_sectors}" ]; then |
|||
rootfs_image_sectors="${rootfs_image_sectors_overhead}" |
|||
fi |
|||
|
|||
if [ ${rootfs_image_sectors} -gt ${rootfs_part_sectors} ]; then |
|||
log_warn "The calculated rootfs partition size $(disk_sectors_to_mb ${rootfs_part_sectors}) MiB is too small." |
|||
log_warn "The actual rootfs image size is $(disk_sectors_to_mb ${rootfs_image_sectors}) MiB" |
|||
log_fatal "You can try adjusting the MENDER_STORAGE_TOTAL_SIZE_MB variable to increase available space, or modify one of the variables IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_EXTRA_SPACE or IMAGE_OVERHEAD_FACTOR to reduce the size of the root filesystem." |
|||
fi |
|||
|
|||
log_info "Rootfs filesystem size will be $(disk_sectors_to_mb ${rootfs_image_sectors}) MiB" |
|||
|
|||
# Extract file-system type from rootfs |
|||
if file ${root_part} | grep -q ext4; then |
|||
image_fs_type="ext4" |
|||
elif file ${root_part} | grep -q XFS; then |
|||
image_fs_type="xfs" |
|||
else |
|||
log_warn "$(file work/${root_part})" |
|||
log_fatal "Could not determinate root file-system type. Aborting..." |
|||
fi |
|||
|
|||
disk_create_file_system_from_folder "work/rootfs/data/" "work/data.img" \ |
|||
"${data_part_sectors}" "${image_fs_type}" |
|||
|
|||
# Clear this area as it will be contained in the data.img |
|||
sudo rm -rf work/rootfs/data/* |
|||
|
|||
disk_create_file_system_from_folder "work/rootfs/" "work/rootfs.img" \ |
|||
"${rootfs_image_sectors}" "${image_fs_type}" |
|||
|
|||
log_info "Copying root filesystem image to deploy directory" |
|||
run_and_log_cmd "cp --sparse=always work/rootfs.img deploy/${image_name}.${image_fs_type}" |
|||
|
|||
mender_create_artifact "${device_type}" "${artifact_name}" |
|||
|
|||
log_info "Creating Mender compatible disk-image" |
|||
|
|||
sdimg_path=deploy/${image_name}.sdimg |
|||
|
|||
log_info "Total disk size: $(disk_sectors_to_mb ${disk_image_total_sectors}) MiB" |
|||
log_info " Boot partition $(disk_sectors_to_mb ${boot_part_sectors}) MiB" |
|||
log_info " RootFS partitions $(disk_sectors_to_mb ${rootfs_part_sectors}) MiB x 2" |
|||
log_info " Data partition $(disk_sectors_to_mb ${data_part_sectors}) MiB" |
|||
|
|||
# Initialize sdcard image file |
|||
run_and_log_cmd \ |
|||
"dd if=/dev/zero of=${sdimg_path} bs=512 count=0 seek=${disk_image_total_sectors} status=none" |
|||
|
|||
# boot_part_start, is defined at the beginning of this file |
|||
boot_part_end=$(( ${boot_part_start} + ${boot_part_sectors} - 1 )) |
|||
|
|||
rootfsa_start=$(disk_align_sectors ${boot_part_end} ${MENDER_PARTITION_ALIGNMENT} ) |
|||
rootfsa_end=$(( ${rootfsa_start} + ${rootfs_part_sectors} - 1 )) |
|||
|
|||
rootfsb_start=$(disk_align_sectors ${rootfsa_end} ${MENDER_PARTITION_ALIGNMENT} ) |
|||
rootfsb_end=$(( ${rootfsb_start} + ${rootfs_part_sectors} - 1 )) |
|||
|
|||
data_start=$(disk_align_sectors ${rootfsb_end} ${MENDER_PARTITION_ALIGNMENT} ) |
|||
data_end=$(( ${data_start} + ${data_part_sectors} - 1 )) |
|||
|
|||
# Create partition table. TODO: GPT support |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} mklabel msdos" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} unit s mkpart primary fat32 ${boot_part_start} ${boot_part_end}" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} set 1 boot on" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} -- unit s mkpart primary ext2 ${rootfsa_start} ${rootfsa_end}" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} -- unit s mkpart primary ext2 ${rootfsb_start} ${rootfsb_end}" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} -- unit s mkpart primary ext2 ${data_start} ${data_end}" |
|||
run_and_log_cmd "${PARTED} -s ${sdimg_path} print" |
|||
|
|||
# Write boot-gap |
|||
if [ "${MENDER_COPY_BOOT_GAP}" == "y" ]; then |
|||
log_info "Writing boot gap of size: ${boot_part_sectors} (sectors)" |
|||
disk_write_at_offset "${output_dir}/boot-gap.bin" "${sdimg_path}" "1" |
|||
fi |
|||
|
|||
# Burn Partitions |
|||
disk_write_at_offset "${boot_part}" "${sdimg_path}" "${boot_part_start}" |
|||
disk_write_at_offset "${output_dir}/rootfs.img" "${sdimg_path}" "${rootfsa_start}" |
|||
disk_write_at_offset "${output_dir}/rootfs.img" "${sdimg_path}" "${rootfsb_start}" |
|||
disk_write_at_offset "${output_dir}/data.img" "${sdimg_path}" "${data_start}" |
|||
|
|||
log_info "Performing platform specific package operations (if any)" |
|||
platform_package |
|||
|
|||
# Create bmap index |
|||
if [ "${MENDER_USE_BMAP}" == "y" ]; then |
|||
BMAP_TOOL="/usr/bin/bmaptool" |
|||
if [ ! -e "${BMAP_TOOL}" ]; then |
|||
log_error "You have enabled the MENDER_USE_BMAP option, but we could not find the required 'bmaptool'" |
|||
log_fatal "You can install 'bmaptool' with: apt-get install bmap-tools (on Debian based distributions)" |
|||
fi |
|||
run_and_log_cmd "${BMAP_TOOL} create ${sdimg_path} > ${sdimg_path}.bmap" |
|||
fi |
|||
|
|||
case "${MENDER_COMPRESS_DISK_IMAGE}" in |
|||
gzip) |
|||
log_info "Compressing ${sdimg_path}.gz" |
|||
run_and_log_cmd "pigz --best --force ${sdimg_path}" |
|||
;; |
|||
lzma) |
|||
log_info "Compressing ${sdimg_path}.xz" |
|||
run_and_log_cmd "pxz --best --force ${sdimg_path}" |
|||
;; |
|||
none) |
|||
: |
|||
;; |
|||
*) |
|||
log_fatal "Unknown MENDER_COMPRESS_DISK_IMAGE value: ${MENDER_COMPRESS_DISK_IMAGE}" |
|||
;; |
|||
esac |
|||
|
|||
log_info "Conversion has completed! \o/" |
|||
|
|||
##################### Create configuration file for tests ###################### |
|||
|
|||
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then |
|||
boot_part_mountpoint="/boot/efi" |
|||
|
|||
# This is the name of the DISTRO_FEATURES in Yocto |
|||
distro_feature="mender-grub" |
|||
else |
|||
boot_part_mountpoint="/uboot" |
|||
|
|||
# This is the name of the DISTRO_FEATURES in Yocto |
|||
distro_feature="mender-uboot" |
|||
fi |
|||
distro_feature="${distro_feature} mender-convert" |
|||
|
|||
cat <<- EOF > deploy/${image_name}.cfg |
|||
MENDER_BOOT_PART="${MENDER_STORAGE_DEVICE}${MENDER_BOOT_PART_INDEX}" |
|||
MENDER_ROOTFS_PART_A="${MENDER_STORAGE_DEVICE}${MENDER_ROOTFS_PART_A_INDEX}" |
|||
MENDER_ROOTFS_PART_B="${MENDER_STORAGE_DEVICE}${MENDER_ROOTFS_PART_B_INDEX}" |
|||
MENDER_BOOT_PART_MOUNT_LOCATION="${boot_part_mountpoint}" |
|||
MENDER_BOOT_PART_SIZE_MB="$(disk_sectors_to_mb ${boot_part_sectors})" |
|||
MENDER_DATA_PART_SIZE_MB="${MENDER_DATA_PART_SIZE_MB}" |
|||
MENDER_DEVICE_TYPE="${device_type}" |
|||
MENDER_PARTITIONING_OVERHEAD_KB="$(( (${overhead_sectors} * 512) / 1024 ))" |
|||
MENDER_PARTITION_ALIGNMENT="${MENDER_PARTITION_ALIGNMENT}" |
|||
MENDER_STORAGE_DEVICE="${MENDER_STORAGE_DEVICE}" |
|||
MENDER_STORAGE_TOTAL_SIZE_MB="${MENDER_STORAGE_TOTAL_SIZE_MB}" |
|||
MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET="12582912" |
|||
MENDER_ARTIFACT_NAME="${artifact_name}" |
|||
DISTRO_FEATURES="${distro_feature}" |
|||
DEPLOY_DIR_IMAGE="${PWD}/deploy" |
|||
MENDER_MACHINE="${device_type}" |
|||
EOF |
|||
|
|||
# Something that the tests expect to be defined (originally from Yocto) |
|||
cat <<- EOF >> deploy/${image_name}.cfg |
|||
IMAGE_FSTYPES="${image_fs_type} mender sdimg" |
|||
ARTIFACTIMG_FSTYPE="${image_fs_type}" |
|||
EOF |
@ -0,0 +1,52 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Credit to: |
|||
# https://github.com/gruntwork-io/bash-commons/blob/master/modules/bash-commons/src/bootstrap.sh |
|||
|
|||
# Sets some Bash options to encourage well formed code. |
|||
# For example, some of the options here will cause the script to terminate as |
|||
# soon as a command fails. Another option will cause an error if an undefined |
|||
# variable is used. |
|||
# See: https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html |
|||
|
|||
# Any trap on ERR is inherited by shell functions, command substitutions, and |
|||
# commands executed in a subshell environment. The ERR trap is normally not |
|||
# inherited in such cases. |
|||
set -o errtrace |
|||
|
|||
# Any trap on DEBUG and RETURN are inherited by shell functions, command |
|||
# substitutions, and commands executed in a subshell environment. The DEBUG and |
|||
# RETURN traps are normally not inherited in such cases. |
|||
set -o functrace |
|||
|
|||
# Exit if any command exits with a non-zero exit status. |
|||
set -o errexit |
|||
|
|||
# Exit if script uses undefined variables. |
|||
set -o nounset |
|||
|
|||
# Prevent masking an error in a pipeline. |
|||
# Look at the end of the 'Use set -e' section for an excellent explanation. |
|||
# see: https://www.davidpashley.com/articles/writing-robust-shell-scripts/ |
|||
set -o pipefail |
|||
|
|||
# Make debugging easier when you use `set -x` |
|||
# See: http://wiki.bash-hackers.org/scripting/debuggingtips#making_xtrace_more_useful |
|||
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' |
|||
|
|||
source modules/log.sh |
|||
source modules/run.sh |
@ -0,0 +1,22 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Read in the array of config files to process |
|||
read -a configs <<< "${@}" |
|||
for config in "${configs[@]}"; do |
|||
log_info "Using configuration file: ${config}" |
|||
source "${config}" |
|||
done |
@ -0,0 +1,176 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Print desired information about a partition |
|||
# |
|||
# Example usage: |
|||
# |
|||
# part_one_start=$(disk_get_part_value ${disk_image_path} 1 START) |
|||
# |
|||
# $1 - path to disk image |
|||
# $2 - part number |
|||
# $3 - information to be printed |
|||
# |
|||
# We use 'partx' to parse input disk image and it supports the following fields: |
|||
# |
|||
# NR partition number |
|||
# START start of the partition in sectors |
|||
# END end of the partition in sectors |
|||
# SECTORS number of sectors |
|||
# SIZE human readable size |
|||
# NAME partition name |
|||
# UUID partition UUID |
|||
# TYPE partition type (a string, a UUID, or hex) |
|||
# FLAGS partition flags |
|||
# SCHEME partition table type (dos, gpt, ...) |
|||
disk_get_part_value() { |
|||
echo "$(partx -o ${3} -g -r --nr ${2} ${1})" |
|||
} |
|||
|
|||
# Prints number of partitions found in disk image |
|||
# |
|||
# Example usage: |
|||
# |
|||
# nr_of_parts=$(disk_get_nr_of_parts ${disk_image_path}) |
|||
# |
|||
# $1 - path to disk image |
|||
disk_get_nr_of_parts() { |
|||
echo "$(partx -l ${1} | wc -l)" |
|||
} |
|||
|
|||
# Extract a file system image from a disk image |
|||
# |
|||
# $1 - path to disk image |
|||
# $2 - sector start (in 512 blocks) |
|||
# $3 - size (in 512 blocks) |
|||
# $4 - path to output file |
|||
disk_extract_part() { |
|||
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 |
|||
# |
|||
# $1 - MiB value |
|||
disk_mb_to_sectors() { |
|||
echo "$(( (${1} * 1024 * 1024) / 512 ))" |
|||
} |
|||
|
|||
# Convert 512 sectors to MiB |
|||
# |
|||
# $1 - number of 512 sectors |
|||
disk_sectors_to_mb() { |
|||
echo "$(( (${1} * 512) / 1024 / 1024 ))" |
|||
} |
|||
|
|||
# Align value (result is number of 512 sectors) |
|||
# |
|||
# $1 - value to align (number of 512 sectors) |
|||
# $2 - alignment in bytes |
|||
disk_align_sectors() { |
|||
local size_in_bytes=$(( ${1} * 512)) |
|||
local reminder=$(( ${size_in_bytes} % ${2} )) |
|||
|
|||
if [ $reminder -ne 0 ]; then |
|||
size_in_bytes=$(( $size_in_bytes - $reminder + ${2} )) |
|||
fi |
|||
|
|||
echo "$(( $size_in_bytes / 512 ))" |
|||
} |
|||
|
|||
# Write file at offset of another file |
|||
# |
|||
# $1 - file to write |
|||
# $2 - destination file |
|||
# $3 - offset in number of 512 sectors |
|||
disk_write_at_offset() { |
|||
run_and_log_cmd "dd if=${1} of=${2} seek=${3} conv=sparse status=none" |
|||
} |
|||
|
|||
# Create file system image from directory content |
|||
# |
|||
# $1 - base folder |
|||
# $2 - destination file |
|||
# $3 - image size in sectors |
|||
# $4 - file system type, e.g ext4, xfs, ... |
|||
disk_create_file_system_from_folder() { |
|||
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" |
|||
|
|||
case "$4" in |
|||
"ext4") |
|||
MKFS_EXT4="/usr/bin/mkfs.ext4" |
|||
if [ ! -f ${MKFS_EXT4} ]; then |
|||
MKFS_EXT4="/sbin/mkfs.ext4" |
|||
fi |
|||
run_and_log_cmd "${MKFS_EXT4} -q -F ${2}" |
|||
;; |
|||
|
|||
"xfs") |
|||
MKFS_XFS="/usr/bin/mkfs.xfs" |
|||
if [ ! -f ${MKFS_XFS} ]; then |
|||
MKFS_XFS="/sbin/mkfs.xfs" |
|||
fi |
|||
run_and_log_cmd "${MKFS_XFS} -q -f ${2}" |
|||
;; |
|||
*) |
|||
log_fatal "Unknown file system type specified: ${4}" |
|||
;; |
|||
esac |
|||
|
|||
run_and_log_cmd "mkdir -p 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 umount work/output" |
|||
} |
|||
|
|||
# Print path to the boot partition filesystem image |
|||
# |
|||
disk_boot_part() { |
|||
# Why this little dance you might wonder. |
|||
# |
|||
# Some disk images do not have a boot partition, but our integration does |
|||
# 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: |
|||
# |
|||
# work/boot-generated.vfat |
|||
# |
|||
# 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 |
|||
# partition that was extracted. |
|||
# |
|||
# We also need to adjust the part number of the rootfs part depending on if |
|||
# boot part was extracted or generated. |
|||
boot_part="work/boot-generated.vfat" |
|||
if [ ! -f ${boot_part} ]; then |
|||
boot_part="work/part-1.fs" |
|||
fi |
|||
echo "${boot_part}" |
|||
} |
|||
|
|||
# Print path to the root partition filesystem image |
|||
# |
|||
disk_root_part() { |
|||
boot_part="work/boot-generated.vfat" |
|||
if [ ! -f ${boot_part} ]; then |
|||
root_part="work/part-2.fs" |
|||
else |
|||
root_part="work/part-1.fs" |
|||
fi |
|||
echo "${root_part}" |
|||
} |
@ -0,0 +1,67 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# This must be an absolute path, as users might call the log functions |
|||
# from sub-directories |
|||
log_file="${PWD}/work/convert.log" |
|||
|
|||
# Log the given message at the given level. |
|||
function log { |
|||
local -r level="$1" |
|||
local -r message="$2" |
|||
local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S") |
|||
local -r script_name="$(basename "$0")" |
|||
>&2 echo -e "${timestamp} [${level}] [$script_name] ${message}" | tee -a ${log_file} |
|||
} |
|||
|
|||
function local_log_debug { |
|||
local -r level="DEBUG" |
|||
local -r message="$1" |
|||
local -r timestamp=$(date +"%Y-%m-%d %H:%M:%S") |
|||
local -r script_name="$(basename "$0")" |
|||
echo -e "${timestamp} [${level}] [$script_name] ${message}" >> ${log_file} |
|||
} |
|||
|
|||
# Log the given message at DEBUG level. |
|||
function log_debug { |
|||
local -r message="$1" |
|||
local_log_debug "$message" |
|||
} |
|||
|
|||
# Log the given message at INFO level. |
|||
function log_info { |
|||
local -r message="$1" |
|||
log "INFO" "$message" |
|||
} |
|||
|
|||
# Log the given message at WARN level. |
|||
function log_warn { |
|||
local -r message="$1" |
|||
log "WARN" "$message" |
|||
} |
|||
|
|||
# Log the given message at ERROR level. |
|||
function log_error { |
|||
local -r message="$1" |
|||
log "ERROR" "$message" |
|||
} |
|||
|
|||
# Log the given message at FATAL level. |
|||
function log_fatal { |
|||
local -r message="$1" |
|||
log "FATAL" "$message" |
|||
exit 1 |
|||
} |
@ -0,0 +1,239 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Prints target architecture |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_arch() { |
|||
# --dereference, means to follow symlinks because 'ls' could be a symlink |
|||
# to busybox |
|||
file_info="" |
|||
for location in bin/ls usr/bin/ls; do |
|||
if [ -e work/rootfs/${location} ]; then |
|||
file_info=$(file -b --dereference work/rootfs/${location}) |
|||
break |
|||
fi |
|||
done |
|||
|
|||
if [ -z "${file_info}" ]; then |
|||
log_fatal "Sorry, where not able to determinate target architecture" |
|||
fi |
|||
|
|||
target_arch="unknown" |
|||
if grep -q x86-64 <<< "${file_info}"; then |
|||
target_arch="x86-64" |
|||
elif grep -Eq "ELF 32-bit.*ARM" <<< "${file_info}"; then |
|||
target_arch="arm" |
|||
elif grep -Eq "ELF 64-bit.*aarch64" <<< "${file_info}"; then |
|||
target_arch="aarch64" |
|||
else |
|||
log_fatal "Unsupported architecture: ${file_info}" |
|||
fi |
|||
echo "${target_arch}" |
|||
} |
|||
|
|||
# Prints GRUB EFI name depending on target architecture |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_grub_efi_name() { |
|||
efi_name="" |
|||
arch=$(probe_arch) |
|||
case "${arch}" in |
|||
"x86-64") |
|||
efi_name="grub-efi-bootx64.efi" |
|||
;; |
|||
"arm") |
|||
efi_name="grub-efi-bootarm.efi" |
|||
;; |
|||
"aarch64") |
|||
efi_name="grub-efi-bootaa64.efi" |
|||
;; |
|||
*) |
|||
log_fatal "Unknown arch: ${arch}" |
|||
;; |
|||
esac |
|||
echo "$efi_name" |
|||
} |
|||
|
|||
# Prints Debian arch name depending on target architecture |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_debian_arch_name() { |
|||
deb_arch="" |
|||
arch=$(probe_arch) |
|||
case "${arch}" in |
|||
"x86-64") |
|||
deb_arch="amd64" |
|||
;; |
|||
"arm") |
|||
deb_arch="armhf" |
|||
;; |
|||
"aarch64") |
|||
deb_arch="arm64" |
|||
;; |
|||
*) |
|||
log_fatal "Unknown arch: ${arch}" |
|||
;; |
|||
esac |
|||
echo "${deb_arch}" |
|||
} |
|||
|
|||
# Prints GRUB EFI target name depending on target architecture |
|||
# |
|||
# This is what the file name should be when put on target boot part. |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_grub_efi_target_name() { |
|||
efi_target_name="" |
|||
arch=$(probe_arch) |
|||
case "$arch" in |
|||
"x86-64") |
|||
efi_target_name="bootx64.efi" |
|||
;; |
|||
"arm") |
|||
efi_target_name="bootarm.efi" |
|||
;; |
|||
"aarch64") |
|||
efi_target_name="bootaa64.efi" |
|||
;; |
|||
*) |
|||
log_fatal "Unknown arch: ${arch}" |
|||
;; |
|||
esac |
|||
echo "$efi_target_name" |
|||
} |
|||
|
|||
# Prints path to the Linux kernel image |
|||
# |
|||
# $1 - directory in which the search is performed |
|||
# |
|||
probe_kernel_image() { |
|||
kernel_image_path="" |
|||
for image in vmlinuz zImage bzImage; do |
|||
# Linux kernel image type and naming varies between different platforms. |
|||
# |
|||
# The wildcard at the end is important, because it is common to suffix the |
|||
# Linux kernel version to the image type/name, e.g: |
|||
# |
|||
# vmlinuz-4.14-x86_64 |
|||
# vmlinuz-3.10.0-862.el7.x86_64 |
|||
# vmlinuz-4.15.0-20-generic |
|||
# |
|||
kernel_image_path=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*') |
|||
if [ -n "${kernel_image_path}" ]; then |
|||
break |
|||
fi |
|||
done |
|||
echo "${kernel_image_path}" |
|||
} |
|||
|
|||
# Prints path to the initrd/initramfs image |
|||
# |
|||
# $1 - directory in which the search is performed |
|||
# |
|||
probe_initrd_image() { |
|||
initrd_image_path="" |
|||
for image in initramfs initrd; do |
|||
# initrd/initramfs naming varies between different platforms. |
|||
# |
|||
# The wildcard at the end is important, because it is common to suffix the |
|||
# Linux kernel version to the image name, e.g: |
|||
# |
|||
# initrd.img-4.15.0-20-generic |
|||
# |
|||
initrd_image_path=$(sudo find ${1} -name ${image}* ! -name '*-rescue-*') |
|||
if [ -n "${initrd_image_path}" ]; then |
|||
break |
|||
fi |
|||
done |
|||
echo "${initrd_image_path}" |
|||
} |
|||
|
|||
# Prints Linux kernel image name |
|||
# |
|||
# It will look for it in both boot and rootfs parts. If image is only present |
|||
# in boot part, it will move it to rootfs/boot |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_kernel_in_boot_and_root() { |
|||
kernel_imagetype_path="" |
|||
|
|||
# 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 |
|||
# image in the rootfs first and use that, to avoid copying it over from |
|||
# boot part when it is already there. |
|||
for boot in work/rootfs/boot work/boot; do |
|||
kernel_imagetype_path=$(probe_kernel_image ${boot}) |
|||
if [ -n "${kernel_imagetype_path}" ] && [ "${boot}" == "work/boot" ]; then |
|||
log_info "Found Linux kernel image in boot part, moving to rootfs/boot" |
|||
sudo cp ${kernel_imagetype_path} work/rootfs/boot |
|||
break; |
|||
elif [ -n "${kernel_imagetype_path}" ]; then |
|||
break; |
|||
fi |
|||
done |
|||
|
|||
if [ -n "${kernel_imagetype_path}" ]; then |
|||
log_info "Found Linux kernel image: \n\n\t${kernel_imagetype_path}\n" |
|||
kernel_imagetype=$(basename ${kernel_imagetype_path}) |
|||
else |
|||
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" |
|||
fi |
|||
echo "${kernel_imagetype}" |
|||
} |
|||
|
|||
# Prints initrd/initramfs image name |
|||
# |
|||
# It will look for it in both boot and rootfs parts. If image is only present |
|||
# in boot part, it will move it to rootfs/boot |
|||
# |
|||
# No input parameters and these work on the assumption that boot and root parts |
|||
# are mounted at work/boot and work/rootfs |
|||
probe_initrd_in_boot_and_root() { |
|||
initrd_image_path="" |
|||
|
|||
# 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 |
|||
# image in the rootfs first and use that, to avoid copying it over from |
|||
# boot part when it is already there. |
|||
for boot in work/rootfs/boot work/boot; do |
|||
initrd_image_path=$(probe_initrd_image ${boot}) |
|||
if [ -n "${initrd_image_path}" ] && [ "${boot}" == "work/boot" ]; then |
|||
sudo cp ${initrd_image_path} ${target_rootfs_dir}/boot |
|||
break; |
|||
elif [ -n "${initrd_image_path}" ]; then |
|||
break; |
|||
fi |
|||
done |
|||
|
|||
if [ -n "${initrd_image_path}" ]; then |
|||
log_info "Found initramfs image: \n\n\t${initrd_image_path}\n" |
|||
initrd_imagetype=$(basename ${initrd_image_path}) |
|||
else |
|||
log_info "Unfortunately we where not able to find the initrd image." |
|||
log_info "Please specify the image name using MENDER_GRUB_INITRD_IMAGETYPE \ |
|||
(only required if your board is using this)" |
|||
initrd_imagetype="" |
|||
fi |
|||
|
|||
echo "${initrd_imagetype}" |
|||
} |
@ -0,0 +1,28 @@ |
|||
#!/usr/bin/env bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Run a command, capture output and log it |
|||
# |
|||
# $1 - command to run |
|||
function run_and_log_cmd() { |
|||
local -r cmd="${1}" |
|||
|
|||
log_debug "Running: \n\r\n\r\t ${cmd}" |
|||
log_debug "Run result: \n\r" |
|||
|
|||
result=$(eval ${cmd}) |
|||
log_debug "${result}" |
|||
} |
@ -1,21 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
|
|||
# Make a copy of Linux kernel arguments and modify. |
|||
mcopy -on -i ${output_dir}/boot.vfat -s ::EFI/BOOT/grub.cfg ${output_dir}/grub.cfg |
|||
sed -i 's/\b[ ]root=[^ ]*/ root=\/dev\/hda2/' ${output_dir}/grub.cfg |
|||
|
|||
# Update Linux kernel command arguments with our custom configuration |
|||
mcopy -o -i ${output_dir}/boot.vfat -s ${output_dir}/grub.cfg ::EFI/BOOT/grub.cfg |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=/dev/mapper/${boot_mapping} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -0,0 +1 @@ |
|||
binutils xz-utils file rsync parted e2fsprogs xfsprogs pigz dosfstools wget git make bmap-tools |
@ -1,22 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
embedded_rootfs_dir=$3 |
|||
uboot_backup_dir=${embedded_rootfs_dir}/opt/backup/uboot |
|||
build_log=$output_dir/build.log |
|||
|
|||
boot_part_dev="/dev/mapper/${boot_mapping}" |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
[ ! -d "${embedded_rootfs_dir}" ] && \ |
|||
{ log "Error: embedded content not mounted."; exit 1; } |
|||
[ ! -e ${boot_part_dev} ] && \ |
|||
{ log "Error: boot part does not exist: ${boot_part_dev}."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=${boot_part_dev} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,14 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=/dev/mapper/${boot_mapping} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,258 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
# Copyright 2018 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. |
|||
|
|||
application_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
files_dir=${application_dir}/files |
|||
output_dir=${application_dir}/output |
|||
uboot_dir=${output_dir}/uboot-mender |
|||
bin_base_dir=${output_dir}/bin |
|||
bin_dir_pi=${bin_base_dir}/raspberrypi |
|||
sdimg_base_dir=$output_dir/sdimg |
|||
build_log=${output_dir}/build.log |
|||
|
|||
declare -a mender_disk_mappings |
|||
declare -a mender_partitions_regular=("boot" "primary" "secondary" "data") |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - ARM toolchain |
|||
# $2 - RPI machine (raspberrypi3 or raspberrypi0w) |
|||
build_uboot_files() { |
|||
local CROSS_COMPILE=${1}- |
|||
local ARCH=arm |
|||
local branch="mender-rpi-2018.07" |
|||
local commit="50f05ab10e" |
|||
local uboot_repo_vc_dir=$uboot_dir/.git |
|||
local defconfig="rpi_3_32b_defconfig" |
|||
|
|||
if [ "$2" == "raspberrypi0w" ]; then |
|||
defconfig="rpi_0_w_defconfig" |
|||
fi |
|||
|
|||
export CROSS_COMPILE=$CROSS_COMPILE |
|||
export ARCH=$ARCH |
|||
|
|||
mkdir -p $bin_dir_pi |
|||
|
|||
log "\tBuilding U-Boot related files." |
|||
|
|||
if [ ! -d $uboot_repo_vc_dir ]; then |
|||
git clone https://github.com/mendersoftware/uboot-mender.git -b $branch >> "$build_log" 2>&1 |
|||
fi |
|||
|
|||
cd $uboot_dir |
|||
|
|||
git checkout $commit >> "$build_log" 2>&1 |
|||
|
|||
make --quiet distclean >> "$build_log" |
|||
make --quiet $defconfig >> "$build_log" 2>&1 |
|||
make --quiet >> "$build_log" 2>&1 |
|||
make --quiet envtools >> "$build_log" 2>&1 |
|||
|
|||
cat<<-'EOF' >boot.cmd |
|||
fdt addr ${fdt_addr} && fdt get value bootargs /chosen bootargs |
|||
run mender_setup |
|||
mmc dev ${mender_uboot_dev} |
|||
if load ${mender_uboot_root} ${kernel_addr_r} /boot/zImage; then |
|||
bootz ${kernel_addr_r} - ${fdt_addr} |
|||
elif load ${mender_uboot_root} ${kernel_addr_r} /boot/uImage; then |
|||
bootm ${kernel_addr_r} - ${fdt_addr} |
|||
else |
|||
echo "No bootable Kernel found." |
|||
fi |
|||
run mender_try_to_recover |
|||
EOF |
|||
|
|||
if [ ! -e $uboot_dir/tools/mkimage ]; then |
|||
log "Error: cannot build U-Boot. Aborting" |
|||
return 1 |
|||
fi |
|||
|
|||
$uboot_dir/tools/mkimage -A arm -T script -C none -n "Boot script" -d "boot.cmd" boot.scr >> "$build_log" 2>&1 |
|||
cp -t $bin_dir_pi $uboot_dir/boot.scr $uboot_dir/tools/env/fw_printenv $uboot_dir/u-boot.bin |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - boot partition mountpoint |
|||
# $2 - primary partition mountpoint |
|||
install_files() { |
|||
local boot_dir=$1 |
|||
local rootfs_dir=$2 |
|||
local kernel_img="kernel7.img" |
|||
|
|||
if [ "${device_type}" == "raspberrypi0w" ]; then |
|||
kernel_img="kernel.img" |
|||
fi |
|||
|
|||
log "\tInstalling U-Boot related files." |
|||
|
|||
# Make a copy of Linux kernel arguments and modify. |
|||
sudo cp ${boot_dir}/cmdline.txt ${output_dir}/cmdline.txt |
|||
|
|||
sed -i 's/\b[ ]root=[^ ]*/ root=\${mender_kernel_root}/' ${output_dir}/cmdline.txt |
|||
|
|||
# Original Raspberry Pi image run once will have init_resize.sh script removed |
|||
# from the init argument from the cmdline. |
|||
# |
|||
# On the other hand in Mender image we want to retain a mechanism of last |
|||
# partition resizing. Check the cmdline.txt file and add it back if necessary. |
|||
if ! grep -q "init=/usr/lib/raspi-config/init_resize.sh" ${output_dir}/cmdline.txt; then |
|||
cmdline=$(cat ${output_dir}/cmdline.txt) |
|||
sh -c -e "echo '${cmdline} init=/usr/lib/raspi-config/init_resize.sh' > ${output_dir}/cmdline.txt"; |
|||
fi |
|||
|
|||
# Update Linux kernel command arguments with our custom configuration |
|||
sudo cp ${output_dir}/cmdline.txt ${boot_dir} |
|||
|
|||
# Mask udisks2.service, otherwise it will mount the inactive part and we |
|||
# might write an update while it is mounted which often result in |
|||
# corruptions. |
|||
# |
|||
# TODO: Find a way to only blacklist mmcblk0pX devices instead of masking |
|||
# the service. |
|||
sudo ln -sf /dev/null ${rootfs_dir}/etc/systemd/system/udisks2.service |
|||
|
|||
# Extract Linux kernel and install to /boot directory on rootfs |
|||
sudo cp ${boot_dir}/${kernel_img} ${rootfs_dir}/boot/zImage |
|||
|
|||
# Replace kernel with U-boot and add boot script |
|||
sudo mkdir -p ${rootfs_dir}/uboot |
|||
|
|||
sudo cp ${bin_dir_pi}/u-boot.bin ${boot_dir}/${kernel_img} |
|||
|
|||
sudo cp ${bin_dir_pi}/boot.scr ${boot_dir} |
|||
|
|||
# Raspberry Pi configuration files, applications expect to find this on |
|||
# the device and in some cases parse the options to determinate |
|||
# functionality. |
|||
sudo ln -fs /uboot/config.txt ${rootfs_dir}/boot/config.txt |
|||
|
|||
sudo install -m 755 ${bin_dir_pi}/fw_printenv ${rootfs_dir}/sbin/fw_printenv |
|||
sudo ln -fs /sbin/fw_printenv ${rootfs_dir}/sbin/fw_setenv |
|||
|
|||
# Override init script to expand the data partition instead of rootfs, which it |
|||
# normally expands in standard Raspberry Pi distributions. |
|||
sudo install -m 755 ${files_dir}/init_resize.sh \ |
|||
${rootfs_dir}/usr/lib/raspi-config/init_resize.sh |
|||
|
|||
# As the whole process must be conducted in two steps, i.e. resize partition |
|||
# during first boot and resize the partition's file system on system's first |
|||
# start-up add systemd service file and script. |
|||
sudo install -m 644 ${files_dir}/resizefs.service \ |
|||
${rootfs_dir}/lib/systemd/system/resizefs.service |
|||
sudo ln -sf /lib/systemd/system/resizefs.service \ |
|||
${rootfs_dir}/etc/systemd/system/multi-user.target.wants/resizefs.service |
|||
sudo install -m 755 ${files_dir}/resizefs.sh \ |
|||
${rootfs_dir}/usr/sbin/resizefs.sh |
|||
|
|||
# Remove original 'resize2fs_once' script and its symbolic link. |
|||
sudo unlink ${rootfs_dir}/etc/rc3.d/S01resize2fs_once |
|||
sudo rm ${rootfs_dir}/etc/init.d/resize2fs_once |
|||
} |
|||
|
|||
do_install_bootloader() { |
|||
if [ -z "${mender_disk_image}" ]; then |
|||
log "Mender raw disk image file not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${bootloader_toolchain}" ]; then |
|||
log "ARM GCC toolchain not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if ! [ -x "$(command -v ${bootloader_toolchain}-gcc)" ]; then |
|||
log "Error: ARM GCC not found in PATH. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
[ ! -f $mender_disk_image ] && \ |
|||
{ log "$mender_disk_image - file not found. Aborting."; exit 1; } |
|||
|
|||
# Map & mount Mender compliant image. |
|||
create_device_maps $mender_disk_image mender_disk_mappings |
|||
|
|||
# Change current directory to 'output' directory. |
|||
cd $output_dir |
|||
|
|||
# Build patched U-Boot files. |
|||
build_uboot_files $bootloader_toolchain $device_type |
|||
rc=$? |
|||
cd $output_dir |
|||
|
|||
if [ $rc -eq 0 ]; then |
|||
mount_mender_disk ${mender_disk_mappings[@]} |
|||
install_files ${output_dir}/sdimg/boot ${output_dir}/sdimg/primary |
|||
fi |
|||
|
|||
detach_device_maps ${mender_disk_mappings[@]} |
|||
rm -rf $sdimg_base_dir |
|||
|
|||
[[ $keep -eq 0 ]] && { rm -f ${output_dir}/config.txt ${output_dir}/cmdline.txt; |
|||
rm -rf $uboot_dir $bin_base_dir; } |
|||
|
|||
[[ "$rc" -ne 0 ]] && { exit 1; } || { log "\tDone."; } |
|||
} |
|||
|
|||
# Conditional once we support other boards |
|||
PARAMS="" |
|||
|
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-m | --mender-disk-image) |
|||
mender_disk_image=$2 |
|||
shift 2 |
|||
;; |
|||
-b | --bootloader-toolchain) |
|||
bootloader_toolchain=$2 |
|||
shift 2 |
|||
;; |
|||
-d | --device-type) |
|||
device_type=$2 |
|||
shift 2 |
|||
;; |
|||
-k | --keep) |
|||
keep=1 |
|||
shift 1 |
|||
;; |
|||
-h | --help) |
|||
show_help |
|||
exit 0 |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
-*) |
|||
log "Error: unsupported option $1" |
|||
exit 1 |
|||
;; |
|||
*) |
|||
PARAMS="$PARAMS $1" |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
eval set -- "$PARAMS" |
|||
|
|||
# Some commands expect elevated privileges. |
|||
sudo true |
|||
|
|||
do_install_bootloader |
@ -0,0 +1,16 @@ |
|||
# Run tests |
|||
|
|||
The tests utilize the provided Docker container in this repository and conversion |
|||
is done using the `docker-mender-convert` command. For this reason we first need |
|||
to build the container (commands must be run from the root directory of |
|||
`mender-convert`): |
|||
|
|||
```bash |
|||
./docker-build |
|||
``` |
|||
|
|||
Run tests: |
|||
|
|||
```bash |
|||
./scripts/run-tests.sh |
|||
``` |
@ -0,0 +1,77 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Exit if any command exits with a non-zero exit status. |
|||
set -o errexit |
|||
|
|||
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) |
|||
if [ "${root_dir}" != "${PWD}" ]; then |
|||
echo "You must execute $(basename $0) from the root directory: ${root_dir}" |
|||
exit 1 |
|||
fi |
|||
|
|||
server_ip="" |
|||
output_dir="" |
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-o | --output-dir) |
|||
output_dir="${2}" |
|||
shift 2 |
|||
;; |
|||
-s | --server-ip) |
|||
server_ip="${2}" |
|||
shift 2 |
|||
;; |
|||
*) |
|||
echo "Sorry but the provided option is not supported: $1" |
|||
echo "Usage: $(basename $0) --output-dir ./rootfs_overlay_demo --server-ip <your server IP address>" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ -z "${output_dir}" ]; then |
|||
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" |
|||
exit 1 |
|||
fi |
|||
if [ -z "${server_ip}" ]; then |
|||
echo "Sorry, but you need to provide a server IP address using the '-s/--server-ip' option" |
|||
exit 1 |
|||
fi |
|||
|
|||
mkdir -p ${output_dir}/etc/mender |
|||
cat <<- EOF > ${output_dir}/etc/mender/mender.conf |
|||
{ |
|||
"InventoryPollIntervalSeconds": 5, |
|||
"RetryPollIntervalSeconds": 30, |
|||
"ServerURL": "https://docker.mender.io", |
|||
"ServerCertificate": "/etc/mender/server.crt", |
|||
"UpdatePollIntervalSeconds": 5 |
|||
} |
|||
EOF |
|||
cat <<- EOF > ${output_dir}/etc/hosts |
|||
127.0.0.1 localhost |
|||
|
|||
# The following lines are desirable for IPv6 capable hosts |
|||
::1 localhost ip6-localhost ip6-loopback |
|||
ff02::1 ip6-allnodes |
|||
ff02::2 ip6-allrouters |
|||
|
|||
${server_ip} docker.mender.io s3.docker.mender.io |
|||
EOF |
|||
wget -q "https://raw.githubusercontent.com/mendersoftware/mender/master/support/demo.crt" -O ${output_dir}/etc/mender/server.crt |
|||
|
|||
echo "Configuration file for using Demo Mender Server written to: ${output_dir}/etc/mender" |
@ -0,0 +1,67 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Exit if any command exits with a non-zero exit status. |
|||
set -o errexit |
|||
|
|||
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) |
|||
if [ "${root_dir}" != "${PWD}" ]; then |
|||
echo "You must execute $(basename $0) from the root directory: ${root_dir}" |
|||
exit 1 |
|||
fi |
|||
|
|||
tenant_token="" |
|||
output_dir="" |
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-t | --tenant-token) |
|||
tenant_token="${2}" |
|||
shift 2 |
|||
;; |
|||
-o | --output-dir) |
|||
output_dir="${2}" |
|||
shift 2 |
|||
;; |
|||
*) |
|||
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>" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ -z "${output_dir}" ]; then |
|||
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${tenant_token}" ]; then |
|||
echo "Sorry, but you need to provide a tenant token using the '-t/--tenant-token' option" |
|||
exit 1 |
|||
fi |
|||
|
|||
mkdir -p ${output_dir}/etc/mender |
|||
cat <<- EOF > ${output_dir}/etc/mender/mender.conf |
|||
{ |
|||
"InventoryPollIntervalSeconds": 5, |
|||
"RetryPollIntervalSeconds": 30, |
|||
"ServerURL": "https://hosted.mender.io/", |
|||
"TenantToken": "${tenant_token}", |
|||
"UpdatePollIntervalSeconds": 5 |
|||
} |
|||
EOF |
|||
|
|||
echo "Configuration file for using Hosted Mender written to: ${output_dir}/etc/mender" |
@ -0,0 +1,80 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Copyright 2019 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. |
|||
|
|||
# Exit if any command exits with a non-zero exit status. |
|||
set -o errexit |
|||
|
|||
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd ) |
|||
if [ "${root_dir}" != "${PWD}" ]; then |
|||
echo "You must execute $(basename $0) from the root directory: ${root_dir}" |
|||
exit 1 |
|||
fi |
|||
|
|||
server_url="" |
|||
output_dir="" |
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-o | --output-dir) |
|||
output_dir="${2}" |
|||
shift 2 |
|||
;; |
|||
-s | --server-url) |
|||
server_url="${2}" |
|||
shift 2 |
|||
;; |
|||
-S | --server-cert) |
|||
server_cert="${2}" |
|||
shift 2 |
|||
;; |
|||
*) |
|||
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>]" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ -z "${output_dir}" ]; then |
|||
echo "Sorry, but you need to provide an output directory using the '-o/--output-dir' option" |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${server_url}" ]; then |
|||
echo "Sorry, but you need to provide a server URL using the '-s/--server-url' option" |
|||
exit 1 |
|||
fi |
|||
|
|||
mkdir -p ${output_dir}/etc/mender |
|||
cat <<- EOF > ${output_dir}/etc/mender/mender.conf |
|||
{ |
|||
"InventoryPollIntervalSeconds": 5, |
|||
"RetryPollIntervalSeconds": 30, |
|||
"ServerURL": "${server_url}", |
|||
EOF |
|||
|
|||
if [ -n "${server_cert}" ]; then |
|||
cat <<- EOF >> ${output_dir}/etc/mender/mender.conf |
|||
"ServerCertificate": "/etc/mender/server.crt", |
|||
EOF |
|||
cp -f "${server_cert}" ${output_dir}/etc/mender/server.crt |
|||
fi |
|||
|
|||
cat <<- EOF >> ${output_dir}/etc/mender/mender.conf |
|||
"UpdatePollIntervalSeconds": 5 |
|||
} |
|||
EOF |
|||
|
|||
echo "Configuration file for using Production Mender Server written to: ${output_dir}/etc/mender" |
@ -0,0 +1,105 @@ |
|||
#!/bin/bash |
|||
|
|||
set -e |
|||
|
|||
usage() { |
|||
echo "$0 [--no-pull] <--all | --prebuilt-image DEVICE_TYPE IMAGE_NAME>" |
|||
exit 1 |
|||
} |
|||
|
|||
root_dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../" && pwd ) |
|||
if [ "${root_dir}" != "${PWD}" ]; then |
|||
echo "You must execute $(basename $0) from the root directory: ${root_dir}" |
|||
exit 1 |
|||
fi |
|||
|
|||
WORKSPACE=./tests |
|||
|
|||
BBB_DEBIAN_IMAGE="bone-debian-9.5-iot-armhf-2018-10-07-4gb.img" |
|||
BBB_DEBIAN_IMAGE_URL="http://debian.beagleboard.org/images/${BBB_DEBIAN_IMAGE}.xz" |
|||
|
|||
RASPBIAN_IMAGE="2019-09-26-raspbian-buster-lite" |
|||
RASPBIAN_IMAGE_URL="http://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-09-30/2019-09-26-raspbian-buster-lite.zip" |
|||
|
|||
TINKER_IMAGE="20170417-tinker-board-linaro-stretch-alip-v1.8" |
|||
TINKER_IMAGE_URL="http://dlcdnet.asus.com/pub/ASUS/mb/Linux/Tinker_Board_2GB/${TINKER_IMAGE}.zip" |
|||
|
|||
UBUNTU_IMAGE="Ubuntu-Bionic-x86-64.img" |
|||
UBUNTU_IMAGE_URL="https://d1b0l86ne08fsf.cloudfront.net/mender-convert/images/${UBUNTU_IMAGE}.gz" |
|||
|
|||
UBUNTU_SERVER_RPI_IMAGE="ubuntu-18.04.3-preinstalled-server-armhf+raspi3.img" |
|||
UBUNTU_SERVER_RPI_IMAGE_URL="http://cdimage.ubuntu.com/ubuntu/releases/bionic/release/${UBUNTU_SERVER_RPI_IMAGE}.xz" |
|||
|
|||
# Keep common function declarations in separate utils script |
|||
UTILS_PATH=${0/$(basename $0)/test-utils.sh} |
|||
source $UTILS_PATH |
|||
|
|||
# Some distros do not have /sbin in path for "normal users" |
|||
export PATH="${PATH}:/sbin" |
|||
|
|||
if [ "$1" = "--no-pull" ]; then |
|||
shift |
|||
else |
|||
echo "Automatically pulling submodules. Use --no-pull to disable" |
|||
git submodule update --init --remote |
|||
fi |
|||
|
|||
mkdir -p ${WORKSPACE} |
|||
|
|||
get_pytest_files |
|||
|
|||
test_result=0 |
|||
|
|||
case "$1" in |
|||
--prebuilt-image) |
|||
if [ -z "$3" ]; then |
|||
echo "Both DEVICE_TYPE and IMAGE_NAME must be specified" |
|||
exit 1 |
|||
fi |
|||
test_result=0 |
|||
run_tests "$2" "$3" || test_result=$? |
|||
exit $test_result |
|||
;; |
|||
|
|||
--all) |
|||
convert_and_test "qemux86_64" \ |
|||
"release-1" \ |
|||
"${UBUNTU_IMAGE_URL}" \ |
|||
"${UBUNTU_IMAGE}" \ |
|||
"${UBUNTU_IMAGE}.gz" \ |
|||
"configs/qemux86-64_config" || test_result=$? |
|||
|
|||
convert_and_test "raspberrypi" \ |
|||
"release-1" \ |
|||
"${RASPBIAN_IMAGE_URL}" \ |
|||
"${RASPBIAN_IMAGE}.img" \ |
|||
"${RASPBIAN_IMAGE}.zip" \ |
|||
"configs/raspberrypi3_config" || test_result=$? |
|||
|
|||
# MEN-2809: Disabled due broken download link |
|||
#convert_and_test "linaro-alip" \ |
|||
# "release-1" \ |
|||
# "${TINKER_IMAGE_URL}" \ |
|||
# "${TINKER_IMAGE}.img" \ |
|||
# "${TINKER_IMAGE}.zip" || test_result=$? |
|||
|
|||
convert_and_test "beaglebone" \ |
|||
"release-1" \ |
|||
"${BBB_DEBIAN_IMAGE_URL}" \ |
|||
"${BBB_DEBIAN_IMAGE}" \ |
|||
"${BBB_DEBIAN_IMAGE}.xz" || test_result=$? |
|||
|
|||
convert_and_test "ubuntu" \ |
|||
"release-1" \ |
|||
"${UBUNTU_SERVER_RPI_IMAGE_URL}" \ |
|||
"${UBUNTU_SERVER_RPI_IMAGE}" \ |
|||
"${UBUNTU_SERVER_RPI_IMAGE}.xz" \ |
|||
"configs/raspberrypi3_config" || test_result=$? |
|||
|
|||
exit $test_result |
|||
;; |
|||
|
|||
*) |
|||
usage |
|||
;; |
|||
esac |
@ -0,0 +1,114 @@ |
|||
MENDER_ACCEPTANCE_URL="https://raw.githubusercontent.com/mendersoftware/meta-mender/master/tests/acceptance" |
|||
|
|||
WORKSPACE=${WORKSPACE:-./tests} |
|||
|
|||
MENDER_CONVERT_DIR=$PWD |
|||
|
|||
convert_and_test() { |
|||
device_type=$1 |
|||
artifact_name=$2 |
|||
image_url=$3 |
|||
image_name=$4 |
|||
image_name_compressed=$5 |
|||
config=$6 # Optional |
|||
|
|||
wget --progress=dot:giga -N ${image_url} -P input/ |
|||
|
|||
echo "Extracting: ${image_name_compressed}" |
|||
case "${image_name_compressed}" in |
|||
*.gz) |
|||
gunzip -f input/${image_name_compressed} |
|||
;; |
|||
*.zip) |
|||
cd input |
|||
unzip -o ${image_name_compressed} |
|||
cd - |
|||
;; |
|||
*.xz) |
|||
xz -d -f input/${image_name_compressed} |
|||
;; |
|||
*) |
|||
echo "Unknown image type: ${image_name_compressed}" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
|
|||
rm -f ${WORKSPACE}/test_config |
|||
|
|||
# Two motives for the following statement |
|||
# |
|||
# - speed up tests by avoiding decompression on all images (majority of images |
|||
# we test have a platform specific configuration) |
|||
# |
|||
# - test providing multiple '--config' options |
|||
# |
|||
# - (when no platform configuration is provided) test conversion without |
|||
# '--config' and with MENDER_COMPRESS_DISK_IMAGE=gzip. Compressed disk |
|||
# images is the default user facing option and we need to ensure that we |
|||
# cover this in the tests. |
|||
if [ -n "${config}" ]; then |
|||
echo "Will disable MENDER_COMPRESS_DISK_IMAGE for this image" |
|||
echo "MENDER_COMPRESS_DISK_IMAGE=none" > ${WORKSPACE}/test_config |
|||
local MENDER_CONVERT_EXTRA_ARGS="--config ${config} --config ${WORKSPACE}/test_config" |
|||
fi |
|||
|
|||
MENDER_ARTIFACT_NAME=${artifact_name} ./docker-mender-convert \ |
|||
--disk-image input/${image_name} \ |
|||
${MENDER_CONVERT_EXTRA_ARGS} |
|||
|
|||
local ret=0 |
|||
run_tests "${device_type}" "${artifact_name}" || ret=$? |
|||
|
|||
rm -f deploy/${device_type}-${artifact_name}.* |
|||
|
|||
return $ret |
|||
} |
|||
|
|||
run_tests() { |
|||
device_type=$1 |
|||
artifact_name=$2 |
|||
shift 2 |
|||
pytest_args_extra=$@ |
|||
|
|||
if pip3 list | grep -q -e pytest-html; then |
|||
html_report_args="--html=${MENDER_CONVERT_DIR}/report_${device_type}.html --self-contained-html" |
|||
fi |
|||
|
|||
# Need to decompress images built with MENDER_COMPRESS_DISK_IMAGE=gzip before |
|||
# running tests. |
|||
if [ -f deploy/${device_type}-${artifact_name}.sdimg.gz ]; then |
|||
# sudo is needed because the image is created using docker-mender-convert |
|||
# which sets root permissions on the image |
|||
sudo gunzip --force deploy/${device_type}-${artifact_name}.sdimg.gz |
|||
fi |
|||
|
|||
cd ${WORKSPACE}/mender-image-tests |
|||
|
|||
# This is a trick to make pytest generate different junit reports |
|||
# for different runs: renaming the tests folder to tests_<testsuite> |
|||
cp -r tests tests_${device_type}_${artifact_name} |
|||
|
|||
python3 -m pytest --verbose \ |
|||
--junit-xml="${MENDER_CONVERT_DIR}/results_${device_type}.xml" \ |
|||
${html_report_args} \ |
|||
--test-conversion \ |
|||
--test-variables="${MENDER_CONVERT_DIR}/deploy/${device_type}-${artifact_name}.cfg" \ |
|||
--board-type="${device_type}" \ |
|||
--mender-image=${device_type}-${artifact_name}.sdimg \ |
|||
--sdimg-location="${MENDER_CONVERT_DIR}/deploy" \ |
|||
tests_${device_type}_${artifact_name} \ |
|||
${pytest_args_extra} |
|||
exitcode=$? |
|||
|
|||
cd - |
|||
|
|||
return $exitcode |
|||
} |
|||
|
|||
get_pytest_files() { |
|||
wget -N ${MENDER_ACCEPTANCE_URL}/pytest.ini -P $WORKSPACE/mender-image-tests |
|||
wget -N ${MENDER_ACCEPTANCE_URL}/common.py -P $WORKSPACE/mender-image-tests |
|||
wget -N ${MENDER_ACCEPTANCE_URL}/conftest.py -P $WORKSPACE/mender-image-tests |
|||
wget -N ${MENDER_ACCEPTANCE_URL}/fixtures.py -P $WORKSPACE/mender-image-tests |
|||
} |
|||
|
Loading…
Reference in new issue