diff options
author | Katze Miau <miaukatzemiau@priveasy.de> | 2011-12-05 20:08:13 (GMT) |
---|---|---|
committer | Katze Miau <miaukatzemiau@priveasy.de> | 2011-12-05 20:08:13 (GMT) |
commit | 5b5101d5dbf15a0794bbb2851a38f87e26b9e9c4 (patch) | |
tree | ec1ebc457d05ccd8f7c79346ee2ffddde7d6e593 | |
parent | 69f9402dfd2ac82b964bcb637f1a687c46ee1f2d (diff) |
add /sbin/fsm
- implements finite state machine given a definition in /etc/fsm/
- see upcoming doc/ commits for detail
-rwxr-xr-x | files/common/sbin/fsm | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/files/common/sbin/fsm b/files/common/sbin/fsm new file mode 100755 index 0000000..2a5c4fb --- /dev/null +++ b/files/common/sbin/fsm @@ -0,0 +1,104 @@ +#!/bin/sh + +set -e + +# paths to state file and definition dir +PState=/var/fsm/$2 +PDef=/etc/fsm/$2 + +watch () { + SO=$(cat $PState) + SN=$(callOne $PDef/watch $SO "xxx" \ + "./$SO + ./default + /bin/false") || fail "watch script failed or missing" + [ -n "$SN" ] || fail "watch script $S0 returned empty state name" + change $SN +} + +change () { + SO=$(cat $PState) + SN=$1 + if [ "$SO" != "$SN" ]; then + if [ -x $PDef/trans/$SO-$SN.trans ]; then + # one script to handle whole transition + callOne $PDef/trans $SO $SN \ + "./$SO-$SN.trans" \ + || fail "state transition script failed" + else + # seperate scripts for leaving and entering states + callOne $PDef/trans $SO $SN \ + "./$SO.leave + ./default.leave + /bin/true" \ + || fail "state leave script failed" + callOne $PDef/trans $SO $SN \ + "./$SN.enter + ./default.enter + /bin/true" \ + || fail "state enter script failed" + + fi + echo $SN > $PState + fi +} + +callOne () { # args: cwd arg1 arg2 cmdlist + echo "$4" | sed 's/ *//' | ( + set -e + cd $1 + while read cmd; do + if [ -x "$cmd" ]; then + $cmd $2 $3 + exit $? + fi + done ) +} + +fail() { + echo "$1" 1>&2 + exit 1 +} + +printArgs () { + fail "Usage: +$0 get fsm +$0 watch fsm +$0 change fsm state" +} + +[ $# -lt 2 ] && printArgs + +# check for minimal FSM definition +if [ -f $PDef/initial_state \ + -a -d $PDef/watch \ + -a -d $PDef/trans ]; then + if [ ! -f $PState ]; then + mkdir -p $(dirname $PState) + S=$(cat $PDef/initial_state) + [ -n "$S" ] || fail "initial state must not be empty" + echo $S >$PState + fi +else + fail "FSM $1 does not exist" +fi + +# lock state file (neccessary also for watch, as it calls scripts that +# assume a certain state as active during their whole execution time) +exec 666<$PState +flock -x 666 + +case "$1" in + get) + cat $PState + ;; + watch) + watch + ;; + change) + [ -n "$3" ] || printArgs + change $3 + ;; + *) + printArgs +esac
\ No newline at end of file |