Search code examples
ubuntu-16.04initsystemdupstart

Systemd + Sys V init.d script: start works, but stop does not


I'm pretty new to writing systemd compatible init scripts. I've tried the following example:

#!/bin/sh
#
### BEGIN INIT INFO
# Provides:          test
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Test.
# Description:       Test. 
### END INIT INFO
#

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

case "$1" in

  stop)
    log_failure_msg "Stop!"
    exit 1
    ;;

  start)
    log_failure_msg "Start!"
    exit 1
    ;;

  restart)
    log_failure_msg "Restart!"
    exit 1
    ;;

  status)
    log_failure_msg "Status!"
    exit 1
    ;;

  *)
    echo "Usage: $SELF start|stop|restart|status"
    exit 1
    ;;
esac

# Some success paths end up returning non-zero, so exit 0 explicitly. See bug #739846.
exit 0

So far, so good. Now, I install the init script like so:

update-rc.d test defaults
update-rc.d test enable

Again, so far, so good. I've setup this init script specifically to fail (I had to do so during my testing to confirm the issue I was having.)

If I run /etc/init.d/test start, it fails as expected, and I can see the error message in my log.

If, however, I run /etc/init.d/test stop, I get nothing in my log, and the script returns successfully.

It seems like systemd is doing some kind of black magic behind the scenes and is hijacking stop somehow, but I can't figure out how, and I've been Googling around forever without success. Can anyone help me to understand why passing stop to my init script doesn't execute the corresponding code in my case block?

As a side note, the status option also doesn't work (systemd just outputs its own status info.)

I'm attempting to run this on Ubuntu 16.04. Thank you!


Solution

  • You'll notice the top of your script loads /lib/lsb/init-functions. You can read the code in there and the related code in /lib/lsb/init-functions.d to understand the related code you are pulling in.

    A summary is that your script likely being converted to a systemd .service in the background and is subject to a whole host of documented incompatibilities with systemd

    There is inherit extra complexity and potential problems when you ask systemd to emulate and support the file formats used by the legacy Upstart and sysVinit init systems.

    Since you are writing new init script from scratch, consider writing a systemd .service file directly, removing all the additional complexity of involving additional init systems.

    A minimal .service file to go in /etc/systemd/system/ could look like:

    [Unit]
    Description=Foo
    
    [Service]
    ExecStart=/usr/sbin/foo-daemon
    
    [Install]
    WantedBy=multi-user.target
    

    More details in man systemd.service. Some additional learning now will save you some debugging later!