tech@,

When external_exec() runs a test synchronously, it refreshes prevstatus
but left lastexec unchanged. A later status change could therefore be
ignored by eval_state(), because that code gates body evaluation on the
first external test timestamp for the current state.

Set lastexec together with prevstatus for synchronous runs; this keeps
the cached test status and execution time consistent across state
re-entry.

Reproducer:

enter_two = '"test -f /tmp/ifstated-repro/enter_two" every 1'
slow_false = '"false" every 2'
go_back = '"test -f /tmp/ifstated-repro/go_back" every 1'
leave_once = '"test -f /tmp/ifstated-repro/leave_once" every 1'

run "rm -rf /tmp/ifstated-repro"
run "mkdir -p /tmp/ifstated-repro"

state one {
        init {
                run "rm -f /tmp/ifstated-repro/enter_two 
/tmp/ifstated-repro/go_back /tmp/ifstated-repro/leave_once"
                run "( sleep 1; touch /tmp/ifstated-repro/enter_two ) &"
        }
        if $enter_two {
                run "rm -f /tmp/ifstated-repro/enter_two"
                set-state two
        }
}

state two {
        init {
                run "rm -f /tmp/ifstated-repro/enter_two 
/tmp/ifstated-repro/go_back /tmp/ifstated-repro/leave_once"
                run "if test -f /tmp/ifstated-repro/seen_two; then touch 
/tmp/ifstated-repro/go_back; else touch /tmp/ifstated-repro/seen_two; ( sleep 
3; touch /tmp/ifstated-repro/leave_once ) & fi"
        }
        if $slow_false || $go_back {
                run "touch /tmp/ifstated-repro/returned"
                set-state one
        }
        if $leave_once
                set-state one
}



Ok?

Index: usr.sbin/ifstated/ifstated.c
===================================================================
RCS file: /home/cvs/src/usr.sbin/ifstated/ifstated.c,v
diff -u -p -r1.68 ifstated.c
--- usr.sbin/ifstated/ifstated.c        23 Apr 2024 13:34:51 -0000      1.68
+++ usr.sbin/ifstated/ifstated.c        14 May 2026 21:34:57 -0000
@@ -340,8 +340,10 @@ external_exec(struct ifsd_external *exte
        if (!async) {
                waitpid(external->pid, &s, 0);
                external->pid = 0;
-               if (WIFEXITED(s))
+               if (WIFEXITED(s)) {
                        external->prevstatus = WEXITSTATUS(s);
+                       external->lastexec = time(NULL);
+               }
        }
 }
 

-- 
wbr, Kirill

Reply via email to