Embedded Linux Software Upgrade Solution – Implementation with Shell Scripts

Recently, due to work requirements, there is a need to implement a software upgrade solution on the embedded Linux platform.

Embedded Platform

The single board contains 2 CPUs, divided into a main control CPU and a management CPU. Only the main control CPU can communicate with the outside through the management network port; the management CPU can communicate with the main control CPU via internal SGMII. The customer also requires a one-click software upgrade for both the main control and management CPUs from the host machine.

Introduction to the Upgrade Data Flow

The software upgrade is divided into 3 stages

ØOn the host side (Linux host or virtual machine), all upgrade data is packaged, distinguishing between zk and mg data through folders (specific content is detailed below), and the HTTP transmission service is started. The data packaging process is: compress -> encrypt -> sign -> calculate MD5 checksum; the transmitted data includes the encrypted compressed package, signature, public key, and MD5 checksum. The tools required on the host include openssl and python3.

ØThe zk_cpu monitors the HTTP packets for upgrade data. If captured, it performs MD5 verification -> signature verification -> decryption -> rollback operation. If after decryption, it is found that mg also needs an upgrade, the first step is repeated, with the difference being: 1. Only package the contents of the mg folder 2. Use scp for transmission to reduce tool dependencies, proceeding to the third step; if mg does not need an upgrade, the upgrade ends.

ØThe mg performs MD5 verification -> signature verification -> decryption -> rollback operation.

File Deployment

ØThe contents of the host folder are copied to the host side.

ØThe contents of the mg_cpu folder are copied to the management CPU’s /opt/tools folder, and openssl is copied to the management CPU’s /usr/bin folder.

ØThe contents of the zk_cpu folder are copied to the main control CPU’s /opt/tools folder, and openssl is copied to the main control CPU’s /usr/bin folder.

Upgrade Steps

1)Modify the script according to requirements.

host/build.sh

#!/bin/bash# Host-side upgrade package generation script | Suitable for Linux###################### Configuration Area (Must Modify) #####################TARGET_IP="192.168.30.184"     # Main control board IP address, can be internal or externalUPGRADE_FILES="$PWD/build_dir"  # Directory to be upgradedPORT=8000                     # HTTP service portPASSWD="[email protected]"   # Encryption password# Create temporary directoryOUTPUT_DIR=$(mktemp -d)trap 'rm -rf "$OUTPUT_DIR"' EXIT###################### Create Upgrade Package #####################echo "[Host] Preparing upgrade files..."mkdir -p ${OUTPUT_DIR}TIMESTAMP=$(date +%Y%m%d-%H%M%S)PKG_NAME="upgrade_${TIMESTAMP}.tar.gz"# Package core files (excluding logs and other irrelevant files)tar czvf ${OUTPUT_DIR}/${PKG_NAME} \  --exclude="*.log" \  --exclude="tmp/*" \  -C ${UPGRADE_FILES} .# Encrypt the fileecho "[Host] Encrypting files..."openssl enc -aes-256-cbc -salt -pbkdf2 -in ${OUTPUT_DIR}/${PKG_NAME} -out ${OUTPUT_DIR}/${PKG_NAME}.enc -pass pass:${PASSWD}# Generate checksum fileecho "[Host] Generating md5 checksum..."cd ${OUTPUT_DIR}md5sum ${PKG_NAME}.enc > ${PKG_NAME}.enc.md5# Generate RSA private key (2048 bits)openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048# Extract public keyopenssl rsa -pubout -in private_key.pem -out ${PKG_NAME}.enc.pem # Generate signatureecho "[Host] Generating signature..."openssl dgst -sha256 -sign private_key.pem -out ${PKG_NAME}.enc.sig ${PKG_NAME}.encrm -f private_key.pemecho "[Host] Upgrade package generated: ${OUTPUT_DIR}/${PKG_NAME}.enc"###################### Start HTTP Service #####################echo "[Host] Starting HTTP service (port:${PORT})"echo "The single board should execute: wget http://${TARGET_IP}:${PORT}/${PKG_NAME}.enc"python3 -m http.server ${PORT} --directory ${OUTPUT_DIR}

zk_cpu/update.sh

#!/bin/bash# Single board upgrade script | Suitable for embedded Linux###################### Configuration Area (Must Modify) #####################HOST_IP="192.168.30.222"     # IP of the hostINSTALL_DIR="/opt/myapp"   # Installation directoryBACKUP_DIR="/opt/backup"   # Backup directoryPORT=8000                  # HTTP service portPASSWD="[email protected]"   # Decryption password###################### Download Upgrade Package #####################echo "[Single Board] Retrieving upgrade package list..."PKG_NAME=$(curl -s http://${HOST_IP}:${PORT}/ | grep -o 'upgrade_[^" ]*\.tar\.gz.enc' | sort | tail -1)PKG_DEC=${PKG_NAME%.enc}if [ -z "${PKG_NAME}" ]; then  echo "[Error] No valid upgrade package found"  exit 1fi echo "[Single Board] Downloading ${PKG_NAME}..."wget -q http://${HOST_IP}:${PORT}/${PKG_NAME}wget -q http://${HOST_IP}:${PORT}/${PKG_NAME}.md5wget -q http://${HOST_IP}:${PORT}/${PKG_NAME}.sigwget -q http://${HOST_IP}:${PORT}/${PKG_NAME}.pem###################### Verify Files #####################echo "[Single Board] Verifying file MD5 checksum..."if ! md5sum -c ${PKG_NAME}.md5; then  @echo "[Error] MD5 checksum verification failed, the file may be corrupted"  rm -f ${PKG_NAME}*  exit 2fi# Verify signatureecho "[Single Board] Verifying file signature..."if ! openssl dgst -sha256 -verify ${PKG_NAME}.pem -signature ${PKG_NAME}.sig ${PKG_NAME}; then echo "[Error] Signature verification failed, the file may be corrupted" rm -f ${PKG_NAME}*  exit 2fi# Decrypt fileecho "[Single Board] Decrypting file..."if ! openssl enc -d -aes-256-cbc -pbkdf2 -in ${PKG_NAME} -out ${PKG_DEC} -pass pass:${PASSWD}; then echo "[Error] Decryption failed, the file may be corrupted" rm -f ${PKG_DEC}* ${PKG_NAME}*  exit 2fi###################### Execute Upgrade #####################echo "[Single Board] Starting upgrade process..."mkdir -p ${BACKUP_DIR}# Create backupBACKUP_NAME="backup_$(date +%Y%m%d-%H%M%S).tar.gz"tar czf ${BACKUP_DIR}/${BACKUP_NAME} -C ${INSTALL_DIR} .# Create temporary directoryTEMP_DIR=$(mktemp -d)trap 'rm -rf "$TEMP_DIR"' EXIT# Extract to temporary directorytar -xf "$PKG_DEC" -C "$TEMP_DIR"# Extract new files, only updating files with the same name or those that do not existfind "$TEMP_DIR/zk_cpu/" -type f -print0 | while IFS= read -r -d $'\0' src_file; do dest_file="$INSTALL_DIR/${src_file#$TEMP_DIR}" dest_file=$(echo "$dest_file" | sed 's/\/zk_cpu\//\/g') if [ ! -f "$dest_file" ] || [ "$src_file" -nt "$dest_file" ]; then mkdir -p "$(dirname "$dest_file")" cp -fv "$src_file" "$dest_file"  # -v shows operation details fi done# Set permissionschown -R root:root ${INSTALL_DIR}chmod -R 755 ${INSTALL_DIR}# Check if management CPU has regular files (including hidden files, excluding subdirectories, up to 10 levels deep)if [ -z "$(find ${TEMP_DIR}/"mg_cpu/" -mindepth 1 -maxdepth 10 -type f)" ]; then echo "Management CPU has no data to update" else echo "Detected data updates for management CPU, preparing to update management CPU data" cp -rf  ${TEMP_DIR}/"mg_cpu" . echo "Preparing to execute management CPU upgrade script" ./update_mg.sh fi###################### Cleanup and Completion #####################echo "[Single Board] Cleaning up temporary files..."rm -f ${PKG_DEC}* *.html*  rm -rf "mg_cpu" "upgrade"echo "[Success] Upgrade completed! Backup location: ${BACKUP_DIR}/${BACKUP_NAME}"echo "It is recommended to restart the single board system to avoid data inconsistency leading to system crashes"       

zk_cpu/update_mg.sh

#!/bin/bash# Host-side upgrade package generation script | Suitable for Linux###################### Configuration Area (Must Modify) #####################UPGRADE_FILES="$PWD/mg_cpu"    # Directory to be upgraded, temporary directoryOUTPUT_DIR="$PWD/upgrade"     # Temporary output directoryPORT=8001                     # HTTP service portPASSWD="[email protected]"   # Encryption passwordTARGET_DIR="/opt/myapp"        # Management CPU's upgrade directoryMG_IP=240.0.0.11TARGET_TOOL="/opt/tools/" # Path where the script is stored, must match the path where mgcpu is stored###################### Create Upgrade Package #####################echo "[zk_CPU] Preparing upgrade files..."mkdir -p ${OUTPUT_DIR}TIMESTAMP=$(date +%Y%m%d-%H%M%S)PKG_NAME="upgrade_${TIMESTAMP}.tar.gz"# Package core files (excluding logs and other irrelevant files)tar czvf ${OUTPUT_DIR}/${PKG_NAME} \  --exclude="*.log" \  --exclude="tmp/*" \  -C ${UPGRADE_FILES} .# Encrypt the fileecho "[zk_CPU] Encrypting files..."openssl enc -aes-256-cbc -salt -pbkdf2 -in ${OUTPUT_DIR}/${PKG_NAME} -out ${OUTPUT_DIR}/${PKG_NAME}.enc -pass pass:${PASSWD}# Generate checksum fileecho "[zk_CPU] Generating md5 checksum..."cd ${OUTPUT_DIR}md5sum ${PKG_NAME}.enc > ${PKG_NAME}.enc.md5# Generate RSA private key (2048 bits)openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048# Extract public keyopenssl rsa -pubout -in private_key.pem -out ${PKG_NAME}.enc.pem # Generate signatureecho "[zk_CPU] Generating signature..."openssl dgst -sha256 -sign private_key.pem -out ${PKG_NAME}.enc.sig ${PKG_NAME}.encrm -f private_key.pem echo "[zk_CPU] Upgrade package generated: ${OUTPUT_DIR}/${PKG_NAME}.enc"###################### Start SSH Service ######################  Generate key pair (default save location ~/.ssh/)ssh-keygen -t ed25519 -C "auto_script_key"  # A more secure encryption algorithm than RSA# After execution, it will prompt:# Enter file in which to save the key...  Press Enter to use the default path# Enter passphrase... Do not enter (press Enter) to achieve non-interactive mode# 2. Copy public key to target serverssh-copy-id -i ~/.ssh/id_ed25519.pub ${MG_IP}# 3. Transfer filesecho "[zk_CPU] Transferring files..."scp -i ~/.ssh/id_ed25519 ${PKG_NAME}.enc  ${PKG_NAME}.enc.md5 ${PKG_NAME}.enc.sig ${PKG_NAME}.enc.pem  ${MG_IP}:${TARGET_DIR}# 4. Remote login to management CPU, execute management CPU's scriptecho "[mg_cpu] Remotely logged into mg_cpu, mg is preparing to upgrade, entering ${TARGET_TOOL}"ssh root@${MG_IP} "${TARGET_TOOL}/update.sh"exit

zk_cpu/update_mg.sh

#!/bin/bash# Single board upgrade script | Suitable for embedded Linux###################### Configuration Area (Must Modify) #####################INSTALL_DIR="/opt/myapp"   # Installation directoryPASSWD="[email protected]"   # Decryption password###################### Download Upgrade Package #####################echo "[mg_cpu] Retrieving upgrade package list..."PKG_NAME=$(find ${INSTALL_DIR} | grep -o 'upgrade_[^" ]*\.tar\.gz.enc' | sort | tail -1)PKG_DEC=${PKG_NAME%.enc}if [ -z "${PKG_NAME}" ]; then  echo "[Error] No valid upgrade package found"  exit 1fi cd $INSTALL_DIR###################### Verify Files #####################echo "[mg_cpu] Verifying file MD5 checksum..."if ! md5sum -c ${PKG_NAME}.md5; then  echo "[Error] MD5 checksum verification failed, the file may be corrupted"  rm -f ${PKG_NAME}*  exit 2fi# Verify signatureecho "[mg_cpu] Verifying file signature..."if ! openssl dgst -sha256 -verify ${PKG_NAME}.pem -signature ${PKG_NAME}.sig ${PKG_NAME}; then echo "[Error] Signature verification failed, the file may be corrupted" rm -f ${PKG_NAME}*  exit 2fi# Decrypt fileecho "[mg_cpu] Decrypting file..."if ! openssl enc -d -aes-256-cbc -pbkdf2 -in ${PKG_NAME} -out ${PKG_DEC} -pass pass:${PASSWD}; then echo "[Error] Decryption failed, the file may be corrupted" rm -f ${PKG_DEC}* ${PKG_NAME}*  exit 2fi###################### Execute Upgrade #####################echo "[mg_cpu] Starting upgrade process..."set -e# Create temporary directoryTEMP_DIR=$(mktemp -d)trap 'rm -rf "$TEMP_DIR"' EXIT# Extract to temporary directorytar -xf "$PKG_DEC" -C "$INSTALL_DIR"# Extract new files, only updating files with the same name or those that do not existfind "$TEMP_DIR" -type f -print0 | while IFS= read -r -d $'\0' src_file; do dest_file="$INSTALL_DIR/${src_file#$TEMP_DIR/}" if [ ! -f "$dest_file" ] || [ "$src_file" -nt "$dest_file" ]; then mkdir -p "$(dirname "$dest_file")" cp -fv "$src_file" "$dest_file"  # -v shows operation details fi done# Set permissionschown -R root:root ${INSTALL_DIR}chmod -R 755 ${INSTALL_DIR}###################### Cleanup and Completion #####################echo "[mg_cpu] Cleaning up temporary files..."rm -f ${PKG_DEC}* *.html*  rm -rf "mg_cpu" "upgrade"echo "[mg_cpu] Upgrade completed!"echo " Exiting mg_CPU"

2)Ensure network connectivity.

1.The host pings the main control CPU’s IP successfully.

2.The main control CPU pings the management CPU (240.0.0.11) successfully.

3)The host creates the upgrade package.

According to the upgrade requirements, place the respective upgrade files into host/mg_cpu and host/zk_cpu, then execute ./build.sh.

4)One-click upgrade for the VPN device.

Remotely connect to the main control CPU’s /opt/tools directory. Execute ./update.sh to complete the one-click upgrade.

Special notes:

1)During the upgrade, only files with different names and files that do not exist on the board will be upgraded; existing files on the board will not be deleted. For example, if the host’s upgrade directory contains a.txt and b.txt; and the board’s upgrade directory contains a.txt and c.txt, after the upgrade, the board’s upgrade target will contain a.txt (new version), b.txt, and c.txt.

2)The main control board has a backup directory /opt/backup, which stores the files (in plaintext) after packaging by the host, and can be deleted or retained as needed.

Leave a Comment