diff options
author | Michael Stapelberg <michael@stapelberg.de> | 2013-09-15 04:20:35 +0000 |
---|---|---|
committer | Michael Stapelberg <michael@stapelberg.de> | 2013-09-15 04:20:35 +0000 |
commit | 9c1373f308d77d4dfaf7f644591facbe1e6825c3 (patch) | |
tree | 4955b38e18b270075c373e37b70354201c8b7ccd | |
parent | 73d6f8a2143f3af90bc229eef8d7cb091f160a03 (diff) | |
download | init-system-helpers-9c1373f308d77d4dfaf7f644591facbe1e6825c3.tar.gz |
d-s-h: implement mask and unmask commands
-rwxr-xr-x | script/deb-systemd-helper | 82 | ||||
-rw-r--r-- | t/001-deb-systemd-helper.t | 35 |
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; |