Migrate socat init script to systemd

9,630

Solution 1

Just figured out that I have to use

Type=forking

like described in http://www.freedesktop.org/software/systemd/man/systemd.service.html.

If set to forking, it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication channels are set up. The child continues to run as the main daemon process. This is the behavior of traditional UNIX daemons. If this setting is used, it is recommended to also use the PIDFile= option, so that systemd can identify the main process of the daemon. systemd will proceed with starting follow-up units as soon as the parent process exits.

Solution 2

For socat, I use a pure systemd approach. This is an example for a serial loopback:

[Unit]
Description=Socat Serial Loopback
#Before=my-other.service

[Service]
Type=simple
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=socat-serial-lo

ExecStart=/usr/bin/socat -d -d pty,raw,echo=0,link=/tmp/seriallo-a pty,raw,echo=0,link=/tmp/seriallo-b
Restart=always

[Install]
WantedBy=multi-user.target

This can be written to /etc/systemd/system/socat-serial-lo.service (in Ubuntu 16.04+), and then:

systemctl daemon-reload
systemctl start socat-serial-lo
systemctl enable socat-serial-lo  # (to start it during bootup)

One advantage of this method is that the command line defined by ExecStart can be tested directly from command line without alterations, in order to test the command.

Share:
9,630
UpCat
Author by

UpCat

Updated on September 18, 2022

Comments

  • UpCat
    UpCat over 1 year

    I use socat with following init script on debian 7.2 with sysVinit. It works perfectly:

    #!/bin/bash
    DESC=socat
    DAEMON=/usr/bin/socat
    LIB=/usr/lib/socat
    SOCAT_ARGS="-d -d -lf /var/log/socat.log"
    
    [ ! -f /etc/default/socat.conf ] || . /etc/default/socat.conf
    
    . /lib/lsb/init-functions
    
    PATH=/bin:/usr/bin:/sbin:/usr/sbin
    
    [ -x $DAEMON ] || exit 0
    
    #
    #       Try to increase the # of filedescriptors we can open.
    #
    maxfds () {
            [ -n "$SOCAT_MAXFD" ] || return
            [ -f /proc/sys/fs/file-max ] || return 0
            [ $SOCAT_MAXFD -le 4096 ] || SQUID_MAXFD=4096
            global_file_max=`cat /proc/sys/fs/file-max`
            minimal_file_max=$(($SOCAT_MAXFD + 4096))
            if [ "$global_file_max" -lt $minimal_file_max ]
            then
                    echo $minimal_file_max > /proc/sys/fs/file-max
            fi
            ulimit -n $SOCAT_MAXFD
    }
    
    start_socat() {
            start-stop-daemon --quiet --start \
                    --pidfile /var/run/socat.$NAME.pid \
                    --background --make-pidfile \
                    --exec $DAEMON -- $SOCAT_ARGS $ARGS < /dev/null
    }
    
    stop_socat() {
            start-stop-daemon --stop --quiet --pidfile /var/run/socat.$NAME.pid --exec $DAEMON
            rm -f /var/run/socat.$NAME.pid
    }
    
    start () {
            echo "Starting $DESC:"
    
            maxfds
            umask 027
            cd /tmp
            if test "x$AUTOSTART" = "xnone" -o -z "x$AUTOSTART" ; then
                    echo "Autostart disabled."
                    exit 0
            fi
            for NAME in $AUTOSTART ; do
                    ARGS=`eval echo \\\$SOCAT_$NAME`
                    echo $ARGS
                    start_socat
                    echo " $NAME $ARGS"
            done
            return $?
    }
    
    stop () {
            echo -n "Stopping $DESC:"
    
            for PIDFILE in `ls /var/run/socat.*.pid 2> /dev/null`; do
                    NAME=`echo $PIDFILE | cut -c16-`
                    NAME=${NAME%%.pid}
                    stop_socat
                    echo -n " $NAME"
            done
    }
    
    case "$1" in
        start)
            log_daemon_msg "Starting socat" "socat"
            if start ; then
                    log_end_msg $?
            else
                    log_end_msg $?
            fi
            ;;
        stop)
            log_daemon_msg "Stopping socat" "socat"
            if stop ; then
                    log_end_msg $?
            else
                    log_end_msg $?
            fi
            ;;
        reload|force-reload|restart)
            log_daemon_msg "Restarting socat" "socat"
            stop
            if start ; then
                    log_end_msg $?
            else
                    log_end_msg $?
            fi
            ;;
            *)
            echo "Usage: /etc/init.d/$NAME {start|stop|reload|force-reload|restart}"
            exit 3
            ;;
    esac
    
    exit 0
    

    However after an upgrade to debian 7.4 the system changed to systemd. So to run the same script on systemd I added a service that wrappes the /etc/init.d/socat script:

    [Unit]
    Description=Socat
    
    [Service]
    ExecStart=/etc/init.d/socat start
    ExecStop=/etc/init.d/socat stop
    
    [Install]
    WantedBy=multi-user.target
    

    When I start the service it is started but stops directly:

    Loaded: loaded (/usr/lib/systemd/system/socat.service; enabled)
    Active: inactive (dead) since Fri, 18 Apr 2014 14:09:46 +0200; 4s ago Process: 5334 ExecStart=/etc/init.d/socat start (code=exited, status=0/SUCCESS) CGroup: name=systemd:/system/socat.service

    Am I missing something?

    • Piotr Dobrogost
      Piotr Dobrogost about 7 years
      Am I missing something? Yes, you missed actually migrating the init.d script to systemd :)