conf: drop the angle brackets from if, infer from the value

The block format spells conditions as bare strings everywhere else, so
requiring `if = "<usr/foo>"` left one sigil behind, carried over from
the line-based `if:` token.  A namespace separator already tells the two
apart: a value with a '/' is a condition, anything else is a service
name.

svc_ifthen() picks its mode from the start of the statement and applies
it to the whole, so a statement naming both kinds cannot be evaluated.
That is now an error, as are the old angle brackets, and either one
skips the block:

    /etc/finit.conf: mixed: if: cannot mix a service name with a
    condition in 'anchor,usr/enable-me', a statement must be all of
    one kind, skipping

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-07-30 15:23:36 +02:00
1 parent c584795202
commit be28436c2d
4 files changed
+182 -7

No files matched your search

+2
View File
@@ -32,6 +32,7 @@ EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
EXTRA_DIST += bootstrap-crash.sh
EXTRA_DIST += cond-start-task.sh
EXTRA_DIST += conf-format.sh
EXTRA_DIST += conf-if.sh
EXTRA_DIST += conf-template.sh
EXTRA_DIST += script-timeout.sh
EXTRA_DIST += crashing.sh
@@ -79,6 +80,7 @@ TESTS += add-remove-dynamic-service-sub-config.sh
TESTS += bootstrap-crash.sh
TESTS += cond-start-task.sh
TESTS += conf-format.sh
TESTS += conf-if.sh
TESTS += conf-template.sh
TESTS += script-timeout.sh
TESTS += crashing.sh
+95
View File
@@ -0,0 +1,95 @@
#!/bin/sh
# Verify the block format 'if' setting: a value with a namespace
# separator is a condition, checked at runtime, anything else is a
# service name, checked when the .conf is read. The two cannot be
# combined, and the legacy angle brackets are rejected.
set -eu
TEST_DIR=$(dirname "$0")
# shellcheck disable=SC2034
BOOTSTRAP="service anchor {
runlevel = \"S12345\"
command = \"serv -np -i anchor\"
}
service byname {
runlevel = \"S12345\"
if = \"anchor\"
command = \"serv -np -i byname\"
}
service noname {
runlevel = \"S12345\"
if = \"nosuchservice\"
command = \"serv -np -i noname\"
}
service negated {
runlevel = \"S12345\"
if = \"!anchor\"
command = \"serv -np -i negated\"
}
service bycond {
runlevel = \"S12345\"
if = \"usr/enable-me\"
command = \"serv -np -i bycond\"
}
service brackets {
runlevel = \"S12345\"
if = \"<usr/enable-me>\"
command = \"serv -np -i brackets\"
}
service mixed {
runlevel = \"S12345\"
if = \"anchor,usr/enable-me\"
command = \"serv -np -i mixed\"
}"
# initctl status prints a detail block for a single match and a table
# only for several, so count lines in the full listing instead.
assert_loaded()
{
assert "Service $1 loaded: $2" \
"$(texec initctl -t status | awk -v n="$1" '$2 == n' | wc -l)" -eq "$2"
}
test_teardown()
{
say "Running test teardown."
run "initctl cond clear enable-me" || true
}
# shellcheck source=/dev/null
. "$TEST_DIR/lib/setup.sh"
say 'A bare value names a service, resolved when the .conf is read'
retry 'assert_loaded byname 1'
say 'A service that is not known keeps the block out of the config'
assert_loaded noname 0
say 'Negation of a known service keeps the block out too'
assert_loaded negated 0
say 'A value with a namespace separator is a condition, so the block is'
say 'loaded, but held until the condition is asserted'
assert_loaded bycond 1
assert_status bycond halted
run "initctl cond set enable-me"
retry 'assert_status bycond running'
# 'if' qualifies the block, it does not track the condition, so
# clearing it does not stop a running service. The qualification is
# re-read when the configuration is, i.e. on reload.
run "initctl cond clear enable-me"
run "initctl reload"
retry 'assert_status bycond halted'
say 'Angle brackets belong to the line-based format, the block is rejected'
assert_loaded brackets 0
say 'A service name and a condition are checked at different times, so'
say 'mixing them in one statement is rejected'
assert_loaded mixed 0
say 'Rejecting a block leaves the rest of the file alone'
assert_loaded anchor 1