On Wed, Sep 30, 2026 at 10:38:31AM +0200, Janne Johansson wrote:
>
> >Synopsis: rc.subr: spurious "kill: <pid>: no such process" on start
> with rc_bg=YES
>
>
>
> When starting a package daemon whose rc.d script sets rc_bg=YES,
> the following message is sometimes printed at boot:
> The daemon starts correctly and "rcctl check oficina" reports ok,
> so the problem is cosmetic.
>
>
> Not just cosmetic.
>
>
>
> With rc_bg=YES, rc_start returns immediately. If rc_check already
> succeeds inside _rc_wait_for_start, the loop breaks, the subshell
> runs "pkill -ALRM -P $$" and exits, so the later
> "kill -ALRM ${_TIMERSUB}" targets a process that no longer exists
> and prints an error.
> - kill -ALRM ${_TIMERSUB}
> + kill -ALRM ${_TIMERSUB} 2>/dev/null
>
>
> I am not talking for the project, but I am quite certain that trying to kill
> the wrong process
> is what needs to be fixed, not silencing that it happens.
> What will the system do if the PID got reused in that time span?
Hi and thanks for the report.
There's a real race here indeed. Hiding is not the solution :-)
The rc_alarm timer sends a SIGALRM to all children of rc_cmd to detach rc_start.
But the timer is also a child... and can then die while rc_cmd() is about to
kill it; that's when you get the error (as it's already gone).
So we make the timer ignore SIGALRM and let it get killed by rc_cmd.
If you're able to easily reproduce, could you try this?
Index: rc.subr
===================================================================
RCS file: /cvs/src/etc/rc.d/rc.subr,v
diff -u -p -r1.168 rc.subr
--- rc.subr 16 Sep 2026 00:52:19 -0000 1.168
+++ rc.subr 30 Sep 2026 16:26:25 -0000
@@ -143,13 +143,6 @@ _rc_exit() {
exit ${_ret}
}
-_rc_alarm()
-{
- trap - ALRM
- kill -ALRM ${_TIMERSUB} 2>/dev/null # timer may not be running anymore
- kill $! 2>/dev/null # kill last job if it's running
-}
-
_rc_printname()
{
local _n
@@ -162,15 +155,20 @@ _rc_sendsig() {
}
_rc_wait_for_start() {
- trap "_rc_alarm" ALRM
+ # catch SIGALRM, it's only needed for the process spawned by rc_start;
+ trap : ALRM
+ trap 'exit' TERM
while ((SECONDS < daemon_timeout)); do
if _rc_do rc_check; then
[ X"${rc_bg}" = X"YES" ] || [ -z "$$" ] && break
fi
- sleep .5
- done & wait
+ sleep .5 & wait
+ done
pkill -ALRM -P $$
- return
+ # wait for rc_cmd() signal
+ while kill -0 $$ 2>/dev/null; do
+ sleep .5 & wait
+ done
}
rc_exec() {
@@ -257,10 +255,10 @@ rc_cmd() {
fi
# prevent hanging the boot sequence
_rc_do _rc_wait_for_start & _TIMERSUB=$!
- trap "_rc_alarm" ALRM
+ trap : ALRM
_rc_do rc_start; _ret=$?
- kill -ALRM ${_TIMERSUB}
- wait ${_TIMERSUB} 2>/dev/null # don't print Alarm clock
+ kill -TERM ${_TIMERSUB}
+ wait ${_TIMERSUB} 2>/dev/null # don't print Terminated
# XXX for unknown reason, rc_check can fail (e.g. redis)
# while it just succeeded in _rc_wait_for_start;
# check to cope with failing daemons returning 0
@@ -292,7 +290,7 @@ rc_cmd() {
break
${_1stloop} && _1stloop=false || sleep .5
done
- kill -ALRM ${_timer} 2>/dev/null
+ pkill -ALRM -P $$
wait ${_timer} # don't print Alarm clock
[[ $? == 0 ]] || _exit=failed
# KILL the process
@@ -314,7 +312,7 @@ rc_cmd() {
pkill -0 -P "$$" 2>/dev/null || break
${_1stloop} && _1stloop=false || sleep .5
done
- kill -ALRM ${_timer} 2>/dev/null
+ pkill -ALRM -P $$
wait ${_timer} # don't print Alarm clock
_ret=$?
[[ ${_ret} == 142 ]] && _exit=timeout || [[ ${_ret} == 0 ]] ||
--
Antoine