Package: sysv-rc
Version: 2.88dsf-22.1
Severity: wishlist
Tags: patch

Just like invoke-rc.d and update-rc.d can properly deal with a system
using upstart, it should support systemd as well.

The attached patches make invoke-rc.d and update-rc.d systemd aware.
This means that the enable/disable action of update-rc.d additionally
create the appropriate links for systemd (regardless of whether you are
running systemd or not). This will lead to users of sysvinit being able
to switch to systemd (and vice-versa) and still get the same set of
services started at boot.

Roger Leigh reviewed this patches and gave me a few valuable hints,
thanks for that.

It would be great if you could upload a new version of sysv-rc to
experimental which contains these patches. That’d be helpful to work on
other aspects of systemd packaging in Debian.

Best regards,
Michael
--- /usr/sbin/invoke-rc.d.O	2012-07-20 14:58:14.140223575 +0200
+++ /usr/sbin/invoke-rc.d	2012-07-28 15:53:26.969445300 +0200
@@ -38,6 +38,7 @@
 RETURNFAILURE=
 RC=
 is_upstart=
+is_systemd=
 
 # Shell options
 set +e
@@ -273,6 +274,8 @@
    && [ -e "$UPSTARTDIR/${INITSCRIPTID}.conf" ]
 then
     is_upstart=1
+elif test -e /sys/fs/cgroup/systemd ; then
+    is_systemd=1
 elif test ! -f "${INITDPREFIX}${INITSCRIPTID}" ; then
     ## Verifies if the given initscript ID is known
     ## For sysvinit, this error is critical
@@ -383,7 +386,18 @@
 esac
 
 # test if /etc/init.d/initscript is actually executable
-if [ -n "$is_upstart" ] || testexec "${INITDPREFIX}${INITSCRIPTID}" ; then
+_executable=
+if [ -n "$is_upstart" ]; then
+    _executable=1
+elif [ -n "$is_systemd" ]; then
+    _state=$(systemctl -p LoadState show "${INITSCRIPTID}.service" 2>/dev/null)
+    if [ "$_state" != "LoadState=masked" ]; then
+        _executable=1
+    fi
+elif testexec "${INITDPREFIX}${INITSCRIPTID}"; then
+   _executable=1
+fi
+if [ "$_executable" = "1" ]; then
     if test x${RC} = x && test x${MODE} = xquery ; then
         RC=105
     fi
@@ -496,6 +510,31 @@
 			initctl "$saction" "$INITSCRIPTID" && exit 0
 			;;
 		esac
+            elif [ -n "$is_systemd" ]; then
+                case $saction in
+                    start|stop|restart|status)
+                        systemctl "${saction}" "${INITSCRIPTID}.service" && exit 0
+                        ;;
+                    reload)
+                        _canreload="$(systemctl -p CanReload show $service 2>/dev/null)"
+                        if [ "$_canreload" = "CanReload=no" ]; then
+                            "${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
+                        else
+                            systemctl reload "${INITSCRIPTID}.service" && exit 0
+                        fi
+                        ;;
+                    force-stop)
+                        systemctl --signal=KILL kill "${INITSCRIPTID}.service" && exit 0
+                        ;;
+                    force-reload)
+                        systemctl restart "${INITSCRIPTID}.service" && exit 0
+                        ;;
+                    *)
+                        # We try to run non-standard actions by running
+                        # the init script directly.
+                        "${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
+                        ;;
+                esac
 	    else
 		"${INITDPREFIX}${INITSCRIPTID}" "${saction}" "$@" && exit 0
 	    fi
--- /usr/sbin/update-rc.d.O	2012-07-20 16:48:26.446152769 +0200
+++ /usr/sbin/update-rc.d	2012-07-21 10:55:41.408503038 +0200
@@ -5,6 +5,7 @@
 
 use strict;
 use warnings;
+use File::Path qw(make_path); # in core since Perl 5.001
 
 my $initd = "/etc/init.d";
 my $etcd  = "/etc/rc";
@@ -424,6 +425,42 @@
             error("initscript does not exist: /etc/init.d/$scriptname");
         }
     } elsif ("disable" eq $action || "enable" eq $action) {
+        # In addition to the insserv call we also enable/disable the service
+        # for systemd by creating the appropriate symlink in case there is a
+        # native systemd service. We need to do this on our own instead of
+        # using systemctl because systemd might not even be installed yet.
+        my $service_path;
+        if (-f "/etc/systemd/system/$scriptname.service") {
+            $service_path = "/etc/systemd/system/$scriptname.service";
+        } elsif (-f "/lib/systemd/system/$scriptname.service") {
+            $service_path = "/lib/systemd/system/$scriptname.service";
+        }
+        if (defined($service_path)) {
+            my $changed_sth;
+            open my $fh, '<', $service_path or error("unable to read $service_path");
+            while (<$fh>) {
+                chomp;
+                if (/^\s*WantedBy=(.+)$/i) {
+                    my $wants_dir = "/etc/systemd/system/$1.wants";
+                    my $service_link = "$wants_dir/$scriptname.service";
+                    if ("enable" eq $action) {
+                        make_path($wants_dir);
+                        symlink($service_path, $service_link);
+                    } else {
+                        unlink($service_link) if -e $service_link;
+                    }
+                    $changed_sth = 1;
+                }
+            }
+            close($fh);
+
+            # If we changed anything and this machine is running systemd, tell
+            # systemd to reload so that it will immediately pick up our
+            # changes.
+            if ($changed_sth && -e "/sys/fs/cgroup/systemd") {
+                system("systemctl", "daemon-reload");
+            }
+        }
         insserv_toggle($notreally, $action, $scriptname, @args);
         # Call insserv to resequence modified links
         my $rc = system("insserv", @opts, $scriptname) >> 8;

Reply via email to