init-system-helpers-1.14/0000755000000000000000000000000012256525223012256 5ustar init-system-helpers-1.14/lib/0000755000000000000000000000000012256525223013024 5ustar init-system-helpers-1.14/lib/Debian/0000755000000000000000000000000012256525223014206 5ustar init-system-helpers-1.14/lib/Debian/Debhelper/0000755000000000000000000000000012256525223016100 5ustar init-system-helpers-1.14/lib/Debian/Debhelper/Sequence/0000755000000000000000000000000012256541666017661 5ustar init-system-helpers-1.14/lib/Debian/Debhelper/Sequence/systemd.pm0000644000000000000000000000070112256525223021674 0ustar #!/usr/bin/perl use warnings; use strict; use Debian::Debhelper::Dh_Lib; # dh_systemd_enable runs unconditionally, and before dh_installinit, so that # the latter can use invoke-rc.d and all symlinks are already in place. insert_before("dh_installinit", "dh_systemd_enable"); # dh_systemd_start handles the case where there is no corresponding init # script, so it runs after dh_installinit. insert_after("dh_installinit", "dh_systemd_start"); 1 init-system-helpers-1.14/script/0000755000000000000000000000000012256526550013566 5ustar init-system-helpers-1.14/script/deb-systemd-invoke0000755000000000000000000000572512256525223017232 0ustar #!/usr/bin/env perl # vim:ts=4:sw=4:expandtab # © 2013 Michael Stapelberg # # 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-invoke - wrapper around systemctl, respecting policy-rc.d =head1 SYNOPSIS B start|stop|restart S ...> =head1 DESCRIPTION B is a Debian-specific helper script which asks /usr/sbin/policy-rc.d before performing a systemctl call. B is intended to be used from maintscripts to start 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. =cut use strict; use warnings; if (@ARGV < 2) { print STDERR "Syntax: $0 [ ...]\n"; exit 1; } my $policyhelper = '/usr/sbin/policy-rc.d'; my @units = @ARGV; my $action = shift @units; if (-x $policyhelper) { for my $unit (@units) { system(qq|$policyhelper $unit "$action"|); # 104 means run # 101 means do not run my $exitcode = ($? >> 8); if ($exitcode == 101) { print STDERR "$policyhelper returned 101, not running '" . join(' ', @ARGV) . "'\n"; exit 0; } elsif ($exitcode != 104) { print STDERR "deb-systemd-invoke only supports $policyhelper return code 101 and 104!\n"; print STDERR "Got return code $exitcode, ignoring.\n"; } } } exec '/bin/systemctl', @ARGV; init-system-helpers-1.14/script/dh_systemd_enable0000755000000000000000000001435412256526547017202 0ustar #!/usr/bin/perl -w =head1 NAME dh_systemd_enable - enable/disable systemd unit files =cut use strict; use Debian::Debhelper::Dh_Lib; use File::Find; use Text::ParseWords qw(shellwords); # in core since Perl 5 =head1 SYNOPSIS B [S>] [B<--no-enable>] [S ...>] =head1 DESCRIPTION B is a debhelper program that is responsible for enabling and disabling systemd unit files. In the simple case, it finds all unit files installed by a package (e.g. bacula-fd.service) and enables them. It is not necessary that the machine actually runs systemd during package installation time, enabling happens on all machines in order to be able to switch from sysvinit to systemd and back. In the complex case, you can call B and B manually (by overwriting the debian/rules targets) and specify flags per unit file. An example is colord, which ships colord.service, a dbus-activated service without an [Install] section. This service file cannot be enabled or disabled (a state called "static" by systemd) because it has no [Install] section. Therefore, running dh_systemd_enable does not make sense. =head1 FILES =over 4 =item debian/I.service If this exists, it is installed into lib/systemd/system/I.service in the package build directory. =item debian/I.tmpfile If this exists, it is installed into usr/lib/tmpfiles.d/I.conf in the package build directory. (The tmpfiles.d mechanism is currently only used by systemd.) =back =head1 OPTIONS =over 4 =item B<--no-enable> Just disable the service(s) on purge, but do not enable them by default. =back =head1 NOTES Note that this command is not idempotent. L should be called between invocations of this command (with the same arguments). Otherwise, it may cause multiple instances of the same text to be added to maintainer scripts. Note that B should be run before B. The default sequence in B does the right thing, this note is only relevant when you are calling B manually. =cut init(options => { "no-enable" => \$dh{NO_ENABLE}, }); sub contains_install_section { my ($unit_path) = @_; my $fh; if (!open($fh, '<', $unit_path)) { warning("Cannot open($unit_path) for extracting the Also= line(s)"); return; } while (my $line = <$fh>) { chomp($line); return 1 if $line =~ /^\s*\[Install\]$/i; } close($fh); return 0; } foreach my $package (@{$dh{DOPACKAGES}}) { my $tmpdir = tmpdir($package); my @installed_units; my @units; # XXX: This is duplicated in dh_installinit, which is unfortunate. # We do need the service files before running dh_installinit though, # every other solution makes things much worse for all the maintainers. # Figure out what filename to install it as. my $script; my $jobfile=$package; if (defined $dh{NAME}) { $jobfile=$script=$dh{NAME}; } elsif ($dh{D_FLAG}) { # -d on the command line sets D_FLAG. We will # remove a trailing 'd' from the package name and # use that as the name. $script=$package; if ($script=~m/(.*)d$/) { $jobfile=$script=$1; } else { warning("\"$package\" has no final d' in its name, but -d was specified."); } } elsif ($dh{INIT_SCRIPT}) { $script=$dh{INIT_SCRIPT}; } else { $script=$package; } my $service=pkgfile($package,"service"); if ($service ne '') { my $path="$tmpdir/lib/systemd/system"; if (! -d "$path") { doit("install","-d","$path"); } doit("install","-p","-m644",$service,"$path/$script.service"); } my $socket=pkgfile($package,"socket"); if ($socket ne '') { my $path="$tmpdir/lib/systemd/system"; if (! -d "$path") { doit("install","-d","$path"); } doit("install","-p","-m644",$socket,"$path/$script.socket"); } my $tmpfile=pkgfile($package,"tmpfile"); if ($tmpfile ne '') { my $path="$tmpdir/usr/lib/tmpfiles.d"; if (! -d "$path") { doit("install","-d","$path"); } doit("install","-p","-m644",$tmpfile,"$path/$script.conf"); } find({ wanted => sub { my $name = $File::Find::name; return unless -f $name; # Skip symbolic links, their only legitimate use is for # adding an alias, e.g. linking smartmontools.service # -> smartd.service. return if -l $name; return unless $name =~ m,^$tmpdir/lib/systemd/system/[^/]+$,; push @installed_units, $name; }, no_chdir => 1, }, $tmpdir); # Handle either only the unit files which were passed as arguments or # all unit files that are installed in this package. my @args = @ARGV > 0 ? @ARGV : @installed_units; for my $name (@args) { my $base = basename($name); # Try to make the path absolute, so that the user can call # dh_installsystemd bacula-fd.service if ($base eq $name) { # NB: This works because @installed_units contains # files from precisely one directory. my ($full) = grep { basename($_) eq $base } @installed_units; if (defined($full)) { $name = $full; } else { warning(qq|Could not find "$name" in the /lib/systemd/system of $package.| . qq|This could be a typo, or using Also= with a service file from another package.| . qq|Please check carefully that this message is harmless.|); } } # Skip template service files like e.g. getty@.service. # Enabling, disabling, starting or stopping those services # without specifying the instance (e.g. getty@ttyS0.service) is # not useful. if ($name =~ /\@/) { next; } # Skip unit files that don’t have an [Install] section. next unless contains_install_section($name); push @units, $name; } next if @units == 0; my $unitargs = join(" ", map { basename($_) } @units); for my $unit (@units) { my $base = basename($unit); if ($dh{NO_ENABLE}) { autoscript($package, "postinst", "postinst-systemd-dont-enable", "s/#UNITFILE#/$base/"); } else { autoscript($package, "postinst", "postinst-systemd-enable", "s/#UNITFILE#/$base/"); } } autoscript($package, "postrm", "postrm-systemd", "s/#UNITFILES#/$unitargs/"); # init-system-helpers ships deb-systemd-helper which we use in our # autoscripts addsubstvar($package, "misc:Depends", "init-system-helpers (>= 1.13~)"); } =head1 SEE ALSO L, L =head1 AUTHORS pkg-systemd-maintainers@lists.alioth.debian.org =cut init-system-helpers-1.14/script/dh_systemd_start0000755000000000000000000001470012256526435017100 0ustar #!/usr/bin/perl -w =head1 NAME dh_systemd_start - start/stop/restart systemd unit files =cut use strict; use Debian::Debhelper::Dh_Lib; use File::Find; use Text::ParseWords qw(shellwords); # in core since Perl 5 use Cwd qw(getcwd abs_path); =head1 SYNOPSIS B [S>] [B<--restart-after-upgrade>] [B<--no-restart-on-upgrade>] [S ...>] =head1 DESCRIPTION B is a debhelper program that is responsible for starting/stopping or restarting systemd unit files in case no corresponding sysv init script is available. As with B, the unit file is stopped before upgrades and started afterwards (unless B<--restart-after-upgrade> is specified, in which case it will only be restarted after the upgrade). This logic is not used when there is a corresponding SysV init script because invoke-rc.d performs the stop/start/restart in that case. =head1 OPTIONS =over 4 =item B<--restart-after-upgrade> Do not stop the unit file until after the package upgrade has been completed. This is different than the default behavior, which stops the unit file in the F and starts it again in the F maintscript. This can be useful for daemons that should not have a possibly long downtime during upgrade. But you should make sure that the daemon will not get confused by the package being upgraded while it's running before using this option. =item B<-r>, B<--no-restart-on-upgrade> Do not stop service on upgrade. =item B<--no-start> Do not start the unit file after upgrades and after initial installation (the latter is only relevant for services without a corresponding init script). =back =head1 NOTES Note that this command is not idempotent. L should be called between invocations of this command (with the same arguments). Otherwise, it may cause multiple instances of the same text to be added to maintainer scripts. Note that B should be run after B so that it can detect corresponding SysV init scripts. The default sequence in B does the right thing, this note is only relevant when you are calling B manually. =cut init(options => { "r" => \$dh{R_FLAG}, "no-restart-on-upgrade" => \$dh{R_FLAG}, "no-start" => \$dh{NO_START}, "R|restart-after-upgrade" => \$dh{RESTART_AFTER_UPGRADE}, "no-also" => \$dh{NO_ALSO}, }); # Extracts the Also= or Alias= line(s) from a unit file. # In case this produces horribly wrong results, you can pass --no-also, but # that should really not be necessary. Please report bugs to # pkg-systemd-maintainers. sub extract_key { my ($unit_path, $key) = @_; my @values; my $fh; if ($dh{NO_ALSO}) { return @values; } if (!open($fh, '<', $unit_path)) { warning("Cannot open($unit_path) for extracting the Also= line(s)"); return; } while (my $line = <$fh>) { chomp($line); if ($line =~ /^\s*$key=(.+)$/i) { @values = (@values, shellwords($1)); } } close($fh); return @values; } foreach my $package (@{$dh{DOPACKAGES}}) { my $tmpdir = tmpdir($package); my @installed_units; my @units; my %aliases; my $oldcwd = getcwd(); find({ wanted => sub { my $name = $File::Find::name; return unless -f; return unless $name =~ m,^$tmpdir/lib/systemd/system/[^/]+$,; if (-l) { my $target = abs_path(readlink()); $target =~ s,^$oldcwd/,,g; $aliases{$target} = [ $_ ]; } else { push @installed_units, $name; } }, }, $tmpdir); chdir($oldcwd); # Handle either only the unit files which were passed as arguments or # all unit files that are installed in this package. my @args = @ARGV > 0 ? @ARGV : @installed_units; # This hash prevents us from looping forever in the following while loop. # An actual real-world example of such a loop is systemd’s # systemd-readahead-drop.service, which contains # Also=systemd-readahead-collect.service, and that file in turn # contains Also=systemd-readahead-drop.service, thus forming an endless # loop. my %seen; # We use while/shift because we push to the list in the body. while (@args) { my $name = shift @args; my $base = basename($name); # Try to make the path absolute, so that the user can call # dh_installsystemd bacula-fd.service if ($base eq $name) { # NB: This works because @installed_units contains # files from precisely one directory. my ($full) = grep { basename($_) eq $base } @installed_units; if (defined($full)) { $name = $full; } else { warning(qq|Could not find "$name" in the /lib/systemd/system of $package. | . qq|This could be a typo, or using Also= with a service file from another package. | . qq|Please check carefully that this message is harmless.|); } } # Skip template service files like e.g. getty@.service. # Enabling, disabling, starting or stopping those services # without specifying the instance (e.g. getty@ttyS0.service) is # not useful. if ($name =~ /\@/) { next; } # Handle all unit files specified via Also= explicitly. # This is not necessary for enabling, but for disabling, as we # cannot read the unit file when disabling (it was already # deleted). my @also = grep { !exists($seen{$_}) } extract_key($name, 'Also'); $seen{$_} = 1 for @also; @args = (@args, @also); push @{$aliases{$name}}, $_ for extract_key($name, 'Alias'); my @sysv = grep { my $base = $_; $base =~ s/\.(?:service|socket)$//g; -f "$tmpdir/etc/init.d/$base" } ($base, @{$aliases{$name}}); if (@sysv == 0 && !grep { $_ eq $name } @units) { push @units, $name; } } next if @units == 0; # The $package and $sed parameters are always the same. # This wrapper function makes the following logic easier to read. my $sd_autoscript = sub { my ($script, $filename) = @_; my $unitargs = join(" ", map { basename($_) } @units); autoscript($package, $script, $filename, "s/#UNITFILES#/$unitargs/"); }; if ($dh{RESTART_AFTER_UPGRADE}) { $sd_autoscript->("postinst", "postinst-systemd-restart"); } elsif (!$dh{NO_START}) { # We need to stop/start before/after the upgrade. $sd_autoscript->("postinst", "postinst-systemd-start"); } $sd_autoscript->("postrm", "postrm-systemd-reload-only"); if ($dh{R_FLAG} || $dh{RESTART_AFTER_UPGRADE}) { # stop service only on remove $sd_autoscript->("prerm", "prerm-systemd-restart"); } elsif (!$dh{NO_START}) { # always stop service $sd_autoscript->("prerm", "prerm-systemd"); } } =head1 SEE ALSO L =head1 AUTHORS pkg-systemd-maintainers@lists.alioth.debian.org =cut init-system-helpers-1.14/script/deb-systemd-helper0000755000000000000000000004230712256525223017213 0ustar #!/usr/bin/env perl # vim:ts=4:sw=4:expandtab # © 2013 Michael Stapelberg # # 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 enable|disable|mask|unmask|is-enabled|was-enabled|debian-installed|update-state|reenable S ...> =head1 DESCRIPTION B 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", 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. 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'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 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::Find; # in core since Perl 5 use File::Temp qw(tempfile); # in core since Perl 5.6.1 use Text::ParseWords qw(shellwords); # in core since Perl 5 use Getopt::Long; # in core since Perl 5 use Data::Dumper; my $quiet = 0; 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. my $changed_sth; 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/system/$scriptname") { $service_path = "/etc/systemd/system/$scriptname"; } elsif (-f "/lib/systemd/system/$scriptname") { $service_path = "/lib/systemd/system/$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; 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 (shellwords($2)) { my $wants_dir = "/etc/systemd/system/$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 (shellwords($1)) { push @links, get_link_closure($value, find_unit($value)); } } if ($line =~ /^\s*Alias=(.+)$/i) { for my $value (shellwords($1)) { push @links, { dest => $service_path, src => "/etc/systemd/system/$1" }; } } } close($fh); return @links; } sub make_systemd_links { my ($scriptname, $service_path) = @_; 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/system/,$enabled_state_dir/,; next if -e $statefile; if (! -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: " . 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: " . Dumper([ state_file_entries($dsh_state) ]); } sub was_enabled { my ($scriptname) = @_; my @entries = state_file_entries(dsh_state_path($scriptname)); debug "Contents: " . 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: " . 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/system/,$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/system/' . 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'; # Otherwise, error out. error("$mask_link already exists"); } make_path(dirname($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/system/,$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/system/' . 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/system/,$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, ); 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; } 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 @links = get_link_closure($scriptname, $service_path); my @missing_links = grep { ! -l $_->{src} } @links; my $enabled = (@missing_links == 0); 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('/var/lib/systemd/deb-systemd-helper-enabled'); # Same with /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('/etc/systemd'); } 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); # 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 && -d "/run/systemd/system") { system("systemctl", "daemon-reload"); } exit $rc; =head1 AUTHOR Michael Stapelberg =cut init-system-helpers-1.14/debian/0000755000000000000000000000000012256557475013516 5ustar init-system-helpers-1.14/debian/dh-systemd.manpages0000644000000000000000000000006712256525223017301 0ustar script/dh_systemd_enable.1p script/dh_systemd_start.1p init-system-helpers-1.14/debian/init-system-helpers.manpages0000644000000000000000000000007212256525223021141 0ustar script/deb-systemd-helper.1p script/deb-systemd-invoke.1p init-system-helpers-1.14/debian/rules0000755000000000000000000000111112256525223014552 0ustar #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 override_dh_auto_build: dh_auto_build for file in $$(ls script); do \ pod2man --section=1p --utf8 script/$$file script/$$file.1p; \ done %: dh $@ init-system-helpers-1.14/debian/control0000644000000000000000000000326012256525223015104 0ustar Source: init-system-helpers Section: admin Priority: extra Maintainer: pkg-systemd-maintainers Uploaders: Michael Stapelberg , Tollef Fog Heen , Michael Biebl Build-Depends: debhelper (>= 8.0.0), perl Standards-Version: 3.9.4 Vcs-Git: git://anonscm.debian.org/collab-maint/init-system-helpers.git Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/init-system-helpers.git;a=summary Package: init-system-helpers Architecture: all Multi-Arch: foreign Depends: ${perl:Depends}, ${misc:Depends} Breaks: systemd (<< 44-12) Description: helper tools for all init systems This package contains helper tools that are necessary for switching between the various init systems that Debian contains (e.g. sysvinit, upstart, systemd). An example is deb-systemd-helper, a script that enables systemd unit files without depending on a running systemd. . While this package is maintained by pkg-systemd-maintainers, it is NOT specific to systemd at all. Maintainers of other init systems are welcome to include their helpers in this package. Package: dh-systemd Architecture: all Multi-Arch: foreign Depends: ${perl:Depends}, ${misc:Depends}, debhelper Description: debhelper add-on to handle systemd unit files dh-systemd provides a debhelper sequence addon named 'systemd' and the dh_systemd_enable/dh_systemd_start commands. . The dh_systemd_enable command adds the appropriate code to the postinst, prerm and postrm maint scripts to properly enable/disable systemd service files. The dh_systemd_start command deals with start/stop/restart on upgrades for systemd-only service files. init-system-helpers-1.14/debian/source/0000755000000000000000000000000012256525223015000 5ustar init-system-helpers-1.14/debian/source/format0000644000000000000000000000001512256525223016207 0ustar 3.0 (native) init-system-helpers-1.14/debian/init-system-helpers.dirs0000644000000000000000000000002112256525223020301 0ustar /var/lib/systemd init-system-helpers-1.14/debian/changelog0000644000000000000000000001127012256557475015371 0ustar init-system-helpers (1.14) unstable; urgency=low * dh_systemd: treat symlinks like aliases (Closes: #731803) -- Michael Stapelberg Wed, 25 Dec 2013 14:35:55 +0100 init-system-helpers (1.13) unstable; urgency=low * d-s-h: cleanup state directory on unmask (for piuparts) -- Michael Stapelberg Wed, 06 Nov 2013 19:10:45 +0100 init-system-helpers (1.12) unstable; urgency=low * dh_systemd: lower generated dependency from 1.11 to 1.11~ * d-s-h: Don’t print action(s) to stderr, no news are good news (Closes: #723727) -- Michael Stapelberg Mon, 04 Nov 2013 19:52:10 +0100 init-system-helpers (1.11) unstable; urgency=low * dh_systemd_enable: unmask service on purge to not leave the mask sylink behind (Closes: #723759) -- Michael Stapelberg Fri, 20 Sep 2013 16:27:46 +0200 init-system-helpers (1.10) unstable; urgency=low * Bugfix: check whether /var/lib/systemd/deb-systemd-helper-enabled exists (Thanks Alf Gaida) (Closes: #723693) * d-s-h: Fix mask/unmask implementation (Thanks Michael Biebl) (Closes: #714903) -- Michael Stapelberg Thu, 19 Sep 2013 02:13:14 +0000 init-system-helpers (1.9) unstable; urgency=low * dh_systemd_enable: document debian/package.{service,tmpfile} * Bugfix: create files with permission 0644 (Closes: #722524) * dh_systemd_enable: skip unit files without an [Install] section (Closes: #721241) * d-s-h: implement mask and unmask commands * update maintscripts to mask a service while removed (but not purged) (Closes: #722521, #714903) -- Michael Stapelberg Wed, 18 Sep 2013 04:46:06 +0200 init-system-helpers (1.8) unstable; urgency=low * Add test suite (development-time, not build-time) * deb-systemd-helper: implement was-enabled, debian-installed, update-state * deb-systemd-helper: update files atomically to be more robust when being cancelled * dh_systemd_enable: deal with changes to the [Install] section (Closes: #717603) -- Michael Stapelberg Wed, 24 Jul 2013 22:43:08 +0200 init-system-helpers (1.7) unstable; urgency=low * Drop dependency on libmodule-install-perl to make it easier to have this package in Ubuntu (Thanks Jeremy Bicha) (Closes: #716929) -- Michael Stapelberg Tue, 16 Jul 2013 23:53:28 +0200 init-system-helpers (1.6) unstable; urgency=low * Fix syntax error in dh_systemd_start (Closes: #716946) -- Michael Stapelberg Mon, 15 Jul 2013 17:49:57 +0200 init-system-helpers (1.5) unstable; urgency=low * deb-systemd-helper: clean up /var/lib/systemd/deb-systemd-helper-enabled and /etc/systemd to pass a piuparts run. * deb-systemd-helper: add --quiet * dh_systemd_enable: add --no-enable * dh_systemd_start: add --no-start -- Michael Stapelberg Sun, 14 Jul 2013 21:53:26 +0200 init-system-helpers (1.4) unstable; urgency=low * deb-systemd-helper: ensure state directory exists before writing to it (Thanks uau, bigon) (Closes: #714265) -- Michael Stapelberg Thu, 27 Jun 2013 18:28:36 +0200 init-system-helpers (1.3) unstable; urgency=low * deb-systemd-helpe): replicate /etc/systemd/system in state dir * deb-systemd-helper: delete state file on remove if user didn’t disable service * deb-systemd-helper: always store .dsh-also state, not only when creating links * add deb-systemd-invoke, a wrapper which respects (basic) policy-rc.d -- Michael Stapelberg Wed, 19 Jun 2013 19:44:59 +0200 init-system-helpers (1.2) unstable; urgency=low * split dh_systemd into dh_systemd_start and dh_systemd_enable. This makes each helper much easier and allows us to do the right thing — we need to run parts of the code _before_ dh_installinit and parts of the code _afterwards_. * deb-systemd-helper: only remove state file on purge. * deb-systemd-helper: store state about which units were enabled in addition to the specified one. This allows us to drop Also= and Alias= units from the call to deb-systemd-helper and behave more like systemctl. -- Michael Stapelberg Tue, 18 Jun 2013 23:38:45 +0200 init-system-helpers (1.1) unstable; urgency=low * deb-systemd-helper: also store enable state for already enabled units * add dh-systemd package which contains the dh_systemd debhelper add-on -- Michael Stapelberg Tue, 11 Jun 2013 23:32:02 +0200 init-system-helpers (1.0) unstable; urgency=low * Initial release -- Michael Stapelberg Sun, 05 May 2013 11:25:48 +0200 init-system-helpers-1.14/debian/copyright0000644000000000000000000000335012256525223015434 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: deb-systemd-helper Copyright: 2013 Michael Stapelberg License: BSD Files: debian/* Copyright: 2013 Michael Stapelberg License: BSD License: BSD Copyright © 2013 Michael Stapelberg 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. init-system-helpers-1.14/debian/compat0000644000000000000000000000000212256525223014676 0ustar 8 init-system-helpers-1.14/debian/init-system-helpers.postinst0000644000000000000000000000043612256525223021235 0ustar #!/bin/sh set -e # See http://bugs.debian.org/722524 if dpkg --compare-versions "$2" lt "1.9"; then if [ -d /var/lib/systemd/deb-systemd-helper-enabled ]; then find /var/lib/systemd/deb-systemd-helper-enabled -type f -exec chmod 644 '{}' \; fi fi #DEBHELPER# exit 0 init-system-helpers-1.14/debian/init-system-helpers.install0000644000000000000000000000010412256525223021010 0ustar script/deb-systemd-helper usr/bin script/deb-systemd-invoke usr/bin init-system-helpers-1.14/debian/dh-systemd.install0000644000000000000000000000026512256525223017154 0ustar script/dh_systemd_start usr/bin script/dh_systemd_enable usr/bin autoscripts usr/share/debhelper lib/Debian/Debhelper/Sequence/systemd.pm usr/share/perl5/Debian/Debhelper/Sequence/ init-system-helpers-1.14/autoscripts/0000755000000000000000000000000012256525223014636 5ustar init-system-helpers-1.14/autoscripts/prerm-systemd-restart0000644000000000000000000000015412256525223021056 0ustar if [ -d /run/systemd/system ] && [ "$1" = remove ]; then deb-systemd-invoke stop #UNITFILES# >/dev/null fi init-system-helpers-1.14/autoscripts/postrm-systemd-reload-only0000644000000000000000000000013412256525223022014 0ustar if [ -d /run/systemd/system ]; then systemctl --system daemon-reload >/dev/null || true fi init-system-helpers-1.14/autoscripts/prerm-systemd0000644000000000000000000000012712256525223017374 0ustar if [ -d /run/systemd/system ]; then deb-systemd-invoke stop #UNITFILES# >/dev/null fi init-system-helpers-1.14/autoscripts/postinst-systemd-enable0000644000000000000000000000113612256525223021357 0ustar # This will only remove masks created by d-s-h on package removal. deb-systemd-helper unmask #UNITFILE# >/dev/null || true # was-enabled defaults to true, so new installations run enable. if deb-systemd-helper --quiet was-enabled #UNITFILE#; then # Enables the unit on first installation, creates new # symlinks on upgrades if the unit file has changed. deb-systemd-helper enable #UNITFILE# >/dev/null || true else # Update the statefile to add new symlinks (if any), which need to be # cleaned up on purge. Also remove old symlinks. deb-systemd-helper update-state #UNITFILE# >/dev/null || true fi init-system-helpers-1.14/autoscripts/postinst-systemd-start0000644000000000000000000000022512256525223021264 0ustar if [ -d /run/systemd/system ]; then systemctl --system daemon-reload >/dev/null || true deb-systemd-invoke start #UNITFILES# >/dev/null || true fi init-system-helpers-1.14/autoscripts/postrm-systemd0000644000000000000000000000054312256525223017575 0ustar if [ "$1" = "remove" ]; then if [ -x "/usr/bin/deb-systemd-helper" ]; then deb-systemd-helper mask #UNITFILES# >/dev/null fi fi if [ "$1" = "purge" ]; then if [ -x "/usr/bin/deb-systemd-helper" ]; then export _DEB_SYSTEMD_HELPER_PURGE=1 deb-systemd-helper disable #UNITFILES# >/dev/null deb-systemd-helper unmask #UNITFILES# >/dev/null fi fi init-system-helpers-1.14/autoscripts/postinst-systemd-dont-enable0000644000000000000000000000101212256525223022312 0ustar if deb-systemd-helper debian-installed #UNITFILE#; then # This will only remove masks created by d-s-h on package removal. deb-systemd-helper unmask #UNITFILE# >/dev/null || true if deb-systemd-helper --quiet was-enabled #UNITFILE#; then # Create new symlinks, if any. deb-systemd-helper enable #UNITFILE# >/dev/null || true fi fi # Update the statefile to add new symlinks (if any), which need to be cleaned # up on purge. Also remove old symlinks. deb-systemd-helper update-state #UNITFILE# >/dev/null || true init-system-helpers-1.14/autoscripts/postinst-systemd-restart0000644000000000000000000000023312256525223021612 0ustar if [ -d /run/systemd/system ]; then systemctl --system daemon-reload >/dev/null || true deb-systemd-invoke try-restart #UNITFILES# >/dev/null || true fi init-system-helpers-1.14/t/0000755000000000000000000000000012256525223012521 5ustar init-system-helpers-1.14/t/002-deb-systemd-helper-update.t0000644000000000000000000003154212256525223020167 0ustar #!perl # vim:ts=4:sw=4:et use strict; use warnings; use Test::More; use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1 use File::Path qw(make_path); # in core since Perl 5.001 use File::Basename; # in core since Perl 5 use FindBin; # in core since Perl 5.00307 use Linux::Clone; # neither in core nor in Debian :-/ # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃ # ┃ /var/lib/systemd to start with clean directories yet use the actual ┃ # ┃ locations and code paths. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $dsh = "$FindBin::Bin/../script/deb-systemd-helper"; # reads in a whole file sub slurp { open my $fh, '<', shift; local $/; <$fh>; } sub state_file_entries { my ($path) = @_; my $bytes = slurp($path); return split("\n", $bytes); } sub _unit_enabled { my ($unit_file, $cb, $verb) = @_; my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh is-enabled $unit_file"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); $cb->($retval >> 8, 0, "random unit file $verb enabled"); } sub is_enabled { _unit_enabled($_[0], \&is, 'is') } sub isnt_enabled { _unit_enabled($_[0], \&isnt, 'isnt') } my $retval = Linux::Clone::unshare Linux::Clone::NEWNS; BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0; sub bind_mount_tmp { my ($dir) = @_; my $tmp = tempdir(CLEANUP => 1); system("mount -n --bind $tmp $dir") == 0 or BAIL_OUT("bind-mounting $tmp to $dir failed: $!"); return $tmp; } my $etc_systemd = bind_mount_tmp('/etc/systemd'); my $lib_systemd = bind_mount_tmp('/lib/systemd'); my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” is not true for a random, non-existing unit file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my ($fh, $random_unit) = tempfile('unitXXXXX', SUFFIX => '.service', TMPDIR => 1, UNLINK => 1); close($fh); $random_unit = basename($random_unit); my $statefile = "/var/lib/systemd/deb-systemd-helper-enabled/$random_unit.dsh-also"; my $servicefile_path = "/lib/systemd/system/$random_unit"; make_path('/lib/systemd/system'); open($fh, '>', $servicefile_path); print $fh <<'EOT'; [Unit] Description=test unit [Service] ExecStart=/bin/sleep 1 [Install] WantedBy=multi-user.target EOT close($fh); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “enable” creates the requested symlinks. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); my $symlink_path = "/etc/systemd/system/multi-user.target.wants/$random_unit"; ok(-l $symlink_path, "$random_unit was enabled"); is(readlink($symlink_path), $servicefile_path, "symlink points to $servicefile_path"); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” now returns true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_enabled($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Modify the unit file and verify that “is-enabled” is no longer true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ open($fh, '>>', $servicefile_path); print $fh "Alias=newalias.service\n"; close($fh); isnt_enabled($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “was-enabled” is still true (operates on the state file). ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh was-enabled $random_unit"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); is($retval >> 8, 0, "random unit file was-enabled"); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify the new symlink is not yet in the state file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_deeply( [ state_file_entries($statefile) ], [ $symlink_path ], 'state file does not contain the new link yet'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “enable” creates the new symlinks. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $new_symlink_path = '/etc/systemd/system/newalias.service'; ok(! -l $new_symlink_path, 'new symlink does not exist yet'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); ok(-l $new_symlink_path, 'new symlink was created'); is(readlink($new_symlink_path), $servicefile_path, "symlink points to $servicefile_path"); is_enabled($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify the new symlink was recorded in the state file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_deeply( [ state_file_entries($statefile) ], [ $symlink_path, $new_symlink_path ], 'state file updated'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Modify the unit file and verify that “is-enabled” is no longer true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ open($fh, '>>', $servicefile_path); print $fh "Alias=another.service\n"; close($fh); isnt_enabled($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “was-enabled” is still true (operates on the state file). ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh was-enabled $random_unit"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); is($retval >> 8, 0, "random unit file was-enabled"); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify the new symlink is not yet in the state file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_deeply( [ state_file_entries($statefile) ], [ $symlink_path, $new_symlink_path ], 'state file does not contain the new link yet'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “update-state” does not create the symlink, but records it in the ┃ # ┃ state file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $new_symlink_path2 = '/etc/systemd/system/another.service'; ok(! -l $new_symlink_path2, 'new symlink does not exist yet'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh update-state $random_unit"); ok(! -l $new_symlink_path2, 'new symlink still does not exist'); isnt_enabled($random_unit); is_deeply( [ state_file_entries($statefile) ], [ $symlink_path, $new_symlink_path, $new_symlink_path2 ], 'state file updated'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Rewrite the original contents and verify “update-state” removes the old ┃ # ┃ links that are no longer present. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ open($fh, '>', $servicefile_path); print $fh <<'EOT'; [Unit] Description=test unit [Service] ExecStart=/bin/sleep 1 [Install] WantedBy=multi-user.target EOT close($fh); unlink($new_symlink_path); ok(! -l $new_symlink_path, 'new symlink still does not exist'); ok(! -l $new_symlink_path2, 'new symlink 2 still does not exist'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh update-state $random_unit"); ok(! -l $new_symlink_path, 'new symlink still does not exist'); ok(! -l $new_symlink_path2, 'new symlink 2 still does not exist'); is_enabled($random_unit); is_deeply( [ state_file_entries($statefile) ], [ $symlink_path ], 'state file updated'); done_testing; init-system-helpers-1.14/t/003-deb-systemd-helper-complex.t0000644000000000000000000001333512256525223020355 0ustar #!perl # vim:ts=4:sw=4:et use strict; use warnings; use Test::More; use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1 use File::Path qw(make_path); # in core since Perl 5.001 use File::Basename; # in core since Perl 5 use FindBin; # in core since Perl 5.00307 use Linux::Clone; # neither in core nor in Debian :-/ # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃ # ┃ /var/lib/systemd to start with clean directories yet use the actual ┃ # ┃ locations and code paths. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $dsh = "$FindBin::Bin/../script/deb-systemd-helper"; sub _unit_check { my ($unit_file, $cmd, $cb, $verb) = @_; my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd $unit_file"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); $cb->($retval >> 8, 0, "random unit file $unit_file $verb $cmd"); } sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') } sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') } sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') } sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') } my $retval = Linux::Clone::unshare Linux::Clone::NEWNS; BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0; sub bind_mount_tmp { my ($dir) = @_; my $tmp = tempdir(CLEANUP => 1); system("mount -n --bind $tmp $dir") == 0 or BAIL_OUT("bind-mounting $tmp to $dir failed: $!"); return $tmp; } my $etc_systemd = bind_mount_tmp('/etc/systemd'); my $lib_systemd = bind_mount_tmp('/lib/systemd'); my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Create two unit files with random names; one refers to the other (Also=). ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my ($fh1, $random_unit1) = tempfile('unitXXXXX', SUFFIX => '.service', TMPDIR => 1, UNLINK => 1); close($fh1); $random_unit1 = basename($random_unit1); my ($fh2, $random_unit2) = tempfile('unitXXXXX', SUFFIX => '.service', TMPDIR => 1, UNLINK => 1); close($fh2); $random_unit2 = basename($random_unit2); my $servicefile_path1 = "/lib/systemd/system/$random_unit1"; my $servicefile_path2 = "/lib/systemd/system/$random_unit2"; make_path('/lib/systemd/system'); open($fh1, '>', $servicefile_path1); print $fh1 <', $servicefile_path2); print $fh2 <; is_deeply( \%links, { $random_unit1 => $servicefile_path1, $random_unit2 => $servicefile_path2, }, 'All expected links present'); my $alias_path = '/etc/systemd/system/alias2.service'; ok(-l $alias_path, 'alias created'); is(readlink($alias_path), $servicefile_path2, 'alias points to the correct service file'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” now returns true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_enabled($random_unit1); is_enabled($random_unit2); is_debian_installed($random_unit1); # $random_unit2 was only enabled _because of_ $random_unit1’s Also= statement # and thus does not have its own state file. isnt_debian_installed($random_unit2); # TODO: cleanup tests? done_testing; init-system-helpers-1.14/t/001-deb-systemd-helper.t0000644000000000000000000003043312256525223016704 0ustar #!perl # vim:ts=4:sw=4:et use strict; use warnings; use Test::More; use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1 use File::Path qw(make_path); # in core since Perl 5.001 use File::Basename; # in core since Perl 5 use FindBin; # in core since Perl 5.00307 use Linux::Clone; # neither in core nor in Debian :-/ # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃ # ┃ /var/lib/systemd to start with clean directories yet use the actual ┃ # ┃ locations and code paths. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $dsh = "$FindBin::Bin/../script/deb-systemd-helper"; sub _unit_check { my ($unit_file, $cmd, $cb, $verb) = @_; my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd $unit_file"); isnt($retval, -1, 'deb-systemd-helper could be executed'); ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal'); $cb->($retval >> 8, 0, "random unit file $verb $cmd"); } sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') } sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') } sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') } sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') } my $retval = Linux::Clone::unshare Linux::Clone::NEWNS; BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0; sub bind_mount_tmp { my ($dir) = @_; my $tmp = tempdir(CLEANUP => 1); system("mount -n --bind $tmp $dir") == 0 or BAIL_OUT("bind-mounting $tmp to $dir failed: $!"); return $tmp; } my $etc_systemd = bind_mount_tmp('/etc/systemd'); my $lib_systemd = bind_mount_tmp('/lib/systemd'); my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” is not true for a random, non-existing unit file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my ($fh, $random_unit) = tempfile('unitXXXXX', SUFFIX => '.service', TMPDIR => 1, UNLINK => 1); close($fh); $random_unit = basename($random_unit); isnt_enabled($random_unit); isnt_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” is not true for a random, existing unit file. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $servicefile_path = "/lib/systemd/system/$random_unit"; make_path('/lib/systemd/system'); open($fh, '>', $servicefile_path); print $fh <<'EOT'; [Unit] Description=test unit [Service] ExecStart=/bin/sleep 1 [Install] WantedBy=multi-user.target EOT close($fh); isnt_enabled($random_unit); isnt_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “enable” creates the requested symlinks. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ok(! -d '/etc/systemd/system/multi-user.target.wants', 'multi-user.target.wants does not exist yet'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); my $symlink_path = "/etc/systemd/system/multi-user.target.wants/$random_unit"; ok(-l $symlink_path, "$random_unit was enabled"); is(readlink($symlink_path), $servicefile_path, "symlink points to $servicefile_path"); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “is-enabled” now returns true. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ is_enabled($random_unit); is_debian_installed($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify deleting the symlinks and running “enable” again does not ┃ # ┃ re-create the symlinks. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ unlink($symlink_path); ok(! -l $symlink_path, 'symlink deleted'); isnt_enabled($random_unit); is_debian_installed($random_unit); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit"); isnt_enabled($random_unit); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “disable” when purging deletes the statefile. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $statefile = "/var/lib/systemd/deb-systemd-helper-enabled/$random_unit.dsh-also"; ok(-f $statefile, 'state file exists'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh disable $random_unit"); ok(! -f $statefile, 'state file does not exist anymore after purging'); isnt_debian_installed($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 “disable” removes the symlinks. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh disable $random_unit"); 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 ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ my $mask_path = "/etc/systemd/system/$random_unit"; ok(! -l $mask_path, 'mask link does not exist yet'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask $random_unit"); ok(-l $mask_path, 'mask link exists'); is(readlink($mask_path), '/dev/null', 'service masked'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask $random_unit"); ok(! -e $mask_path, 'mask link does not exist anymore'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ 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"); ok(-l $mask_path, 'mask link exists'); is(readlink($mask_path), '/dev/null', 'service masked'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask $random_unit"); ok(! -e $mask_path, 'symlink no longer exists'); # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ # ┃ Verify “mask”/unmask don’t do anything when the user already masked. ┃ # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ok(! -l $mask_path, 'mask link does not exist yet'); symlink('/dev/null', $mask_path); ok(-l $mask_path, 'mask link exists'); is(readlink($mask_path), '/dev/null', 'service masked'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask $random_unit"); ok(-l $mask_path, 'mask link exists'); is(readlink($mask_path), '/dev/null', 'service still masked'); $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask $random_unit"); ok(-l $mask_path, 'mask link exists'); is(readlink($mask_path), '/dev/null', 'service still masked'); done_testing; init-system-helpers-1.14/t/README0000644000000000000000000000151312256525223013401 0ustar These test cases need the Linux::Clone module, which is not yet in Debian. See http://michael.stapelberg.de/cpan/#Linux::Clone on how to install it. Note that you need to run the test cases as root because they use Linux mount namespaces and bind mounts (requires Linux ≥ 2.4.19). Note that you should mark / as a private subtree before running these tests, or they will fail. Use mount --make-rprivate /. Unfortunately, the version of util-linux in Debian at the time of writing (2.20.1) is broken and its --make-rprivate does not actually work. See #731574. The intention is that the testcases are _not_ run automatically during package building because they might be too fragile and additional dependencies make it harder to port this package to Ubuntu or Debian backports. It is enough if the test cases are run on every code change.