How can I tell if a script was called from systemd or from a user?
I created a service for an old school daemon. We just switched to systemd and some of my admin like to call the rc-script directly. This won't work very well in the case of machine reboot. Systemd won't honor the PIDFile=
because the new started daemon is not part of it's cgroup for the service.
I added the service file and the rc_script. I can't differ by user id, because to use the script the user has to be foobaruser
.
The stop service is now problem, because systemd will recognize this from the deleted pid file.
So how do I find out if the script was called from systemd?
foobar.service
[Unit]
Description=Foobar Service
After=syslog.target network.target
[Service]
Type=forking
User=foobaruser
LimitNOFILE=60000
LimitNPROC=8000
TasksMax=8000
PIDFile=/local/foobar/foo.pid
ExecStart=/opt/foobar/rc_script start
ExecStop=/opt/foobar/rc_script stop
TimeoutSec=100
TimeoutStopSec=300
KillMode=none
RemainAfterExit=no
Environment=LANG=de_DE.UTF-8
[Install]
WantedBy=multi-user.target
/opt/foobar/rc_script skeleton
#!/bin/bash
case $1 in
start)
VAR_IS_SYSTEMD=$( ... script to check if bash is run from systemd ... )
if [ "$VAR_IS_SYSTEMD" = false ] ; then
sudo systemctl start foobar.service
exit
fi
# start service within systemd
;;
stop)
# stop service
;;
esac
I agree with the other posters that you should try to rewrite the service to not call the script at all (it’s fine if your admins want to keep using it, but does the systemd service need all the 36 options?) – but it’s also not hard to detect if the script was called from systemd.
systemd v232 added the concept of an invocation ID of a unit, which is passed to the unit in the
$INVOCATION_ID
environment variable. You can check if that’s set or not.systemd v231+ sets the
$JOURNAL_STREAM
variable for services whose stdout or stderr is connected to the journal, which seems to be the case for your service, so you could also check for that variable if you’re on systemd v231. (On v232+,$INVOCATION_ID
is definitely the better choice.)On older systemd versions, I don’t think there’s an environment variable that’s always present, but you can of course define one yourself by adding something like this to your service:
A simple solution is to use a different script for systemd to start. The /opt/foobar/rc_script should just call
systemctl start foobar.service
andsystemctl stop foobar.service
.Suse uses
$SYSTEMD_NO_WRAP
, but I don't know whether that is systemd standard or Suse specific.For "Amazon Linux 2" and "Red Hat Enterprise Linux 7" I found a solution.
On these linux systems system process
PID=1
iscomm=systemd
. The parent IDPPID
of the systemd started script is1
.There may be other linux systems where this is not the case.
Elements/Commands used:
ps -o comm -p 1 --no-headers
Get command name of process 1
tr -d ' '
Remove formatting whitespace from ps command
"${PPID}"
Parent PID of bash process