switch-to-configuration.pl: Interact via DBus
Currently switch-to-configuration.pl uses system() calls to interact with DBus. This can be error prone, especially when we are parsing output that could change. In this commit, almost all calls to the systemctl binary have been replaced with equivalent operations via DBus.
This commit is contained in:
parent
f3ac3a265b
commit
41775167ac
@ -4,6 +4,7 @@ use strict;
|
||||
use warnings;
|
||||
use File::Basename;
|
||||
use File::Slurp;
|
||||
use Net::DBus;
|
||||
use Sys::Syslog qw(:standard :macros);
|
||||
use Cwd 'abs_path';
|
||||
|
||||
@ -59,17 +60,18 @@ syslog(LOG_NOTICE, "switching to system configuration $out");
|
||||
# virtual console 1 and we restart the "tty1" unit.
|
||||
$SIG{PIPE} = "IGNORE";
|
||||
|
||||
my $dbus = Net::DBus->find;
|
||||
my $systemdService = $dbus->get_service('org.freedesktop.systemd1');
|
||||
my $systemdManager = $systemdService->get_object('/org/freedesktop/systemd1');
|
||||
|
||||
sub getActiveUnits {
|
||||
# FIXME: use D-Bus or whatever to query this, since parsing the
|
||||
# output of list-units is likely to break.
|
||||
my $lines = `@systemd@/bin/systemctl list-units --full`;
|
||||
my $res = {};
|
||||
foreach my $line (split '\n', $lines) {
|
||||
chomp $line;
|
||||
last if $line eq "";
|
||||
$line =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s/ or next;
|
||||
next if $1 eq "UNIT";
|
||||
$res->{$1} = { load => $2, state => $3, substate => $4 };
|
||||
foreach my $unit (@{ $systemdManager->ListUnits() }) {
|
||||
$res->{$unit->[0]} = {
|
||||
load => $unit->[2],
|
||||
state => $unit->[3],
|
||||
substate => $unit->[4]
|
||||
};
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
@ -277,7 +279,7 @@ foreach my $device (keys %$prevSwaps) {
|
||||
if (scalar @unitsToStop > 0) {
|
||||
@unitsToStop = unique(@unitsToStop);
|
||||
print STDERR "stopping the following units: ", join(", ", sort(@unitsToStop)), "\n";
|
||||
system("@systemd@/bin/systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors?
|
||||
$systemdManager->StopUnit($_, "replace") for @unitsToStop;
|
||||
}
|
||||
|
||||
print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n"
|
||||
@ -292,21 +294,22 @@ system("$out/activate", "$out") == 0 or $res = 2;
|
||||
# Restart systemd if necessary.
|
||||
if (abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd")) {
|
||||
print STDERR "restarting systemd...\n";
|
||||
system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2;
|
||||
|
||||
$systemdManager->Reexecute();
|
||||
}
|
||||
|
||||
# Forget about previously failed services.
|
||||
system("@systemd@/bin/systemctl", "reset-failed");
|
||||
$systemdManager->ResetFailed();
|
||||
|
||||
# Make systemd reload its units.
|
||||
system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
|
||||
# Make systemd reload its units
|
||||
$systemdManager->Reload();
|
||||
|
||||
# Restart changed services (those that have to be restarted rather
|
||||
# than stopped and started).
|
||||
my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // ""));
|
||||
if (scalar @restart > 0) {
|
||||
print STDERR "restarting the following units: ", join(", ", sort(@restart)), "\n";
|
||||
system("@systemd@/bin/systemctl", "restart", "--", @restart) == 0 or $res = 4;
|
||||
$systemdManager->Restart($_, "replace") for @restart;
|
||||
unlink($restartListFile);
|
||||
}
|
||||
|
||||
@ -318,7 +321,7 @@ if (scalar @restart > 0) {
|
||||
# systemd.
|
||||
my @start = unique("default.target", "timers.target", split('\n', read_file($startListFile, err_mode => 'quiet') // ""));
|
||||
print STDERR "starting the following units: ", join(", ", sort(@start)), "\n";
|
||||
system("@systemd@/bin/systemctl", "start", "--", @start) == 0 or $res = 4;
|
||||
$systemdManager->StartUnit($_, "replace") for @start;
|
||||
unlink($startListFile);
|
||||
|
||||
# Reload units that need it. This includes remounting changed mount
|
||||
@ -326,19 +329,31 @@ unlink($startListFile);
|
||||
my @reload = unique(split '\n', read_file($reloadListFile, err_mode => 'quiet') // "");
|
||||
if (scalar @reload > 0) {
|
||||
print STDERR "reloading the following units: ", join(", ", sort(@reload)), "\n";
|
||||
system("@systemd@/bin/systemctl", "reload", "--", @reload) == 0 or $res = 4;
|
||||
$systemdManager->ReloadUnit($_, "replace") for @reload;
|
||||
unlink($reloadListFile);
|
||||
}
|
||||
|
||||
# Signal dbus to reload its configuration.
|
||||
system("@systemd@/bin/systemctl", "reload", "dbus.service");
|
||||
$systemdManager->ReloadUnit("dbus.service", "replace");
|
||||
|
||||
# Print failed and new units.
|
||||
my (@failed, @new, @restarting);
|
||||
my $activeNew = getActiveUnits;
|
||||
while (my ($unit, $state) = each %{$activeNew}) {
|
||||
push @failed, $unit if $state->{state} eq "failed" || $state->{substate} eq "auto-restart";
|
||||
push @new, $unit if $state->{state} ne "failed" && !defined $activePrev->{$unit};
|
||||
if ($state->{state} eq "failed") {
|
||||
push @failed, $unit;
|
||||
}
|
||||
elsif ($state->{state} eq "auto-restart") {
|
||||
# A unit in auto-restart state is a failure *if* it previously failed to start
|
||||
my $unit = $systemdManager->GetUnit($unit);
|
||||
|
||||
if ($unit->ExecMainStatus ne '0') {
|
||||
push @failed, $unit;
|
||||
}
|
||||
}
|
||||
elsif ($state->{state} ne "failed" && !defined $activePrev->{$unit}) {
|
||||
push @new, $unit;
|
||||
}
|
||||
}
|
||||
|
||||
print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n"
|
||||
|
@ -108,7 +108,7 @@ let
|
||||
configurationName = config.boot.loader.grub.configurationName;
|
||||
|
||||
# Needed by switch-to-configuration.
|
||||
perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
|
||||
perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.XMLTwig}/lib/perl5/site_perl -I${pkgs.perlPackages.XMLParser}/lib/perl5/site_perl -I${pkgs.perlPackages.NetDBus}/lib/perl5/site_perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user