summaryrefslogtreecommitdiff
path: root/files/common
diff options
context:
space:
mode:
Diffstat (limited to 'files/common')
-rw-r--r--files/common/etc/fsm/update/common.sh36
-rw-r--r--files/common/etc/fsm/update/initial_state1
-rwxr-xr-xfiles/common/etc/fsm/update/trans/default.enter5
-rwxr-xr-xfiles/common/etc/fsm/update/trans/scheduled-applying.trans6
-rwxr-xr-xfiles/common/etc/fsm/update/trans/scheduled.enter9
-rwxr-xr-xfiles/common/etc/fsm/update/trans/scheduled.leave9
-rwxr-xr-xfiles/common/etc/fsm/update/watch/default72
7 files changed, 138 insertions, 0 deletions
diff --git a/files/common/etc/fsm/update/common.sh b/files/common/etc/fsm/update/common.sh
new file mode 100644
index 0000000..8218dd5
--- /dev/null
+++ b/files/common/etc/fsm/update/common.sh
@@ -0,0 +1,36 @@
+Tbl=/tmp/p2ptbl/update
+TblIf=br-mesh
+FwDir=/tmp/firmware
+
+# updates global state using current internal state; implicit
+# definition of the table format
+GS_update () {
+ p2ptbl update $Tbl "$NodeId" "$CurFw\t$TargetFw\t$TargetTime\t$AckTime" $TblIf
+}
+
+# assemble internal state
+CurState=$1
+CurTime=$(date +%s)
+NodeId=$(cat /proc/sys/kernel/random/boot_id) # TODO: replace with stable machine id
+CurFw="$(cat /etc/firmware)"
+[ -n "$NodeId" -a -n "$CurFw" ]
+
+# get current global state from p2ptable
+p2ptbl init $Tbl
+GS=$(p2ptbl get $Tbl $NodeId)
+if [ -n "$GS" ]; then
+ GSCurFw=$( echo "$GS" | cut -f1)
+ TargetFw=$( echo "$GS" | cut -f2)
+ TargetTime=$(echo "$GS" | cut -f3)
+ AckTime=$( echo "$GS" | cut -f4)
+ # update stale firmware entries .. should only happen after manual
+ # edit of /etc/firmware
+ [ "$CurFw" == "$GSCurFw" ] || GS_update
+else
+ # no entry exists -> create one
+ TargetFw=""
+ TargetTime=""
+ AckTime=""
+ GS_update
+fi
+FwDst=$FwDir/$TargetFw
diff --git a/files/common/etc/fsm/update/initial_state b/files/common/etc/fsm/update/initial_state
new file mode 100644
index 0000000..5a5e41c
--- /dev/null
+++ b/files/common/etc/fsm/update/initial_state
@@ -0,0 +1 @@
+idle
diff --git a/files/common/etc/fsm/update/trans/default.enter b/files/common/etc/fsm/update/trans/default.enter
new file mode 100755
index 0000000..ffdb026
--- /dev/null
+++ b/files/common/etc/fsm/update/trans/default.enter
@@ -0,0 +1,5 @@
+#!/bin/sh -e
+. ../common.sh
+
+CurState=$2
+GS_update
diff --git a/files/common/etc/fsm/update/trans/scheduled-applying.trans b/files/common/etc/fsm/update/trans/scheduled-applying.trans
new file mode 100755
index 0000000..928d9eb
--- /dev/null
+++ b/files/common/etc/fsm/update/trans/scheduled-applying.trans
@@ -0,0 +1,6 @@
+#!/bin/sh -e
+. ../common.sh
+
+(echo "I would have called: sysupgrade $FwDst"
+ date
+ echo) > /tmp/updatophilie \ No newline at end of file
diff --git a/files/common/etc/fsm/update/trans/scheduled.enter b/files/common/etc/fsm/update/trans/scheduled.enter
new file mode 100755
index 0000000..7488570
--- /dev/null
+++ b/files/common/etc/fsm/update/trans/scheduled.enter
@@ -0,0 +1,9 @@
+#!/bin/sh -e
+. ../common.sh
+
+AckTime=$TargetTime
+CurState=$2
+GS_update
+
+# TODO: may be increase gossip frequency to allow faster updates
+# despite packet loss and queue overflows in hbbpd \ No newline at end of file
diff --git a/files/common/etc/fsm/update/trans/scheduled.leave b/files/common/etc/fsm/update/trans/scheduled.leave
new file mode 100755
index 0000000..69826fe
--- /dev/null
+++ b/files/common/etc/fsm/update/trans/scheduled.leave
@@ -0,0 +1,9 @@
+#!/bin/sh -e
+. ../common.sh
+
+AckTime=""
+
+# disable gossip during update - the new state is broadcasted during
+# *.enter immediately
+TblIf=
+GS_update
diff --git a/files/common/etc/fsm/update/watch/default b/files/common/etc/fsm/update/watch/default
new file mode 100755
index 0000000..a6858af
--- /dev/null
+++ b/files/common/etc/fsm/update/watch/default
@@ -0,0 +1,72 @@
+#!/bin/sh -e
+set -x
+
+. ../common.sh
+
+# announce a transition and terminate
+trans () {
+ echo $1
+ exit
+}
+
+# is the firmware file available?
+checkFw () {
+ [ -n "$TargetFw" -a -f "$FwDst" ] || trans idle
+}
+
+checkFwHash () {
+ [ "$(sha256sum <$FwDst 2>/dev/null | cut -f1 -d' ')" == "$TargetFw" ] || trans idle
+}
+
+# is target time passed but not set
+checkTime () {
+ [ $CurTime -lt "$TargetTime" -o "$AckTime" -eq "$TargetTime" ] 2>/dev/null \
+ || trans ready
+}
+
+# check all-or-nothing-invariant for whole update state table
+checkPeerState() {
+ p2ptbl show $Tbl \
+ | (
+ IFS=$'\t'
+ while read OId OCurFw OTargetFw OTargetTime OAckTime; do
+ [ -z "$OTargetFw" -a -z "$OTargetTime" -a -z "$OAckTime" ] && continue
+ [ -n "$OTargetFw" -a "$OTargetTime" -eq "$OAckTime" ] && continue
+ exit 1
+ done ) || trans ready
+}
+
+
+case $CurState in
+ idle)
+ checkFw
+ checkFwHash
+ # ^^ check hash of firmware file once if the hash is correct;
+ # do not optimize for the rare case of a wrong hash or
+ # continuously failing updates
+ trans ready
+ ;;
+ ready)
+ checkFw
+ checkTime
+ [ "$TargetTime" -gt $CurTime ] 2>/dev/null || trans ready
+ trans scheduled
+ ;;
+ scheduled)
+ checkFw
+ checkTime
+ [ $CurTime -gt "$TargetTime" ] || trans scheduled
+ checkPeerState
+ trans applying
+ ;;
+ *)
+ # anything else is illegal; especially the state "applying"
+ # must not be reached: during transition toward it the
+ # firmware is flashed and the router rebooted
+ echo "illegal state $CurState" >&2
+ exit 1
+ ;;
+esac
+
+# default and if any case falls through
+trans idle \ No newline at end of file
contact: Jan Huwald // Impressum