0

I am in the process of converting an existing /etc/init.d service to systemd. It seemed to be working but I have encountered a strange issue. The systemd service will happily start with the command "systemctl start service_name" and stop with "systemctl stop service_name" but it doesn't seem to be stopping cleanly. The underlying application checks if it is already running and terminates immediately if this is the case. This is what is happening.

Here is an equivalent snippet from the old /etc/init.d script:

kill_process() {
    pkill -SIGINT service_name
    sleep 1
    if [ -n "$(pgrep service_name)" ]; then
        pkill -SIGTERM service_name
        sleep 1
    fi 
    if [ -n "$(pgrep service_name)" ]; then
        pkill -SIGKILL service_name
        sleep 1
    fi 
    if [ -z "$(pgrep service_name)" ]; then
        rm -f /var/lock/subsys/service_name
    fi
}

start() {
    action $"Starting Service: " /sbin/service_name
}

stop() {
    action $"Stopping Service: " kill_process
}

restart() {
    stop
    start
}

And this is my initial attempt at the systemd equivelent:

[Unit]
Description=Service Name

[Service]
ExecStart=/sbin/service_name

[Install]
WantedBy=multi-user.target

My understanding was that the systemd service would handle the process termination using SIGTERM but I have experimented with other values for KillSignal and ExecStop. However, I have yet to understand this difference in the termination behaviour. Furthermore, if I kill the application manually using SIGINT it doesn't kill the service cleanly either. I am wondering if /etc/init.d is doing something else behind the scenes.

Any suggestions appreciated.

7
  • How does your service perform the "already running" check? Does the systemd unit show up as "active (running)" after you start it? Does service_name fork on startup? Commented Jan 8, 2021 at 14:54
  • You probably need to add an ExecStop=/bin/rm -f /var/lock/subsys/service_name or similar.
    – meuh
    Commented Jan 8, 2021 at 17:00
  • Thanks for the comments. @user1686 The "already running" check is done by querying shared memory which is cleared when the application terminates cleanly. The systemd unit does show as "active (running)" after the initial start and every second time it is run - otherwise it is "inactive (dead)" due to the shared memory not being cleared when it was stopped. The service does not fork.
    – Alan Spark
    Commented Jan 11, 2021 at 7:52
  • @meuh Thanks, I will look into it.
    – Alan Spark
    Commented Jan 11, 2021 at 7:52
  • 1
    The difference between /etc/init.d and systemd seems to be that /etc/init.d IS forking (it checks getppid() == 1 and if so it is already forked. This is always returning 1 in systemd and I assume is related to the difference in behaviour that I am seeing... I have tried Type=forking in the systemd config but that made no difference.
    – Alan Spark
    Commented Jan 11, 2021 at 16:03

1 Answer 1

1

I just wanted to draw a line under this post in case it is of interest to anyone else.

The C application that runs as part of the service was previously using fork() if getppid() was not already 1 (i.e. not already forked). It seems that when the application is run by systemd it already has a parent PID of 1. Our application did not have explicit SIGTERM handling before but did shut down gracefully when reacting to SIGINT in the context of /etc/init.d. I have added a specific SIGTERM handler and the service now behaves as expected.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .