> Is something not working correctly?
> Your text does not explain the diff.
> What's the problem here?

I should have given the details of what I saw during testing.
Sorry about that, I'll try to explain.

When I was reading more of "man ksh" it was by the description of
functions that I saw the note about getopts's optind being reset
or not being reset depending how the function is defined.  My
mistake was assuming getopts would always work whenever it's used
in functions.  Now I see why the man page took the extra time to
talk about optind in the getopts section.  This is what prompted
me to test the getopts used in the rc.d scripts.

Ok, my setup (using unbound), I do have two instances configured.

/etc/rc.d# ls -l unbound2
lr-xr-xr-x  1 root  wheel  7 Nov 13 08:13 unbound2 -> unbound

/etc# grep unbound rc.conf.local
pkg_scripts=unbound2
unbound2_flags=-c /var/unbound/etc/unbound2.conf
unbound_flags=

For testing I added several echo lines to unbound so I can watch
a few variables to see how they change.  What is OPTIND before
the getopts loop, all the getopts variables during the while loop,
and what is _config after the loop as that will be the value used
by unbound-checkconf.

/etc/rc.d# diff -u unbound.orig unbound.debug
--- unbound.orig   Fri Nov 28 06:44:10 2025     1.10
+++ unbound.debug  Fri Nov 28 06:43:48 2025
@@ -10,9 +10,12 @@
 rc_pre() {
        local _anchor _config _opt

+       echo OPTIND=$OPTIND > /tmp/output
        while getopts :c: _opt $daemon_flags; do
+               echo _opt=$_opt  OPTIND=$OPTIND  OPTARG=$OPTARG >> /tmp/output
                [[ $_opt == c ]] && _config=$OPTARG
        done
+       echo _config=$_config >> /tmp/output

        _anchor=$($daemon-checkconf -o auto-trust-anchor-file $_config)

/etc/rc.d#

Now the testing, first lets see what happens during a normal run.
The echo lines saves their output to /tmp/output.

/etc/rc.d# rcctl restart unbound2
unbound2(ok)
unbound2(ok)
/etc/rc.d# cat /tmp/output
OPTIND=1
_opt=c OPTIND=3 OPTARG=/var/unbound/etc/unbound2.conf
_config=/var/unbound/etc/unbound2.conf
/etc/rc.d#

The next tests passes an option to rcctl, doesn't matter
if it's -q or -f or -f -q, OPTIND is greater than 1 and
the while loop contents never run to set _config.

/etc/rc.d# rcctl -q restart unbound2
/etc/rc.d# cat /tmp/output
OPTIND=2
_config=
/etc/rc.d#

/etc/rc.d# rcctl -f restart unbound2
unbound2(ok)
unbound2(ok)
/etc/rc.d# cat /tmp/output
OPTIND=2
_config=
/etc/rc.d#

/etc/rc.d# rcctl -fq restart unbound2
/etc/rc.d# cat /tmp/output
OPTIND=3
_config=
/etc/rc.d#

Now if I add just OPTIND to the local line
-       local _anchor _config _opt
+       local _anchor _config _opt OPTIND
and repeat the -q test.

/etc/rc.d# rcctl -q restart unbound2
/etc/rc.d# cat /tmp/output
OPTIND=2
_config=
/etc/rc.d#

OPTIND did not get reset and the issue persisted.
When I add OPTIND=1 to the local line
-       local _anchor _config _opt
+       local _anchor _config _opt OPTIND=1
and repeat the -q test.

/etc/rc.d# rcctl -q restart unbound2
/etc/rc.d# cat /tmp/output
OPTIND=1
_opt=c OPTIND=3 OPTARG=/var/unbound/etc/unbound2.conf
_config=/var/unbound/etc/unbound2.conf
/etc/rc.d#

Now I see the correct response and it matches the
normal test run output from above.  So to ensure
getopts always behaves properly I believe we need
to add OPTIND=1 to the function's local definitions
for both unbound and spamlogd.

/etc/rc.d$ diff -u unbound unbound
--- unbound     Sun Nov 16 13:27:50 2025     1.10
+++ unbound     Mon Nov 24 22:21:24 2025
@@ -8,7 +8,7 @@
 . /etc/rc.d/rc.subr
 
 rc_pre() {
-       local _anchor _config _opt
+       local _anchor _config _opt OPTIND=1
 
        while getopts :c: _opt $daemon_flags; do
                [[ $_opt == c ]] && _config=$OPTARG

/etc/rc.d$ diff -u spamlogd spamlogd
--- spamlogd     Sun Nov 16 13:29:02 2025     1.7
+++ spamlogd     Mon Nov 24 22:21:37 2025
@@ -9,7 +9,7 @@
 rc_reload=NO
 
 rc_pre() {
-       local _opt pflog=pflog0
+       local _opt pflog=pflog0 OPTIND=1
 
        while getopts :l: _opt $daemon_flags; do
                [[ $_opt == l ]] && pflog=$OPTARG

Reply via email to