Browse Source
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
29 changed files with 0 additions and 3747 deletions
@ -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"] |
@ -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. |
@ -1,2 +0,0 @@ |
|||
beb140be4cd64599bedc691a55b2729c9cc611a4b9d6ec44e01270105daf18a2 LICENSE |
|||
beb140be4cd64599bedc691a55b2729c9cc611a4b9d6ec44e01270105daf18a2 mendertesting/LICENSE |
@ -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) |
@ -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 |
@ -1,22 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
rootfs_mapping=$2 |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f ${output_dir}/rootfs.img ] && \ |
|||
{ log "Error: extracted rootfs partition not found. Aborting."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/rootfs.img of=/dev/mapper/${rootfs_mapping} bs=8M conv=sparse >> "$build_log" 2>&1 |
|||
sync |
|||
|
|||
sudo e2fsck -y -f /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
sudo resize2fs /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
# Check Linux ext4 file system just in case. |
|||
sudo fsck.ext4 -fp /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
# Make sure the rootfs partition's label follows Mender naming convention. |
|||
sudo tune2fs -L "primary" /dev/mapper/${rootfs_mapping} >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,366 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
set -e |
|||
|
|||
show_help() { |
|||
cat << EOF |
|||
|
|||
Mender executables, service and configuration files installer. |
|||
|
|||
Usage: $0 [options] |
|||
|
|||
Options: [-m|--mender-disk-image | -g|--mender-client | -a|--artifact-name | |
|||
-d|--device-type | -n|--demo | -p|--demo-host-ip | -u| --server-url | |
|||
-c|--server-cert -t| --tenant-token -k|--keep -h|--help] |
|||
|
|||
--mender-disk-image - Mender raw disk image |
|||
--mender-client - Mender client binary file |
|||
--artifact-name - artifact info |
|||
--device-type - target device type identification |
|||
--demo - Configure image using demo parameters |
|||
--demo-host-ip - Mender demo server IP address |
|||
--server-url - Mender production server url |
|||
--server-cert - Mender server certificate |
|||
--tenant-token - Mender tenant token |
|||
--keep - Keep intermediate files in output directory |
|||
--help - Show help and exit |
|||
|
|||
For examples, see: ./mender-convert --help |
|||
|
|||
EOF |
|||
exit 1 |
|||
} |
|||
|
|||
jq_inplace() { |
|||
jq_args="$1" |
|||
dest_file="$2" |
|||
sudo sh -c -e "jq \"${jq_args}\" ${dest_file} > ${dest_file}.tmp && mv ${dest_file}.tmp ${dest_file}" |
|||
} |
|||
|
|||
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
output_dir=${tool_dir}/output |
|||
|
|||
meta_mender_repo="https://raw.githubusercontent.com/mendersoftware/meta-mender" |
|||
meta_mender_revision="thud" |
|||
|
|||
mender_dir=$output_dir/mender |
|||
device_type= |
|||
artifact_name= |
|||
# Mender demo server IP address. |
|||
demo_host_ip= |
|||
# Mender production server url passed as CLI option. |
|||
server_url= |
|||
# Mender production certificate. |
|||
server_cert= |
|||
# Mender tenant token passed as CLI option. |
|||
tenant_token= |
|||
# Mender tenant token. |
|||
mender_tenant_token="dummy" |
|||
# Mender state-script format version |
|||
mender_state_scripts_version="3" |
|||
|
|||
declare -a mender_disk_mappings |
|||
|
|||
append_rootfs_configuration() { |
|||
local conffile=$1 |
|||
|
|||
local rootfsparta="/dev/mmcblk0p2" |
|||
local rootfspartb="/dev/mmcblk0p3" |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
rootfsparta="/dev/hda2" |
|||
rootfspartb="/dev/hda3" |
|||
elif [ "$device_type" == "rockpro64" ]; then |
|||
rootfsparta="/dev/mmcblk1p2" |
|||
rootfspartb="/dev/mmcblk1p3" |
|||
fi |
|||
|
|||
jq_inplace '.RootfsPartA = \"'$rootfsparta'\" | .RootfsPartB = \"'$rootfspartb'\"' ${conffile} |
|||
} |
|||
|
|||
create_client_files() { |
|||
cat <<- EOF > $mender_dir/device_type |
|||
device_type=${device_type} |
|||
EOF |
|||
|
|||
case "$device_type" in |
|||
"beaglebone" | "qemux86_64") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk0 0x800000 0x20000 |
|||
/dev/mmcblk0 0x1000000 0x20000 |
|||
EOF |
|||
;; |
|||
"raspberrypi3"|"raspberrypi0w") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk0 0x400000 0x4000 |
|||
/dev/mmcblk0 0x800000 0x4000 |
|||
EOF |
|||
;; |
|||
"rockpro64") |
|||
cat <<- EOF > $mender_dir/fw_env.config |
|||
/dev/mmcblk1 0x400000 0x8000 |
|||
/dev/mmcblk1 0x800000 0x8000 |
|||
EOF |
|||
;; |
|||
|
|||
esac |
|||
} |
|||
|
|||
get_mender_files_from_upstream() { |
|||
|
|||
mkdir -p $mender_dir |
|||
|
|||
log "\tDownloading demo server certificate." |
|||
|
|||
wget -q -O $mender_dir/server.demo.crt \ |
|||
$meta_mender_repo/$meta_mender_revision/meta-mender-demo/recipes-mender/mender/files/server.crt |
|||
} |
|||
|
|||
install_files() { |
|||
local primary_dir=$1 |
|||
local data_dir=$2 |
|||
|
|||
sysconfdir="etc/mender" |
|||
bindir="usr/bin" |
|||
localstatedir="var/lib/mender" |
|||
dataconfdir="mender" |
|||
databootdir="u-boot" |
|||
|
|||
log "\tInstalling files." |
|||
|
|||
# Prepare 'data' partition |
|||
sudo install -d -m 755 ${data_dir}/${dataconfdir} |
|||
sudo install -d -m 755 ${data_dir}/${databootdir} |
|||
|
|||
sudo install -d -m 755 ${primary_dir}/${sysconfdir}/scripts/ |
|||
echo -n "${mender_state_scripts_version}" | sudo tee ${primary_dir}/${sysconfdir}/scripts/version |
|||
|
|||
sudo install -m 0444 ${mender_dir}/device_type ${data_dir}/${dataconfdir} |
|||
sudo install -m 0644 ${mender_dir}/fw_env.config ${data_dir}/${databootdir} |
|||
|
|||
sudo ln -sf /data/${databootdir}/fw_env.config ${primary_dir}/etc/fw_env.config |
|||
|
|||
# Create mount-points |
|||
# |
|||
# Note that only one of /boot/efi or /uboot will be used depending on what |
|||
# type of Mender integration is used (GRUB or U-boot). I do not see any |
|||
# problems with keeping an empty directory to reduce complexity of creating |
|||
# this directory structure. |
|||
sudo install -d -m 755 ${primary_dir}/data |
|||
sudo install -d -m 755 ${primary_dir}/boot/efi |
|||
sudo install -d -m 755 ${primary_dir}/uboot |
|||
|
|||
case "$device_type" in |
|||
"qemux86_64") |
|||
sudo install -d ${primary_dir}/lib64 |
|||
sudo ln -sf /lib/ld-linux-x86-64.so.2 ${primary_dir}/lib64/ld-linux-x86-64.so.2 |
|||
;; |
|||
esac |
|||
|
|||
sudo ln -sf /data/${dataconfdir} ${primary_dir}/${localstatedir} |
|||
|
|||
# Call mender make install target |
|||
( cd $GOPATH/src/github.com/mendersoftware/mender && \ |
|||
sudo make install prefix=$primary_dir ) |
|||
|
|||
# If specified, replace Mender client binary |
|||
if [ -n "${mender_client}" ]; then |
|||
sudo install -m 0755 ${mender_client} ${primary_dir}/${bindir}/mender |
|||
fi |
|||
|
|||
# Enable menderd service starting on boot. |
|||
if [ -z "${standalone_operation}" ]; then |
|||
# Enable menderd service starting on boot. |
|||
sudo ln -sf /lib/systemd/system/mender.service \ |
|||
${primary_dir}/etc/systemd/system/multi-user.target.wants/mender.service |
|||
fi |
|||
|
|||
# By default production settings configuration is installed |
|||
if [ -n "${demo}" ] && [ ${demo} -eq 1 ]; then |
|||
sudo install -m 0644 ${primary_dir}/${sysconfdir}/mender.conf.demo ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# If specified, replace server URL |
|||
if [ -n "${server_url}" ]; then |
|||
jq_inplace '.ServerURL = \"'${server_url}'\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# Set tenant token |
|||
if [ -n "${tenant_token}" ]; then |
|||
jq_inplace '.TenantToken = \"'${tenant_token}'\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
|
|||
# Append RootfsPartA/B to mender.conf |
|||
append_rootfs_configuration ${primary_dir}/${sysconfdir}/mender.conf |
|||
|
|||
# Set artifact name |
|||
if [ -n "${artifact_name}" ]; then |
|||
sudo sh -c -e "echo artifact_name=${artifact_name} > ${primary_dir}/${sysconfdir}/artifact_info"; |
|||
fi |
|||
|
|||
# Set demo server and install demo certificate |
|||
if [ -n "${demo_host_ip}" ]; then |
|||
sudo sh -c -e "echo '$demo_host_ip docker.mender.io s3.docker.mender.io' >> $primary_dir/etc/hosts"; |
|||
jq_inplace '.ServerURL = \"https://docker.mender.io\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
sudo install -m 0444 ${mender_dir}/server.demo.crt ${primary_dir}/${sysconfdir}/server.crt |
|||
fi |
|||
|
|||
# Install provided |
|||
if [ -n "${server_cert}" ]; then |
|||
sudo install -m 0444 ${server_cert} ${primary_dir}/${sysconfdir}/server.crt |
|||
fi |
|||
|
|||
if [ -e "${primary_dir}/${sysconfdir}/server.crt" ]; then |
|||
jq_inplace '.ServerCertificate = \"/'${sysconfdir}'/server.crt\"' ${primary_dir}/${sysconfdir}/mender.conf |
|||
fi |
|||
} |
|||
|
|||
do_install_mender() { |
|||
if [ -z "${mender_disk_image}" ]; then |
|||
log "Mender raw disk image not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${device_type}" ]; then |
|||
log "Target device type name not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${artifact_name}" ]; then |
|||
log "Artifact info not set. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
if [ -z "${server_url}" ] && [ -z "${demo_host_ip}" ] && \ |
|||
[ -z "${tenant_token}" ]; then |
|||
log "No Mender server configuration was provided, it will only be possible to update using standalone mode." |
|||
standalone_operation="true" |
|||
fi |
|||
|
|||
if [ -n "${server_url}" ] && [ -n "${demo_host_ip}" ]; then |
|||
log "Incompatible server type choice. Aborting." |
|||
show_help |
|||
fi |
|||
|
|||
[ ! -f $mender_disk_image ] && \ |
|||
{ log "$mender_disk_image - file not found. Aborting."; exit 1; } |
|||
|
|||
test -n "$(go version)" || \ |
|||
{ log "go binary not found in PATH. Aborting."; exit 1; } |
|||
|
|||
test -n "$GOPATH" || \ |
|||
{ log "GOPATH not set. Aborting."; exit 1; } |
|||
|
|||
test -d $GOPATH/src/github.com/mendersoftware/mender || \ |
|||
{ log "mender source not found in \$GOPATH/src/github.com/mendersoftware/mender. Aborting."; exit 1; } |
|||
|
|||
# Mount rootfs partition A. |
|||
create_device_maps $mender_disk_image mender_disk_mappings |
|||
|
|||
# Change current directory to 'output' directory. |
|||
cd $output_dir |
|||
|
|||
primary=${mender_disk_mappings[1]} |
|||
data=${mender_disk_mappings[3]} |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
data=${mender_disk_mappings[4]} |
|||
fi |
|||
|
|||
map_primary=/dev/mapper/"$primary" |
|||
map_data=/dev/mapper/"$data" |
|||
path_primary=$output_dir/sdimg/primary |
|||
path_data=$output_dir/sdimg/data |
|||
mkdir -p ${path_primary} ${path_data} |
|||
|
|||
sudo mount ${map_primary} ${path_primary} |
|||
sudo mount ${map_data} ${path_data} |
|||
|
|||
# Get Mender client related files. |
|||
get_mender_files_from_upstream |
|||
|
|||
# Create all necessary client's files. |
|||
create_client_files |
|||
|
|||
# Create all required paths and install files. |
|||
install_files ${path_primary} ${path_data} |
|||
|
|||
# Back to working directory. |
|||
cd $tool_dir && sync |
|||
|
|||
# Clean stuff. |
|||
detach_device_maps ${mender_disk_mappings[@]} |
|||
rm -rf $output_dir/sdimg |
|||
[[ $keep -eq 0 ]] && { rm -rf $mender_dir; } |
|||
|
|||
log "\tDone." |
|||
} |
|||
|
|||
PARAMS="" |
|||
|
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-m | --mender-disk-image) |
|||
mender_disk_image=$2 |
|||
shift 2 |
|||
;; |
|||
-g | --mender-client) |
|||
mender_client=$2 |
|||
shift 2 |
|||
;; |
|||
-d | --device-type) |
|||
device_type=$2 |
|||
shift 2 |
|||
;; |
|||
-a | --artifact-name) |
|||
artifact_name=$2 |
|||
shift 2 |
|||
;; |
|||
-n | --demo) |
|||
demo="1" |
|||
shift 1 |
|||
;; |
|||
-i | --demo-host-ip) |
|||
demo_host_ip=$2 |
|||
shift 2 |
|||
;; |
|||
-c | --server-cert) |
|||
server_cert=$2 |
|||
shift 2 |
|||
;; |
|||
-u | --server-url) |
|||
server_url=$2 |
|||
shift 2 |
|||
;; |
|||
-t | --tenant-token) |
|||
tenant_token=$2 |
|||
shift 2 |
|||
;; |
|||
-k | --keep) |
|||
keep="1" |
|||
shift 1 |
|||
;; |
|||
-h | --help) |
|||
show_help |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
-*) |
|||
log "Error: unsupported option $1" |
|||
exit 1 |
|||
;; |
|||
*) |
|||
PARAMS="$PARAMS $1" |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
eval set -- "$PARAMS" |
|||
|
|||
# Some commands expect elevated privileges. |
|||
sudo true |
|||
|
|||
do_install_mender |
@ -1,389 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
show_help() { |
|||
cat << EOF |
|||
|
|||
Tool adding GRUB specific files to Mender compliant image file. |
|||
|
|||
Usage: $0 [options] |
|||
|
|||
Options: [-m|--mender-disk-image | -b|--bootloader-toolchain | |
|||
-k|--keep | -d|--device-type] |
|||
|
|||
--mender-disk-image - Mender raw disk image |
|||
--bootloader-toolchain - GNU Arm Embedded Toolchain |
|||
--device-type - target device type identification |
|||
--keep - prevent deleting GRUB workspace |
|||
|
|||
Note: supported device types are: beaglebone, raspberrypi3 |
|||
|
|||
Examples: |
|||
|
|||
./mender-convert install-bootloader-to-mender-disk-image |
|||
--mender-disk-image <mender_image_path> |
|||
--device-type <beaglebone | raspberrypi3> |
|||
--bootloader-toolchain arm-linux-gnueabihf |
|||
|
|||
Note: toolchain naming convention is arch-vendor-(os-)abi |
|||
|
|||
arch is for architecture: arm, mips, x86, i686... |
|||
vendor is tool chain supplier: apple, Codesourcery, Linux, |
|||
os is for operating system: linux, none (bare metal) |
|||
abi is for application binary interface convention: eabi, gnueabi, gnueabihf |
|||
|
|||
EOF |
|||
} |
|||
|
|||
tool_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
output_dir=${tool_dir}/output |
|||
integration_dir=${tool_dir}/integration |
|||
grub_dir=$output_dir/grub |
|||
grubenv_dir=$output_dir/grubenv |
|||
mender_disk_image= |
|||
bootloader_toolchain= |
|||
device_type= |
|||
keep=0 |
|||
efi_boot=EFI/BOOT |
|||
EFI_STUB_VER="4.12.0" |
|||
build_log=$output_dir/build.log |
|||
|
|||
declare -a mender_disk_mappings |
|||
|
|||
version() { |
|||
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }' |
|||
} |
|||
|
|||
get_kernel_version() { |
|||
local search_path=$1/boot |
|||
local resultvar=$2 |
|||
|
|||
[ ! -d "$search_path" ] && { return 1; } |
|||
|
|||
kernel_image=$(ls -1 $search_path | grep -E "^vmlinuz") |
|||
|
|||
local myresult=${kernel_image#*-} |
|||
eval $resultvar="'$myresult'" |
|||
return 0 |
|||
} |
|||
|
|||
build_env_lock_boot_files() { |
|||
log "\tBuilding boot scripts and tools." |
|||
local grubenv_repo_vc_dir=$grubenv_dir/.git |
|||
local grubenv_build_dir=$grubenv_dir/build |
|||
|
|||
mkdir -p $grubenv_dir |
|||
|
|||
if [ ! -d $grubenv_repo_vc_dir ]; then |
|||
git clone https://github.com/mendersoftware/grub-mender-grubenv.git $grubenv_dir >> "$build_log" 2>&1 |
|||
fi |
|||
cd $grubenv_dir |
|||
|
|||
mkdir -p $grubenv_build_dir |
|||
|
|||
# Remove old defines & settings. |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
# Prepare configuration file. |
|||
cp mender_grubenv_defines.example mender_grubenv_defines |
|||
|
|||
local kernel_imagetype=kernel |
|||
local kernel_devicetree=dtb |
|||
|
|||
sed -i '/^kernel_imagetype/s/=.*$/='${kernel_imagetype}'/' mender_grubenv_defines |
|||
sed -i '/^kernel_devicetree/s/=.*$/='${kernel_devicetree//\//\\/}'/' mender_grubenv_defines |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
local root_base=/dev/hda |
|||
sed -i '/^mender_kernel_root_base/s/=.*$/='${root_base//\//\\/}'/' mender_grubenv_defines |
|||
fi |
|||
|
|||
make --quiet >> "$build_log" 2>&1 |
|||
rc=$? |
|||
[[ $rc -eq 0 ]] && { make --quiet DESTDIR=$grubenv_build_dir install >> "$build_log" 2>&1; } |
|||
rc=$? |
|||
[[ $rc -ne 0 ]] && { log "\tError: building process failed. Aborting."; } |
|||
|
|||
cd ${output_dir} |
|||
return $rc |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - linux kernel version |
|||
build_grub_efi() { |
|||
if [ "$device_type" == "rockpro64" ]; then |
|||
return 0 |
|||
fi |
|||
|
|||
log "\tBuilding GRUB efi file." |
|||
|
|||
local grub_build_dir=$grub_dir/build |
|||
local grub_arm_dir=$grub_build_dir/arm |
|||
local host=$(uname -m) |
|||
local grub_host_dir=$grub_build_dir/$host |
|||
local grub_repo_vc_dir=$grub_dir/.git |
|||
|
|||
local version=$(echo $1 | sed 's/[^0-9.]*\([0-9.]*\).*/\1/') |
|||
|
|||
# Build grub modules for arm platform and executables for the host. |
|||
if [ ! -d $grub_repo_vc_dir ]; then |
|||
git clone git://git.savannah.gnu.org/grub.git $grub_dir >> "$build_log" 2>&1 |
|||
fi |
|||
|
|||
cd $grub_dir |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
if [ $(version $version) -lt $(version $EFI_STUB_VER) ]; then |
|||
# To avoid error message: "plain image kernel not supported - rebuild |
|||
# with CONFIG_(U)EFI_STUB enabled" - use a specific commit. |
|||
git checkout 9b37229f0 >> "$build_log" 2>&1 |
|||
else |
|||
git checkout 72e80c025 >> "$build_log" 2>&1 |
|||
fi |
|||
|
|||
mkdir -p $grub_arm_dir |
|||
mkdir -p $grub_host_dir |
|||
|
|||
local cores=$(nproc) |
|||
|
|||
# First build host tools. |
|||
./autogen.sh >> "$build_log" 2>&1 |
|||
./configure --quiet CC=gcc --target=${host} --with-platform=efi --prefix=$grub_host_dir >> "$build_log" 2>&1 |
|||
make --quiet -j$cores >> "$build_log" 2>&1 |
|||
make --quiet install >> "$build_log" 2>&1 |
|||
|
|||
local format=${host}-efi |
|||
grub_name=bootx64.efi |
|||
local modules_path=$grub_host_dir/lib/grub/$format/ |
|||
|
|||
if [ "$device_type" == "beaglebone" ]; then |
|||
# Clean workspace. |
|||
make --quiet clean >> "$build_log" 2>&1 |
|||
make --quiet distclean >> "$build_log" 2>&1 |
|||
|
|||
# Now build ARM modules. |
|||
./configure --quiet --host=$bootloader_toolchain --with-platform=efi \ |
|||
--prefix=$grub_arm_dir CFLAGS="-Os -march=armv7-a" \ |
|||
CCASFLAGS="-march=armv7-a" --disable-werror >> "$build_log" 2>&1 |
|||
make --quiet -j$cores >> "$build_log" 2>&1 |
|||
make --quiet install >> "$build_log" 2>&1 |
|||
|
|||
format=arm-efi |
|||
grub_name=grub-arm.efi |
|||
modules_path=$grub_arm_dir/lib/grub/$format/ |
|||
fi |
|||
|
|||
# Build GRUB EFI image. |
|||
${grub_host_dir}/bin/grub-mkimage -v -p /$efi_boot -o $grub_name --format=$format \ |
|||
-d $modules_path boot linux ext2 fat serial part_msdos part_gpt normal \ |
|||
efi_gop iso9660 configfile search loadenv test cat echo gcry_sha256 halt \ |
|||
hashsum loadenv reboot >> "$build_log" 2>&1 |
|||
|
|||
rc=$? |
|||
[[ $rc -ne 0 ]] && { log "\tBuilding grub.efi failed. Aborting."; } \ |
|||
|| { log "\tBuilding grub.efi succeeded."; } |
|||
|
|||
cd ${output_dir} |
|||
return $rc |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - boot partition mountpoint |
|||
set_uenv() { |
|||
local boot_dir=$1 |
|||
# Erase/create uEnv.txt file. |
|||
sudo install -b -m 644 /dev/null $boot_dir/uEnv.txt |
|||
|
|||
# Fill uEnv.txt file. |
|||
cat <<- 'EOF' | sudo tee $boot_dir/uEnv.txt 2>&1 >/dev/null |
|||
bootdir= |
|||
grubfile=EFI/BOOT/grub-arm.efi |
|||
grubaddr=0x80007fc0 |
|||
loadgrub=fatload mmc 0:1 ${grubaddr} ${grubfile} |
|||
grubstart=bootefi ${grubaddr} |
|||
uenvcmd=mmc rescan; run loadgrub; run grubstart; |
|||
EOF |
|||
} |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - boot partition mountpoint |
|||
# $2 - primary partition mountpoint |
|||
# $3 - linux kernel version |
|||
install_files() { |
|||
log "\tInstalling GRUB files." |
|||
local boot_dir=$1 |
|||
local rootfs_dir=$2 |
|||
local linux_version=$3 |
|||
|
|||
if [ "$device_type" == "rockpro64" ]; then |
|||
cp $integration_dir/rockpro64/boot.scr ${boot_dir}/ |
|||
|
|||
# It is not possible to resize rootfs part when using Mender. so disable |
|||
# the service |
|||
touch ${rootfs_dir}/root/.no_rootfs_resize |
|||
return 0 |
|||
fi |
|||
|
|||
local grub_build_dir=$grub_dir/build |
|||
local grub_arm_dir=$grub_build_dir/arm |
|||
local grub_host_dir=$grub_build_dir/$(uname -m) |
|||
|
|||
local grubenv_build_dir=$grubenv_dir/build |
|||
local grubenv_efi_boot_dir=$grubenv_build_dir/boot/efi/EFI/BOOT/ |
|||
|
|||
local efi_boot_dir=$boot_dir/$efi_boot |
|||
|
|||
# Make sure env, lock, lock.sha256sum files exists in working directory. |
|||
[[ ! -d $grubenv_efi_boot_dir/mender_grubenv1 || \ |
|||
! -d $grubenv_efi_boot_dir/mender_grubenv2 ]] && \ |
|||
{ log "Error: cannot find mender grub related files."; return 1; } |
|||
|
|||
sudo install -d -m 755 $efi_boot_dir |
|||
|
|||
cd $grubenv_efi_boot_dir && find . -type f -exec sudo install -Dm 644 "{}" "$efi_boot_dir/{}" \; |
|||
cd ${output_dir} |
|||
|
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
sudo install -m 0755 ${grub_host_dir}/bin/grub-editenv $rootfs_dir/usr/bin |
|||
else |
|||
sudo install -m 0755 ${grub_arm_dir}/bin/grub-editenv $rootfs_dir/usr/bin |
|||
fi |
|||
|
|||
sudo install -m 0644 ${grub_dir}/${grub_name} $efi_boot_dir |
|||
|
|||
sudo install -m 0755 $grubenv_build_dir/usr/bin/fw_printenv $rootfs_dir/sbin/fw_printenv |
|||
sudo install -m 0755 $grubenv_build_dir/usr/bin/fw_setenv $rootfs_dir/sbin/fw_setenv |
|||
|
|||
# Replace U-Boot default printenv/setenv commands. |
|||
sudo ln -fs /sbin/fw_printenv $rootfs_dir/usr/bin/fw_printenv |
|||
sudo ln -fs /sbin/fw_setenv $rootfs_dir/usr/bin/fw_setenv |
|||
|
|||
#Create links for grub |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
# Copy kernel image to fit the grubenv defines. |
|||
sudo cp $boot_dir/bzImage $rootfs_dir/boot/kernel |
|||
elif [ "$device_type" == "beaglebone" ]; then |
|||
#Replace U-Boot default images for Debian 9.5 |
|||
if [ `grep -s '9.5' $rootfs_dir/etc/debian_version | wc -l` -eq 1 ]; then |
|||
sudo cp ${tool_dir}/files/uboot_debian_9.4/MLO ${boot_dir}/MLO |
|||
sudo cp ${tool_dir}/files/uboot_debian_9.4/u-boot.img ${boot_dir}/u-boot.img |
|||
fi |
|||
# Make links to kernel and device tree files. |
|||
sudo ln -sf /boot/dtbs/$linux_version/am335x-boneblack.dtb $rootfs_dir/boot/dtb |
|||
sudo ln -sf /boot/vmlinuz-$linux_version $rootfs_dir/boot/kernel |
|||
set_uenv $boot_dir |
|||
fi |
|||
} |
|||
|
|||
do_install_bootloader() { |
|||
if [ -z "${mender_disk_image}" ]; then |
|||
log "Mender raw disk image not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${bootloader_toolchain}" ]; then |
|||
log "ARM GCC toolchain not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if [ -z "${device_type}" ]; then |
|||
log "Target device type name not set. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
if ! [ -x "$(command -v ${bootloader_toolchain}-gcc)" ]; then |
|||
log "Error: ARM GCC not found in PATH. Aborting." |
|||
exit 1 |
|||
fi |
|||
|
|||
[ ! -f $mender_disk_image ] && \ |
|||
{ log "$mender_disk_image - file not found. Aborting."; exit 1; } |
|||
|
|||
# Map & mount Mender compliant image. |
|||
create_device_maps $mender_disk_image mender_disk_mappings |
|||
|
|||
# Change current directory to 'output' directory. |
|||
cd $output_dir |
|||
|
|||
boot=${mender_disk_mappings[0]} |
|||
primary=${mender_disk_mappings[1]} |
|||
map_boot=/dev/mapper/"$boot" |
|||
map_primary=/dev/mapper/"$primary" |
|||
path_boot=$output_dir/sdimg/boot |
|||
path_primary=$output_dir/sdimg/primary |
|||
mkdir -p ${path_boot} ${path_primary} |
|||
|
|||
sudo mount ${map_boot} ${path_boot} |
|||
sudo mount ${map_primary} ${path_primary} |
|||
|
|||
get_kernel_version ${path_primary} kernel_version |
|||
log "\tFound kernel version: $kernel_version" |
|||
|
|||
build_env_lock_boot_files |
|||
rc=$? |
|||
if [ "$device_type" == "qemux86_64" ]; then |
|||
[[ $rc -eq 0 ]] && { build_grub_efi ${EFI_STUB_VER}; } |
|||
else |
|||
[[ $rc -eq 0 ]] && { build_grub_efi ${kernel_version}; } |
|||
fi |
|||
rc=$? |
|||
[[ $rc -eq 0 ]] && { install_files ${path_boot} ${path_primary} ${kernel_version}; } |
|||
rc=$? |
|||
|
|||
# Back to working directory. |
|||
cd $tool_dir && sync |
|||
|
|||
detach_device_maps ${mender_disk_mappings[@]} |
|||
# Clean files. |
|||
rm -rf $output_dir/sdimg |
|||
|
|||
[[ $keep -eq 0 ]] && { rm -rf $grubenv_dir $grub_dir; } |
|||
[[ $rc -ne 0 ]] && { exit 1; } || { log "\tDone."; } |
|||
} |
|||
|
|||
PARAMS="" |
|||
|
|||
while (( "$#" )); do |
|||
case "$1" in |
|||
-m | --mender-disk-image) |
|||
mender_disk_image=$2 |
|||
shift 2 |
|||
;; |
|||
-b | --bootloader-toolchain) |
|||
bootloader_toolchain=$2 |
|||
shift 2 |
|||
;; |
|||
-d | --device-type) |
|||
device_type=$2 |
|||
shift 2 |
|||
;; |
|||
-k | --keep) |
|||
keep=1 |
|||
shift 1 |
|||
;; |
|||
-h | --help) |
|||
show_help |
|||
exit 0 |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
-*) |
|||
log "Error: unsupported option $1" |
|||
exit 1 |
|||
;; |
|||
*) |
|||
PARAMS="$PARAMS $1" |
|||
shift |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
eval set -- "$PARAMS" |
|||
|
|||
# Some commands expect elevated privileges. |
|||
sudo true |
|||
|
|||
do_install_bootloader |
@ -1 +0,0 @@ |
|||
output/ |
@ -1,13 +0,0 @@ |
|||
FROM ubuntu:18.04 |
|||
|
|||
ARG MENDER_ARTIFACT_VERSION=3.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"] |
@ -1,64 +0,0 @@ |
|||
Device Image Shell |
|||
================== |
|||
|
|||
This directory contains a tool that takes the root file system of your device as input and emulates a shell session on your device. |
|||
Any commands you run (e.g. apt update, apt upgrade) will behave as if you were logged into your actual device! |
|||
|
|||
The purpose of the tool is to create a new root file system image and Mender Artifact that can be deployed to a fleet of devices in the field. |
|||
|
|||
|
|||
## Docker environment |
|||
|
|||
To ensure dependencies are correctly set up and it is portable, a docker environment is used. |
|||
|
|||
You need to [install Docker Engine](https://docs.docker.com/install) to use this tool. |
|||
|
|||
|
|||
### Build the device-image-shell container image |
|||
|
|||
To build a container based on Ubuntu 18.04 with the required dependencies, copy this directory to your workstation and change the current directory to it. |
|||
|
|||
Then run |
|||
|
|||
```bash |
|||
./docker-build |
|||
``` |
|||
|
|||
This will create a container image `device-image-shell`. |
|||
|
|||
|
|||
### Use the device-image-shell container image |
|||
|
|||
The also assumes your device is based on the ARM architecture, which is the most common (e.g. Raspberry Pi, BeagleBoard, etc.). |
|||
|
|||
You need a root file system image (usually with .ext4 extension) for your device as a starting point, such as one output by [mender-convert](https://github.com/mendersoftware/mender-convert). Make sure to have `qemu-user-static` installed on a host machine. |
|||
|
|||
You can now enter a shell in your device root file system image by running `docker-device-image-shell` with the desired arguments: |
|||
|
|||
1. path to your existing root file system image |
|||
2. desired name for the generated Mender Artifact |
|||
3. device type, which Mender uses to ensure compatibility between devices and software |
|||
|
|||
For example, if you are using a Raspberry Pi 3, you can run: |
|||
|
|||
```bash |
|||
./docker-device-image-shell ../output/2018-11-13-raspbian-stretch-lite.ext4 2018-11-13-raspbian-stretch-lite-aptupgrade raspberrypi3 |
|||
``` |
|||
|
|||
You should now see a shell prompt. You are in an emulated environment, so any commands run here will behave as if you ran them on your device! In addition, any changes you make will be preserved in the output root file system image and Mender Artifact. |
|||
|
|||
For example, to update to the latest packages run: |
|||
|
|||
```bash |
|||
apt update |
|||
apt upgrade |
|||
``` |
|||
|
|||
When you are done, press `Ctrl+D` or run the `exit` command. Generating the Mender Artifact will take a few more minutes, depending on the size of the input image and resources available on your workstation. |
|||
|
|||
After it finishes you can find your new `.ext4` and `.mender` files in the `output/` directory. For devices where Mender is installed, you can use the Mender Artifact (`.mender` file) to deploy the changes you made in the shell to all your devices! |
|||
|
|||
|
|||
### Use caution |
|||
|
|||
Please note that since this tool is using an emulated environment (based on `qemu`) and you are not properly logged in to your device, some things may not work as expected. Look for any relevant errors in commands you run and make sure to test your changes before deploying to production devices! |
@ -1,7 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
DOCKER_IMAGE_NAME=device-image-shell |
|||
|
|||
docker build . -t ${DOCKER_IMAGE_NAME} |
@ -1,58 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
DOCKER_IMAGE_NAME=device-image-shell |
|||
OUTPUT_DIR="$(pwd)/output" |
|||
|
|||
show_usage() { |
|||
echo "Usage:" |
|||
echo "$0 <rootfs input file> <output Artifact name> <device type>" |
|||
} |
|||
|
|||
if [ "$#" -ne 3 ]; then |
|||
echo "ERROR: 3 parameters required." |
|||
show_usage |
|||
exit 1 |
|||
fi |
|||
|
|||
ROOTFS_INPUT_FILE=$1 |
|||
ARTIFACT_NAME=$2 |
|||
DEVICE_TYPE=$3 |
|||
|
|||
if [ ! -f "$ROOTFS_INPUT_FILE" ]; then |
|||
echo "ERROR: File passed as first argument is not accessible." |
|||
echo "Got ROOTFS_INPUT_FILE=\"$ROOTFS_INPUT_FILE\"" |
|||
show_usage |
|||
exit 1 |
|||
fi |
|||
|
|||
|
|||
mkdir -p $OUTPUT_DIR |
|||
|
|||
ROOTFS_INPUT_FILE_NAME="$(basename -- $ROOTFS_INPUT_FILE)" |
|||
ROOTFS_INPUT_FILE_EXTENSION="${ROOTFS_INPUT_FILE_NAME##*.}" |
|||
|
|||
ROOTFS_OUTPUT_FILE_NAME="$ARTIFACT_NAME.$ROOTFS_INPUT_FILE_EXTENSION" |
|||
|
|||
echo "Copying rootfs input file..." |
|||
rsync -h --progress $ROOTFS_INPUT_FILE $OUTPUT_DIR/$ROOTFS_OUTPUT_FILE_NAME |
|||
|
|||
docker run \ |
|||
-ti \ |
|||
--privileged=true \ |
|||
--mount type=bind,source=$OUTPUT_DIR,target=/root_images \ |
|||
$DOCKER_IMAGE_NAME $ROOTFS_OUTPUT_FILE_NAME $ARTIFACT_NAME $DEVICE_TYPE |
|||
|
|||
|
|||
# Output Artifact gets root owner and group, change to current logged in |
|||
CURRENT_USER=$(id -u -n) |
|||
CURRENT_GROUP=$(id -g -n) |
|||
|
|||
echo "Changing ownership of Mender Artifact (may ask you to authenticate)" |
|||
sudo chown $CURRENT_USER:$CURRENT_GROUP $OUTPUT_DIR/$ARTIFACT_NAME.mender |
|||
|
|||
echo "Image generation complete!" |
|||
/bin/echo -e "The new root file system is at:\n\t$OUTPUT_DIR/$ROOTFS_OUTPUT_FILE_NAME" |
|||
/bin/echo -e "The new Mender Artifact you can upload to your Mender server to deploy to your devices is at:\ |
|||
\n\t$OUTPUT_DIR/$ARTIFACT_NAME.mender" |
@ -1,38 +0,0 @@ |
|||
#!/bin/sh |
|||
set -e |
|||
|
|||
ROOTFS_OUTPUT_FILE_NAME=$1 |
|||
ARTIFACT_NAME=$2 |
|||
DEVICE_TYPE=$3 |
|||
|
|||
mkdir /root_system |
|||
|
|||
mount /root_images/$ROOTFS_OUTPUT_FILE_NAME /root_system |
|||
|
|||
if [ -f /root_system/usr/bin/qemu-arm-static ]; then |
|||
echo "WARNING: /usr/bin/qemu-arm-static already exists in image. Using this but may be of incompatible version." |
|||
QEMU_STATIC_COPIED=false |
|||
else |
|||
# trick to make chroot into ARM image work |
|||
cp /usr/bin/qemu-arm-static /root_system/usr/bin |
|||
QEMU_STATIC_COPIED=true |
|||
fi |
|||
|
|||
echo "Entering emulated shell in device image. All commands are run as the root user of the device image." |
|||
echo "Make changes (e.g. apt update, apt upgrade, wget ...) and press Ctrl-D when done." |
|||
|
|||
# Using bash for command completion support and other conveniences |
|||
chroot /root_system /bin/bash |
|||
|
|||
# Mender Artifact name must also be present inside |
|||
echo artifact_name=$ARTIFACT_NAME > /root_system/etc/mender/artifact_info |
|||
|
|||
if [ "$QEMU_STATIC_COPIED" = true ]; then |
|||
rm /root_system/usr/bin/qemu-arm-static |
|||
fi |
|||
|
|||
umount /root_system |
|||
|
|||
echo "Creating Mender Artifact. This may take 10-20 minutes (using LZMA)..." |
|||
mender-artifact --compression lzma write rootfs-image -t $DEVICE_TYPE -n $ARTIFACT_NAME -f /root_images/$ROOTFS_OUTPUT_FILE_NAME -o /root_images/$ARTIFACT_NAME.mender |
|||
sync |
@ -1,21 +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} |
@ -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 "$@" |
@ -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 "$@" |
@ -1,112 +0,0 @@ |
|||
#!/bin/sh |
|||
|
|||
reboot_pi () { |
|||
umount /uboot |
|||
sync |
|||
echo b > /proc/sysrq-trigger |
|||
sleep 5 |
|||
exit 0 |
|||
} |
|||
|
|||
check_commands () { |
|||
if ! command -v whiptail > /dev/null; then |
|||
FAIL_REASON="whiptail not found" |
|||
sleep 5 |
|||
return 1 |
|||
fi |
|||
for COMMAND in grep cut sed parted fdisk; do |
|||
if ! command -v $COMMAND > /dev/null; then |
|||
FAIL_REASON="$COMMAND not found" |
|||
return 1 |
|||
fi |
|||
done |
|||
return 0 |
|||
} |
|||
|
|||
get_variables () { |
|||
# /sys/block/mmcblk0/mmcblk0p4/ |
|||
ROOT_PART_NAME="mmcblk0p4" |
|||
ROOT_DEV_NAME="mmcblk0" |
|||
ROOT_DEV="/dev/${ROOT_DEV_NAME}" |
|||
ROOT_PART_NUM=`cat /sys/block/${ROOT_DEV_NAME}/${ROOT_PART_NAME}/partition` |
|||
|
|||
BOOT_PART_DEV=`cat /proc/mounts | grep " /uboot " | cut -d " " -f 1` |
|||
BOOT_PART_NAME=`echo $BOOT_PART_DEV | cut -d "/" -f 3` |
|||
BOOT_DEV_NAME=`echo /sys/block/*/${BOOT_PART_NAME} | cut -d "/" -f 4` |
|||
BOOT_PART_NUM=`cat /sys/block/${BOOT_DEV_NAME}/${BOOT_PART_NAME}/partition` |
|||
|
|||
ROOT_DEV_SIZE=`cat /sys/block/${ROOT_DEV_NAME}/size` |
|||
TARGET_END=`expr $ROOT_DEV_SIZE - 1` |
|||
|
|||
PARTITION_TABLE=`parted -m $ROOT_DEV unit s print | tr -d 's'` |
|||
|
|||
LAST_PART_NUM=`echo "$PARTITION_TABLE" | tail -n 1 | cut -d ":" -f 1` |
|||
|
|||
ROOT_PART_LINE=`echo "$PARTITION_TABLE" | grep -e "^${ROOT_PART_NUM}:"` |
|||
ROOT_PART_START=`echo $ROOT_PART_LINE | cut -d ":" -f 2` |
|||
ROOT_PART_END=`echo $ROOT_PART_LINE | cut -d ":" -f 3` |
|||
} |
|||
|
|||
check_variables () { |
|||
if [ $ROOT_PART_NUM -ne $LAST_PART_NUM ]; then |
|||
FAIL_REASON="Data partition should be last partition" |
|||
return 1 |
|||
fi |
|||
|
|||
if [ $ROOT_PART_END -gt $TARGET_END ]; then |
|||
FAIL_REASON="Data partition runs past the end of device" |
|||
return 1 |
|||
fi |
|||
|
|||
if [ ! -b $ROOT_DEV ] || [ ! -b $ROOT_PART_DEV ] || [ ! -b $BOOT_PART_DEV ] ; then |
|||
FAIL_REASON="Could not determine partitions" |
|||
return 1 |
|||
fi |
|||
} |
|||
|
|||
main () { |
|||
get_variables |
|||
|
|||
if ! check_variables; then |
|||
return 1 |
|||
fi |
|||
|
|||
if [ $ROOT_PART_END -eq $TARGET_END ]; then |
|||
reboot_pi |
|||
fi |
|||
|
|||
if ! parted -m $ROOT_DEV u s resizepart $ROOT_PART_NUM $TARGET_END; then |
|||
FAIL_REASON="Data partition resize failed" |
|||
return 1 |
|||
fi |
|||
|
|||
return 0 |
|||
} |
|||
|
|||
mount -t proc proc /proc |
|||
mount -t sysfs sys /sys |
|||
|
|||
mount /uboot |
|||
sed -i 's| init=/usr/lib/raspi-config/init_resize.sh||' /uboot/cmdline.txt |
|||
sed -i 's| sdhci\.debug_quirks2=4||' ${output_dir}/cmdline.txt |
|||
if ! grep -q splash /uboot/cmdline.txt; then |
|||
sed -i "s/ quiet//g" /uboot/cmdline.txt |
|||
fi |
|||
mount /uboot -o remount,ro |
|||
sync |
|||
|
|||
echo 1 > /proc/sys/kernel/sysrq |
|||
|
|||
if ! check_commands; then |
|||
reboot_pi |
|||
fi |
|||
|
|||
if main; then |
|||
whiptail --infobox "Resized data partition. Rebooting in 5 seconds..." 20 60 |
|||
sleep 5 |
|||
else |
|||
sleep 5 |
|||
whiptail --msgbox "Could not expand filesystem, please try raspi-config.\n${FAIL_REASON}" 20 60 |
|||
fi |
|||
|
|||
reboot_pi |
@ -1,13 +0,0 @@ |
|||
[Unit] |
|||
Description=Expand data partition file system |
|||
After=mender.service |
|||
|
|||
[Service] |
|||
Type=simple |
|||
User=root |
|||
Group=root |
|||
ExecStart=/bin/sh -c 'sleep 1 ; /usr/sbin/resizefs.sh start' |
|||
RemainAfterExit=true |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
@ -1,42 +0,0 @@ |
|||
#!/bin/sh |
|||
### BEGIN INIT INFO |
|||
# Provides: resizefs |
|||
# Required-Start: |
|||
# Required-Stop: |
|||
# Default-Start: 3 |
|||
# Default-Stop: |
|||
# Short-Description: Resize the data filesystem to fill partition |
|||
# Description: |
|||
### END INIT INFO |
|||
|
|||
. /lib/lsb/init-functions |
|||
|
|||
case "$1" in |
|||
start) |
|||
log_daemon_msg "Starting resizefs service (once)" |
|||
DISK=$(lsblk -f | sed -n '2{p;q}') |
|||
DISK_DEV="/dev/$DISK" |
|||
DISK_SIZE=$(blockdev --getsize $DISK_DEV) |
|||
DATA_PART_DEV=$(findmnt /data -o source -n) |
|||
DATA_PART=$(basename $DATA_PART_DEV) |
|||
DATA_PART_START=$(parted -m $DISK_DEV unit s print | tr -d 's' | tail -n 1 | cut -d ":" -f 2) |
|||
DATA_PART_SIZE=$(blockdev --getsize $DATA_PART_DEV) |
|||
FREE_SPACE=`expr $DISK_SIZE - $DATA_PART_START - $DATA_PART_SIZE` |
|||
|
|||
if [ $FREE_SPACE -eq 0 ]; then |
|||
log_daemon_msg "Data partition already resized, aborting" |
|||
else |
|||
resize2fs $DATA_PART_DEV |
|||
FSSIZEMEG=`expr $FREE_SPACE + $DATA_PART_SIZE` |
|||
FSSIZEMEG=`expr $FSSIZEMEG / 2 / 1024`"M" |
|||
log_daemon_msg "Resizing $DATA_PART finished, new size is $FSSIZEMEG" |
|||
fi |
|||
|
|||
systemctl --no-reload disable resizefs.service |
|||
log_end_msg $? |
|||
;; |
|||
*) |
|||
echo "Usage: $0 start" >&2 |
|||
exit 3 |
|||
;; |
|||
esac |
Binary file not shown.
Binary file not shown.
@ -1,31 +0,0 @@ |
|||
MENDER_BOOT_PART="/dev/mmcblk0p1" |
|||
MENDER_BOOT_PART_DEFAULT="/dev/mmcblk0p1" |
|||
MENDER_BOOT_PART_FSTYPE="auto" |
|||
MENDER_BOOT_PART_FSTYPE_DEFAULT="auto" |
|||
MENDER_BOOT_PART_MOUNT_LOCATION="" |
|||
MENDER_BOOT_PART_SIZE_MB="16" |
|||
MENDER_BOOT_PART_SIZE_MB_DEFAULT="16" |
|||
MENDER_DATA_PART_DEFAULT="/dev/mmcblk0p4" |
|||
MENDER_DATA_PART_FSTYPE="auto" |
|||
MENDER_DATA_PART_FSTYPE_DEFAULT="auto" |
|||
MENDER_DATA_PART_SIZE_MB="128" |
|||
MENDER_DATA_PART_SIZE_MB_DEFAULT="128" |
|||
MENDER_DEVICE_TYPE="vexpress-qemu" |
|||
MENDER_DEVICE_TYPES_COMPATIBLE="vexpress-qemu" |
|||
MENDER_DEVICE_TYPES_COMPATIBLE_DEFAULT="vexpress-qemu" |
|||
MENDER_DEVICE_TYPE_DEFAULT="vexpress-qemu" |
|||
MENDER_PARTITIONING_OVERHEAD_KB="32768" |
|||
MENDER_PARTITION_ALIGNMENT="" |
|||
MENDER_ROOTFS_PART_A="/dev/mmcblk0p2" |
|||
MENDER_ROOTFS_PART_B="/dev/mmcblk0p3" |
|||
MENDER_STORAGE_DEVICE="/dev/mmcblk0" |
|||
MENDER_STORAGE_TOTAL_SIZE_MB="" |
|||
MENDER_UBOOT_ENV_STORAGE_DEVICE_OFFSET="" |
|||
MENDER_CALC_ROOTFS_SIZE="" |
|||
MENDER_ARTIFACT_NAME="release-1" |
|||
MENDER_MACHINE="vexpress-qemu" |
|||
HOST_ARCH="arm" |
|||
IMAGE_FSTYPES=" tar.bz2 ext4 mender mender.bmap sdimg sdimg.bmap" |
|||
ARTIFACTIMG_FSTYPE="ext4" |
|||
DISTRO_FEATURES="" |
|||
DEPLOY_DIR_IMAGE="" |
@ -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 |
@ -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 |
|||
} |
@ -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 |
@ -1,22 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
embedded_rootfs_dir=$3 |
|||
uboot_backup_dir=${embedded_rootfs_dir}/opt/backup/uboot |
|||
build_log=$output_dir/build.log |
|||
|
|||
boot_part_dev="/dev/mapper/${boot_mapping}" |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
[ ! -d "${embedded_rootfs_dir}" ] && \ |
|||
{ log "Error: embedded content not mounted."; exit 1; } |
|||
[ ! -e ${boot_part_dev} ] && \ |
|||
{ log "Error: boot part does not exist: ${boot_part_dev}."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=${boot_part_dev} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,14 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
output_dir=$1 |
|||
boot_mapping=$2 |
|||
build_log=$output_dir/build.log |
|||
|
|||
[ ! -f $output_dir/boot.vfat ] && \ |
|||
{ log "Error: extracted boot partition not found. Aborting."; exit 1; } |
|||
|
|||
sudo dd if=${output_dir}/boot.vfat of=/dev/mapper/${boot_mapping} bs=1M conv=sparse >> "$build_log" 2>&1 |
|||
|
|||
log "\tDone." |
|||
|
|||
exit 0 |
@ -1,258 +0,0 @@ |
|||
#!/bin/bash |
|||
|
|||
# Copyright 2018 Northern.tech AS |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
application_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
|||
files_dir=${application_dir}/files |
|||
output_dir=${application_dir}/output |
|||
uboot_dir=${output_dir}/uboot-mender |
|||
bin_base_dir=${output_dir}/bin |
|||
bin_dir_pi=${bin_base_dir}/raspberrypi |
|||
sdimg_base_dir=$output_dir/sdimg |
|||
build_log=${output_dir}/build.log |
|||
|
|||
declare -a mender_disk_mappings |
|||
declare -a mender_partitions_regular=("boot" "primary" "secondary" "data") |
|||
|
|||
# Takes following arguments: |
|||
# |
|||
# $1 - ARM toolchain |
|||
# $2 - RPI machine (raspberrypi3 or raspberrypi0w) |
|||
build_uboot_files() { |
|||
local CROSS_COMPILE=${1}- |
|||
local ARCH=arm |
|||
local branch="mender-rpi-2018.07" |
|||
local commit="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…
Reference in new issue