-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Ash Shell Background Process PID Tracking Issue
This document explains a known limitation when using SVC_BACKGROUND=y with SVC_WRITE_PID=y on DSM 5 and SRM systems where /bin/sh is ash (not bash).
When the spksrc framework starts a service on DSM < 6 with a SERVICE_USER set, it uses:
su ${EFF_USER} -s /bin/sh -c "${service}" >> ${LOG} 2>&1 &Then captures $! to write to the PID file.
In ash (used in DSM 5 and SRM), when you run:
/bin/sh -c "command arg1 arg2" &The $! returns the PID of the /bin/sh process, not the actual command being executed. The subshell may exit quickly while the command continues running (or vice versa), leaving an incorrect PID in the file.
In bash, this typically works because bash handles this differently, but ash has this limitation.
This issue affects packages that have ALL of:
-
SERVICE_USERset in Makefile (triggerssuwrapper) -
SERVICE_COMMANDwith parameters (triggers/bin/sh -c) -
SVC_BACKGROUND=y(runs command in background) -
SVC_WRITE_PID=y(attempts to capture PID with$!) - Target firmware is DSM < 6 or SRM (uses ash shell)
Create a wrapper script that:
- Accepts no parameters (SERVICE_COMMAND runs it directly without
/bin/sh -c) - Runs the actual binary in background
- Captures and writes the PID
Example start.sh:
#!/bin/sh
if [ -z "${SYNOPKG_PKGDEST}" ] || [ -z "${PID_FILE}" ]; then
echo "ERROR: Required variables not set"
exit 1
fi
${SYNOPKG_PKGDEST}/bin/myapp --some-arg &
echo "$!" > "${PID_FILE}"Important Notes:
- The wrapper itself runs the binary with
&and captures the PID - Pass required variables via environment exports in
service-setup.sh - The wrapper must NOT be set to run in background by the framework
(i.e., do NOT set
SVC_BACKGROUND=ywhen using a wrapper that handles backgrounding itself)
If the application supports a daemon/background mode with PID file writing:
SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/myapp --daemon --pid-file ${PID_FILE}"
# Don't set SVC_BACKGROUND or SVC_WRITE_PID - let the app handle itIf DSM 5/SRM support is not required, the issue is moot:
- DSM 6+ uses
conf/privilegefor user context (nosuwrapper) - The framework runs
${service} >> ${OUT} 2>&1 &directly -
$!correctly captures the PID
See mk/spksrc.service.start-stop-status, relevant sections:
# Line 52-67: DSM < 6 code path (problematic with ash)
if [ -n "${USER}" -a "$SYNOPKG_DSM_VERSION_MAJOR" -lt 6 ]; then
...
$SU /bin/sh -c "${service}" >> ${OUT} 2>&1 &
fi
# Line 69-81: DSM 6+ code path (works correctly)
else
${service} >> ${OUT} 2>&1 &
fi
# Line 82-85: PID capture (uses $!)
if [ -n "${SVC_WRITE_PID}" -a -n "${SVC_BACKGROUND}" ]; then
echo -ne "$!" > ${PID_FILE}
fiThis issue was documented in PR #5652 for the ympd package. A wrapper script was introduced to work around the ash shell limitation, but the implementation had a bug:
Original buggy start.sh:
${SYNOPKG_PKGDEST}/bin/ympd -w ${SERVICE_PORT} # No & here - blocks!
echo "$!" > ${PID_FILE} # Never reached, or captures wrong PIDThe command ran in foreground (blocking), so echo "$!" either:
- Never executed (blocked forever), or
- If ympd exited, captured the PID of some previous background process
The wrapper was later reverted in favor of direct SERVICE_COMMAND usage, which works on DSM 6/7 but may have issues on DSM 5/SRM if all the affected conditions apply.
- DSM 5 reached end-of-life in 2019
- Default toolchains are DSM 6.2.4 and 7.1
- SRM (Synology Router Manager) still uses ash
- Most packages no longer explicitly support DSM 5 or SRM
This issue is primarily a concern for SRM deployments or legacy DSM 5 systems.
- PR #5652: Original ympd start.sh wrapper implementation
- PR #6932: Reverted wrapper, discussion on SRM compatibility
- Home
-
Packages
- Adminer
- Aria2
- Beets
- BicBucStriim
- Borgmatic
- cloudflared
- Comskip
- Debian Chroot
- Deluge
- Duplicity
- dnscrypt-proxy
- FFmpeg
- FFsync
- Flexget
- Gstreamer
- Google Authenticator
- Home Assistant Core
- Jellyfin
- Kiwix
- [matrix] Synapse homeserver
- MinIO
- Mono
- Mosh
- Mosquitto
- Node-Exporter
- OpenList
- ownCloud
- Radarr/Sonarr/Lidarr/Jackett
- rclone
- ruTorrent (rTorrent)
- SaltStack
- SickBeard Custom
- SynoCLI-Disk
- SynoCLI-Devel
- SynoCLI-File
- SynoCLI-Kernel
- SynoCLI-Misc.
- SynoCLI-Monitor
- SynoCLI-NET
- Synogear
- Vaultwarden
- Concepts
- Development
- Resources