Write a unit, then break it four ways
Task
Create a working service unit, then introduce each of the four failures that account for most systemd support tickets, and learn to read the exact status code that identifies each.
Steps
- Write a small script at
/usr/local/bin/demo.shthat logs a line every few seconds, and make it executable. - Write
/etc/systemd/system/demo.servicewithExecStartpointing at it,Restart=on-failure, and a[Install]section. Rundaemon-reload, thenenable --now, and confirm it is active. - Break it the first way: edit the unit to change a setting and restart the service WITHOUT
daemon-reload. Confirm the change has no effect, and explain why. - Break it the second way: point
ExecStartat a path that does not exist. Read the status output and findstatus=203/EXEC. - Break it the third way: set
WorkingDirectoryto a directory that does not exist. Findstatus=200/CHDIR. - Break it the fourth way:
systemctl disable demoand reboot the container, confirming it does not start; thenenableand confirm that it does. This is the "works until reboot" scenario. - Finally, mask it and observe that even an explicit
startis refused.
Verify
systemctl is-active demo && echo "running"
systemctl show demo -p ExecStart --value
systemctl status demo --no-pager | grep -o 'status=[0-9]*/[A-Z]*'
systemctl is-enabled demo
systemctl mask demo && systemctl start demo 2>&1 | grep -qi masked && echo "mask blocks start"
systemctl unmask demo
Step 3 is the one to dwell on: systemctl show reports the OLD ExecStart until daemon-reload runs, which is exactly why an edit appears to have done nothing.
Notes
Learn to read the status code rather than the prose. 203/EXEC and 200/CHDIR each name their cause precisely, and both are frequently misdiagnosed as permission problems because the message that reaches the operator says only that the service failed.