You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

281 lines
9.2 KiB

#!/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, 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 [ -z "${kernel_imagetype_path}" ]; then
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
log_info "Found Linux kernel image: \n\n\t${kernel_imagetype_path}\n"
kernel_imagetype=$(basename ${kernel_imagetype_path})
if [ "${MENDER_GRUB_EFI_INTEGRATION}" == "y" ]; then
check_efi_compatible_kernel ${kernel_imagetype_path}
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}"
}
check_for_broken_uboot_uefi_support() {
local path="$1"
# Broken UEFI support in range v2018.09 - v2019.07 (see MEN-2404)
local regex='U-Boot 20(18\.(09|1[0-2])|19\.0[1-7])'
if egrep -qr "$regex" "$path"; then
local log_level=log_fatal
if [ "$MENDER_IGNORE_UBOOT_BROKEN_UEFI" = 1 ]; then
log_level=log_warn
fi
$log_level 'Detected a U-Boot version in the range v2018.09 - v2019.07. These U-Boot versions are known to have broken UEFI support, and therefore the MENDER_GRUB_EFI_INTEGRATION feature is unlikely to work. This only affects newly flashed devices using the partition image (extension ending in "img"). The Mender artifact should still work to upgrade an existing, working device. There are two possible workarounds for this issue: 1) Use either an older or a newer image that works, and use a Mender artifact afterwards to up/down-grade it to the version you want. 2) If the device has a non-UEFI U-Boot port in mender-convert, use that (look for a board specific file in `configs`) . If you want to ignore this error and force creation of the image, set the MENDER_IGNORE_UBOOT_BROKEN_UEFI=1 config option.'
fi
}
check_efi_compatible_kernel() {
kernel_path="$1"
case "$(probe_arch)" in
arm|aarch64)
# On ARM, as of version 2.04, GRUB can only boot kernels which have an EFI
# stub in them. See MEN-2404.
if ! file -k $kernel_path | fgrep 'EFI application'; then
local log_level=log_fatal
if [ "$MENDER_IGNORE_MISSING_EFI_STUB" = 1 ]; then
log_level=log_warn
fi
$log_level 'Detected a kernel which does not have an EFI stub. This kernel is not supported when booting with UEFI. Please consider using a U-Boot port if the board has one (look for a board specific file in `configs`), or find a kernel which has the CONFIG_EFI_STUB turned on. To ignore this message and proceed anyway, set the MENDER_IGNORE_MISSING_EFI_STUB=1 config option.'
fi
;;
*)
# Other platforms are fine.
:
;;
esac
}