Browse Source

remove mender-convert (version 1)

See https://hub.mender.io/t/new-iteration-of-the-mender-convert-tool/824 for
more details.

Will be replaced by mender-convert (version 2)

Changelog: Title

Signed-off-by: Mirza Krak <mirza.krak@northern.tech>
2.0.x
Mirza Krak 5 years ago
parent
commit
3c916f9a8b
  1. 105
      Dockerfile
  2. 181
      LICENSE
  3. 2
      LIC_FILES_CHKSUM.sha256
  4. 138
      README.md
  5. 44
      bbb-convert-stage-2.sh
  6. 22
      convert-stage-3.sh
  7. 366
      convert-stage-4.sh
  8. 389
      convert-stage-5.sh
  9. 1
      device-image-shell/.dockerignore
  10. 13
      device-image-shell/Dockerfile
  11. 64
      device-image-shell/README.md
  12. 7
      device-image-shell/docker-build
  13. 58
      device-image-shell/docker-device-image-shell
  14. 38
      device-image-shell/docker-entrypoint.sh
  15. 21
      docker-build
  16. 11
      docker-entrypoint.sh
  17. 16
      docker-mender-convert
  18. 112
      files/init_resize.sh
  19. 13
      files/resizefs.service
  20. 42
      files/resizefs.sh
  21. BIN
      files/uboot_debian_9.4/MLO
  22. BIN
      files/uboot_debian_9.4/u-boot.img
  23. 31
      files/variables.template
  24. 870
      mender-convert
  25. 888
      mender-convert-functions.sh
  26. 21
      qemux86_64-convert-stage-2.sh
  27. 22
      rockpro64-convert-stage-2.sh
  28. 14
      rpi-convert-stage-2.sh
  29. 258
      rpi-convert-stage-5.sh

105
Dockerfile

@ -1,105 +0,0 @@
FROM ubuntu:18.04
ARG MENDER_ARTIFACT_VERSION=3.0.1
ARG GOLANG_VERSION=1.11.2
RUN apt-get update && apt-get install -y \
kpartx \
bison \
flex \
mtools \
parted \
mtd-utils \
e2fsprogs \
u-boot-tools \
pigz \
device-tree-compiler \
autoconf \
autotools-dev \
libtool \
pkg-config \
python \
jq \
# for mender-convert to run (mkfs.vfat is required for boot partition)
sudo \
dosfstools \
# to compile U-Boot
bc \
# to download mender-artifact
wget \
# to download mender-convert and U-Boot sources
git \
# for arm64 support
gcc-aarch64-linux-gnu
# Disable sanity checks made by mtools. These checks reject copy/paste operations on converted disk images.
RUN echo "mtools_skip_check=1" >> $HOME/.mtoolsrc
# To provide support for Raspberry Pi Zero W a toolchain tuned for ARMv6 architecture must be used.
# https://tracker.mender.io/browse/MEN-2399
# Assumes $(pwd) is /
RUN wget -nc -q https://toolchains.bootlin.com/downloads/releases/toolchains/armv6-eabihf/tarballs/armv6-eabihf--glibc--stable-2018.11-1.tar.bz2 \
&& tar -xjf armv6-eabihf--glibc--stable-2018.11-1.tar.bz2 \
&& rm armv6-eabihf--glibc--stable-2018.11-1.tar.bz2 \
&& echo 'export PATH=$PATH:/armv6-eabihf--glibc--stable-2018.11-1/bin' >> /root/.bashrc
RUN wget -q -O /usr/bin/mender-artifact https://d1b0l86ne08fsf.cloudfront.net/mender-artifact/$MENDER_ARTIFACT_VERSION/linux/mender-artifact \
&& chmod +x /usr/bin/mender-artifact
# Golang environment, for cross-compiling the Mender client
RUN wget https://dl.google.com/go/go$GOLANG_VERSION.linux-amd64.tar.gz \
&& tar -C /usr/local -xzf go$GOLANG_VERSION.linux-amd64.tar.gz \
&& echo 'export PATH=$PATH:/usr/local/go/bin' >> /root/.bashrc
ENV PATH "$PATH:/usr/local/go/bin:/armv6-eabihf--glibc--stable-2018.11-1/bin"
ENV GOPATH "/root/go"
# Download Mender client
ARG mender_client_version
RUN test -n "$mender_client_version" || (echo "Argument 'mender_client_version' is mandatory." && exit 1)
ENV MENDER_CLIENT_VERSION=$mender_client_version
RUN go get -d github.com/mendersoftware/mender
WORKDIR $GOPATH/src/github.com/mendersoftware/mender
RUN git checkout $MENDER_CLIENT_VERSION
# Toolchain configuration
ARG toolchain_host
RUN test -n "$toolchain_host" || (echo "Argument 'toolchain_host' is mandatory." && exit 1)
ENV TOOLCHAIN_HOST=${toolchain_host}
ARG go_flags
RUN test -n "$go_flags" || (echo "Argument 'go_flags' is mandatory." && exit 1)
ENV GO_FLAGS=$go_flags
RUN test -n "$mender_client_version" || (echo "Argument 'mender_client_version' is mandatory." && exit 1)
ENV MENDER_CLIENT_VERSION=$mender_client_version
ENV CC "${TOOLCHAIN_HOST}-gcc"
# Build liblzma from source
RUN wget -q https://tukaani.org/xz/xz-5.2.4.tar.gz \
&& tar -C /root -xzf xz-5.2.4.tar.gz \
&& cd /root/xz-5.2.4 \
&& ./configure --host=${TOOLCHAIN_HOST} --prefix=/root/xz-5.2.4/install \
&& make \
&& make install
ENV LIBLZMA_INSTALL_PATH "/root/xz-5.2.4/install"
# NOTE: we are assuming generic ARM board here, needs to be extended later
RUN env CGO_ENABLED=1 \
CGO_CFLAGS="-I${LIBLZMA_INSTALL_PATH}/include" \
CGO_LDFLAGS="-L${LIBLZMA_INSTALL_PATH}/lib" \
CC=$CC \
GOOS=linux \
${GO_FLAGS} make build
# allow us to keep original PATH variables when sudoing
RUN echo "Defaults secure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:$PATH\"" > /etc/sudoers.d/secure_path_override
RUN chmod 0440 /etc/sudoers.d/secure_path_override
WORKDIR /
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]

181
LICENSE

@ -1,181 +0,0 @@
Copyright 2019 Northern.tech AS
All content in this project is licensed under the Apache License v2, unless
indicated otherwise.
-------------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

2
LIC_FILES_CHKSUM.sha256

@ -1,2 +0,0 @@
beb140be4cd64599bedc691a55b2729c9cc611a4b9d6ec44e01270105daf18a2 LICENSE
beb140be4cd64599bedc691a55b2729c9cc611a4b9d6ec44e01270105daf18a2 mendertesting/LICENSE

138
README.md

@ -1,138 +0,0 @@
[![Build Status](https://travis-ci.com/mendersoftware/mender-convert.svg?branch=master)](https://travis-ci.com/mendersoftware/mender-convert)
mender-convert
==============
Mender is an open source over-the-air (OTA) software updater for embedded Linux devices. Mender comprises a client running at the embedded device, as well as a server that manages deployments across many devices.
This repository contains mender-convert, which is used to convert pre-built disk images (Debian, Ubuntu, Raspbian, etc) to a Mender compatible
image by restructuring partition table and injecting the necessary files.
Currently official Raspberry Pi 3 and BeagleBone Black images are supported and this will be extended.
![Mender logo](https://mender.io/user/pages/resources/06.digital-assets/mender.io.png)
## Getting started
To start using Mender, we recommend that you begin with the Getting started
section in [the Mender documentation](https://docs.mender.io/).
## Docker environment for mender-convert
In order to correctly set up partitions and bootloaders, mender-convert has many dependencies,
and their version and name vary between Linux distributions.
To make using mender-convert easier, a reference setup using a Ubuntu 18.04 Docker container
is provided.
You need to [install Docker Engine](https://docs.docker.com/install) to use this environment.
### Build the mender-convert container image
To build a container based on Ubuntu 18.04 with all required dependencies for mender-convert,
copy this directory to your workstation and change the current directory to it.
Then run
```bash
./docker-build
```
This will create a container image you can use to run mender-convert.
### Use the mender-convert container image
Create a directory `input` under the directory where you copied these files (`docker-build`, `docker-mender-convert`, etc.):
```bash
mkdir input
```
Then put your raw disk image into `input/`, e.g.
```bash
mv ~/Downloads/2018-11-13-raspbian-stretch.img input/2018-11-13-raspbian-stretch.img
```
You can run mender-convert from inside the container with your desired options, e.g.
```bash
DEVICE_TYPE="raspberrypi3"
RAW_DISK_IMAGE="input/2018-11-13-raspbian-stretch.img"
ARTIFACT_NAME="2018-11-13-raspbian-stretch"
MENDER_DISK_IMAGE="2018-11-13-raspbian-stretch.sdimg"
TENANT_TOKEN="<INSERT-TOKEN-FROM Hosted Mender>"
./docker-mender-convert from-raw-disk-image \
--raw-disk-image $RAW_DISK_IMAGE \
--mender-disk-image $MENDER_DISK_IMAGE \
--device-type $DEVICE_TYPE \
--artifact-name $ARTIFACT_NAME \
--bootloader-toolchain arm-buildroot-linux-gnueabihf \
--server-url "https://hosted.mender.io" \
--tenant-token $TENANT_TOKEN
```
By default conversion in containter uses GCC 7.3.0 bootlin toolchain tuned for
ARMv6 architecture (especially for ARM1176(F)-S single-core processor).
The aim of that is to provide a support for the Raspberry Pi Zero W development board.
ARMv7 is backward compatible with ARMv6, so binaries compiled for ARMv6 should also work on ARMv7.
Note that the default Mender client is the latest stable and cross-compiled for generic ARM boards,
which should work well in most cases. If you would like to use a different Mender client,
place it in `input/` and adjust the `--mender-client` argument.
Conversion will take 10-15 minutes, depending on your storage and resources available.
You can watch `output/build.log` for progress and diagnostics information.
After it finishes, you can find your images in the `output` directory on your host machine!
### Known issues
* An issue for `Raspberry Pi Zero W` has been spotted with the `mender-convert` tool version 1.1.0.
After an initial boot, having last partition resized to the end of the SD card, the correct device
tree cannot be found. As a result the boot cannot succeed.
For more information and current status, see [issue tracker](https://tracker.mender.io/browse/MEN-2436).
* If building U-boot fails with:
```
D scripts/Kconfig
input in flex scanner failed
....
include/linux/kconfig.h:4:32: fatal error: generated/autoconf.h: No such file or directory
#include <generated/autoconf.h>
```
you might be using a case-sensitive filesystem which is not supported. Case-sensitive filesystems are typically used on OSX (Mac) and Windows but you can also run in to this on Linux if running on a NTFS formatted partition.
For details see this [discussion](https://hub.mender.io/t/raspberry-pi-3-model-b-b-raspbian/140/10)
## Contributing
We welcome and ask for your contribution. If you would like to contribute to Mender, please read our guide on how to best get started [contributing code or documentation](https://github.com/mendersoftware/mender/blob/master/CONTRIBUTING.md).
## License
Mender is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/mendersoftware/mender-crossbuild/blob/master/LICENSE) for the full license text.
## Security disclosure
We take security very seriously. If you come across any issue regarding
security, please disclose the information by sending an email to
[security@mender.io](security@mender.io). Please do not create a new public
issue. We thank you in advance for your cooperation.
## Connect with us
* Join the [Mender Hub discussion forum](https://hub.mender.io)
* Follow us on [Twitter](https://twitter.com/mender_io). Please
feel free to tweet us questions.
* Fork us on [Github](https://github.com/mendersoftware)
* Create an issue in the [bugtracker](https://tracker.mender.io/projects/MEN)
* Email us at [contact@mender.io](mailto:contact@mender.io)
* Connect to the [#mender IRC channel on Freenode](http://webchat.freenode.net/?channels=mender)

44
bbb-convert-stage-2.sh

@ -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

22
convert-stage-3.sh

@ -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

366
convert-stage-4.sh

@ -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

389
convert-stage-5.sh

@ -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
device-image-shell/.dockerignore

@ -1 +0,0 @@
output/

13
device-image-shell/Dockerfile

@ -1,13 +0,0 @@
FROM ubuntu:18.04
ARG MENDER_ARTIFACT_VERSION=3.0.1
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"]

64
device-image-shell/README.md

@ -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!

7
device-image-shell/docker-build

@ -1,7 +0,0 @@
#!/bin/sh
set -e
DOCKER_IMAGE_NAME=device-image-shell
docker build . -t ${DOCKER_IMAGE_NAME}

58
device-image-shell/docker-device-image-shell

@ -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"

38
device-image-shell/docker-entrypoint.sh

@ -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

21
docker-build

@ -1,21 +0,0 @@
#!/bin/sh
set -e
if [ -z "$IMAGE_NAME" ]; then
IMAGE_NAME=mender-convert
fi
MENDER_CLIENT_VERSION="2.0.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}

11
docker-entrypoint.sh

@ -1,11 +0,0 @@
#!/bin/sh
set -e
# run conversion, args provided to container (end of docker run ...)
cd /mender-convert
echo "Running mender-convert "$@""
./mender-convert "$@"

16
docker-mender-convert

@ -1,16 +0,0 @@
#!/bin/sh
set -e
IMAGE_NAME=mender-convert
MENDER_CONVERT_DIR="$(pwd)"
mkdir -p output
docker run \
--mount type=bind,source="$MENDER_CONVERT_DIR,target=/mender-convert" \
--privileged=true \
--cap-add=SYS_MODULE \
-v /dev:/dev \
-v /lib/modules:/lib/modules:ro \
$IMAGE_NAME "$@"

112
files/init_resize.sh

@ -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

13
files/resizefs.service

@ -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

42
files/resizefs.sh

@ -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

BIN
files/uboot_debian_9.4/MLO

Binary file not shown.

BIN
files/uboot_debian_9.4/u-boot.img

Binary file not shown.

31
files/variables.template

@ -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=""

870
mender-convert

@ -1,870 +0,0 @@
#!/bin/bash
show_help() {
cat << EOF
Mender conversion tool
A tool that takes an existing embedded image (Debian, Ubuntu, Raspbian, etc)
and converts it to a Mender image by restructuring partition table and adding
necessary files.
Usage: $0 COMMAND [options]
General commands:
from-raw-disk-image - composes fully functional Mender
image compliant with Mender
partition layout, having all
necessary files installed
mender-disk-image-to-artifact - creates Mender artifact file
from Mender image
Options: [-r|--raw-disk-image | -m|--mender-disk-image | -s|--data-part-size-mb |
-d|--device-type | -p|--rootfs-partition-id | -n|--demo | -i|--demo-host-ip |
-c|--server-cert | -u|--server-url | -t|--tenant-token |
-g|--mender-client | -b|--bootloader-toolchain | -a|--artifact-name |
-e|--storage-total-size-mb | -k|--keep | -v|--version -h|--help]
raw-disk-image - raw disk embedded Linux (Debian, Raspbian,
Ubuntu, etc.) image path
mender-disk-image - Mender disk image name where the script writes to
should have "sdimg" suffix
data-part-size-mb - data partition size in MB; default value 128MB
device-type - target device identification used to build
Mender image
rootfs-partition-id - selects root filesystem (primary|secondary)
as the source filesystem for an artifact
demo - Configure image using demo parameters
demo-host-ip - server demo ip used for testing purposes
server-cert - server certificate file
server-url - production server url
tenant-token - Mender tenant token
mender-client - Mender client binary
bootloader-toolchain - GNU Arm Embedded Toolchain
artifact-name - Mender artifact name
storage-total-size-mb - total storage size in MB; default value 8000MB;
it is used to calculate the rootfs final size
keep - keep intermediate files in output directory
version - print the version
help - show help and exit
Note: root filesystem size used in Mender image creation can be found as
an output from 'raw-disk-image-shrink-rootfs' command or, in case
of using unmodified embedded raw disk image, can be checked with
any partition manipulation program (e.g. parted, fdisk, etc.).
Examples:
To create fully functional Mender image from raw disk image in a single step:
./mender-convert from-raw-disk-image
--raw-disk-image <raw_disk_image_path>
[--mender-disk-image <mender_image_name>]
--device-type <beaglebone | raspberrypi3>
[--mender-client <mender_binary_path>]
--artifact-name release-1_1.5.0
--bootloader-toolchain arm-linux-gnueabihf
--demo-host-ip 192.168.10.2
--keep
Output:
- Mender image: ready to use image with client and bootloader installed
- Mender artifact: update file based on the already built Mender image
- Mender root filesystem: EXT4 image used to produce the Mender artifact
To create Mender artifact file from Mender image:
./mender-convert mender-disk-image-to-artifact
--mender-disk-image <mender_image_path>
--device-type <beaglebone | raspberrypi3>
--artifact-name release-1_1.5.0
--rootfs-partition-id <primary | secondary>
Note: artifact name format is: release-<release_no>_<mender_version>
EOF
}
show_version() {
local version=$(cd "$tool_dir" && (git describe --tags --dirty --exact-match 2>/dev/null || git rev-parse --short HEAD))
echo "mender-convert version: $version"
}
if [ $# -eq 0 ]; then
show_help
exit 1
fi
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
mender_disk_image=
raw_disk_image=
device_type=
mender_disk_counts=
artifact_name=
rootfs_partition_id=
raw_disk_counts=
mender_client=
# Mender production certificate.
server_cert=
# Mender production server url.
server_url=
# Mender demo server IP address.
demo_host_ip=
# Mender hosted token.
tenant_token=
# Conversion progress.
declare -i step=1
declare -i total=
declare -a rootfs_partition_ids=("primary" "secondary")
declare -a mender_disk_mappings
declare -a raw_disk_mappings
#Supported devices
declare -a supported_devices=("beaglebone" "raspberrypi3" "qemux86_64" "raspberrypi0w" "rockpro64")
do_raw_disk_image_shrink_rootfs() {
log "$step/$total Shrinking raw disk image root filesystem..."
((step++))
if [ -z "${raw_disk_image}" ]; then
log "Raw disk image not set. Aborting."
return 1
fi
# For root filesystem partition set 8MB alignment for shrinking purpose.
partition_alignment=$PART_ALIGN_8MB
# Gather information about raw disk image.
get_raw_disk_sizes ${raw_disk_image} raw_disk_counts raw_disk_sizes
local sector_size=${raw_disk_sizes[sector_size]}
if [[ $raw_disk_counts -eq 1 ]]; then
offset=${raw_disk_sizes[pboot_start]}
elif [[ $raw_disk_counts -eq 2 ]]; then
offset=${raw_disk_sizes[prootfs_start]}
else
log "Warning: invalid/unsupported embedded raw disk image. Skipping resize..."
return 0
fi
# Find first available loopback device and mount appropriate partition.
loopdevice=$(sudo losetup --show -f -o $((${offset} * $sector_size)) $raw_disk_image)
[ $? -ne 0 ] && { log "Error: inaccesible loopback device"; return 1; }
block_size=($(sudo dumpe2fs -h $loopdevice | grep 'Block size' | tr -s ' ' | cut -d ' ' -f3))
min_size_blocks=($(sudo resize2fs -P $loopdevice | awk '{print $NF}'))
new_size_sectors=$(( $min_size_blocks * $block_size / $sector_size ))
align_partition_size new_size_sectors $sector_size
log "\tRoot filesystem size:\
\n\tminimal: $(( $min_size_blocks * $block_size )) \
\n\taligned: $(( $new_size_sectors * $sector_size ))\
\n\tsectors: $new_size_sectors"
sudo e2fsck -y -f $loopdevice >> "$build_log" 2>&1
sudo resize2fs -p $loopdevice ${new_size_sectors}s >> "$build_log" 2>&1
sudo e2fsck -y -f $loopdevice >> "$build_log" 2>&1
sudo losetup -d $loopdevice
loopdevice=$(sudo losetup --show -f $raw_disk_image)
if [[ $raw_disk_counts -eq 1 ]]; then
create_single_disk_partition_table $loopdevice \
${raw_disk_sizes[pboot_start]} $new_size_sectors
elif [[ $raw_disk_counts -eq 2 ]]; then
create_double_disk_partition_table $loopdevice \
${raw_disk_sizes[prootfs_start]} $new_size_sectors
fi
sudo partprobe
endsector=($(sudo parted $loopdevice -ms unit s print | grep "^$raw_disk_counts" | cut -f3 -d: | sed 's/[^0-9]*//g'))
sudo losetup -d $loopdevice
log "\tRaw disk image new endsector: $endsector"
sudo truncate -s $((($endsector+1) * $sector_size)) $raw_disk_image
log "\tNew root filesystem size (sectors): $new_size_sectors"
return 0
}
do_raw_disk_image_create_partitions() {
log "$step/$total Repartitioning raw disk image..."
((step++))
if [ -z "$raw_disk_image" ] || [ -z "$device_type" ] || \
[ -z "$artifact_name" ]; then
show_help
return 1
fi
if [[ ! -f ${raw_disk_image} ]]; then
log "Raw disk image not found. Aborting."
return 1
fi
local supported=$(echo ${supported_devices[@]} | grep -o $device_type | wc -w)
[[ $supported -eq 0 ]] && \
{ log "Error: incorrect device type. Aborting."; return 1; }
# Change current directory to 'output' directory.
cd $output_dir
set_mender_disk_alignment $device_type partition_alignment vfat_storage_offset
get_raw_disk_sizes ${raw_disk_image} raw_disk_counts raw_disk_sizes
rc=$?
[ $rc -eq 0 ] || { return 1; }
log "\tDetected raw disk image with $raw_disk_counts partition(s)."
log "\tCalculating partitions' sizes of the Mender image."
set_mender_disk_sizes ${raw_disk_counts} ${partition_alignment} \
${vfat_storage_offset} ${data_part_size_mb} \
raw_disk_sizes mender_disk_sizes
local mender_disk_image_size=
calculate_mender_disk_size ${partition_alignment} mender_disk_sizes \
mender_disk_counts mender_disk_image_size
mender_image_size_to_total_storage_size ${mender_disk_counts} \
mender_disk_image_size ${storage_total_size_mb} \
mender_disk_sizes
rc=$?
[ $rc -eq 0 ] || { return 1; }
if [[ ${raw_disk_counts} -gt 1 ]]; then
log "\tExtracting boot partition from raw disk image."
extract_file_from_image ${raw_disk_image} ${raw_disk_sizes[pboot_start]} \
${raw_disk_sizes[pboot_size]} "boot.vfat"
log "\tExtracting root filesystem partition from raw disk image."
extract_file_from_image ${raw_disk_image} ${raw_disk_sizes[prootfs_start]} \
${raw_disk_sizes[prootfs_size]} "rootfs.img"
else
log "\tGenerating boot partition (required, does not exist in original image)"
dd if=/dev/zero of=${output_dir}/boot.vfat count=${mender_disk_sizes[pboot_size]} bs=512 >> "$build_log" 2>&1
mkfs.vfat ${output_dir}/boot.vfat >> "$build_log" 2>&1
log "\tExtracting root filesystem partition from raw disk image."
extract_file_from_image ${raw_disk_image} ${raw_disk_sizes[pboot_start]} \
${raw_disk_sizes[pboot_size]} "rootfs.img"
fi
local sector_size=${mender_disk_sizes[sector_size]}
log "\tCreating blank Mender disk image:\
\n\t\timage size: ${mender_disk_image_size} bytes\
\n\t\tboot partition size: $((${mender_disk_sizes[pboot_size]} * $sector_size)) bytes\
\n\t\troot filesystem size: $((${mender_disk_sizes[prootfs_size]} * $sector_size)) bytes\
\n\t\tdata partition size: $((${mender_disk_sizes[pdata_size]} * $sector_size)) bytes"
if [ -v mender_disk_sizes[pswap_size] ]; then
log "\t\tswap partition size: $((${mender_disk_sizes[pswap_size]} * $sector_size)) bytes"
fi
create_test_config_file $device_type $partition_alignment $mender_disk_image_size \
mender_disk_sizes
create_mender_disk $mender_disk_image $mender_disk_image_size
format_mender_disk $mender_disk_image $mender_disk_image_size \
$partition_alignment mender_disk_sizes
rc=$?
[ $rc -eq 0 ] || { return 1; }
verify_mender_disk $mender_disk_image $mender_disk_counts
rc=$?
[ $rc -eq 0 ] || { return 1; }
create_device_maps $mender_disk_image mender_disk_mappings
log "$step/$total Formatting repartitioned raw disk image..."
((step++))
make_mender_disk_filesystem ${mender_disk_mappings[@]}
case "$device_type" in
"beaglebone")
do_make_sdimg_beaglebone
;;
"raspberrypi3" | "raspberrypi0w")
do_make_sdimg_raspberrypi3
;;
"qemux86_64")
do_make_sdimg_qemux86_64
;;
"rockpro64")
do_make_sdimg_rockpro64
;;
*)
log "Error: unsupported device type $device_type"
exit 1
;;
esac
rc=$?
log "$step/$total Cleaning intermediate files..."
((step++))
# Clean and detach.
detach_device_maps ${mender_disk_mappings[@]}
detach_device_maps ${raw_disk_mappings[@]}
sync
rm -rf $embedded_base_dir
rm -rf $sdimg_base_dir
[ $rc -eq 0 ] || { log "\nRepartitioning of $raw_disk_image image failed."; }
return $rc
}
do_make_sdimg_rockpro64() {
local ret=0
create_device_maps $raw_disk_image raw_disk_mappings
mount_raw_disk ${raw_disk_mappings[@]}
log "$step/$total Setting boot partition..."
((step++))
stage_2_args="$output_dir ${mender_disk_mappings[0]} ${embedded_rootfs_dir}"
${tool_dir}/rockpro64-convert-stage-2.sh ${stage_2_args} || ret=$?
[[ $ret -ne 0 ]] && { log "Aborting."; return $ret; }
log "$step/$total Setting root filesystem partition..."
((step++))
stage_3_args="$output_dir ${mender_disk_mappings[1]}"
${tool_dir}/convert-stage-3.sh ${stage_3_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
mount_mender_disk ${mender_disk_mappings[@]}
log "$step/$total Setting file system table..."
((step++))
set_fstab $device_type
log "Write bootloader"
dd if=$integration_dir/rockpro64/rksd_loader.img of=$mender_disk_image \
seek=64 conv=notrunc status=none
return $ret
}
do_make_sdimg_beaglebone() {
local ret=0
create_device_maps $raw_disk_image raw_disk_mappings
mount_raw_disk ${raw_disk_mappings[@]}
log "$step/$total Setting boot partition..."
((step++))
stage_2_args="$output_dir ${mender_disk_mappings[0]} ${embedded_rootfs_dir}"
${tool_dir}/bbb-convert-stage-2.sh ${stage_2_args} || ret=$?
[[ $ret -ne 0 ]] && { log "Aborting."; return $ret; }
log "$step/$total Setting root filesystem partition..."
((step++))
stage_3_args="$output_dir ${mender_disk_mappings[1]}"
${tool_dir}/convert-stage-3.sh ${stage_3_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
mount_mender_disk ${mender_disk_mappings[@]}
log "$step/$total Setting file system table..."
((step++))
set_fstab $device_type
return $ret
}
do_make_sdimg_raspberrypi3() {
log "$step/$total Setting boot partition..."
((step++))
stage_2_args="$output_dir ${mender_disk_mappings[0]}"
${tool_dir}/rpi-convert-stage-2.sh ${stage_2_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
log "$step/$total Setting root filesystem partition..."
((step++))
stage_3_args="$output_dir ${mender_disk_mappings[1]}"
${tool_dir}/convert-stage-3.sh ${stage_3_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
mount_mender_disk ${mender_disk_mappings[@]}
log "$step/$total Setting file system table..."
((step++))
set_fstab $device_type
return 0
}
do_make_sdimg_qemux86_64() {
log "$step/$total Setting boot partition..."
((step++))
stage_2_args="$output_dir ${mender_disk_mappings[0]}"
${tool_dir}/qemux86_64-convert-stage-2.sh ${stage_2_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
log "$step/$total Setting root filesystem partition..."
((step++))
stage_3_args="$output_dir ${mender_disk_mappings[1]}"
${tool_dir}/convert-stage-3.sh ${stage_3_args} || ret=$?
[[ $ret -ne 0 ]] && { return $ret; }
mount_mender_disk ${mender_disk_mappings[@]}
log "$step/$total Setting file system table..."
((step++))
set_fstab $device_type
return 0
}
do_install_mender_to_mender_disk_image() {
log "$step/$total Installing Mender to Mender disk image..."
((step++))
if [ -z "$mender_disk_image" ] || [ -z "$device_type" ] || \
[ -z "$artifact_name" ]; then
show_help
return 1
fi
local supported=$(echo ${supported_devices[@]} | grep -o $device_type | wc -w)
[[ $supported -eq 0 ]] && \
{ log "Error: incorrect device type. Aborting."; return 1; }
# mender-image-1.5.0
stage_4_args="-m $mender_disk_image -d $device_type -a ${artifact_name}"
if [ -n "$mender_client" ]; then
stage_4_args="${stage_4_args} --mender-client ${mender_client}"
fi
if [ -n "$demo" ] && [ ${demo} -eq 1 ]; then
stage_4_args="${stage_4_args} --demo"
fi
if [ -n "$demo_host_ip" ]; then
stage_4_args="${stage_4_args} -i ${demo_host_ip}"
fi
if [ -n "$server_cert" ]; then
stage_4_args="${stage_4_args} -c ${server_cert}"
fi
if [ -n "$server_url" ]; then
stage_4_args="${stage_4_args} -u ${server_url}"
fi
if [ -n "${tenant_token}" ]; then
stage_4_args="${stage_4_args} -t ${tenant_token}"
fi
if [ -n "${keep}" ]; then
stage_4_args="${stage_4_args} -k"
fi
eval set -- " ${stage_4_args}"
${tool_dir}/convert-stage-4.sh ${stage_4_args} || ret=$?
[[ $ret -ne 0 ]] && { log "\nInstalling Mender to Mender disk image failed."; return $ret; }
# Update test configuration file
update_test_config_file $device_type artifact-name $artifact_name
return 0
}
do_install_bootloader_to_mender_disk_image() {
log "$step/$total Installing Bootloader to Mender disk image..."
((step++))
if [ -z "$mender_disk_image" ] || [ -z "$device_type" ] || \
[ -z "$bootloader_toolchain" ]; then
show_help
return 1
fi
local supported=$(echo ${supported_devices[@]} | grep -o $device_type | wc -w)
[[ $supported -eq 0 ]] && \
{ log "Error: incorrect device type. Aborting."; return 1; }
case "$device_type" in
"beaglebone" | "qemux86_64" | "rockpro64")
stage_5_args="-m $mender_disk_image -d $device_type -b ${bootloader_toolchain} $keep"
eval set -- " ${stage_5_args}"
${tool_dir}/convert-stage-5.sh ${stage_5_args}|| ret=$?
[[ $ret -ne 0 ]] && { log "\nInstalling Bootloader failed."; return $ret; }
# Update test configuration file
update_test_config_file $device_type distro-feature "mender-grub" \
mount-location "\/boot\/efi"
;;
"raspberrypi3"|"raspberrypi0w")
stage_5_args="-m $mender_disk_image -d $device_type -b ${bootloader_toolchain} $keep"
eval set -- " ${stage_5_args}"
${tool_dir}/rpi-convert-stage-5.sh ${stage_5_args}|| ret=$?
[[ $ret -ne 0 ]] && { log "\nInstalling Bootloader failed."; return $ret; }
# Update test configuration file
update_test_config_file $device_type distro-feature "mender-uboot" \
mount-location "\/uboot"
;;
*)
log "Error: unsupported device type $device_type"
exit 1
;;
esac
return 0
}
do_mender_disk_image_to_artifact() {
log "$step/$total Creating Mender Artifact..."
((step++))
if [ -z "${mender_disk_image}" ]; then
log "Mender disk image not set. Aborting."
return 1
fi
if [ -z "${device_type}" ]; then
log "Target device_type name not set. Aborting."
return 1
fi
if [ -z "${artifact_name}" ]; then
log "Artifact name not set. Aborting."
return 1
fi
if [ -z "${rootfs_partition_id}" ]; then
log "\tRootfs partition id not set - 'primary' will be used by default."
rootfs_partition_id="primary"
fi
local supported=$(echo ${supported_devices[@]} | grep -o $device_type | wc -w)
[[ $supported -eq 0 ]] && \
{ log "Error: incorrect device type. Aborting."; return 1; }
inarray=$(echo ${rootfs_partition_ids[@]} | grep -o $rootfs_partition_id | wc -w)
[[ $inarray -eq 0 ]] && \
{ log "Error: invalid rootfs partition id provided. Aborting."; return 1; }
local count=0
local sector_size=0
local prootfs_start=0
local prootfs_size=0
local rootfs_a_start=0
local rootfs_a_size=0
local rootfs_b_start=0
local rootfs_b_size=0
local rootfs_path=
local mender_device_type=
get_mender_disk_sizes $mender_disk_image count sector_size rootfs_a_start \
rootfs_a_size rootfs_b_start rootfs_b_size
ret=$?
[[ $ret -ne 0 ]] && \
{ log "Error: cannot validate Mender disk image. Aborting."; return 1; }
# Check if device type matches.
create_device_maps $mender_disk_image mender_disk_mappings
mount_mender_disk ${mender_disk_mappings[@]}
# Find .sdimg file's dedicated device type.
mender_device_type=$( cat $sdimg_data_dir/mender/device_type | sed 's/[^=].*=//' )
if [ "$mender_device_type" != "$device_type" ]; then
log "Error: device types of Mender artifact & Mender not matching. Aborting."
ret=1
fi
if ! [ -x "$(command -v mender-artifact)" ]; then
log "Error: mender-artifact not found in PATH. Aborting."
ret=1
fi
if [ $ret -eq 0 ]; then
if [[ $rootfs_partition_id == "primary" ]]; then
prootfs_start=$rootfs_a_start
prootfs_size=$rootfs_a_size
rootfs_path=$sdimg_primary_dir
elif [[ $rootfs_partition_id == "secondary" ]]; then
prootfs_start=$rootfs_b_start
prootfs_size=$rootfs_b_size
rootfs_path=$sdimg_secondary_dir
fi
# Extract root filesystem ext4 image to use it to generate Mender artifact.
# Ext4 disk image will be also verified in acceptance tests.
extract_file_from_image $mender_disk_image $prootfs_start \
$prootfs_size $mender_rootfs_basename
fsck.ext4 -fp $mender_rootfs_image &> /dev/null || ret=$?
[[ $ret -ne 0 ]] && \
{ log "Error: checking $mender_rootfs_basename file system failed. Aborting."; }
# Find first available loopback device and use it.
loopdevice=($(sudo losetup --show -f ${mender_rootfs_image} || ret=$?))
[[ $ret -ne 0 ]] && \
{ log "Error: cannot find an unused loop device. Aborting."; }
if [ $ret -eq 0 ]; then
# Mount extracted ext4 partition to verify 'artifact_info' file content.
rootfs_mountpoint=${output_dir}/mnt/${rootfs_partition_id}
mkdir -p ${rootfs_mountpoint}
sudo mount $loopdevice ${rootfs_mountpoint}
# Set 'artifact name' as passed in the command line.
sudo sed -i '/^artifact/s/=.*$/='${artifact_name}'/' "${rootfs_mountpoint}/etc/mender/artifact_info"
sudo umount -l ${rootfs_mountpoint}
sudo losetup -d $loopdevice
rm -rf ${output_dir}/mnt
log "\tWriting Mender artifact to: ${mender_artifact}"
log "\tThis may take 10-20 minutes (using LZMA)..."
#Create Mender artifact
mender-artifact \
--compression lzma \
write rootfs-image \
--file ${mender_rootfs_image} \
--output-path ${mender_artifact} \
--artifact-name ${artifact_name} \
--device-type ${device_type}
ret=$?
[[ $ret -eq 0 ]] && \
{ log "\tCreating Mender Artifact succeeded."; } || \
{ log "\tCreating Mender Artifact failed."; }
fi
fi
# Clean and detach.
detach_device_maps ${mender_disk_mappings[@]}
rm -rf $sdimg_base_dir
return $ret
}
do_from_raw_disk_image() {
if [ -z "$raw_disk_image" ] || [ -z "$device_type" ] || \
[ -z "$artifact_name" ] || \
[ -z "$bootloader_toolchain" ]; then
show_help
return 1
fi
do_raw_disk_image_shrink_rootfs || rc=$?
[[ $rc -ne 0 ]] && { return 1; }
do_raw_disk_image_create_partitions || rc=$?
[[ $rc -ne 0 ]] && { return 1; }
do_install_mender_to_mender_disk_image || rc=$?
[[ $rc -ne 0 ]] && { return 1; }
do_install_bootloader_to_mender_disk_image || rc=$?
[[ $rc -ne 0 ]] && { return 1; }
do_mender_disk_image_to_artifact || rc=$?
[[ $rc -ne 0 ]] && { return 1; }
return 0
}
PARAMS=""
# Load necessary functions.
source ${tool_dir}/mender-convert-functions.sh
export -f create_device_maps
export -f detach_device_maps
export -f mount_mender_disk
export -f log
export -f logsetup
while (( "$#" )); do
case "$1" in
-p | --rootfs-partition-id)
rootfs_partition_id=$2
shift 2
;;
-m | --mender-disk-image)
mender_disk_image=$2
shift 2
;;
-r | --raw-disk-image)
raw_disk_image=$(get_path $2)
shift 2
;;
-s | --data-part-size-mb)
data_part_size_mb=$2
shift 2
;;
-d | --device-type)
device_type=$2
shift 2
;;
-a | --artifact-name)
artifact_name=$2
shift 2
;;
-g | --mender-client)
mender_client=$(get_path $2)
shift 2
;;
-b | --bootloader-toolchain)
bootloader_toolchain=$2
shift 2
;;
-n | --demo)
demo="1"
shift 1
;;
-i | --demo-host-ip)
demo_host_ip=$2
shift 2
;;
-c | --server-cert)
server_cert=$(get_path $2)
shift 2
;;
-u | --server-url)
server_url=$2
shift 2
;;
-t | --tenant-token)
tenant_token=$2
shift 2
;;
-e | --storage-total-size-mb)
storage_total_size_mb=$2
shift 2
;;
-k | --keep)
keep="-k"
shift 1
;;
-v | --version)
show_version
exit 0
;;
-h | --help)
show_help
exit 0
;;
--)
shift
break
;;
-*)
log "Error: unsupported option $1"
exit 1
;;
*)
PARAMS="$PARAMS $1"
shift
;;
esac
done
[ -z "${data_part_size_mb}" ] && \
{ log "*** Data partition size set to default value: 128MB ***"; \
data_part_size_mb=$DATA_PART_SIZE_MB; }
[ -z "${storage_total_size_mb}" ] && \
{ log "*** Total storage size set to default value: 8GB ***"; \
storage_total_size_mb=$STORAGE_TOTAL_SIZE_MB; }
eval set -- "$PARAMS"
# Before running any command first create output directory
# and configure where logs should be redirected.
mkdir -p $output_dir
logsetup
# Fetch integration binaries
MENDER_INTEGRATION_URL="https://d1b0l86ne08fsf.cloudfront.net/mender-convert"
if [ "$device_type" == "rockpro64" ]; then
if [ ! -f $integration_dir/rockpro64/emmc-boot-integration.tar.gz ]; then
rockpro64_integration_dir=$integration_dir/rockpro64
mkdir -p $rockpro64_integration_dir
wget -P $rockpro64_integration_dir \
${MENDER_INTEGRATION_URL}/armbian/rockpro64/emmc-boot-integration.tar.gz
tar xvf $rockpro64_integration_dir/emmc-boot-integration.tar.gz -C $rockpro64_integration_dir
fi
fi
# Some commands expect elevated privileges.
sudo true
# Make sure the user's given Mender image name has a correct extension.
# If Mender image name is not provided, then use following syntax:
# mender-<device_name>-<artifact_name>.sdimg
if [ -n "${mender_disk_image}" ]; then
mender_disk_filename=$(basename -- "$mender_disk_image")
if [[ $mender_disk_filename =~ \.sdimg$ ]]; then
mender_disk_image=$output_dir/${mender_disk_filename}
else
mender_disk_image=$output_dir/${mender_disk_filename}.sdimg
fi
else
mender_disk_filename="mender-${device_type}-${artifact_name}"
mender_disk_image=$output_dir/${mender_disk_filename}.sdimg
fi
mender_disk_basename="${mender_disk_filename%.*}"
mender_rootfs_basename=${mender_disk_basename}.ext4
mender_rootfs_image=${output_dir}/${mender_rootfs_basename}
mender_artifact=${output_dir}/${mender_disk_basename}.mender
case "$1" in
mender-disk-image-to-artifact)
total=1
do_mender_disk_image_to_artifact || rc=$?
[[ $rc -ne 0 ]] && { log "Check $build_log for details."; exit 1; }
log "A Mender Artifact has been successfully extracted from your Mender disk image!"
log "You can find the Mender Artifact at:\n\t$mender_artifact\nand use it to deploy updates."
;;
from-raw-disk-image)
total=10
do_from_raw_disk_image || rc=$?
[[ $rc -ne 0 ]] && { log "Check $build_log for details."; exit 1; }
log "Conversion complete!"
log "The Mender disk image you can provision your device storage with is at:\
\n\t${mender_disk_image}"
log "The Mender root file system partition is at:\n\t${mender_rootfs_image}"
log "The Mender Artifact you can upload to your Mender server to deploy to your devices is at:\
\n\t${mender_artifact}"
;;
*)
show_help
;;
esac
[[ $keep != "-k" ]] && { rm -f $output_dir/boot.vfat \
$output_dir/cmdline.txt $output_dir/config.txt \
$output_dir/syslinux.cfg $output_dir/rootfs.img; }
exit 0

888
mender-convert-functions.sh

@ -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
}

21
qemux86_64-convert-stage-2.sh

@ -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

22
rockpro64-convert-stage-2.sh

@ -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

14
rpi-convert-stage-2.sh

@ -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

258
rpi-convert-stage-5.sh

@ -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="884893e54a"
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
Loading…
Cancel
Save