While fixing S95majestic in #2324 I traced a family of init-script bugs to a single flag, and eleven other scripts still carry the same pattern.
The defect
Busybox start-stop-daemon's do_procinit() reads only the pid the -p pidfile holds and never scans /proc. -x is then just a filter applied to that one pid. So once the pidfile is stale, start-stop-daemon cannot see the live daemon at all.
Measured on a Hi3516EV300 (busybox 1.36.1), with the daemon live as pid 1177 and the pidfile poisoned with a dead pid:
# start-stop-daemon -b -m -S -q -p /var/run/majestic.pid -x majestic -- -s
rc=0 # started a SECOND instance, pid 1233
# cat /var/run/majestic.pid
1233 # -m overwrote the file with the duplicate's pid
Two consequences:
- Duplicate daemons.
-S cannot see the running instance, so it starts another one. If the duplicate then dies, -m has already replaced the pidfile with its dead pid, so the state is self-perpetuating.
- Killing unrelated processes. Every one of these scripts stops with
start-stop-daemon -K -q -p "$PIDFILE" and no -x guard, so it signals whatever process now owns that pid. With the pidfile pointing at an unrelated live process, I watched it kill that process while the real daemon kept running.
Affected scripts
| Script |
Package |
S01syslogd |
general/overlay/etc/init.d/ |
S49ntpd |
general/overlay/etc/init.d/ |
S50dropbear |
general/overlay/etc/init.d/ |
S60crond |
general/overlay/etc/init.d/ |
S50mdnsd |
mdnsd-openipc |
S60siproxd |
siproxd-openipc |
S60precision-time |
openipc-precision-time |
S89edge |
n3n-openipc |
S90matter |
matter |
S96onvifserver |
onvif-simple-server |
S97baresip |
baresip-openipc |
These bite far less often than majestic did, because those daemons rarely die and get restarted — majestic is the one that gets OOM-killed, hits a busy sensor HAL, and is restarted by watchdogs and sysupgrade. The defect is latent, not theoretical.
S60crond deserves priority: a crond watchdog is the intended recovery path for a dead majestic, so a crond that cannot be reliably restarted defeats the recovery story.
The fix
Same shape as #2324 — drop -p, match on the absolute executable, and keep argv[0] stable:
DAEMON="foo"
DAEMON_PATH="/usr/bin/$DAEMON"
running() { start-stop-daemon -t -K -q -x "$DAEMON_PATH"; }
start() { start-stop-daemon -b -S -q -x "$DAEMON_PATH" -a "$DAEMON" -- $DAEMON_ARGS; }
stop() { start-stop-daemon -K -q -x "$DAEMON_PATH"
i=0; while running && [ $i -lt 10 ]; do i=$((i + 1)); sleep 1; done
running && return 1
rm -f "/var/run/$DAEMON.pid"; }
-a "$DAEMON" matters: without it argv[0] becomes the absolute path, ps output changes, and bare-name -x matchers break. With it, ps, pidof and killall behave exactly as they do today.
Worth doing as one sweep once #2324 has settled, since it touches every board's boot path. Each script's binary path needs checking individually — they are not all under /usr/bin.
While fixing
S95majesticin #2324 I traced a family of init-script bugs to a single flag, and eleven other scripts still carry the same pattern.The defect
Busybox
start-stop-daemon'sdo_procinit()reads only the pid the-ppidfile holds and never scans/proc.-xis then just a filter applied to that one pid. So once the pidfile is stale,start-stop-daemoncannot see the live daemon at all.Measured on a Hi3516EV300 (busybox 1.36.1), with the daemon live as pid 1177 and the pidfile poisoned with a dead pid:
Two consequences:
-Scannot see the running instance, so it starts another one. If the duplicate then dies,-mhas already replaced the pidfile with its dead pid, so the state is self-perpetuating.start-stop-daemon -K -q -p "$PIDFILE"and no-xguard, so it signals whatever process now owns that pid. With the pidfile pointing at an unrelated live process, I watched it kill that process while the real daemon kept running.Affected scripts
S01syslogdgeneral/overlay/etc/init.d/S49ntpdgeneral/overlay/etc/init.d/S50dropbeargeneral/overlay/etc/init.d/S60crondgeneral/overlay/etc/init.d/S50mdnsdmdnsd-openipcS60siproxdsiproxd-openipcS60precision-timeopenipc-precision-timeS89edgen3n-openipcS90mattermatterS96onvifserveronvif-simple-serverS97baresipbaresip-openipcThese bite far less often than majestic did, because those daemons rarely die and get restarted — majestic is the one that gets OOM-killed, hits a busy sensor HAL, and is restarted by watchdogs and
sysupgrade. The defect is latent, not theoretical.S60cronddeserves priority: a crond watchdog is the intended recovery path for a dead majestic, so a crond that cannot be reliably restarted defeats the recovery story.The fix
Same shape as #2324 — drop
-p, match on the absolute executable, and keep argv[0] stable:-a "$DAEMON"matters: without it argv[0] becomes the absolute path,psoutput changes, and bare-name-xmatchers break. With it,ps,pidofandkillallbehave exactly as they do today.Worth doing as one sweep once #2324 has settled, since it touches every board's boot path. Each script's binary path needs checking individually — they are not all under
/usr/bin.