summaryrefslogtreecommitdiff
path: root/script/dh_systemd_start
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-06-17 19:34:06 +0200
committerMichael Stapelberg <michael@stapelberg.de>2013-06-17 19:44:43 +0200
commit6fb60249226eb4950bb5cc725cd0ac879e0095b6 (patch)
tree164021262b624776707d23b53f88f2c143f68fd9 /script/dh_systemd_start
parentd50611823c584b891ad076ef922cfddd67c51752 (diff)
downloadinit-system-helpers-6fb60249226eb4950bb5cc725cd0ac879e0095b6.tar.gz
refactor step 1: copy dh_systemd to dh_systemd_{enable,start}
Diffstat (limited to 'script/dh_systemd_start')
-rwxr-xr-xscript/dh_systemd_start301
1 files changed, 301 insertions, 0 deletions
diff --git a/script/dh_systemd_start b/script/dh_systemd_start
new file mode 100755
index 0000000..e513e14
--- /dev/null
+++ b/script/dh_systemd_start
@@ -0,0 +1,301 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+dh_systemd - enable/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
+
+=head1 SYNOPSIS
+
+B<dh_systemd> [S<I<debhelper options>>] [B<--no-enable>] [B<--restart-after-upgrade>] [B<--no-restart-on-upgrade>] [B<--assume-sysv-present>] [S<I<unit file> ...>]
+
+=head1 DESCRIPTION
+
+B<dh_systemd> is a debhelper program that is responsible for enabling,
+starting/stopping or restarting 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.
+
+Furthermore, as with B<dh_installinit>, 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.
+
+In the complex case, you can call B<dh_systemd> manually 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, run
+
+ dh_systemd --no-enable colord.service
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--no-enable>
+
+Do not enable the unit file. This option is most useful when calling
+B<dh_systemd> for a specific unit file.
+
+Example (see DESCRIPTION):
+ dh_systemd --no-enable colord.service
+
+=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<prerm> and starts it again in the F<postinst> 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<--assume-sysv-present>
+
+When running B<dh_systemd> before B<dh_installinit>, init scripts might
+not be installed yet and thus cannot be found by B<dh_systemd>. By
+specifying B<--assume-sysv-present>, start/stop/restart will be done through
+invoke-rc.d, i.e. no systemd-specific code will be generated.
+
+This option is only useful in cases where the init script is installed with a
+different name and you need to run B<dh_systemd> before B<dh_installinit> in
+order to get aliases (symlinks) created in the scripts before invoke-rc.d is
+called.
+
+=back
+
+=head1 NOTES
+
+Note that this command is not idempotent. L<dh_prep(1)> 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<dh_systemd> should be run after B<dh_installinit> so that it
+can detect corresponding SysV init scripts. The default sequence in B<dh> does
+the right thing, this note is only relevant when you are calling
+B<dh_systemd> manually.
+
+=cut
+
+init(options => {
+ "r" => \$dh{R_FLAG},
+ "no-restart-on-upgrade" => \$dh{R_FLAG},
+ "no-start" => \$dh{NO_START},
+ "no-enable" => \$dh{NO_ENABLE},
+ "R|restart-after-upgrade" => \$dh{RESTART_AFTER_UPGRADE},
+ "assume-sysv-present" => \$dh{ASSUME_SYSV_PRESENT},
+ "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 %unitfiles;
+ my %aliases;
+
+ find({
+ wanted => sub {
+ my $name = $File::Find::name;
+ return unless -f $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;
+
+ # 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 =~ /\@/) {
+ return;
+ }
+
+ # 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);
+
+ $aliases{$name} = [ extract_key($name, 'Alias') ];
+ my @sysv = grep {
+ my $base = $_;
+ $base =~ s/\.service$//g;
+ -f "$tmpdir/etc/init.d/$base"
+ } ($base, @{$aliases{$name}});
+ if (@sysv > 0 || $dh{ASSUME_SYSV_PRESENT}) {
+ $unitfiles{$name} = 'sysv';
+ } else {
+ $unitfiles{$name} = 'systemd-only';
+ }
+ }
+
+ # Calls autoscript() as appropriate.
+ # Called once for all systemd files that have a corresponding SysV init
+ # script (invoke-rc.d handles start/stop/restart) and once for all
+ # systemd files without a corresponding SysV init script (systemctl
+ # handles start/stop/restart).
+ my $add_scripts = sub {
+ my ($units, $sysv_present) = @_;
+
+ return 0 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{NO_ENABLE}) {
+ if ($sysv_present) {
+ $sd_autoscript->("postinst", "postinst-systemd-enable");
+ } elsif ($dh{RESTART_AFTER_UPGRADE}) {
+ $sd_autoscript->("postinst", "postinst-systemd-enable-restart");
+ } elsif ($dh{NO_START}) {
+ # RESTART_AFTER_UPGRADE takes precedence
+ $sd_autoscript->("postinst", "postinst-systemd-enable");
+ } else {
+ $sd_autoscript->("postinst", "postinst-systemd-enable-start");
+ }
+ } else {
+ if (!$sysv_present && $dh{RESTART_AFTER_UPGRADE}) {
+ $sd_autoscript->("postinst", "postinst-systemd-restart");
+ } elsif (!$sysv_present) {
+ # We need to stop/start before/after the upgrade.
+ $sd_autoscript->("postinst", "postinst-systemd-start");
+ }
+ }
+
+ if (! $dh{NO_ENABLE}) {
+ # These autoscripts contain a call to deb-systemd-helper disable,
+ # which needs to have all Aliases passed explicitly
+ # in order to properly cleanup the state file (the
+ # information is stored only in the symlinks which the
+ # admin might have removed).
+ my $filename = 'postrm-systemd';
+ $filename .= '-reload' if !$sysv_present;
+
+ my @both = @$units;
+ for my $unit (@$units) {
+ @both = (@both, @{$aliases{$unit}});
+ }
+
+ my $unitargs = join(" ", map { basename($_) } @both);
+ autoscript($package, "postrm", $filename, "s/#UNITFILES#/$unitargs/");
+ } else {
+ if (!$sysv_present) {
+ $sd_autoscript->("postrm", "postrm-systemd-reload-only");
+ }
+ }
+
+ if (!$sysv_present) {
+ 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");
+ }
+ }
+
+ return 1;
+ };
+
+ if (($add_scripts->([ grep { $unitfiles{$_} eq 'systemd-only' } keys %unitfiles ], 0) +
+ $add_scripts->([ grep { $unitfiles{$_} eq 'sysv' } keys %unitfiles ], 1)) > 0) {
+ # init-system-helpers ships deb-systemd-helper which we use in
+ # our autoscripts
+ addsubstvar($package, "misc:Depends", "init-system-helpers");
+ }
+}
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+=head1 AUTHORS
+
+pkg-systemd-maintainers@lists.alioth.debian.org
+
+=cut