]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/Systemd.pm
bump version to 8.2.1
[pve-common.git] / src / PVE / Systemd.pm
index 46fc90fb3404580b179359104851da723e24182b..07c912e35a4a60c6387f45ddacba73c88fc8791f 100644 (file)
@@ -3,10 +3,37 @@ package PVE::Systemd;
 use strict;
 use warnings;
 
-use Net::DBus qw(dbus_uint32 dbus_uint64);
+use Net::DBus qw(dbus_uint32 dbus_uint64 dbus_boolean);
 use Net::DBus::Callback;
 use Net::DBus::Reactor;
 
+use PVE::Tools qw(file_set_contents file_get_contents trim);
+
+sub escape_unit {
+    my ($val, $is_path) = @_;
+
+    # NOTE: this is not complete, but enough for our needs. normally all
+    # characters which are not alpha-numerical, '.' or '_' would need escaping
+    $val =~ s/\-/\\x2d/g;
+
+    if ($is_path) {
+       $val =~ s/^\///g;
+       $val =~ s/\/$//g;
+    }
+    $val =~ s/\//-/g;
+
+    return $val;
+}
+
+sub unescape_unit {
+    my ($val) = @_;
+
+    $val =~ s/-/\//g;
+    $val =~ s/\\x([a-fA-F0-9]{2})/chr(hex($1))/eg;
+
+    return $val;
+}
+
 # $code should take the parameters ($interface, $reactor, $finish_callback).
 #
 # $finish_callback can be used by dbus-signal-handlers to stop the reactor.
@@ -80,7 +107,9 @@ sub enter_systemd_scope {
     foreach my $key (keys %extra) {
        if ($key eq 'Slice' || $key eq 'KillMode') {
            push @{$properties}, [$key, $extra{$key}];
-       } elsif ($key eq 'CPUShares') {
+       } elsif ($key eq 'SendSIGKILL') {
+           push @{$properties}, [$key, dbus_boolean($extra{$key})];
+       } elsif ($key eq 'CPUShares' || $key eq 'CPUWeight' || $key eq 'TimeoutStopUSec') {
            push @{$properties}, [$key, dbus_uint64($extra{$key})];
        } elsif ($key eq 'CPUQuota') {
            push @{$properties}, ['CPUQuotaPerSecUSec',
@@ -138,4 +167,91 @@ sub wait_for_unit_removed($;$) {
     }, $timeout);
 }
 
+sub is_unit_active($;$) {
+    my ($unit) = @_;
+
+    my $bus = Net::DBus->system();
+    my $reactor = Net::DBus::Reactor->main();
+
+    my $service = $bus->get_service('org.freedesktop.systemd1');
+    my $if = $service->get_object('/org/freedesktop/systemd1', 'org.freedesktop.systemd1.Manager');
+
+    my $unit_path = eval { $if->GetUnit($unit) }
+       or return 0;
+    $if = $service->get_object($unit_path, 'org.freedesktop.systemd1.Unit')
+       or return 0;
+    my $state = $if->ActiveState;
+    return defined($state) && $state eq 'active';
+}
+
+sub read_ini {
+    my ($filename) = @_;
+
+    my $content = file_get_contents($filename);
+    my @lines = split /\n/, $content;
+
+    my $result = {};
+    my $section;
+
+    foreach my $line (@lines) {
+       $line = trim($line);
+       if ($line =~ m/^\[([^\]]+)\]/) {
+           $section = $1;
+           if (!defined($result->{$section})) {
+               $result->{$section} = {};
+           }
+       } elsif ($line =~ m/^(.*?)=(.*)$/) {
+           my ($key, $val) = ($1, $2);
+           if (!$section) {
+               warn "key value pair found without section, skipping\n";
+               next;
+           }
+
+           if ($result->{$section}->{$key}) {
+               # make duplicate properties to arrays to keep the order
+               my $prop = $result->{$section}->{$key};
+               if (ref($prop) eq 'ARRAY') {
+                   push @$prop, $val;
+               } else {
+                   $result->{$section}->{$key} = [$prop, $val];
+               }
+           } else {
+               $result->{$section}->{$key} = $val;
+           }
+       }
+       # ignore everything else
+    }
+
+    return $result;
+};
+
+sub write_ini {
+    my ($ini, $filename) = @_;
+
+    my $content = "";
+
+    foreach my $sname (sort keys %$ini) {
+       my $section = $ini->{$sname};
+
+       $content .= "[$sname]\n";
+
+       foreach my $pname (sort keys %$section) {
+           my $prop = $section->{$pname};
+
+           if (!ref($prop)) {
+               $content .= "$pname=$prop\n";
+           } elsif (ref($prop) eq 'ARRAY') {
+               foreach my $val (@$prop) {
+                   $content .= "$pname=$val\n";
+               }
+           } else {
+               die "invalid property '$pname'\n";
+           }
+       }
+       $content .= "\n";
+    }
+
+    file_set_contents($filename, $content);
+};
+
 1;