diff options
Diffstat (limited to 'files/common')
-rw-r--r-- | files/common/etc/fsm/update/common.sh | 36 | ||||
-rw-r--r-- | files/common/etc/fsm/update/initial_state | 1 | ||||
-rwxr-xr-x | files/common/etc/fsm/update/trans/default.enter | 5 | ||||
-rwxr-xr-x | files/common/etc/fsm/update/trans/scheduled-applying.trans | 6 | ||||
-rwxr-xr-x | files/common/etc/fsm/update/trans/scheduled.enter | 9 | ||||
-rwxr-xr-x | files/common/etc/fsm/update/trans/scheduled.leave | 9 | ||||
-rwxr-xr-x | files/common/etc/fsm/update/watch/default | 72 |
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 |