Control: severity -1 important
Control: tags -1 + patch
Dear Maintainer,
(Cc systemd maintainers, because it's of interest to them.)
I have created a patch that implements the previously missing parts of
systemd integration into update-rc.d, following along the lines of the
patch I have written for deb-systemd-helper (bug #780522).
The patch now makes update-rc.d support:
- drop-in configuration snippets
- multiple words per setting (i.e. "WantedBy=a b")
- RequiredBy=, Alias=, Also=
(Note that the patch currently implements the full systemd logic of
also looking at /run/systemd/generator*, which may or may not be
something one wants or not - I would defer to the systemd team as to
whether they'd want to see that included - but it should be consistent
across update-rc.d and deb-systemd-helper.)
Since systemctl enable/disable calls out to update-rc.d, I think this
is something that should definitely be fixed for Jessie (otherwise,
doing systemctl (en|dis)able something-with-alias.service will not work
properly!).
I have diverted update-rc.d on my local machine and replaced it with
the patched version. I've also tested it with some examples and as far
as I can tell it works properly.
Christian
diff -Nru sysvinit-2.88dsf/debian/src/sysv-rc/sbin/update-rc.d
sysvinit-2.88dsf/debian/src/sysv-rc/sbin/update-rc.d
--- sysvinit-2.88dsf/debian/src/sysv-rc/sbin/update-rc.d 2014-10-25
23:15:12.000000000 +0200
+++ sysvinit-2.88dsf/debian/src/sysv-rc/sbin/update-rc.d 2015-03-15
15:49:27.000000000 +0100
@@ -7,6 +7,7 @@
use warnings;
# NB: All Perl modules used here must be in perl-base. Specifically, depending
# on modules in perl-modules is not okay! See bug #716923
+use Text::ParseWords qw(shellwords); # in core since Perl 5
my $initd = "/etc/init.d";
my $etcd = "/etc/rc";
@@ -63,46 +64,121 @@
map { push @dirs, $_; mkdir join('/', @dirs), 0755; } @path;
}
+# Recursively deletes a directory structure, if all (!) components are empty,
+# e.g. to clean up after purging.
+# (Taken from deb-systemd-helper)
+sub rmdir_if_empty {
+ my ($dir) = @_;
+
+ rmdir_if_empty($_) for (grep { -d } <$dir/*>);
+ rmdir($dir);
+}
+
# Creates the necessary links to enable/disable the service (equivalent of an
# initscript) in systemd.
sub make_systemd_links {
- my ($scriptname, $action) = @_;
+ my ($scriptname, $action, $recursive) = @_;
+
+ my @unit_paths = (
+ "/run/systemd/generator.late",
+ "/lib/systemd/system",
+ "/run/systemd/generator",
+ "/etc/systemd/system",
+ "/run/systemd/generator.early"
+ );
# 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);
+
+ # The following code is adapted from deb-systemd-helper
+ my ($service_path, %dropins);
+
+ foreach (@unit_paths) {
+ if (-f "$_/$scriptname") {
+ $service_path = "$_/$scriptname";
+ }
+ foreach (<$_/$scriptname.d/*.conf>) {
+ $dropins{basename($_)} = $_;
+ }
+ }
+
+ return unless defined($service_path);
+
+ my $changed_sth = 0;
+ my $unit_config = {
+ 'WantedBy' => [],
+ 'RequiredBy' => [],
+ 'Also' => [],
+ 'Alias' => []
+ };
+
+ foreach ($service_path, sort values %dropins) {
+ open my $fh, '<', $_ or error("unable to read $_");
+ while (my $line = <$fh>) {
+ chomp($line);
+ if ($line =~ /^\s*(WantedBy|RequiredBy|Also|Alias)=(.*)$/i) {
+ my @values = shellwords($2);
+
+ # systemd will reset a list to empty if it encounters an
+ # empty value
+ if (scalar (@values) == 0) {
+ $unit_config->{$1} = [];
} else {
- unlink($service_link) if -e $service_link;
+ push(@{$unit_config->{$1}}, @values);
}
- $changed_sth = 1;
}
}
close($fh);
+ }
+
+ for my $value (@{$unit_config->{'WantedBy'}}) {
+ my $wants_dir = "/etc/systemd/system/$value.wants";
+ my $service_link = "$wants_dir/$scriptname";
+ if ("enable" eq $action) {
+ make_path($wants_dir);
+ symlink($service_path, $service_link);
+ } else {
+ unlink($service_link) if -e $service_link;
+ rmdir_if_empty($wants_dir);
+ }
+ $changed_sth = 1;
+ }
+
+ for my $value (@{$unit_config->{'RequiredBy'}}) {
+ my $requires_dir = "/etc/systemd/system/$value.requires";
+ my $service_link = "$requires_dir/$scriptname";
+ if ("enable" eq $action) {
+ make_path($requires_dir);
+ symlink($service_path, $service_link);
+ } else {
+ unlink($service_link) if -e $service_link;
+ rmdir_if_empty($requires_dir);
+ }
+ $changed_sth = 1;
+ }
- # 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 && -d "/run/systemd/system") {
- system("systemctl", "daemon-reload");
+ for my $value (@{$unit_config->{'Alias'}}) {
+ my $link = "/etc/systemd/system/$value";
+ if ("enable" eq $action) {
+ symlink($service_path, $link);
+ } else {
+ unlink($link) if -e $link;
}
+ $changed_sth = 1;
+ }
+
+ for my $value (@{$unit_config->{'Also'}}) {
+ make_systemd_links($value, $action, 1);
+ $changed_sth = 1;
+ }
+
+ # If we changed anything and this machine is running systemd, tell
+ # systemd to reload so that it will immediately pick up our
+ # changes. Only do this if we aren't calling ourselves recursively.
+ if (!$recursive && $changed_sth && -d "/run/systemd/system") {
+ system("systemctl", "daemon-reload");
}
}
@@ -213,7 +289,9 @@
error("initscript does not exist: /etc/init.d/$scriptname");
}
} elsif ("disable" eq $action || "enable" eq $action) {
- make_systemd_links($scriptname, $action);
+ # add .service suffix here because make_systemd_links must
+ # be able to call itself recursively for Also= in units
+ make_systemd_links("$scriptname.service", $action, 0);
upstart_toggle($scriptname, $action);
_______________________________________________
Pkg-sysvinit-devel mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-sysvinit-devel