initial commit
This commit is contained in:
4
Config.in
Normal file
4
Config.in
Normal file
@@ -0,0 +1,4 @@
|
||||
# Config.in for Auracaster System BR2_EXTERNAL tree
|
||||
|
||||
# Include custom packages
|
||||
source "$BR2_EXTERNAL_AURACASTER_SYSTEM_PATH/package/swupdate-scripts/Config.in"
|
||||
134
README.md
Normal file
134
README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Auracaster System - Buildroot with SWUpdate A/B System
|
||||
|
||||
This project implements a Buildroot-based system for Raspberry Pi 3 with SWUpdate A/B partitioning for robust over-the-air updates.
|
||||
|
||||
## Overview
|
||||
|
||||
The Auracaster System provides a complete solution for creating a robust embedded Linux system with A/B partition updates using the SWUpdate framework. This allows for safe, reliable updates with automatic rollback capability if an update fails.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **A/B Partition System**: Two rootfs partitions (A and B) for failsafe updates
|
||||
- **SWUpdate Integration**: Web interface for uploading and applying updates
|
||||
- **Automatic Fallback**: If an update fails to boot, the system reverts to the previous partition
|
||||
- **Raspberry Pi 3 Support**: Optimized for Raspberry Pi 3 hardware
|
||||
- **BR2_EXTERNAL Structure**: Follows Buildroot's recommended external tree pattern
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
auracaster-system/
|
||||
├── Config.in # Main config file for BR2_EXTERNAL
|
||||
├── external.desc # BR2_EXTERNAL description file
|
||||
├── configs/ # Custom defconfigs
|
||||
│ └── raspberrypi3_swupdate_defconfig
|
||||
├── board/ # Board-specific files
|
||||
│ └── raspberrypi3_swupdate/ # Configuration for RPi3 with SWUpdate
|
||||
├── package/ # Custom packages
|
||||
│ └── swupdate-scripts/ # Custom scripts for SWUpdate
|
||||
├── example/ # Example update package
|
||||
│ └── create-update-package.sh # Script to create a sample update
|
||||
└── flash_sdcard.sh # Script to flash SD card
|
||||
```
|
||||
|
||||
## Building the System
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Buildroot checkout (in `../buildroot` relative to this repository)
|
||||
- Build dependencies for Buildroot (see Buildroot documentation)
|
||||
- At least 10GB of free disk space
|
||||
- Root/sudo access (for SD card flashing)
|
||||
|
||||
### Build Steps
|
||||
|
||||
1. Configure Buildroot to use this external tree:
|
||||
|
||||
```bash
|
||||
cd ../buildroot
|
||||
make BR2_EXTERNAL=../auracaster-system raspberrypi3_swupdate_defconfig
|
||||
```
|
||||
|
||||
2. Build the system:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
The build process will take some time (30-60 minutes depending on your system). Once complete, the output images will be in `../buildroot/output/images/`.
|
||||
|
||||
## Flashing to SD Card
|
||||
|
||||
Use the provided script to flash the image to your SD card:
|
||||
|
||||
```bash
|
||||
sudo ./flash_sdcard.sh
|
||||
```
|
||||
|
||||
Follow the on-screen prompts to select the correct device and confirm the flashing operation.
|
||||
|
||||
## Partition Layout
|
||||
|
||||
The system uses the following partition layout on the SD card:
|
||||
|
||||
1. **Boot Partition (64MB)**: Contains bootloader, kernel, and boot configuration
|
||||
2. **RootFS A (512MB)**: First root filesystem partition
|
||||
3. **RootFS B (512MB)**: Second root filesystem partition
|
||||
4. **Data Partition (Remaining Space)**: For persistent data storage
|
||||
|
||||
## Update Process
|
||||
|
||||
### Creating an Update Package
|
||||
|
||||
Use the provided example script to create an update package:
|
||||
|
||||
```bash
|
||||
cd example
|
||||
./create-update-package.sh
|
||||
```
|
||||
|
||||
This creates an `auracaster-update.swu` file that can be applied through the web interface.
|
||||
|
||||
### Applying an Update via Web Interface
|
||||
|
||||
1. Boot the Raspberry Pi with the flashed SD card
|
||||
2. Connect to the same network as the Raspberry Pi
|
||||
3. Access the web interface at `http://<raspberry-pi-ip>:8080`
|
||||
4. Upload the `.swu` file through the web interface
|
||||
5. Once the update is complete, reboot the device
|
||||
6. The system will boot from the updated partition
|
||||
|
||||
### Update Verification
|
||||
|
||||
The system will track boot attempts. If the updated system fails to boot properly (as determined by the boot counter mechanism), it will automatically fall back to the previous working partition.
|
||||
|
||||
## U-Boot Environment
|
||||
|
||||
The U-Boot environment manages the A/B boot selection. Key variables include:
|
||||
|
||||
- `active_part`: Current active partition (A or B)
|
||||
- `inactive_part`: Partition that will receive updates
|
||||
- `bootcount`: Number of boot attempts for the current partition
|
||||
- `bootlimit`: Maximum allowed boot attempts before fallback
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### System Won't Boot
|
||||
|
||||
If the system fails to boot completely:
|
||||
|
||||
1. Connect a monitor to the Raspberry Pi to view boot messages
|
||||
2. If the system is falling back to the previous partition, check the logs for errors
|
||||
3. You can manually force a boot from a specific partition by editing the U-Boot environment
|
||||
|
||||
### Update Fails
|
||||
|
||||
If an update fails to apply:
|
||||
|
||||
1. Check network connectivity
|
||||
2. Verify the SWUpdate web server is running (port 8080)
|
||||
3. Examine the update package format and contents
|
||||
|
||||
## License
|
||||
|
||||
This project is distributed under the terms of the GPL v2 license.
|
||||
108
USAGE_GUIDE.md
Normal file
108
USAGE_GUIDE.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Auracaster System - Quick Start Guide
|
||||
|
||||
This guide walks you through building the Auracaster system, flashing it to an SD card, and performing an A/B update.
|
||||
|
||||
## Building the System
|
||||
|
||||
1. Clone or navigate to your Buildroot repository:
|
||||
|
||||
```bash
|
||||
cd ../buildroot
|
||||
```
|
||||
|
||||
2. Configure Buildroot to use our external tree:
|
||||
|
||||
```bash
|
||||
make BR2_EXTERNAL=../auracaster-system raspberrypi3_swupdate_defconfig
|
||||
```
|
||||
|
||||
3. Build the system (this will take some time):
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
## Flashing to SD Card
|
||||
|
||||
1. Insert your SD card into your computer
|
||||
|
||||
2. Run the flashing script with sudo:
|
||||
|
||||
```bash
|
||||
cd ../auracaster-system
|
||||
sudo ./flash_sdcard.sh
|
||||
```
|
||||
|
||||
3. Follow the prompts to select your SD card device
|
||||
|
||||
## Initial Boot
|
||||
|
||||
1. Insert the SD card into your Raspberry Pi 3
|
||||
2. Connect Ethernet and power
|
||||
3. Wait for the system to boot (1-2 minutes)
|
||||
4. Discover the IP address (check your router or use `nmap -sP 192.168.1.0/24`)
|
||||
5. The system will be initially running from partition A
|
||||
|
||||
## Creating an Update Package
|
||||
|
||||
1. Create a simple update package:
|
||||
|
||||
```bash
|
||||
cd example
|
||||
./create-update-package.sh
|
||||
```
|
||||
|
||||
2. This creates `auracaster-update.swu` which would update the inactive partition (B)
|
||||
|
||||
## Applying the Update
|
||||
|
||||
1. Access the SWUpdate web interface in your browser:
|
||||
|
||||
```
|
||||
http://<raspberry-pi-ip>:8080
|
||||
```
|
||||
|
||||
2. You should see the Auracaster System Update interface
|
||||
3. Select "Choose File" and pick the `auracaster-update.swu` file
|
||||
4. Click "Upload" to start the update process
|
||||
5. The progress bar will show the update status
|
||||
6. Once complete, you'll see "Update successful"
|
||||
|
||||
## Verifying the Update
|
||||
|
||||
1. Reboot the system (either through the web interface or SSH)
|
||||
2. After reboot, the system will now be running from partition B
|
||||
3. You can verify this by checking the system status:
|
||||
|
||||
```bash
|
||||
swupdate-ab-helper --status
|
||||
```
|
||||
|
||||
## Testing Automatic Fallback
|
||||
|
||||
If you want to test the automatic fallback mechanism:
|
||||
|
||||
1. SSH into the system
|
||||
2. Make the active partition unbootable (for testing purposes only):
|
||||
|
||||
```bash
|
||||
# Corrupt kernel on the currently active partition
|
||||
swupdate-ab-helper --toggle
|
||||
reboot
|
||||
```
|
||||
|
||||
3. The system will attempt to boot from the now-corrupt partition
|
||||
4. After 3 failed attempts, it will automatically fall back to the previous partition
|
||||
|
||||
## Tips and Troubleshooting
|
||||
|
||||
- **Network Issues**: If you can't access the web interface, check your network connection and firewall settings
|
||||
- **Update Failures**: Check for errors in the swupdate logs: `journalctl -u swupdate`
|
||||
- **Manual Partition Toggle**: You can manually switch between partitions: `swupdate-ab-helper --toggle && reboot`
|
||||
- **Checking Update Status**: Run `swupdate-check status` to see current system status
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Create your own custom update packages
|
||||
- Modify the web interface to include your branding
|
||||
- Implement secure updates with cryptographic signatures
|
||||
56
board/raspberrypi3_swupdate/boot.scr.txt
Normal file
56
board/raspberrypi3_swupdate/boot.scr.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
# U-Boot boot script for Raspberry Pi 3 with A/B boot
|
||||
# This script will be converted to boot.scr by the post-image.sh script
|
||||
|
||||
echo "DEBUG: Starting boot process..."
|
||||
echo "DEBUG: U-Boot version: ${ver}"
|
||||
echo "DEBUG: Board: ${board_name}"
|
||||
|
||||
# Set load addresses
|
||||
setenv kernel_addr_r 0x01000000
|
||||
setenv fdt_addr_r 0x02000000
|
||||
echo "DEBUG: Load addresses set - kernel: ${kernel_addr_r}, fdt: ${fdt_addr_r}"
|
||||
|
||||
# Print current environment variables
|
||||
echo "DEBUG: Current boot variables:"
|
||||
echo "DEBUG: active_part=${active_part}"
|
||||
echo "DEBUG: active_root=${active_root}"
|
||||
echo "DEBUG: bootcount=${bootcount}"
|
||||
echo "DEBUG: bootlimit=${bootlimit}"
|
||||
|
||||
# Read and increment boot count
|
||||
echo "DEBUG: Checking bootcount..."
|
||||
if test ${bootcount} -lt ${bootlimit}; then
|
||||
echo "DEBUG: Incrementing bootcount from ${bootcount} to $((${bootcount} + 1))"
|
||||
setexpr bootcount ${bootcount} + 1
|
||||
echo "DEBUG: Saving environment..."
|
||||
saveenv
|
||||
echo "DEBUG: Environment saved"
|
||||
fi
|
||||
|
||||
# If bootcount has reached bootlimit, switch to alternate boot
|
||||
echo "DEBUG: Checking if bootcount >= bootlimit..."
|
||||
if test ${bootcount} -ge ${bootlimit}; then
|
||||
echo "Boot failed too many times. Switching to alternate partition."
|
||||
echo "DEBUG: Running altbootcmd..."
|
||||
run altbootcmd
|
||||
echo "DEBUG: Resetting bootcount to 0"
|
||||
setenv bootcount 0
|
||||
echo "DEBUG: Saving environment..."
|
||||
saveenv
|
||||
echo "DEBUG: Environment saved"
|
||||
fi
|
||||
|
||||
# List files in boot partition
|
||||
echo "DEBUG: Listing files in boot partition:"
|
||||
ls mmc 0:1
|
||||
|
||||
# Boot the system
|
||||
echo "DEBUG: Preparing to boot from partition ${active_part}..."
|
||||
echo "DEBUG: Will execute: bootcmd_${active_part}"
|
||||
echo "DEBUG: bootcmd_${active_part}=${bootcmd_${active_part}}"
|
||||
echo "DEBUG: Booting from partition ${active_part}..."
|
||||
run bootcmd_${active_part}
|
||||
|
||||
# If we reach here, booting failed. Try alternate boot.
|
||||
echo "DEBUG: Primary boot failed. Trying alternate partition..."
|
||||
run altbootcmd
|
||||
1
board/raspberrypi3_swupdate/cmdline.txt
Normal file
1
board/raspberrypi3_swupdate/cmdline.txt
Normal file
@@ -0,0 +1 @@
|
||||
console=ttyS0,115200 rootwait
|
||||
20
board/raspberrypi3_swupdate/config.txt
Normal file
20
board/raspberrypi3_swupdate/config.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
# Enable 64-bit mode
|
||||
arm_64bit=1
|
||||
|
||||
# configure the uart
|
||||
enable_uart=1
|
||||
core_freq=250
|
||||
init_uart_clock=48000000
|
||||
init_uart_baud=115200
|
||||
uart_2ndstage=1
|
||||
|
||||
# Disable HDMI to reduce noise
|
||||
hdmi_ignore_hotplug=1
|
||||
hdmi_blanking=2
|
||||
disable_splash=1
|
||||
|
||||
# gpu mem config (seems to be totally nececcarry - smaller than 32m does not boot on rpi3)
|
||||
gpu_mem=32
|
||||
|
||||
# start the bootloader which then selects system A or B
|
||||
kernel=u-boot.bin
|
||||
23
board/raspberrypi3_swupdate/config.txt.old
Normal file
23
board/raspberrypi3_swupdate/config.txt.old
Normal file
@@ -0,0 +1,23 @@
|
||||
# Raspberry Pi 3 configuration for UART debugging
|
||||
|
||||
# Enable 64-bit mode
|
||||
arm_64bit=1
|
||||
|
||||
# UART configuration - Comprehensive settings
|
||||
enable_uart=1
|
||||
core_freq=250
|
||||
init_uart_clock=48000000
|
||||
init_uart_baud=115200
|
||||
uart_2ndstage=1
|
||||
#dtparam=uart0=on
|
||||
|
||||
# Disable HDMI to reduce noise
|
||||
hdmi_ignore_hotplug=1
|
||||
hdmi_blanking=2
|
||||
disable_splash=1
|
||||
|
||||
# Use zImage as the kernel
|
||||
kernel=zImage
|
||||
|
||||
# For better performance (seems to be totally nececcarry)
|
||||
gpu_mem=128
|
||||
@@ -0,0 +1,78 @@
|
||||
image boot.vfat {
|
||||
vfat {
|
||||
files = {
|
||||
"bcm2710-rpi-3-b.dtb",
|
||||
"bcm2710-rpi-3-b-plus.dtb",
|
||||
"bcm2710-rpi-cm3.dtb",
|
||||
"cmdline.txt",
|
||||
"config.txt",
|
||||
"boot.scr",
|
||||
"uboot-env.img",
|
||||
"zImage"
|
||||
}
|
||||
file overlays/README {
|
||||
image = "rpi-firmware/overlays/README"
|
||||
}
|
||||
file bootcode.bin {
|
||||
image = "rpi-firmware/bootcode.bin"
|
||||
}
|
||||
file fixup.dat {
|
||||
image = "rpi-firmware/fixup.dat"
|
||||
}
|
||||
file start.elf {
|
||||
image = "rpi-firmware/start.elf"
|
||||
}
|
||||
}
|
||||
size = 32M
|
||||
}
|
||||
|
||||
image rootfs-A.ext4 {
|
||||
ext4 {
|
||||
label = "rootfs-A"
|
||||
use-mke2fs = true
|
||||
}
|
||||
size = 256M
|
||||
}
|
||||
|
||||
image rootfs-B.ext4 {
|
||||
ext4 {
|
||||
label = "rootfs-B"
|
||||
use-mke2fs = true
|
||||
}
|
||||
size = 256M
|
||||
}
|
||||
|
||||
image data.ext4 {
|
||||
ext4 {
|
||||
label = "data"
|
||||
use-mke2fs = true
|
||||
}
|
||||
size = 128M
|
||||
}
|
||||
|
||||
image sdcard.img {
|
||||
hdimage {
|
||||
partition-table-type = "mbr"
|
||||
}
|
||||
|
||||
partition boot {
|
||||
partition-type = 0xC
|
||||
bootable = "true"
|
||||
image = "boot.vfat"
|
||||
}
|
||||
|
||||
partition rootfs-A {
|
||||
partition-type = 0x83
|
||||
image = "rootfs-A.ext4"
|
||||
}
|
||||
|
||||
partition rootfs-B {
|
||||
partition-type = 0x83
|
||||
image = "rootfs-B.ext4"
|
||||
}
|
||||
|
||||
partition data {
|
||||
partition-type = 0x83
|
||||
image = "data.ext4"
|
||||
}
|
||||
}
|
||||
42
board/raspberrypi3_swupdate/post-build.sh
Executable file
42
board/raspberrypi3_swupdate/post-build.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
BOARD_DIR="$(dirname $0)"
|
||||
BOARD_NAME="$(basename ${BOARD_DIR})"
|
||||
GENIMAGE_CFG="${BOARD_DIR}/genimage-${BOARD_NAME}.cfg"
|
||||
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
|
||||
|
||||
# Add a console on tty1
|
||||
if [ -e ${TARGET_DIR}/etc/inittab ]; then
|
||||
grep -qE '^tty1::' ${TARGET_DIR}/etc/inittab || \
|
||||
sed -i '/GENERIC_SERIAL/a\
|
||||
tty1::respawn:/sbin/getty -L tty1 0 vt100 # HDMI console' ${TARGET_DIR}/etc/inittab
|
||||
fi
|
||||
|
||||
# Create swupdate directory structure
|
||||
mkdir -p ${TARGET_DIR}/etc/swupdate
|
||||
mkdir -p ${TARGET_DIR}/var/www/swupdate
|
||||
mkdir -p ${TARGET_DIR}/var/lib/swupdate
|
||||
mkdir -p ${TARGET_DIR}/etc/swupdate/conf.d
|
||||
|
||||
# Copy swupdate configuration
|
||||
install -m 0644 ${BOARD_DIR}/swupdate.cfg ${TARGET_DIR}/etc/swupdate/swupdate.cfg
|
||||
|
||||
# Set up fstab for A/B partitioning
|
||||
cat > ${TARGET_DIR}/etc/fstab << EOF
|
||||
# <file system> <mount pt> <type> <options> <dump> <pass>
|
||||
/dev/mmcblk0p1 /boot vfat defaults 0 0
|
||||
/dev/root / ext4 rw,noauto 0 1
|
||||
/dev/mmcblk0p4 /data ext4 defaults 0 0
|
||||
proc /proc proc defaults 0 0
|
||||
devpts /dev/pts devpts defaults,gid=5,mode=620,ptmxmode=0666 0 0
|
||||
tmpfs /dev/shm tmpfs mode=0777 0 0
|
||||
tmpfs /tmp tmpfs mode=1777 0 0
|
||||
tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0
|
||||
sysfs /sys sysfs defaults 0 0
|
||||
EOF
|
||||
|
||||
# Create systemd services for swupdate
|
||||
mkdir -p ${TARGET_DIR}/etc/systemd/system/
|
||||
install -m 0644 ${BOARD_DIR}/swupdate.service ${TARGET_DIR}/etc/systemd/system/
|
||||
63
board/raspberrypi3_swupdate/post-image.sh
Executable file
63
board/raspberrypi3_swupdate/post-image.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
BOARD_DIR="$(dirname $0)"
|
||||
BOARD_NAME="$(basename ${BOARD_DIR})"
|
||||
GENIMAGE_CFG="${BOARD_DIR}/genimage-${BOARD_NAME}.cfg"
|
||||
GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"
|
||||
|
||||
# Copy u-boot.bin to the firmware directory for Raspberry Pi bootloader
|
||||
echo "Copying u-boot.bin to rpi-firmware directory..."
|
||||
if [ -f "${BINARIES_DIR}/u-boot.bin" ]; then
|
||||
cp "${BINARIES_DIR}/u-boot.bin" "${BINARIES_DIR}/rpi-firmware/"
|
||||
else
|
||||
echo "WARNING: u-boot.bin not found in ${BINARIES_DIR}" >&2
|
||||
fi
|
||||
|
||||
# Pass arguments to genimage
|
||||
GENIMAGE_ARGS="--rootpath ${TARGET_DIR}"
|
||||
|
||||
# Create the boot.scr U-Boot script
|
||||
${HOST_DIR}/bin/mkimage -A arm -O linux -T script -C none -d ${BOARD_DIR}/boot.scr.txt ${BINARIES_DIR}/boot.scr
|
||||
|
||||
# Create a file to indicate that this is rootfs A
|
||||
touch ${TARGET_DIR}/etc/rootfs-A
|
||||
|
||||
# Create an empty ext4 rootfs-B image of the same size as rootfs
|
||||
cp ${BINARIES_DIR}/rootfs.ext4 ${BINARIES_DIR}/rootfs-B.ext4
|
||||
|
||||
# Create uboot environment
|
||||
${HOST_DIR}/bin/mkenvimage -s 131072 -o "${BINARIES_DIR}/uboot-env.img" "${BOARD_DIR}/uboot-env.txt"
|
||||
# Copy U-Boot environment image as uboot.env to rpi-firmware directory
|
||||
cp "${BINARIES_DIR}/uboot-env.img" "${BINARIES_DIR}/rpi-firmware/uboot.env"
|
||||
|
||||
# Create version file
|
||||
echo "VERSION=${BR2_VERSION_FULL}" > ${BINARIES_DIR}/version
|
||||
|
||||
# Mark inactive rootfs partition as clean
|
||||
touch ${BINARIES_DIR}/.rootfs-B.ext4.done
|
||||
|
||||
# Copy the cmdline.txt and config.txt files
|
||||
cp ${BOARD_DIR}/cmdline.txt ${BINARIES_DIR}/cmdline.txt
|
||||
cp ${BOARD_DIR}/config.txt ${BINARIES_DIR}/config.txt
|
||||
|
||||
rm -rf "${GENIMAGE_TMP}"
|
||||
|
||||
genimage \
|
||||
--loglevel 1 \
|
||||
${GENIMAGE_ARGS} \
|
||||
--tmppath "${GENIMAGE_TMP}" \
|
||||
--inputpath "${BINARIES_DIR}" \
|
||||
--outputpath "${BINARIES_DIR}" \
|
||||
--config "${GENIMAGE_CFG}"
|
||||
|
||||
# Create symlink for easy flashing with dd
|
||||
ln -sf "${BINARIES_DIR}/sdcard.img" "${BINARIES_DIR}/auracaster-swupdate.img"
|
||||
|
||||
# Create a compressed version for distribution
|
||||
if [ -x "$(command -v xz)" ]; then
|
||||
xz -T0 -c "${BINARIES_DIR}/sdcard.img" > "${BINARIES_DIR}/auracaster-swupdate.img.xz"
|
||||
fi
|
||||
|
||||
exit $?
|
||||
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
36
board/raspberrypi3_swupdate/swupdate.cfg
Normal file
36
board/raspberrypi3_swupdate/swupdate.cfg
Normal file
@@ -0,0 +1,36 @@
|
||||
# SWUpdate runtime configuration
|
||||
|
||||
globals = {
|
||||
verbose = true;
|
||||
loglevel = 5;
|
||||
syslog = true;
|
||||
# Create a file to notify scripts that update is complete
|
||||
postupdatecmd = "touch /tmp/swupdate.done";
|
||||
};
|
||||
|
||||
# Partition handler for raw partitions
|
||||
raw-handler = {
|
||||
# Example: Specify which partitions can be updated
|
||||
partitions = ( { name = "rootfs-B"; device = "/dev/mmcblk0p3"; } );
|
||||
};
|
||||
|
||||
# For bootloader environment
|
||||
bootloader = {
|
||||
# U-Boot environment
|
||||
environment = {
|
||||
device = "/dev/mmcblk0p1";
|
||||
file = "uboot-env.img";
|
||||
};
|
||||
# What to set after successful update
|
||||
set-variables = (
|
||||
{name = "bootcount"; value = "0";},
|
||||
{name = "upgrade_available"; value = "1";},
|
||||
{name = "active_part"; value = "${inactive_part}";},
|
||||
{name = "active_root"; value = "${inactive_root}";},
|
||||
{name = "inactive_part"; value = "${active_part}";},
|
||||
{name = "inactive_root"; value = "${active_root}";}
|
||||
);
|
||||
};
|
||||
|
||||
# Include additional configuration files
|
||||
include = "conf.d/*.cfg";
|
||||
41
board/raspberrypi3_swupdate/swupdate.config
Normal file
41
board/raspberrypi3_swupdate/swupdate.config
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SWUpdate configuration file */
|
||||
|
||||
globals :
|
||||
{
|
||||
verbose = true;
|
||||
loglevel = 5;
|
||||
syslog = true;
|
||||
/* Create a file on startup for the web interface */
|
||||
postupdatecmd = "touch /tmp/swupdate.done";
|
||||
};
|
||||
|
||||
webserver :
|
||||
{
|
||||
document_root = "/var/www/swupdate";
|
||||
port = 8080;
|
||||
};
|
||||
|
||||
download :
|
||||
{
|
||||
retries = 3;
|
||||
timeout = 1800;
|
||||
};
|
||||
|
||||
identify :
|
||||
{
|
||||
/* This identifies the device for update targeting */
|
||||
board = "raspberrypi3";
|
||||
hw-revision = "1.0";
|
||||
software-set = "stable";
|
||||
};
|
||||
|
||||
suricatta :
|
||||
{
|
||||
/* Configure for push notifications - not enabled by default */
|
||||
enabled = false;
|
||||
server = "";
|
||||
id = 0;
|
||||
};
|
||||
|
||||
/* Include external handlers */
|
||||
#include "conf.d/handlers.conf"
|
||||
11
board/raspberrypi3_swupdate/swupdate.service
Normal file
11
board/raspberrypi3_swupdate/swupdate.service
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=SWUpdate daemon
|
||||
Documentation=https://sbabic.github.io/swupdate/
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/swupdate -w "-r /var/www/swupdate" -k /etc/swupdate-public.pem -i "board=raspberrypi3" -u "stable"
|
||||
KillMode=mixed
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
37
board/raspberrypi3_swupdate/uboot-env.txt
Normal file
37
board/raspberrypi3_swupdate/uboot-env.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
# U-Boot environment variables for A/B boot system
|
||||
# Default variables for first boot - these will be modified during operation
|
||||
|
||||
# Active partition (A or B)
|
||||
active_part=A
|
||||
active_root=/dev/mmcblk0p2
|
||||
inactive_part=B
|
||||
inactive_root=/dev/mmcblk0p3
|
||||
|
||||
# Boot attempt counters
|
||||
bootcount=0
|
||||
bootlimit=3
|
||||
|
||||
# Default bootcmd
|
||||
bootcmd=run bootcmd_${active_part}
|
||||
|
||||
# Kernel boot arguments
|
||||
bootargs=console=ttyAMA0,115200 console=tty1 root=${active_root} rootwait
|
||||
|
||||
# Commands for booting from A or B partitions
|
||||
bootcmd_A=setenv bootargs console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootwait; load mmc 0:1 ${kernel_addr_r} zImage; load mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}
|
||||
bootcmd_B=setenv bootargs console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 rootwait; load mmc 0:1 ${kernel_addr_r} zImage; load mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb; bootz ${kernel_addr_r} - ${fdt_addr_r}
|
||||
|
||||
# Fallback logic for failed boots
|
||||
altbootcmd=if test ${active_part} = A; then setenv active_part B; setenv active_root /dev/mmcblk0p3; setenv inactive_part A; setenv inactive_root /dev/mmcblk0p2; else setenv active_part A; setenv active_root /dev/mmcblk0p2; setenv inactive_part B; setenv inactive_root /dev/mmcblk0p3; fi; setenv bootcount 0; saveenv; run bootcmd
|
||||
|
||||
# Memory addresses
|
||||
kernel_addr_r=0x01000000
|
||||
fdt_addr_r=0x02000000
|
||||
|
||||
# Board name
|
||||
board_name=rpi3
|
||||
|
||||
# Network configuration (DHCP)
|
||||
autoload=no
|
||||
ethact=smi
|
||||
ethaddr_sdio0=00:44:55:66:77:88
|
||||
20
board/raspberrypi3_swupdate/uboot.config
Normal file
20
board/raspberrypi3_swupdate/uboot.config
Normal file
@@ -0,0 +1,20 @@
|
||||
# Disable EFI capsule which requires GnuTLS
|
||||
CONFIG_EFI_CAPSULE=n
|
||||
CONFIG_EFI_CAPSULE_ON_DISK=n
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=n
|
||||
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=n
|
||||
CONFIG_EFI_CAPSULE_AUTHENTICATE=n
|
||||
|
||||
# Ensure the basic features we need are enabled
|
||||
CONFIG_ENV_IS_IN_FAT=y
|
||||
CONFIG_CMD_GPT=y
|
||||
CONFIG_CMD_MMC=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_FS_GENERIC=y
|
||||
|
||||
# Explicitly enable UART
|
||||
CONFIG_BAUDRATE=115200
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_PRESENT=y
|
||||
CONFIG_CONS_INDEX=0
|
||||
CONFIG_OF_STDOUT_VIA_ALIAS=y
|
||||
0
board/raspberrypi3_swupdate/users.txt
Normal file
0
board/raspberrypi3_swupdate/users.txt
Normal file
105
configs/raspberrypi3_swupdate_defconfig
Normal file
105
configs/raspberrypi3_swupdate_defconfig
Normal file
@@ -0,0 +1,105 @@
|
||||
# Architecture
|
||||
# Use 32-bit ARM mode for compatibility with U-Boot (64-bit mode causes build errors)
|
||||
# BR2_arm=y
|
||||
# BR2_cortex_a53=y
|
||||
# BR2_ARM_FPU_NEON_VFPV4=y
|
||||
BR2_aarch64=y
|
||||
BR2_ARM_FPU_VFPV4=y
|
||||
# Linux headers
|
||||
BR2_TOOLCHAIN_BUILDROOT_CXX=y
|
||||
BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_6_6=y
|
||||
|
||||
# Kernel
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,576cc10e1ed50a9eacffc7a05c796051d7343ea4)/linux-576cc10e1ed50a9eacffc7a05c796051d7343ea4.tar.gz"
|
||||
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi3"
|
||||
BR2_LINUX_KERNEL_DTS_SUPPORT=y
|
||||
BR2_LINUX_KERNEL_INTREE_DTS_NAME="broadcom/bcm2710-rpi-3-b broadcom/bcm2710-rpi-3-b-plus broadcom/bcm2710-rpi-cm3"
|
||||
BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
|
||||
|
||||
# Filesystem
|
||||
BR2_TARGET_ROOTFS_EXT2=y
|
||||
BR2_TARGET_ROOTFS_EXT2_4=y
|
||||
BR2_TARGET_ROOTFS_EXT2_SIZE="256M"
|
||||
|
||||
# Bootloader
|
||||
BR2_TARGET_UBOOT=y
|
||||
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
|
||||
#BR2_TARGET_UBOOT_CUSTOM_VERSION=y
|
||||
#BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2023.07.02"
|
||||
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="rpi_3"
|
||||
BR2_TARGET_UBOOT_NEEDS_DTC=y
|
||||
BR2_TARGET_UBOOT_NEEDS_PYTHON3=y
|
||||
BR2_TARGET_UBOOT_NEEDS_PYLIBFDT=y
|
||||
BR2_TARGET_UBOOT_FORMAT_BIN=y
|
||||
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/uboot.config"
|
||||
BR2_PACKAGE_UBOOT_TOOLS=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_MKIMAGE=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_MKENVIMAGE=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_BOOT_SCRIPT=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_BOOT_SCRIPT_SOURCE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/boot.scr.txt"
|
||||
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE=y
|
||||
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE_SOURCE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/uboot-env.txt"
|
||||
BR2_PACKAGE_UBOOT_TOOLS_ENVIMAGE_SIZE="0x20000"
|
||||
|
||||
# Raspberry Pi firmware
|
||||
BR2_PACKAGE_RPI_FIRMWARE=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE_BOOTCODE_BIN=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE_VARIANT_PI=y
|
||||
BR2_PACKAGE_RPI_FIRMWARE_CONFIG_FILE="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/config.txt"
|
||||
|
||||
# Image creation
|
||||
BR2_ROOTFS_POST_BUILD_SCRIPT="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/post-build.sh"
|
||||
BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/post-image.sh"
|
||||
|
||||
# SWUpdate
|
||||
BR2_PACKAGE_SWUPDATE=y
|
||||
BR2_PACKAGE_SWUPDATE_CONFIG="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/swupdate.config"
|
||||
BR2_PACKAGE_SWUPDATE_WEBSERVER=y
|
||||
BR2_PACKAGE_SWUPDATE_INSTALL_WEBSITE=y
|
||||
|
||||
# Custom swupdate-scripts package
|
||||
BR2_PACKAGE_SWUPDATE_SCRIPTS=y
|
||||
|
||||
# Required dependencies
|
||||
BR2_PACKAGE_LIBCURL=y
|
||||
BR2_PACKAGE_LIBCURL_OPENSSL=y
|
||||
BR2_PACKAGE_LIBCONFIG=y
|
||||
BR2_PACKAGE_LIBARCHIVE=y
|
||||
BR2_PACKAGE_JSON_C=y
|
||||
BR2_PACKAGE_LIBUBOOTENV=y
|
||||
BR2_PACKAGE_LIBUBOOTENV_TARGET=y
|
||||
|
||||
# Utilities
|
||||
BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y
|
||||
BR2_PACKAGE_XZ=y
|
||||
BR2_PACKAGE_KMOD=y
|
||||
BR2_PACKAGE_KMOD_TOOLS=y
|
||||
BR2_PACKAGE_UTIL_LINUX=y
|
||||
BR2_PACKAGE_UTIL_LINUX_LIBBLKID=y
|
||||
BR2_PACKAGE_E2FSPROGS=y
|
||||
BR2_PACKAGE_E2FSPROGS_RESIZE2FS=y
|
||||
|
||||
# Network
|
||||
BR2_SYSTEM_DHCP="eth0"
|
||||
BR2_PACKAGE_DHCPCD=y
|
||||
BR2_PACKAGE_ETHTOOL=y
|
||||
BR2_PACKAGE_DROPBEAR=y
|
||||
|
||||
# System
|
||||
BR2_TARGET_GENERIC_HOSTNAME="auracaster"
|
||||
BR2_TARGET_GENERIC_ISSUE="Welcome to Auracaster System"
|
||||
BR2_INIT_SYSTEMD=y
|
||||
BR2_SYSTEM_DEFAULT_PATH="/bin:/sbin:/usr/bin:/usr/sbin"
|
||||
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/rootfs_overlay"
|
||||
BR2_ROOTFS_USERS_TABLES="$(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/board/raspberrypi3_swupdate/users.txt"
|
||||
|
||||
# No duplicate needed - already defined above
|
||||
|
||||
# Host tools
|
||||
BR2_PACKAGE_HOST_DOSFSTOOLS=y
|
||||
BR2_PACKAGE_HOST_GENIMAGE=y
|
||||
BR2_PACKAGE_HOST_MTOOLS=y
|
||||
BR2_PACKAGE_HOST_GNUTLS=y
|
||||
BR2_PACKAGE_HOST_UBOOT_TOOLS=y
|
||||
109
example/create-update-package.sh
Executable file
109
example/create-update-package.sh
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to create SWUpdate update package for A/B system
|
||||
# This demonstrates the format of a SWUpdate package for A/B partitioning
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
BUILDROOT_DIR="../buildroot"
|
||||
OUTPUT_DIR="$BUILDROOT_DIR/output"
|
||||
BINARIES_DIR="$OUTPUT_DIR/images"
|
||||
ROOTFS_FILE="$BINARIES_DIR/rootfs.ext4"
|
||||
SWU_FILE="auracaster-update.swu"
|
||||
SW_VERSION="1.0.1"
|
||||
SW_DESCRIPTION="example/sw-description"
|
||||
|
||||
# Check if necessary files exist
|
||||
if [ ! -f "$ROOTFS_FILE" ]; then
|
||||
echo "Error: rootfs.ext4 not found at $ROOTFS_FILE"
|
||||
echo "You need to build the project first using:"
|
||||
echo "cd $BUILDROOT_DIR && make BR2_EXTERNAL=../auracaster-system auracaster_raspberrypi3_swupdate_defconfig && make"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create temporary directory
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
echo "Creating update package in $TEMP_DIR"
|
||||
|
||||
# Create sw-description file
|
||||
cat > $SW_DESCRIPTION << EOF
|
||||
software = {
|
||||
version = "$SW_VERSION";
|
||||
|
||||
raspberrypi3 = {
|
||||
hardware-compatibility: [ "1.0" ];
|
||||
|
||||
/* We have 2 systems, A and B */
|
||||
stable = {
|
||||
/* Selection based on U-Boot variable 'active_part' */
|
||||
/* If active_part == A, then use B for update */
|
||||
/* If active_part == B, then use A for update */
|
||||
|
||||
/* Update copy based on active_part variable */
|
||||
copy1 = {
|
||||
/* Install on the inactive partition */
|
||||
images: (
|
||||
{
|
||||
filename = "rootfs.ext4";
|
||||
device = "/dev/mmcblk0p\${inactive_part == "A" ? "2" : "3"}";
|
||||
type = "raw";
|
||||
}
|
||||
);
|
||||
|
||||
/* Update U-Boot environment to boot from the updated partition */
|
||||
uboot: (
|
||||
{
|
||||
name = "bootcount";
|
||||
value = "0";
|
||||
},
|
||||
{
|
||||
name = "upgrade_available";
|
||||
value = "1";
|
||||
},
|
||||
{
|
||||
name = "active_part";
|
||||
value = "\${inactive_part}";
|
||||
},
|
||||
{
|
||||
name = "active_root";
|
||||
value = "\${inactive_root}";
|
||||
},
|
||||
{
|
||||
name = "inactive_part";
|
||||
value = "\${active_part}";
|
||||
},
|
||||
{
|
||||
name = "inactive_root";
|
||||
value = "\${active_root}";
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
# Copy required files to temp directory
|
||||
cp $ROOTFS_FILE $TEMP_DIR/
|
||||
cp $SW_DESCRIPTION $TEMP_DIR/
|
||||
|
||||
# Create update package
|
||||
echo "Creating SWUpdate package $SWU_FILE"
|
||||
(cd $TEMP_DIR && \
|
||||
for i in sw-description rootfs.ext4; do
|
||||
echo $i;
|
||||
done | cpio -ov -H crc > ../$SWU_FILE)
|
||||
|
||||
# Clean up
|
||||
rm -rf $TEMP_DIR
|
||||
|
||||
echo "Update package created: $SWU_FILE"
|
||||
echo "To apply this update:"
|
||||
echo "1. Boot the Raspberry Pi with the SD card image"
|
||||
echo "2. Access the web interface at http://<raspberry-pi-ip>:8080"
|
||||
echo "3. Upload $SWU_FILE to update the inactive partition"
|
||||
echo "4. After update completes, reboot the device"
|
||||
echo "5. The device will boot from the updated partition"
|
||||
|
||||
exit 0
|
||||
2
external.desc
Normal file
2
external.desc
Normal file
@@ -0,0 +1,2 @@
|
||||
name: AURACASTER_SYSTEM
|
||||
desc: Auracaster System with SWUpdate A/B layout for Raspberry Pi 3
|
||||
2
external.mk
Normal file
2
external.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
# Include custom package makefiles
|
||||
include $(sort $(wildcard $(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/package/*/*.mk))
|
||||
169
flash_sdcard.sh
Executable file
169
flash_sdcard.sh
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to flash the Auracaster System image to an SD card
|
||||
# This script must be run with sudo privileges
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
BUILDROOT_DIR="../buildroot"
|
||||
IMAGE_FILE="$BUILDROOT_DIR/output/images/sdcard.img"
|
||||
AUTO_YES=false
|
||||
|
||||
# Parse command line arguments
|
||||
while getopts "y" opt; do
|
||||
case $opt in
|
||||
y)
|
||||
AUTO_YES=true
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if script is run as root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root (sudo)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if image exists
|
||||
if [ ! -f "$IMAGE_FILE" ]; then
|
||||
echo "Error: Image file not found at $IMAGE_FILE"
|
||||
echo "You need to build the project first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Find SD cards (both removable devices and mmcblk devices)
|
||||
echo "Looking for SD cards..."
|
||||
echo
|
||||
|
||||
# Get list of potential SD cards (both removable devices and mmcblk devices)
|
||||
SD_CARDS=$(lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | grep -v "loop" | grep -E '(1$|mmcblk)' | awk '{print $1}')
|
||||
SD_CARD_COUNT=$(echo "$SD_CARDS" | grep -v "^$" | wc -l)
|
||||
|
||||
if [ "$SD_CARD_COUNT" -eq 0 ]; then
|
||||
echo "No SD cards found. Please insert an SD card and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display available SD cards
|
||||
echo "Available SD cards:"
|
||||
echo
|
||||
lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | head -n 1
|
||||
lsblk -d -o NAME,SIZE,MODEL,VENDOR,TRAN,RM | grep -v "loop" | grep -E '(1$|mmcblk)'
|
||||
echo
|
||||
|
||||
# Safety check - get list of internal disks to avoid (exclude mmcblk devices from this check)
|
||||
INTERNAL_DISKS=$(lsblk -d -o NAME,RM | grep -E '0$' | grep -v "mmcblk" | awk '{print $1}')
|
||||
|
||||
# Select SD card
|
||||
DEVICE=""
|
||||
if [ "$SD_CARD_COUNT" -eq 1 ]; then
|
||||
DEVICE=$(echo "$SD_CARDS" | tr -d '[:space:]')
|
||||
echo "Found single SD card: /dev/$DEVICE"
|
||||
else
|
||||
echo "Multiple SD cards found. Please select which one to use:"
|
||||
select DEVICE in $SD_CARDS; do
|
||||
if [ -n "$DEVICE" ]; then
|
||||
break
|
||||
else
|
||||
echo "Invalid selection. Please try again."
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Safety check - ensure we're not flashing to an internal disk
|
||||
if echo "$INTERNAL_DISKS" | grep -q "$DEVICE"; then
|
||||
echo "ERROR: Selected device /dev/$DEVICE appears to be an internal disk!"
|
||||
echo "This script will only flash to removable devices or mmcblk devices for safety."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate device exists
|
||||
if [[ "$DEVICE" == mmcblk* ]]; then
|
||||
DEV_PATH="/dev/$DEVICE"
|
||||
else
|
||||
DEV_PATH="/dev/$DEVICE"
|
||||
fi
|
||||
|
||||
if [ ! -b "$DEV_PATH" ]; then
|
||||
echo "Error: Device $DEV_PATH does not exist or is not a block device."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Double-check with clear warning
|
||||
echo
|
||||
echo "You are about to erase ALL DATA on $DEV_PATH and write the Auracaster System image to it."
|
||||
echo "This operation cannot be undone."
|
||||
echo
|
||||
|
||||
# Check if pv is available for better progress display
|
||||
if command -v pv >/dev/null 2>&1; then
|
||||
# Get image size for pv
|
||||
IMAGE_SIZE=$(stat -c %s "$IMAGE_FILE")
|
||||
|
||||
# Show the command that will be executed with pv
|
||||
FLASH_COMMAND="pv -s $IMAGE_SIZE \"$IMAGE_FILE\" | dd of=\"$DEV_PATH\" bs=4M conv=fsync oflag=direct"
|
||||
echo "The following command will be executed (with progress bar):"
|
||||
echo "$FLASH_COMMAND"
|
||||
else
|
||||
# Fallback to dd with status=progress
|
||||
FLASH_COMMAND="dd if=\"$IMAGE_FILE\" of=\"$DEV_PATH\" bs=4M status=progress conv=fsync oflag=direct"
|
||||
echo "The following command will be executed:"
|
||||
echo "$FLASH_COMMAND"
|
||||
echo "For better progress visualization, consider installing 'pv' (Pipe Viewer)."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [ "$AUTO_YES" = true ]; then
|
||||
CONFIRM="y"
|
||||
echo "Auto-confirming with -y flag"
|
||||
else
|
||||
read -p "Are you ABSOLUTELY SURE you want to continue? (y/n): " CONFIRM
|
||||
|
||||
if [ "$CONFIRM" != "y" ]; then
|
||||
echo "Operation cancelled."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Unmount any partitions on the device
|
||||
echo "Unmounting any mounted partitions on $DEV_PATH..."
|
||||
if [[ "$DEVICE" == mmcblk* ]]; then
|
||||
for partition in $(lsblk -n -o NAME | grep "^$DEVICE"); do
|
||||
if [ "$partition" != "$DEVICE" ]; then
|
||||
umount "/dev/$partition" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
else
|
||||
for partition in $(lsblk -n -o NAME /dev/$DEVICE | grep -v "^$DEVICE$"); do
|
||||
umount "/dev/$partition" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
# Flash the image
|
||||
echo "Flashing image to $DEV_PATH..."
|
||||
echo "This may take several minutes. Please wait..."
|
||||
echo
|
||||
|
||||
# Execute the flashing command
|
||||
eval "$FLASH_COMMAND"
|
||||
|
||||
# Sync to ensure all writes are complete
|
||||
sync
|
||||
|
||||
echo
|
||||
echo "Flash complete!"
|
||||
echo
|
||||
|
||||
# Remind user to eject the card safely
|
||||
echo "You can now safely remove the SD card."
|
||||
echo "1. Insert the SD card into your Raspberry Pi 3"
|
||||
echo "2. Power on the device"
|
||||
echo "3. Access the SWUpdate web interface at http://<raspberry-pi-ip>:8080"
|
||||
echo
|
||||
|
||||
exit 0
|
||||
8
package/swupdate-scripts/Config.in
Normal file
8
package/swupdate-scripts/Config.in
Normal file
@@ -0,0 +1,8 @@
|
||||
config BR2_PACKAGE_SWUPDATE_SCRIPTS
|
||||
bool "swupdate-scripts"
|
||||
select BR2_PACKAGE_SWUPDATE
|
||||
help
|
||||
Custom scripts for SWUpdate A/B partitioning system.
|
||||
|
||||
Provides scripts to manage the A/B partition system and
|
||||
facilitate software updates.
|
||||
119
package/swupdate-scripts/files/custom.css
Normal file
119
package/swupdate-scripts/files/custom.css
Normal file
@@ -0,0 +1,119 @@
|
||||
/* Custom CSS for SWUpdate Web Interface */
|
||||
|
||||
body {
|
||||
font-family: 'Roboto', Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.upload-form {
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
margin: 20px auto;
|
||||
max-width: 600px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.upload-form h2 {
|
||||
color: #2c3e50;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
margin: 20px auto;
|
||||
max-width: 600px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
height: 20px;
|
||||
margin: 10px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar-inner {
|
||||
background-color: #27ae60;
|
||||
height: 100%;
|
||||
transition: width 0.3s ease-in-out;
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: #3498db;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
padding: 10px 15px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background-color: #27ae60;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background-color: #219955;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #e74c3c;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
|
||||
.system-info {
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
margin: 20px auto;
|
||||
max-width: 600px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.system-info h2 {
|
||||
color: #2c3e50;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
154
package/swupdate-scripts/files/custom.js
Normal file
154
package/swupdate-scripts/files/custom.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Custom JavaScript for SWUpdate Web Interface
|
||||
* Enhances the default web interface with additional functionality
|
||||
*/
|
||||
|
||||
// Wait for DOM to be fully loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Add custom header
|
||||
addHeader();
|
||||
|
||||
// Add system information section
|
||||
addSystemInfo();
|
||||
|
||||
// Enhance progress display
|
||||
enhanceProgressDisplay();
|
||||
|
||||
// Initialize update status polling
|
||||
initStatusPolling();
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds a custom header to the page
|
||||
*/
|
||||
function addHeader() {
|
||||
const header = document.createElement('div');
|
||||
header.className = 'header';
|
||||
header.innerHTML = '<h1>Auracaster System Update</h1>';
|
||||
|
||||
const body = document.body;
|
||||
body.insertBefore(header, body.firstChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds system information section to the page
|
||||
*/
|
||||
function addSystemInfo() {
|
||||
const systemInfo = document.createElement('div');
|
||||
systemInfo.className = 'system-info';
|
||||
systemInfo.innerHTML = `
|
||||
<h2>System Information</h2>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Device:</span>
|
||||
<span class="info-value">Raspberry Pi 3</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Active Partition:</span>
|
||||
<span class="info-value" id="active-partition">Loading...</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Current Version:</span>
|
||||
<span class="info-value" id="current-version">Loading...</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">Last Update:</span>
|
||||
<span class="info-value" id="last-update">Loading...</span>
|
||||
</div>
|
||||
<div class="actions" style="margin-top: 15px;">
|
||||
<button class="btn" id="refresh-info">Refresh</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Insert before the upload form
|
||||
const uploadForm = document.querySelector('form');
|
||||
if (uploadForm) {
|
||||
uploadForm.parentNode.insertBefore(systemInfo, uploadForm);
|
||||
} else {
|
||||
document.body.appendChild(systemInfo);
|
||||
}
|
||||
|
||||
// Add event listener for refresh button
|
||||
document.getElementById('refresh-info').addEventListener('click', fetchSystemInfo);
|
||||
|
||||
// Initial fetch of system info
|
||||
fetchSystemInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches system information via AJAX
|
||||
*/
|
||||
function fetchSystemInfo() {
|
||||
// In a real implementation, this would call an API endpoint
|
||||
// For now, we'll use dummy data that would typically come from swupdate-check.sh
|
||||
const activePartition = Math.random() > 0.5 ? 'A' : 'B';
|
||||
const version = '1.0.' + Math.floor(Math.random() * 10);
|
||||
const lastUpdate = new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toLocaleString();
|
||||
|
||||
document.getElementById('active-partition').textContent = activePartition;
|
||||
document.getElementById('current-version').textContent = version;
|
||||
document.getElementById('last-update').textContent = lastUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhances the progress display with better visuals
|
||||
*/
|
||||
function enhanceProgressDisplay() {
|
||||
// Find the progress container (assuming it exists in the default UI)
|
||||
const progressContainer = document.querySelector('.progress');
|
||||
|
||||
if (!progressContainer) return;
|
||||
|
||||
// Create enhanced progress container
|
||||
const enhancedProgress = document.createElement('div');
|
||||
enhancedProgress.className = 'progress-container';
|
||||
enhancedProgress.innerHTML = `
|
||||
<h2>Update Progress</h2>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-bar-inner" id="progress-bar"></div>
|
||||
</div>
|
||||
<div class="status" id="progress-status">Waiting for update...</div>
|
||||
`;
|
||||
|
||||
// Replace the original progress container
|
||||
progressContainer.parentNode.replaceChild(enhancedProgress, progressContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes polling for update status
|
||||
*/
|
||||
function initStatusPolling() {
|
||||
// In a real implementation, this would poll an API endpoint
|
||||
// For demonstration, we'll simulate progress updates
|
||||
let progress = 0;
|
||||
|
||||
const updateProgress = setInterval(() => {
|
||||
// This would normally only run during an active update
|
||||
// For demo purposes, it increments regardless
|
||||
if (progress < 100) {
|
||||
progress += Math.floor(Math.random() * 5);
|
||||
if (progress > 100) progress = 100;
|
||||
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const progressStatus = document.getElementById('progress-status');
|
||||
|
||||
if (progressBar) {
|
||||
progressBar.style.width = progress + '%';
|
||||
}
|
||||
|
||||
if (progressStatus) {
|
||||
if (progress < 30) {
|
||||
progressStatus.textContent = 'Downloading update...';
|
||||
} else if (progress < 60) {
|
||||
progressStatus.textContent = 'Verifying update...';
|
||||
} else if (progress < 90) {
|
||||
progressStatus.textContent = 'Installing to inactive partition...';
|
||||
} else if (progress < 100) {
|
||||
progressStatus.textContent = 'Finalizing update...';
|
||||
} else {
|
||||
progressStatus.textContent = 'Update complete! Reboot to apply.';
|
||||
clearInterval(updateProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
40
package/swupdate-scripts/files/handlers.conf
Normal file
40
package/swupdate-scripts/files/handlers.conf
Normal file
@@ -0,0 +1,40 @@
|
||||
/* SWUpdate handlers configuration */
|
||||
|
||||
/* Enable raw partition handler */
|
||||
raw: {
|
||||
/* Partitions that can be updated */
|
||||
partitions = (
|
||||
{
|
||||
/* Inactive partition will be updated */
|
||||
type = "ubipartition";
|
||||
name = "inactive";
|
||||
|
||||
/* This is a key-value substitution */
|
||||
/* Will be replaced with the actual inactive partition */
|
||||
device = "${inactive_part}";
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/* Enable U-Boot environment handler */
|
||||
bootenv: {
|
||||
/* U-Boot environment variables to update */
|
||||
bootloader = {
|
||||
/* Where the U-Boot environment is stored */
|
||||
environment = {
|
||||
/* DeviceA = PART, DeviceB = FILE */
|
||||
device = "/dev/mmcblk0p1";
|
||||
file = "uboot-env.img";
|
||||
};
|
||||
|
||||
/* Variables to set after successful update */
|
||||
set-variables = (
|
||||
{name = "bootcount"; value = "0";},
|
||||
{name = "upgrade_available"; value = "1";},
|
||||
{name = "active_part"; value = "${inactive_part}";},
|
||||
{name = "active_root"; value = "${inactive_root}";},
|
||||
{name = "inactive_part"; value = "${active_part}";},
|
||||
{name = "inactive_root"; value = "${active_root}";}
|
||||
);
|
||||
};
|
||||
};
|
||||
110
package/swupdate-scripts/files/swupdate-ab-helper.sh
Executable file
110
package/swupdate-scripts/files/swupdate-ab-helper.sh
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/bin/sh
|
||||
# A/B partition management helper for SWUpdate
|
||||
|
||||
# Print usage
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTION]"
|
||||
echo "Manage A/B partitioning system for SWUpdate"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -s, --status Show current partition status"
|
||||
echo " -t, --toggle Toggle active/inactive partitions"
|
||||
echo " -c, --commit Commit current boot (reset bootcount)"
|
||||
echo " -r, --reboot Reboot to apply changes"
|
||||
echo " -h, --help Show this help message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Show current status
|
||||
show_status() {
|
||||
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
|
||||
INACTIVE_PART=$(fw_printenv -n inactive_part 2>/dev/null || echo "Unknown")
|
||||
BOOTCOUNT=$(fw_printenv -n bootcount 2>/dev/null || echo "Unknown")
|
||||
BOOTLIMIT=$(fw_printenv -n bootlimit 2>/dev/null || echo "Unknown")
|
||||
|
||||
echo "A/B Partition Status:"
|
||||
echo " Active partition: $ACTIVE_PART (/dev/mmcblk0p$([ "$ACTIVE_PART" = "A" ] && echo "2" || echo "3"))"
|
||||
echo " Inactive partition: $INACTIVE_PART (/dev/mmcblk0p$([ "$INACTIVE_PART" = "A" ] && echo "2" || echo "3"))"
|
||||
echo " Boot count: $BOOTCOUNT/$BOOTLIMIT"
|
||||
|
||||
# Check if an update is pending
|
||||
if [ -e /tmp/swupdate.done ]; then
|
||||
echo " Update status: Completed, pending reboot"
|
||||
else
|
||||
echo " Update status: No recent update"
|
||||
fi
|
||||
}
|
||||
|
||||
# Toggle active/inactive partitions
|
||||
toggle_partitions() {
|
||||
ACTIVE_PART=$(fw_printenv -n active_part)
|
||||
INACTIVE_PART=$(fw_printenv -n inactive_part)
|
||||
|
||||
if [ "$ACTIVE_PART" = "A" ]; then
|
||||
NEW_ACTIVE="B"
|
||||
NEW_INACTIVE="A"
|
||||
NEW_ACTIVE_ROOT="/dev/mmcblk0p3"
|
||||
NEW_INACTIVE_ROOT="/dev/mmcblk0p2"
|
||||
else
|
||||
NEW_ACTIVE="A"
|
||||
NEW_INACTIVE="B"
|
||||
NEW_ACTIVE_ROOT="/dev/mmcblk0p2"
|
||||
NEW_INACTIVE_ROOT="/dev/mmcblk0p3"
|
||||
fi
|
||||
|
||||
echo "Switching active partition from $ACTIVE_PART to $NEW_ACTIVE"
|
||||
|
||||
fw_setenv active_part "$NEW_ACTIVE"
|
||||
fw_setenv inactive_part "$NEW_INACTIVE"
|
||||
fw_setenv active_root "$NEW_ACTIVE_ROOT"
|
||||
fw_setenv inactive_root "$NEW_INACTIVE_ROOT"
|
||||
fw_setenv bootcount 0
|
||||
|
||||
echo "Partition switch complete. Reboot to apply changes."
|
||||
}
|
||||
|
||||
# Commit current boot (reset bootcount)
|
||||
commit_boot() {
|
||||
echo "Committing current boot by resetting bootcount"
|
||||
fw_setenv bootcount 0
|
||||
echo "Bootcount reset to 0"
|
||||
}
|
||||
|
||||
# Reboot system
|
||||
reboot_system() {
|
||||
echo "Rebooting system..."
|
||||
sync
|
||||
reboot
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-s|--status)
|
||||
show_status
|
||||
;;
|
||||
-t|--toggle)
|
||||
toggle_partitions
|
||||
;;
|
||||
-c|--commit)
|
||||
commit_boot
|
||||
;;
|
||||
-r|--reboot)
|
||||
reboot_system
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
exit 0
|
||||
69
package/swupdate-scripts/files/swupdate-check.sh
Executable file
69
package/swupdate-scripts/files/swupdate-check.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/sh
|
||||
# Helper script to check for updates and system status
|
||||
|
||||
# Configuration
|
||||
UPDATE_SERVER=""
|
||||
BOARD_NAME="raspberrypi3"
|
||||
SW_VERSION=$(cat /etc/sw-version 2>/dev/null || echo "1.0.0")
|
||||
|
||||
# Get current system state
|
||||
get_current_status() {
|
||||
# Get active partition
|
||||
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
|
||||
echo "Active partition: $ACTIVE_PART"
|
||||
|
||||
# Get inactive partition
|
||||
INACTIVE_PART=$(fw_printenv -n inactive_part 2>/dev/null || echo "Unknown")
|
||||
echo "Inactive partition: $INACTIVE_PART"
|
||||
|
||||
# Get boot count
|
||||
BOOT_COUNT=$(fw_printenv -n bootcount 2>/dev/null || echo "Unknown")
|
||||
echo "Boot count: $BOOT_COUNT"
|
||||
|
||||
# Check if system was recently updated
|
||||
if [ -e /tmp/swupdate.done ]; then
|
||||
echo "System was updated"
|
||||
UPDATED=1
|
||||
else
|
||||
echo "No recent update"
|
||||
UPDATED=0
|
||||
fi
|
||||
|
||||
# Check if there's an update available (if server is configured)
|
||||
if [ -n "$UPDATE_SERVER" ]; then
|
||||
echo "Checking for updates from $UPDATE_SERVER..."
|
||||
# Simple curl check - in production, this would be more robust
|
||||
if curl -s -f "$UPDATE_SERVER/api/check?board=$BOARD_NAME&version=$SW_VERSION" >/dev/null; then
|
||||
echo "Update available"
|
||||
UPDATE_AVAILABLE=1
|
||||
else
|
||||
echo "No update available"
|
||||
UPDATE_AVAILABLE=0
|
||||
fi
|
||||
else
|
||||
echo "No update server configured"
|
||||
UPDATE_AVAILABLE=0
|
||||
fi
|
||||
}
|
||||
|
||||
# Reset update status
|
||||
reset_update_status() {
|
||||
echo "Resetting update status"
|
||||
rm -f /tmp/swupdate.done
|
||||
}
|
||||
|
||||
# Main
|
||||
case "$1" in
|
||||
status)
|
||||
get_current_status
|
||||
;;
|
||||
reset)
|
||||
reset_update_status
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {status|reset}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
62
package/swupdate-scripts/files/swupdate-progress.sh
Executable file
62
package/swupdate-scripts/files/swupdate-progress.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
# Monitor progress of SWUpdate and report it
|
||||
|
||||
TMPDIR="/tmp"
|
||||
FIFO="$TMPDIR/swupdate-progress"
|
||||
|
||||
# Create FIFO if it doesn't exist
|
||||
if [ ! -e "$FIFO" ]; then
|
||||
mkfifo "$FIFO"
|
||||
fi
|
||||
|
||||
# If no arguments, print usage
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 <command>"
|
||||
echo "Commands:"
|
||||
echo " monitor - Monitor progress of an update"
|
||||
echo " status - Show current status"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
monitor)
|
||||
# Start monitoring FIFO
|
||||
while true; do
|
||||
if read line <"$FIFO"; then
|
||||
echo "$line"
|
||||
# Extract progress percentage
|
||||
PROGRESS=$(echo "$line" | grep -o '[0-9]*%' | grep -o '[0-9]*')
|
||||
if [ -n "$PROGRESS" ] && [ "$PROGRESS" = "100" ]; then
|
||||
echo "Update complete!"
|
||||
break
|
||||
fi
|
||||
# Check for error messages
|
||||
if echo "$line" | grep -q "FAILURE"; then
|
||||
echo "Update failed!"
|
||||
break
|
||||
fi
|
||||
else
|
||||
# FIFO closed
|
||||
echo "Connection closed"
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
status)
|
||||
# Show which partition is active
|
||||
ACTIVE_PART=$(fw_printenv -n active_part 2>/dev/null || echo "Unknown")
|
||||
echo "Active partition: $ACTIVE_PART"
|
||||
# Show update status if available
|
||||
if [ -e /tmp/swupdate.done ]; then
|
||||
echo "Last update: Successful"
|
||||
else
|
||||
echo "No recent update"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
21
package/swupdate-scripts/swupdate-scripts.mk
Normal file
21
package/swupdate-scripts/swupdate-scripts.mk
Normal file
@@ -0,0 +1,21 @@
|
||||
################################################################################
|
||||
#
|
||||
# swupdate-scripts
|
||||
#
|
||||
################################################################################
|
||||
|
||||
SWUPDATE_SCRIPTS_VERSION = 1.0
|
||||
SWUPDATE_SCRIPTS_SITE = $(BR2_EXTERNAL_AURACASTER_SYSTEM_PATH)/package/swupdate-scripts/files
|
||||
SWUPDATE_SCRIPTS_SITE_METHOD = local
|
||||
|
||||
define SWUPDATE_SCRIPTS_INSTALL_TARGET_CMDS
|
||||
$(INSTALL) -D -m 0755 $(@D)/swupdate-progress.sh $(TARGET_DIR)/usr/bin/swupdate-progress
|
||||
$(INSTALL) -D -m 0755 $(@D)/swupdate-check.sh $(TARGET_DIR)/usr/bin/swupdate-check
|
||||
$(INSTALL) -D -m 0755 $(@D)/swupdate-ab-helper.sh $(TARGET_DIR)/usr/bin/swupdate-ab-helper
|
||||
$(INSTALL) -D -m 0644 $(@D)/handlers.conf $(TARGET_DIR)/etc/swupdate/conf.d/handlers.conf
|
||||
mkdir -p $(TARGET_DIR)/var/www/swupdate/custom
|
||||
$(INSTALL) -D -m 0644 $(@D)/custom.js $(TARGET_DIR)/var/www/swupdate/custom/custom.js
|
||||
$(INSTALL) -D -m 0644 $(@D)/custom.css $(TARGET_DIR)/var/www/swupdate/custom/custom.css
|
||||
endef
|
||||
|
||||
$(eval $(generic-package))
|
||||
Reference in New Issue
Block a user