summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2013-09-15 04:20:35 +0000
committerMichael Stapelberg <michael@stapelberg.de>2013-09-15 04:20:35 +0000
commit9c1373f308d77d4dfaf7f644591facbe1e6825c3 (patch)
tree4955b38e18b270075c373e37b70354201c8b7ccd
parent73d6f8a2143f3af90bc229eef8d7cb091f160a03 (diff)
downloadinit-system-helpers-9c1373f308d77d4dfaf7f644591facbe1e6825c3.tar.gz
d-s-h: implement mask and unmask commands
-rwxr-xr-xscript/deb-systemd-helper82
-rw-r--r--t/001-deb-systemd-helper.t35
2 files changed, 112 insertions, 5 deletions
diff --git a/script/deb-systemd-helper b/script/deb-systemd-helper
index 62ffc79..ae83cfa 100755
--- a/script/deb-systemd-helper
+++ b/script/deb-systemd-helper
@@ -35,7 +35,7 @@ deb-systemd-helper - subset of systemctl for machines not running systemd
=head1 SYNOPSIS
-B<deb-systemd-helper> enable|disable|is-enabled|was-enabled|debian-installed|update-state|reenable S<I<unit file> ...>
+B<deb-systemd-helper> enable|disable|mask|unmask|is-enabled|was-enabled|debian-installed|update-state|reenable S<I<unit file> ...>
=head1 DESCRIPTION
@@ -47,6 +47,9 @@ package). On the first "enable", an state file is created which will be deleted
upon "disable", but only when _DEB_SYSTEMD_HELPER_PURGE=1 to distinguish purge
from remove.
+The "mask" action will keep state on whether the service was enabled/disabled
+before and will properly return to that state on "unmask".
+
The "was-enabled" action is not present in systemctl, but is required in Debian
so that we can figure out whether a service was enabled before we installed an
updated service file. See http://bugs.debian.org/717603 for details.
@@ -89,7 +92,8 @@ use Getopt::Long; # in core since Perl 5
use Data::Dumper;
my $quiet = 0;
-my $state_dir = '/var/lib/systemd/deb-systemd-helper-enabled';
+my $enabled_state_dir = '/var/lib/systemd/deb-systemd-helper-enabled';
+my $masked_state_dir = '/var/lib/systemd/deb-systemd-helper-masked';
# Globals are bad, but in this specific case, it really makes things much
# easier to write and understand.
@@ -124,7 +128,7 @@ sub find_unit {
sub dsh_state_path {
my ($scriptname) = @_;
- return $state_dir . '/' . basename($scriptname) . '.dsh-also';
+ return $enabled_state_dir . '/' . basename($scriptname) . '.dsh-also';
}
sub state_file_entries {
@@ -221,7 +225,7 @@ sub make_systemd_links {
record_in_statefile($dsh_state, $service_link);
my $statefile = $service_link;
- $statefile =~ s,^/etc/systemd/system/,$state_dir/,;
+ $statefile =~ s,^/etc/systemd/system/,$enabled_state_dir/,;
next if -e $statefile;
if (! -l $service_link) {
@@ -321,7 +325,7 @@ sub remove_links {
# but not re-created when re-installing the package.
if (is_purge() || -l $link) {
my $link_state = $link;
- $link_state =~ s,^/etc/systemd/system/,$state_dir/,;
+ $link_state =~ s,^/etc/systemd/system/,$enabled_state_dir/,;
unlink($link_state);
}
@@ -365,6 +369,66 @@ sub rmdir_if_empty {
}
}
+sub mask_service {
+ my ($scriptname, $service_path) = @_;
+
+ my @links = get_link_closure($scriptname, $service_path);
+ for my $link (@links) {
+ my $service_link = $link->{src};
+
+ my $statefile = $service_link;
+ $statefile =~ s,^/etc/systemd/system/,$masked_state_dir/,;
+ next if -e $statefile;
+
+ my $old_dest;
+ if (-l $service_link) {
+ $old_dest = readlink($service_link);
+ unlink($service_link);
+ } else {
+ make_path(dirname($service_link));
+ }
+ print STDERR "ln -s '/dev/null' '$service_link'\n" unless $quiet;
+ symlink('/dev/null', $service_link) or
+ error("unable to link $service_link to /dev/null: $!");
+ $changed_sth = 1;
+
+ # Store the old destination of the symlink so that we can unmask
+ # properly later.
+ make_path(dirname($statefile));
+ open(my $fh, '>>', $statefile);
+ print $fh $old_dest if defined($old_dest);
+ close($fh);
+ }
+}
+
+sub unmask_service {
+ my ($scriptname, $service_path) = @_;
+
+ my @links = get_link_closure($scriptname, $service_path);
+ for my $link (@links) {
+ my $service_link = $link->{src};
+
+ my $statefile = $service_link;
+ $statefile =~ s,^/etc/systemd/system/,$masked_state_dir/,;
+ next if ! -e $statefile;
+
+ my @entries = state_file_entries($statefile);
+
+ unlink($service_link) if -l $service_link;
+
+ if (@entries > 0) {
+ my $service_path = $entries[0];
+ make_path(dirname($service_link));
+ print STDERR "ln -s '$service_path' '$service_link'\n" unless $quiet;
+ symlink($service_path, $service_link) or
+ error("unable to link $service_link to $service_path: $!");
+ $changed_sth = 1;
+ }
+
+ unlink($statefile);
+ }
+}
+
my $result = GetOptions(
"quiet" => \$quiet,
);
@@ -446,6 +510,14 @@ for my $scriptname (@ARGV) {
if ($action eq 'enable') {
make_systemd_links($scriptname, $service_path);
}
+
+ if ($action eq 'mask') {
+ mask_service($scriptname, $service_path);
+ }
+
+ if ($action eq 'unmask') {
+ unmask_service($scriptname, $service_path);
+ }
}
# If we changed anything and this machine is running systemd, tell
diff --git a/t/001-deb-systemd-helper.t b/t/001-deb-systemd-helper.t
index c27408c..9c1773f 100644
--- a/t/001-deb-systemd-helper.t
+++ b/t/001-deb-systemd-helper.t
@@ -164,4 +164,39 @@ $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh
isnt_enabled($random_unit);
+# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+# ┃ Verify “enable” after purging does re-create the symlinks. ┃
+# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+ok(! -l $symlink_path, 'symlink does not exist yet');
+isnt_enabled($random_unit);
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit");
+
+is_enabled($random_unit);
+is_debian_installed($random_unit);
+
+# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+# ┃ Verify “mask” (when enabled) results in the symlink pointing to /dev/null ┃
+# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask $random_unit");
+is(readlink($symlink_path), '/dev/null', 'service masked');
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask $random_unit");
+isnt(readlink($symlink_path), '/dev/null', 'service no longer masked');
+
+# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+# ┃ Verify “mask” (when disabled) works the same way ┃
+# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh disable $random_unit");
+ok(! -e $symlink_path, 'symlink no longer exists');
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask $random_unit");
+is(readlink($symlink_path), '/dev/null', 'service masked');
+
+$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask $random_unit");
+ok(! -e $symlink_path, 'symlink no longer exists');
+
done_testing;