new file mode 100644
@@ -0,0 +1,64 @@
+setenv tmp_update
+if test "z$force_rescue" != "z"; then
+ echo "Boot on rescue partition..."
+ run part_r_cmd
+ echo "System cannot boot!"
+ exit 1
+fi
+if test "z$max_attempts" = "z"; then
+ echo "Set maximum boot attempts to default (=3)"
+ setenv max_attempts 3
+fi
+for i in $boot_seq;
+do
+ setenv tmp setenv tmp \$part_${i}_flag
+ run tmp
+ if test "z$tmp" != "z"; then
+ if test $tmp = "OK" -o $tmp = "UPDATE"; then
+ if test $tmp = "UPDATE"; then
+ setenv tmp_update 1
+ echo "Partition $i is an update"
+ fi
+ if test "z$tmp_update" != "z"; then
+ setenv tmp setenv tmp \$part_${i}_count
+ run tmp
+ if test "z$tmp" != "z"; then
+ echo "Try to boot on partition $i..."
+ else
+ echo "Reset counter and try to boot on partition $i..."
+ setenv "part_${i}_count" 0
+ setenv tmp 0
+ fi
+ while test $tmp -lt $max_attempts;
+ do
+ setexpr tmp $tmp + 1
+ echo " -> Attempt $tmp on partition $i"
+ setenv "part_${i}_count" $tmp
+ setenv tmp
+ setenv tmp_update
+ saveenv
+ run part_${i}_cmd
+ echo " -> Boot failed!"
+ done
+ if test $tmp -eq $max_attempts; then
+ setenv "part_${i}_count" 254
+ setenv tmp
+ setenv tmp_update
+ saveenv
+ fi
+ echo "Partition $i failed to boot!"
+ else
+ echo "Boot on partition $i..."
+ run part_${i}_cmd
+ echo " -> Boot failed on partition $i!"
+ fi
+ fi
+ else
+ echo "No flag for partition $i"
+ fi
+done
+echo "Boot on partitions failed! Boot on rescue partition..."
+run part_r_cmd
+echo "System cannot boot!"
+exit 1
+
Linux script:
new file mode 100755
@@ -0,0 +1,523 @@
+#!/bin/sh
+
+# Script Configuration
+SETENV_CMD="fw_setenv" # Path to fw_setenv binary
+PRINTENV_CMD="fw_printenv" # Path to fw_printenv binary
+TMP_FILE="/tmp/smart_boot.tmp" # Temporary file used for env writting
+# Entry name in env
+PART_FLAG_NAME="part_\${i}_flag" # Partition 'i' flag
+PART_CMD_NAME="part_\${i}_cmd" # Boot command for partition 'i'
+PART_COUNT_NAME="part_\${i}_count" # Boot ttempts number for partition 'i'
+PART_TEXT_NAME="part_\${i}_text" # Partition 'i' description text
+PART_NB_NAME="part_nb" # Total partition number
+BOOT_SEQ_NAME="boot_seq" # Boot sequence (ordrer = "first second ... last")
+FORCE_RESCUE_NAME="force_rescue" # Boot on rescue flag
+MAX_ATTEMPT_NAME="max_attempts" # Number of attempts before switching to previous partition
+BOOT_PART_NAME="boot_part" # Name of param appended to linux boot command line. This param contain booted partition index
+
+# Print usage
+print_usage () {
+ echo "Usage: ./smart_boot TASK PARMAS" 1>&2
+ echo "List of tasks (=TASK) available:" 1>&2
+ echo " print: Print boot configuration." 1>&2
+ echo " allocate: Allocate an empty/bad partition or " 1>&2
+ echo " oldest partition to install an update." 1>&2
+ echo " update: Mark the allocated parititon with UPDATED flag. " 1>&2
+ echo " Needs to call 'allocate' before." 1>&2
+ echo " validate: Validate a partition with UPDATED flag." 1>&2
+ echo " invalidate: Invalidate a partition with UPDATED flag." 1>&2
+ echo " partition: Return theorical booted partition." 1>&2
+ echo " real-partition: Return real booted partition (from linux cmdline)." 1>&2
+ echo " clean: Corrects boot configuration." 1>&2
+ echo " force-rescue: Force system to boot on rescue partition." 1>&2
+ echo " unforce-rescue: Unforce system to boot on rescue partition." 1>&2
+ echo " status: Return a status number of boot case." 1>&2
+ echo "Manual informations:" 1>&2
+ echo " get-flag PART: Get flag for partition PART." 1>&2
+ echo " get-text PART: Get text description for partition PART." 1>&2
+ echo " get-count PART: Get boot attempt count for partition PART." 1>&2
+ echo " get-boot-seq: Get boot sequence." 1>&2
+ echo "Manual modification:" 1>&2
+ echo " set-flag PART FLAG: Set flag with FLAG for partition PART." 1>&2
+ echo " set-text PART TXT: Set text description with TXT for partition PART." 1>&2
+ echo " set-count PART CNT: Set boot attempt count to CNT for partition PART." 1>&2
+ echo " set-boot-seq SEQ: Set boot sequence with SEQ." 1>&2
+ return
+}
+
+# Verify number of arguments and print usage if lower than 1
+if [ $# -lt 1 ]; then
+ print_usage
+ exit 1
+fi
+
+# Get arguments
+task=$1
+
+# Get number of partition
+part_nb=$($PRINTENV_CMD -n $PART_NB_NAME 2>/dev/null)
+if [ $part_nb -lt 2 ]; then
+ echo "Bad number of partition: you need at least 2 partitions!" 1>&2
+ exit 1
+fi
+
+# Count entries in boot_seq
+boot_seq_count=0
+boot_seq="$($PRINTENV_CMD -n $BOOT_SEQ_NAME 2>/dev/null)"
+if [ $? -eq 0 ]; then
+ boot_seq_count=$(echo $boot_seq | wc -w)
+fi
+
+# Get maximum boot attempts
+nb_attempt="$($PRINTENV_CMD -n $MAX_ATTEMPT_NAME 2>/dev/null)"
+if [ $? -ne 0 ]; then
+ nb_attempt=3
+ echo "No maximum boot attempts in environment: set with default value (3)!" 1>&2
+fi
+
+# Switch case for each tasks (=TASK)
+case $task in
+ # Print boot configuration
+ print )
+ # Print flags for each partition
+ for i in $(seq 1 $part_nb)
+ do
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ echo "Partition $i: $flag (boot attempts: $count)"
+ txt=$($PRINTENV_CMD -n $(eval echo $PART_TEXT_NAME) 2>/dev/null)
+ if [ $? -eq 0 ]; then
+ echo " ($txt)"
+ fi
+ done
+ # Print boot sequence
+ echo "Boot sequence: $($PRINTENV_CMD -n $(eval echo $BOOT_SEQ_NAME) 2>/dev/null)"
+ ;;
+ # Allocate an empty/bad partition or oldest partition to install an update.
+ allocate )
+ i=0
+ # If all partitions are used, pick the oldest
+ if [ $boot_seq_count -eq $part_nb ]; then
+ # Verify flag of first partition
+ i=${boot_seq%% *}
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ "$flag" = "OK" ]; then
+ # Get last partition in boot seq
+ i=$(echo $boot_seq | awk '{print $'$part_nb'}')
+ fi
+ # Else search for an allocated partition or a partition unavailable in boot sequence
+ else
+ part=0
+ for i in $(seq 1 $part_nb)
+ do
+ #If partition isn't in boot sequenc
+ if [ "${boot_seq/$i/}" = "$boot_seq" ]; then
+ # Get partition flag
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $flag = "LOCK" ]; then
+ echo "Partition $i is already allocated!" 1>&2
+ echo $i
+ exit 0
+ else
+ part=$i
+ break
+ fi
+ fi
+ done
+ i=$part
+ fi
+
+ # Change flag of partition with 'LOCK' and remove partition from boot sequence
+ if [ $i -gt 0 ]; then
+ echo "$(eval echo $PART_FLAG_NAME) LOCK" > $TMP_FILE
+ echo "$BOOT_SEQ_NAME ${boot_seq/$i/}" >> $TMP_FILE
+ $SETENV_CMD -s $TMP_FILE
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!"
+ exit 1
+ fi
+ echo "Partition $i has been allocated." 1>&2
+ echo $i
+ else
+ echo "Can't allocate a parititon!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Mark the allocated parititon with UPDATED flag. Needs to call 'allocate' before.
+ update )
+ # Search allocated partition
+ part=0
+ for i in $(seq 1 $part_nb)
+ do
+ #If partition isn't in boot sequenc
+ if [ "${boot_seq/$i/}" = "$boot_seq" ]; then
+ # Get partition flag
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ "z$flag" != "z" -a $flag = "LOCK" ]; then
+ part=$i
+ break
+ fi
+ fi
+ done
+ if [ $part -gt 0 ]; then
+ i=$part
+ # Set partition flag to UPDATE and add partition to boot sequence
+ echo "$(eval echo $PART_FLAG_NAME) UPDATE" > $TMP_FILE
+ echo "$BOOT_SEQ_NAME $i $boot_seq" >> $TMP_FILE
+ if [ $# -gt 1 ]; then
+ echo "$(eval echo $PART_TEXT_NAME) $2" >> $TMP_FILE
+ else
+ echo "$(eval echo $PART_TEXT_NAME)" >> $TMP_FILE
+ fi
+ for i in $(seq 1 $part_nb)
+ do
+ echo "$(eval echo $PART_COUNT_NAME) 0" >> $TMP_FILE
+ done
+ $SETENV_CMD -s $TMP_FILE
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!"
+ exit 1
+ fi
+ echo "Partition $part has been marked as an update." 1>&2
+ echo $part
+ else
+ echo "Please allocate a partition before calling 'update'!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Validate a partition with UPDATED flag.
+ validate )
+ # Get flag of first partition of boot sequence
+ if [ $boot_seq_count -lt 1 ]; then
+ echo "No partitions in boot sequence!" 1>&2
+ exit 1
+ fi
+ i=${boot_seq%% *}
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $? -eq 0 -a $flag = "UPDATE" ]; then
+ # Verify number of attempts
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ if [ $? -ne 0 -o $count -gt $nb_attempt ]; then
+ echo "Partition $i has failed to boot: you can't mark it as good! Please use invalidate or clean." 1>&2
+ exit 1
+ fi
+ # Set flag to OK
+ $SETENV_CMD "$(eval echo $PART_FLAG_NAME)" "OK"
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!"
+ exit 1
+ fi
+ echo "Partition $i has been marked as ok. Now system will boot on this partition." 1>&2
+ echo $i
+ else
+ echo "The first partition is not an update!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Invalidate a partition with UPDATED flag.
+ invalidate )
+ # Get flag of first partition of boot sequence
+ if [ $boot_seq_count -lt 1 ]; then
+ echo "No partitions in boot sequence!" 1>&2
+ exit 1
+ fi
+ i=${boot_seq%% *}
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $? -eq 0 -a $flag = "UPDATE" ]; then
+ # Set flag to BAD and remove partition from boot sequence
+ echo "$(eval echo $PART_FLAG_NAME) BAD" > $TMP_FILE
+ echo "$BOOT_SEQ_NAME ${boot_seq#* }" >> $TMP_FILE
+ $SETENV_CMD -s $TMP_FILE
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!"
+ exit 1
+ fi
+ echo "Partition $i has been marked as bad." 1>&2
+ echo $i
+ else
+ echo "The first partition is not an update!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Return theorical booted partition.
+ partition )
+ update=0
+ force=$($PRINTENV_CMD -n $(eval echo $FORCE_RESCUE_NAME) 2>/dev/null)
+ if [ $? -eq 0 ]; then
+ echo "Booted on rescue partition (forced)." 1>&2
+ echo 0
+ exit 0
+ fi
+ for i in $boot_seq
+ do
+ # Get flag and boot attempt count for partition
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ if [ $count -le $nb_attempt ]; then
+ echo "Booted on partition $i" 1>&2
+ echo $i
+ exit 0
+ fi
+ done
+ echo "Booted on rescue partition" 1>&2
+ echo 0
+ ;;
+ # Return real booted partition.
+ real-partition )
+ boot_part="$(sed -n 's|.*'$BOOT_PART_NAME'=\([^ ]\+\).*|\1|p' < /proc/cmdline)"
+ if [ "z$boot_part" != "z" ]; then
+ if [ $boot_part = "r" ]; then
+ echo "Booted on rescue partition" 1>&2
+ echo 0
+ else
+ echo "Booted on partition $boot_part" 1>&2
+ echo $boot_part
+ fi
+ else
+ echo "No $BOOT_PART_NAME in kernel command line!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Fix on boot configuration.
+ clean )
+ update=0
+ echo -n "" > $TMP_FILE
+ for i in $(seq 1 $part_nb)
+ do
+ #If partition is in boot sequenc
+ if [ "${boot_seq/$i/}" != "$boot_seq" ]; then
+ # Verify flag
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $? -ne 0 ]; then
+ # Remove partition from boot sequence and set flag to NONE
+ echo "$(eval echo $PART_FLAG_NAME) NONE" >> $TMP_FILE
+ echo "$(eval echo $PART_TEXT_NAME)" >> $TMP_FILE
+ boot_seq=${boot_seq/$i/}
+ else
+ # Verify if it is an update or a good partition
+ if [ "$flag" != "OK" -a "$flag" != "UPDATE" ]; then
+ # Set partition as NONE and remove it from boot sequence
+ echo "$(eval echo $PART_FLAG_NAME) NONE" >> $TMP_FILE
+ echo "$(eval echo $PART_TEXT_NAME)" >> $TMP_FILE
+ boot_seq=${boot_seq/$i/}
+ else
+ # Verify if it is an update parition
+ if [ $flag = "UPDATE" ]; then
+ update=1
+ fi
+ # If we are in an update case, verify boot attempts
+ if [ $update -eq 1 ]; then
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ if [ $? -ne 0 -o $count -gt $nb_attempt ]; then
+ # Set partition as BAD and remove it from boot sequence
+ echo "$(eval echo $PART_FLAG_NAME) BAD" >> $TMP_FILE
+ boot_seq=${boot_seq/$i/}
+ else
+ #Set partition as OK
+ if [ $count -gt 0 ]; then
+ echo "$(eval echo $PART_FLAG_NAME) OK" >> $TMP_FILE
+ elif [ "$flag" = "UPDATE" ]; then
+ echo "$(eval echo $PART_FLAG_NAME) NONE" >> $TMP_FILE
+ echo "$(eval echo $PART_TEXT_NAME)" >> $TMP_FILE
+ boot_seq=${boot_seq/$i/}
+ fi
+ fi
+ fi
+ fi
+ # Reset boot attempt count
+ echo "$(eval echo $PART_COUNT_NAME) 0" >> $TMP_FILE
+ fi
+ else
+ # Set flag as NONE and boot attempt to 0
+ echo "$(eval echo $PART_FLAG_NAME) NONE" >> $TMP_FILE
+ echo "$(eval echo $PART_TEXT_NAME)" >> $TMP_FILE
+ echo "$(eval echo $PART_COUNT_NAME) 0" >> $TMP_FILE
+ fi
+ done
+ echo "$BOOT_SEQ_NAME $boot_seq" >> $TMP_FILE
+ $SETENV_CMD -s $TMP_FILE
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Force to boot on rescue partition.
+ force-rescue )
+ $SETENV_CMD $FORCE_RESCUE_NAME "1"
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Unforce boot on rescue partition.
+ unforce-rescue )
+ $SETENV_CMD $FORCE_RESCUE_NAME ""
+ if [ $? -ne 0 ]; then
+ echo "Failed to write in Environment!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Return a number for boot status
+ status )
+ echo "Code meanings:" 1>&2
+ echo " -> 0: Boot on normal partition." 1>&2
+ echo " -> 1: Boot on updated partition (needs to be validated)." 1>&2
+ echo " -> 2: Boot on normal partition after boot failure on updated partition." 1>&2
+ echo " -> 3: Boot on rescue partition after multiple boot failure." 1>&2
+ echo " -> 4: Boot on rescue partition." 1>&2
+ echo " -> 5: Forced boot on rescue partition." 1>&2
+ if $PRINTENV_CMD "$FORCE_RESCUE_NAME" 2>/dev/null; then
+ echo "Forced boot on rescue partition." 1>&2
+ echo "5"
+ else
+ if [ $boot_seq_count -eq 0 ]; then
+ echo "Boot on rescue partition." 1>&2
+ echo "4"
+ else
+ update=0
+ for i in $boot_seq
+ do
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $? -eq 0 -a $flag = "UPDATE" ]; then
+ update=1
+ fi
+ if [ $update -eq 1 ]; then
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ if [ $? -eq 0 -a $count -le $nb_attempt ]; then
+ if [ $flag = "OK" ]; then
+ echo "Boot on normal partition after boot failure on updated partition." 1>&2
+ echo "2"
+ exit 0
+ else
+ echo "Boot on updated partition (needs to be validated)." 1>&2
+ echo "1"
+ exit 0
+ fi
+ fi
+ else
+ echo "Boot on normal partition." 1>&2
+ echo "0"
+ exit 0
+ fi
+ done
+ echo "Boot on rescue partition after multiple boot failure." 1>&2
+ echo "3"
+ fi
+ fi
+ ;;
+ # Get partition flag
+ get-flag )
+ if [ $# -ge 2 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ flag=$($PRINTENV_CMD -n $(eval echo $PART_FLAG_NAME) 2>/dev/null)
+ if [ $? -eq 0 ]; then
+ echo "$flag"
+ else
+ echo "Flag partition not defined!" 1>&2
+ exit 1
+ fi
+ else
+ echo "Please specify a correct partition!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Get partition text description
+ get-text )
+ if [ $# -ge 2 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ text=$($PRINTENV_CMD -n $(eval echo $PART_TEXT_NAME) 2>/dev/null)
+ if [ $? -eq 0 ]; then
+ echo "$text"
+ else
+ echo "Flag partition not defined!" 1>&2
+ exit 1
+ fi
+ else
+ echo "Please specify a correct partition!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Get boot attempt count of a partition
+ get-count )
+ if [ $# -ge 2 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ count=$($PRINTENV_CMD -n $(eval echo $PART_COUNT_NAME) 2>/dev/null)
+ if [ $? -eq 0 ]; then
+ echo "$count"
+ else
+ echo "Flag partition not defined!" 1>&2
+ exit 1
+ fi
+ else
+ echo "Please specify a correct partition!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Get boot sequence
+ get-boot-seq )
+ echo "$($PRINTENV_CMD -n $BOOT_SEQ_NAME 2>/dev/null)"
+ ;;
+ # Set a partition flag
+ set-flag )
+ if [ $# -ge 3 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ $SETENV_CMD "$(eval echo $PART_FLAG_NAME)" "$3"
+ echo "Flag of partition $i updated!" 1>&2
+ else
+ echo "Please specify a partition and a flag to set!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Set a partition text description
+ set-text )
+ if [ $# -ge 3 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ $SETENV_CMD "$(eval echo $PART_TEXT_NAME)" "$3"
+ echo "Text description of partition $i updated!" 1>&2
+ else
+ echo "Please specify a partition and a text to set!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Set boot attempt count of a partition
+ set-count )
+ if [ $# -ge 3 -a $2 -le $part_nb -a $2 -ne 0 ]; then
+ i=$2
+ $SETENV_CMD "$(eval echo $PART_COUNT_NAME)" "$3"
+ echo "Boot attempt count of partition $i updated!" 1>&2
+ else
+ echo "Please specify a partition and a count to set!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Set boot sequence
+ set-boot-seq )
+ if [ $# -ge 2 ]; then
+ # Verify sequence
+ for i in $2
+ do
+ if [ $i -le 0 -o $i -gt $part_nb ]; then
+ echo "Bad boot sequence!" 1>&2
+ exit 1
+ fi
+ done
+ $SETENV_CMD "$BOOT_SEQ_NAME" "$2"
+ echo "Boot sequence changed." 1>&2
+ else
+ echo "Please specify a boot sequence!" 1>&2
+ exit 1
+ fi
+ ;;
+ # Print usage message.
+ help )
+ print_usage
+ ;;
+ # Unknown task
+ * )
+ print_usage
+ exit 1
+ ;;
+esac
+
+exit 0
+