624 lines
21 KiB
Perl
Executable File
624 lines
21 KiB
Perl
Executable File
#!/usr/bin/perl
|
||
# vim:ts=4:sw=4:expandtab
|
||
# © 2013-2014 Michael Stapelberg <stapelberg@debian.org>
|
||
#
|
||
# All rights reserved.
|
||
#
|
||
# Redistribution and use in source and binary forms, with or without
|
||
# modification, are permitted provided that the following conditions are met:
|
||
#
|
||
# * Redistributions of source code must retain the above copyright
|
||
# notice, this list of conditions and the following disclaimer.
|
||
#
|
||
# * Redistributions in binary form must reproduce the above copyright
|
||
# notice, this list of conditions and the following disclaimer in the
|
||
# documentation and/or other materials provided with the distribution.
|
||
#
|
||
# * Neither the name of Michael Stapelberg nor the
|
||
# names of contributors may be used to endorse or promote products
|
||
# derived from this software without specific prior written permission.
|
||
# .
|
||
# THIS SOFTWARE IS PROVIDED BY Michael Stapelberg ''AS IS'' AND ANY
|
||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
# DISCLAIMED. IN NO EVENT SHALL Michael Stapelberg BE LIABLE FOR ANY
|
||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
||
=head1 NAME
|
||
|
||
deb-systemd-helper - subset of systemctl for machines not running systemd
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
B<deb-systemd-helper> enable | disable | purge | mask | unmask | is-enabled | was-enabled | debian-installed | update-state | reenable S<I<unit file> ...>
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
B<deb-systemd-helper> is a Debian-specific helper script which re-implements
|
||
the enable, disable, is-enabled and reenable commands from systemctl.
|
||
|
||
The "enable" action will only be performed once (when first installing the
|
||
package). On the first "enable", a state file is created which will be deleted
|
||
upon "purge".
|
||
|
||
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.
|
||
|
||
The "debian-installed" action is also not present in systemctl. It returns 0 if
|
||
the state file of at least one of the given units is present.
|
||
|
||
The "update-state" action is also not present in systemctl. It updates
|
||
B<deb-systemd-helper>'s state file, removing obsolete entries (e.g. service
|
||
files that are no longer shipped by the package) and adding new entries (e.g.
|
||
new service files shipped by the package) without enabling them.
|
||
|
||
B<deb-systemd-helper> is intended to be used from maintscripts to enable
|
||
systemd unit files. It is specifically NOT intended to be used interactively by
|
||
users. Instead, users should run systemd and use systemctl, or not bother about
|
||
the systemd enabled state in case they are not running systemd.
|
||
|
||
=head1 ENVIRONMENT
|
||
|
||
=over 4
|
||
|
||
=item B<_DEB_SYSTEMD_HELPER_DEBUG>
|
||
|
||
If you export _DEB_SYSTEMD_HELPER_DEBUG=1, deb-systemd-helper will print debug
|
||
messages to stderr (thus visible in dpkg runs). Please include these when
|
||
filing a bugreport.
|
||
|
||
=back
|
||
|
||
=cut
|
||
|
||
use strict;
|
||
use warnings;
|
||
use File::Path qw(make_path); # in core since Perl 5.001
|
||
use File::Basename; # in core since Perl 5
|
||
use File::Temp qw(tempfile); # in core since Perl 5.6.1
|
||
use Getopt::Long; # in core since Perl 5
|
||
# Make Data::Dumper::Dumper available if present (not present on systems that
|
||
# only have perl-base, not perl).
|
||
eval { require Data::Dumper; } or *Data::Dumper::Dumper = sub { "no Data::Dumper" };
|
||
|
||
use constant {
|
||
SYSTEM_INSTANCE_ENABLED_STATE_DIR => '/var/lib/systemd/deb-systemd-helper-enabled',
|
||
USER_INSTANCE_ENABLED_STATE_DIR => '/var/lib/systemd/deb-systemd-user-helper-enabled',
|
||
SYSTEM_INSTANCE_MASKED_STATE_DIR => '/var/lib/systemd/deb-systemd-helper-masked',
|
||
USER_INSTANCE_MASKED_STATE_DIR => '/var/lib/systemd/deb-systemd-user-helper-masked',
|
||
};
|
||
|
||
my $quiet = 0;
|
||
my $instance = 'system';
|
||
my $enabled_state_dir = SYSTEM_INSTANCE_ENABLED_STATE_DIR;
|
||
my $masked_state_dir = SYSTEM_INSTANCE_MASKED_STATE_DIR;
|
||
|
||
# Globals are bad, but in this specific case, it really makes things much
|
||
# easier to write and understand.
|
||
my $changed_sth;
|
||
my $has_systemctl = -x "/bin/systemctl";
|
||
|
||
sub error {
|
||
print STDERR "$0: error: @_\n";
|
||
exit (1);
|
||
}
|
||
|
||
sub debug {
|
||
my ($msg) = @_;
|
||
return if !defined($ENV{_DEB_SYSTEMD_HELPER_DEBUG}) || $ENV{_DEB_SYSTEMD_HELPER_DEBUG} != 1;
|
||
print STDERR "(deb-systemd-helper DEBUG) $msg\n";
|
||
}
|
||
|
||
sub is_purge {
|
||
return (defined($ENV{_DEB_SYSTEMD_HELPER_PURGE}) && $ENV{_DEB_SYSTEMD_HELPER_PURGE} == 1)
|
||
}
|
||
|
||
sub find_unit {
|
||
my ($scriptname) = @_;
|
||
|
||
my $service_path = $scriptname;
|
||
|
||
if (-f "/etc/systemd/$instance/$scriptname") {
|
||
$service_path = "/etc/systemd/$instance/$scriptname";
|
||
} elsif (-f "/lib/systemd/$instance/$scriptname") {
|
||
$service_path = "/lib/systemd/$instance/$scriptname";
|
||
} elsif (-f "/usr/lib/systemd/$instance/$scriptname") {
|
||
$service_path = "/usr/lib/systemd/$instance/$scriptname";
|
||
}
|
||
|
||
return $service_path;
|
||
}
|
||
|
||
sub dsh_state_path {
|
||
my ($scriptname) = @_;
|
||
return $enabled_state_dir . '/' . basename($scriptname) . '.dsh-also';
|
||
}
|
||
|
||
sub state_file_entries {
|
||
my ($dsh_state) = @_;
|
||
debug "Reading state file $dsh_state";
|
||
my @entries;
|
||
if (open(my $fh, '<', $dsh_state)) {
|
||
@entries = map { chomp; $_ } <$fh>;
|
||
close($fh);
|
||
}
|
||
return @entries;
|
||
}
|
||
|
||
# Writes $service_link into $dsh_state unless it’s already in there.
|
||
sub record_in_statefile {
|
||
my ($dsh_state, $service_link) = @_;
|
||
|
||
# Appending a newline makes the following code simpler; we can skip
|
||
# chomp()ing and appending newlines in every print.
|
||
$service_link .= "\n";
|
||
|
||
make_path(dirname($dsh_state));
|
||
my $line_exists;
|
||
my ($outfh, $tmpname) = tempfile('.stateXXXXX',
|
||
DIR => dirname($dsh_state),
|
||
SUFFIX => '.tmp',
|
||
UNLINK => 0);
|
||
chmod(0644, $tmpname);
|
||
if (-e $dsh_state) {
|
||
open(my $infh, '<', $dsh_state) or error("unable to read from $dsh_state");
|
||
while (<$infh>) {
|
||
$line_exists = 1 if $_ eq $service_link;
|
||
print $outfh $_;
|
||
}
|
||
close($infh);
|
||
}
|
||
print $outfh $service_link unless $line_exists;
|
||
close($outfh);
|
||
|
||
debug "Renaming temp file $tmpname to state file $dsh_state";
|
||
rename($tmpname, $dsh_state) or
|
||
error("Unable to move $tmpname to $dsh_state");
|
||
}
|
||
|
||
# Gets the transitive closure of links, i.e. all links that need to be created
|
||
# when enabling this service file. Not straight-forward because service files
|
||
# can refer to other service files using Also=.
|
||
sub get_link_closure {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my @links;
|
||
|
||
my $unit_name = basename($service_path);
|
||
|
||
# The keys parsed from the unit file below can only have unit names
|
||
# as values. Since unit names can't have whitespace in systemd,
|
||
# simply use split and strip any leading/trailing quotes. See
|
||
# systemd-escape(1) for examples of valid unit names.
|
||
open my $fh, '<', $service_path or error("unable to read $service_path");
|
||
while (my $line = <$fh>) {
|
||
chomp($line);
|
||
my $service_link;
|
||
|
||
if ($line =~ /^\s*(WantedBy|RequiredBy)=(.+)$/i) {
|
||
for my $value (split(/\s+/, $2)) {
|
||
$value =~ s/^(["'])(.*)\g1$/$2/;
|
||
my $wants_dir = "/etc/systemd/$instance/$value";
|
||
$wants_dir .= '.wants' if $1 eq 'WantedBy';
|
||
$wants_dir .= '.requires' if $1 eq 'RequiredBy';
|
||
push @links, { dest => $service_path, src => "$wants_dir/$scriptname" };
|
||
}
|
||
}
|
||
|
||
if ($line =~ /^\s*Also=(.+)$/i) {
|
||
for my $value (split(/\s+/, $1)) {
|
||
$value =~ s/^(["'])(.*)\g1$/$2/;
|
||
if ($value ne $unit_name) {
|
||
push @links, get_link_closure($value, find_unit($value));
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($line =~ /^\s*Alias=(.+)$/i) {
|
||
for my $value (split(/\s+/, $1)) {
|
||
$value =~ s/^(["'])(.*)\g1$/$2/;
|
||
if ($value ne $unit_name) {
|
||
push @links, { dest => $service_path, src => "/etc/systemd/$instance/$1" };
|
||
}
|
||
}
|
||
}
|
||
}
|
||
close($fh);
|
||
|
||
return @links;
|
||
}
|
||
|
||
sub all_links_installed {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my @links = get_link_closure($scriptname, $service_path);
|
||
my @missing_links = grep { ! -l $_->{src} } @links;
|
||
|
||
return (@missing_links == 0);
|
||
}
|
||
|
||
sub no_link_installed {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my @links = get_link_closure($scriptname, $service_path);
|
||
my @existing_links = grep { -l $_->{src} } @links;
|
||
|
||
return (@existing_links == 0);
|
||
}
|
||
|
||
sub enable {
|
||
my ($scriptname, $service_path) = @_;
|
||
if ($has_systemctl) {
|
||
# We use 'systemctl preset' on the initial installation only.
|
||
# On upgrade, we manually add the missing symlinks only if the
|
||
# service already has some links installed. Using 'systemctl
|
||
# preset' allows administrators and downstreams to alter the
|
||
# enable policy using systemd-native tools.
|
||
my $create_links = 0;
|
||
if (debian_installed($scriptname)) {
|
||
$create_links = 1 unless no_link_installed($scriptname, $service_path);
|
||
} else {
|
||
debug "Using systemctl preset to enable $scriptname";
|
||
system("/bin/systemctl",
|
||
$instance eq "user" ? "--global" : "--system",
|
||
"--preset-mode=enable-only",
|
||
"preset", $scriptname) == 0
|
||
or error("systemctl preset failed on $scriptname: $!");
|
||
}
|
||
make_systemd_links($scriptname, $service_path, create_links => $create_links);
|
||
} else {
|
||
# We create all the symlinks ourselves
|
||
make_systemd_links($scriptname, $service_path);
|
||
}
|
||
}
|
||
|
||
sub make_systemd_links {
|
||
my ($scriptname, $service_path, %opts) = @_;
|
||
$opts{'create_links'} //= 1;
|
||
|
||
my $dsh_state = dsh_state_path($scriptname);
|
||
|
||
my @links = get_link_closure($scriptname, $service_path);
|
||
for my $link (@links) {
|
||
my $service_path = $link->{dest};
|
||
my $service_link = $link->{src};
|
||
|
||
record_in_statefile($dsh_state, $service_link);
|
||
|
||
my $statefile = $service_link;
|
||
$statefile =~ s,^/etc/systemd/$instance/,$enabled_state_dir/,;
|
||
next if -e $statefile;
|
||
|
||
if ($opts{'create_links'} && ! -l $service_link) {
|
||
make_path(dirname($service_link));
|
||
symlink($service_path, $service_link) or
|
||
error("unable to link $service_link to $service_path: $!");
|
||
$changed_sth = 1;
|
||
}
|
||
|
||
# Store the fact that we ran enable for this service_path,
|
||
# so that we can skip enable the next time.
|
||
# This allows us to call deb-systemd-helper unconditionally
|
||
# and still only enable unit files on the initial installation
|
||
# of a package.
|
||
make_path(dirname($statefile));
|
||
open(my $fh, '>>', $statefile);
|
||
close($fh);
|
||
}
|
||
|
||
}
|
||
|
||
# In contrary to make_systemd_links(), which only modifies the state file in an
|
||
# append-only fashion, update_state() can also remove entries from the state
|
||
# file.
|
||
#
|
||
# The distinction is important because update_state() should only be called
|
||
# when the unit file(s) are guaranteed to be on-disk, e.g. on package updates,
|
||
# but not on package removals.
|
||
sub update_state {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my $dsh_state = dsh_state_path($scriptname);
|
||
my @links = get_link_closure($scriptname, $service_path);
|
||
|
||
debug "Old state file contents: " .
|
||
Data::Dumper::Dumper([ state_file_entries($dsh_state) ]);
|
||
|
||
make_path(dirname($dsh_state));
|
||
my ($outfh, $tmpname) = tempfile('.stateXXXXX',
|
||
DIR => dirname($dsh_state),
|
||
SUFFIX => '.tmp',
|
||
UNLINK => 0);
|
||
chmod(0644, $tmpname);
|
||
for my $link (@links) {
|
||
print $outfh $link->{src} . "\n";
|
||
}
|
||
close($outfh);
|
||
|
||
debug "Renaming temp file $tmpname to state file $dsh_state";
|
||
rename($tmpname, $dsh_state) or
|
||
error("Unable to move $tmpname to $dsh_state");
|
||
|
||
debug "New state file contents: " .
|
||
Data::Dumper::Dumper([ state_file_entries($dsh_state) ]);
|
||
}
|
||
|
||
sub was_enabled {
|
||
my ($scriptname) = @_;
|
||
|
||
my @entries = state_file_entries(dsh_state_path($scriptname));
|
||
debug "Contents: " . Data::Dumper::Dumper(\@entries);
|
||
|
||
for my $link (@entries) {
|
||
if (! -l $link) {
|
||
debug "Link $link is missing, considering $scriptname was-disabled.";
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
debug "All links present, considering $scriptname was-enabled.";
|
||
return 1;
|
||
}
|
||
|
||
sub debian_installed {
|
||
my ($scriptname) = @_;
|
||
return -f dsh_state_path($scriptname);
|
||
}
|
||
|
||
sub remove_links {
|
||
my ($service_path) = @_;
|
||
|
||
my $dsh_state = dsh_state_path($service_path);
|
||
my @entries = state_file_entries($dsh_state);
|
||
debug "Contents: " . Data::Dumper::Dumper(\@entries);
|
||
|
||
if (is_purge()) {
|
||
unlink($dsh_state) if -e $dsh_state;
|
||
}
|
||
|
||
# Also disable all the units which were enabled when this one was enabled.
|
||
for my $link (@entries) {
|
||
# Delete the corresponding state file:
|
||
# • Always when purging
|
||
# • If the user did not disable (= link still exists) the service.
|
||
# If we don’t do this, the link will be deleted a few lines down,
|
||
# but not re-created when re-installing the package.
|
||
if (is_purge() || -l $link) {
|
||
my $link_state = $link;
|
||
$link_state =~ s,^/etc/systemd/$instance/,$enabled_state_dir/,;
|
||
unlink($link_state);
|
||
}
|
||
|
||
next unless -l $link;
|
||
unlink($link) or
|
||
print STDERR "$0: unable to remove '$link': $!\n";
|
||
|
||
$changed_sth = 1;
|
||
}
|
||
|
||
# Read $service_path, recurse for all Also= units.
|
||
# This might not work when $service_path was already deleted,
|
||
# i.e. after apt-get remove. In this case we just return
|
||
# silently in order to not confuse the user about whether
|
||
# disabling actually worked or not — the case is handled by
|
||
# dh_installsystemd generating an appropriate disable
|
||
# command by parsing the service file at debhelper-time.
|
||
open(my $fh, '<', $service_path) or return;
|
||
while (my $line = <$fh>) {
|
||
chomp($line);
|
||
my $service_link;
|
||
|
||
if ($line =~ /^\s*Also=(.+)$/i) {
|
||
remove_links(find_unit($1));
|
||
}
|
||
}
|
||
close($fh);
|
||
}
|
||
|
||
# Recursively deletes a directory structure, if all (!) components are empty,
|
||
# e.g. to clean up after purging.
|
||
sub rmdir_if_empty {
|
||
my ($dir) = @_;
|
||
|
||
debug "rmdir_if_empty $dir";
|
||
|
||
rmdir_if_empty($_) for (grep { -d } <$dir/*>);
|
||
|
||
if (!rmdir($dir)) {
|
||
debug "rmdir($dir) failed ($!)";
|
||
}
|
||
}
|
||
|
||
sub mask_service {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my $mask_link = "/etc/systemd/$instance/" . basename($service_path);
|
||
|
||
if (-e $mask_link) {
|
||
# If the link already exists, don’t do anything.
|
||
return if -l $mask_link && readlink($mask_link) eq '/dev/null';
|
||
|
||
# If the file already exists, the user most likely copied the .service
|
||
# file to /etc/ to change it in some way. In this case we don’t need to
|
||
# mask the .service in the first place, since it will not be removed by
|
||
# dpkg.
|
||
debug "$mask_link already exists, not masking.";
|
||
return;
|
||
}
|
||
|
||
make_path(dirname($mask_link));
|
||
# clean up after possible leftovers from Alias= to self (LP#1439793)
|
||
unlink($mask_link);
|
||
symlink('/dev/null', $mask_link) or
|
||
error("unable to link $mask_link to /dev/null: $!");
|
||
$changed_sth = 1;
|
||
|
||
my $statefile = $mask_link;
|
||
$statefile =~ s,^/etc/systemd/$instance/,$masked_state_dir/,;
|
||
|
||
# Store the fact that we masked this service, so that we can unmask it on
|
||
# installation time. We cannot unconditionally unmask because that would
|
||
# interfere with the user’s decision to mask a service.
|
||
make_path(dirname($statefile));
|
||
open(my $fh, '>>', $statefile);
|
||
close($fh);
|
||
}
|
||
|
||
sub unmask_service {
|
||
my ($scriptname, $service_path) = @_;
|
||
|
||
my $mask_link = "/etc/systemd/$instance/" . basename($service_path);
|
||
|
||
# Not masked? Nothing to do.
|
||
return unless -e $mask_link;
|
||
|
||
if (! -l $mask_link || readlink($mask_link) ne '/dev/null') {
|
||
debug "Not unmasking $mask_link because it is not a link to /dev/null";
|
||
return;
|
||
}
|
||
|
||
my $statefile = $mask_link;
|
||
$statefile =~ s,^/etc/systemd/$instance/,$masked_state_dir/,;
|
||
|
||
if (! -e $statefile) {
|
||
debug "Not unmasking $mask_link because the state file $statefile does not exist";
|
||
return;
|
||
}
|
||
|
||
unlink($mask_link) or
|
||
error("unable to remove $mask_link: $!");
|
||
$changed_sth = 1;
|
||
unlink($statefile);
|
||
}
|
||
|
||
my $result = GetOptions(
|
||
"quiet" => \$quiet,
|
||
"user" => sub { $instance = 'user'; },
|
||
"system" => sub { $instance = 'system'; }, # default
|
||
);
|
||
|
||
if ($instance eq 'user') {
|
||
debug "is user unit = yes";
|
||
$enabled_state_dir = USER_INSTANCE_ENABLED_STATE_DIR;
|
||
$masked_state_dir = USER_INSTANCE_MASKED_STATE_DIR;
|
||
}
|
||
|
||
my $action = shift;
|
||
if (!defined($action)) {
|
||
# Called without arguments. Explain that this script should not be run interactively.
|
||
print "$0 is a program which should be called by dpkg maintscripts only.\n";
|
||
print "Please do not run it interactively, ever. Also see the manpage deb-systemd-helper(1).\n";
|
||
exit 0;
|
||
}
|
||
|
||
if (!$ENV{DPKG_MAINTSCRIPT_PACKAGE}) {
|
||
print STDERR "$0 was not called from dpkg. Exiting.\n";
|
||
exit 1;
|
||
}
|
||
|
||
if ($action eq 'purge') {
|
||
$ENV{_DEB_SYSTEMD_HELPER_PURGE} = 1;
|
||
$action = 'disable';
|
||
}
|
||
|
||
debug "is purge = " . (is_purge() ? "yes" : "no");
|
||
|
||
my $rc = 0;
|
||
if ($action eq 'is-enabled' ||
|
||
$action eq 'was-enabled' ||
|
||
$action eq 'debian-installed') {
|
||
$rc = 1;
|
||
}
|
||
for my $scriptname (@ARGV) {
|
||
my $service_path = find_unit($scriptname);
|
||
|
||
debug "action = $action, scriptname = $scriptname, service_path = $service_path";
|
||
|
||
if ($action eq 'is-enabled') {
|
||
my $enabled = all_links_installed($scriptname, $service_path);
|
||
print STDERR ($enabled ? "enabled\n" : "disabled\n") unless $quiet;
|
||
$rc = 0 if $enabled;
|
||
}
|
||
|
||
# was-enabled is the same as is-enabled, but only considers links recorded
|
||
# in the state file. This is useful after package upgrades, to determine
|
||
# whether the unit file was enabled before upgrading, even if the unit file
|
||
# has changed and is not entirely enabled currently (due to a new Alias=
|
||
# line for example).
|
||
#
|
||
# If all machines were running systemd, this issue would not be present
|
||
# because is-enabled would query systemd, which would not have picked up
|
||
# the new unit file yet.
|
||
if ($action eq 'was-enabled') {
|
||
my $enabled = was_enabled($scriptname);
|
||
print STDERR ($enabled ? "enabled\n" : "disabled\n") unless $quiet;
|
||
$rc = 0 if $enabled;
|
||
}
|
||
|
||
if ($action eq 'update-state') {
|
||
update_state($scriptname, $service_path);
|
||
}
|
||
|
||
if ($action eq 'debian-installed') {
|
||
$rc = 0 if debian_installed($scriptname);
|
||
}
|
||
|
||
if ($action eq 'reenable') {
|
||
remove_links($service_path);
|
||
make_systemd_links($scriptname, $service_path);
|
||
}
|
||
|
||
if ($action eq 'disable') {
|
||
remove_links($service_path);
|
||
# Clean up the state dir if it’s empty, or at least clean up all empty
|
||
# subdirectories. Necessary to cleanly pass a piuparts run.
|
||
rmdir_if_empty(SYSTEM_INSTANCE_ENABLED_STATE_DIR);
|
||
rmdir_if_empty(USER_INSTANCE_ENABLED_STATE_DIR);
|
||
|
||
# Same with directories below /etc/systemd, where we create symlinks.
|
||
# If systemd is not installed (and no other package shipping service
|
||
# files), this would make piuparts fail, too.
|
||
rmdir_if_empty($_) for (grep { -d } </etc/systemd/system/*>);
|
||
rmdir_if_empty($_) for (grep { -d } </etc/systemd/user/*>);
|
||
}
|
||
|
||
if ($action eq 'enable') {
|
||
enable($scriptname, $service_path);
|
||
}
|
||
|
||
if ($action eq 'mask') {
|
||
mask_service($scriptname, $service_path);
|
||
}
|
||
|
||
if ($action eq 'unmask') {
|
||
unmask_service($scriptname, $service_path);
|
||
# Clean up the state dir if it’s empty, or at least clean up all empty
|
||
# subdirectories. Necessary to cleanly pass a piuparts run.
|
||
rmdir_if_empty('/var/lib/systemd/deb-systemd-helper-masked');
|
||
}
|
||
}
|
||
|
||
# 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 && $instance eq 'system' && -d "/run/systemd/system") {
|
||
system("systemctl", "daemon-reload");
|
||
}
|
||
|
||
exit $rc;
|
||
|
||
=head1 AUTHOR
|
||
|
||
Michael Stapelberg <stapelberg@debian.org>
|
||
|
||
=cut
|