[systemd-devel] [PATCH] journal, coredump: allow relative values in some configuration options

jsynacek at redhat.com jsynacek at redhat.com
Mon May 25 04:48:36 PDT 2015


From: Jan Synacek <jsynacek at redhat.com>

Journald options SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=,
RuntimeMaxUse=, RuntimeKeepFree= and RuntimeMaxFileSize= can now be
specified as a percentage of the available space. Ditto for coredump
options MaxUse=, KeepFree=, ExternalSizeMax=, JournalSizeMax= and
ProcessSizeMax=.
---
 man/journald.conf.xml         |   4 +-
 src/journal/coredump.c        |  39 ++++++++----
 src/journal/journal-file.c    | 140 +++++++++++++++++++++++++-----------------
 src/journal/journal-file.h    |  17 +++--
 src/journal/journald-server.c |  23 ++++---
 src/shared/conf-parser.c      |  35 +++++++++--
 6 files changed, 172 insertions(+), 86 deletions(-)

diff --git a/man/journald.conf.xml b/man/journald.conf.xml
index 2cbe58b..ec871a8 100644
--- a/man/journald.conf.xml
+++ b/man/journald.conf.xml
@@ -230,7 +230,9 @@
         <varname>RuntimeMaxUse=</varname>, so that usually seven
         rotated journal files are kept as history. Specify values in
         bytes or use K, M, G, T, P, E as units for the specified sizes
-        (equal to 1024, 1024²,... bytes).  Note that size limits are
+        (equal to 1024, 1024²,... bytes).  Alternatively, values can
+        be specified as a percentage (e.g. 33%) of the available
+        space of the respective file system. Note that size limits are
         enforced synchronously when journal files are extended, and no
         explicit rotation step triggered by time is
         needed.</para></listitem>
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 1c747aa..938ea6a 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/prctl.h>
+#include <sys/statvfs.h>
 #include <sys/xattr.h>
 
 #ifdef HAVE_ELFUTILS
@@ -47,6 +48,7 @@
 #include "acl-util.h"
 #include "capability.h"
 #include "journald-native.h"
+#include "journal-file.h"
 #include "coredump-vacuum.h"
 #include "process-util.h"
 
@@ -97,11 +99,11 @@ static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage,
 
 static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
 static bool arg_compress = true;
-static off_t arg_process_size_max = PROCESS_SIZE_MAX;
-static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
-static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
-static off_t arg_keep_free = (off_t) -1;
-static off_t arg_max_use = (off_t) -1;
+static SizeParameter arg_process_size_max = {PROCESS_SIZE_MAX, false};
+static SizeParameter arg_external_size_max = {EXTERNAL_SIZE_MAX, false};
+static SizeParameter arg_journal_size_max = {JOURNAL_SIZE_MAX, false};
+static SizeParameter arg_keep_free = {(uint64_t) -1, false};
+static SizeParameter arg_max_use = {(uint64_t) -1, false};
 
 static int parse_config(void) {
         static const ConfigTableItem items[] = {
@@ -109,7 +111,7 @@ static int parse_config(void) {
                 { "Coredump", "Compress",         config_parse_bool,              0, &arg_compress          },
                 { "Coredump", "ProcessSizeMax",   config_parse_iec_off,           0, &arg_process_size_max  },
                 { "Coredump", "ExternalSizeMax",  config_parse_iec_off,           0, &arg_external_size_max },
-                { "Coredump", "JournalSizeMax",   config_parse_iec_size,          0, &arg_journal_size_max  },
+                { "Coredump", "JournalSizeMax",   config_parse_iec_off,           0, &arg_journal_size_max  },
                 { "Coredump", "KeepFree",         config_parse_iec_off,           0, &arg_keep_free         },
                 { "Coredump", "MaxUse",           config_parse_iec_off,           0, &arg_max_use           },
                 {}
@@ -122,6 +124,15 @@ static int parse_config(void) {
                                  false, NULL);
 }
 
+static uint64_t get_available(void) {
+        struct statvfs ss;
+
+        if (statvfs("/var/lib/systemd/coredump", &ss) >= 0)
+                return ss.f_bsize * ss.f_bavail;
+
+        return 0;
+}
+
 static int fix_acl(int fd, uid_t uid) {
 
 #ifdef HAVE_ACL
@@ -229,7 +240,7 @@ static int maybe_remove_external_coredump(const char *filename, off_t size) {
         /* Returns 1 if might remove, 0 if will not remove, < 0 on error. */
 
         if (IN_SET(arg_storage, COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_BOTH) &&
-            size <= arg_external_size_max)
+            size <= (off_t) size_parameter_evaluate(&arg_external_size_max, get_available()))
                 return 0;
 
         if (!filename)
@@ -311,7 +322,7 @@ static int save_external_coredump(
         if (fd < 0)
                 return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
 
-        r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false);
+        r = copy_bytes(STDIN_FILENO, fd, size_parameter_evaluate(&arg_process_size_max, get_available()), false);
         if (r == -EFBIG) {
                 log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
                 goto fail;
@@ -552,6 +563,7 @@ int main(int argc, char* argv[]) {
         pid_t pid;
         char *t;
         const char *p;
+        uint64_t max_use, keep_free, available, journal_size_max;
 
         /* Make sure we never enter a loop */
         prctl(PR_SET_DUMPABLE, 0);
@@ -779,8 +791,12 @@ int main(int argc, char* argv[]) {
         IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
         IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");
 
+        available = get_available();
+        max_use = size_parameter_evaluate(&arg_max_use, available);
+        keep_free = size_parameter_evaluate(&arg_keep_free, available);
+
         /* Vacuum before we write anything again */
-        coredump_vacuum(-1, arg_keep_free, arg_max_use);
+        coredump_vacuum(-1, keep_free, max_use);
 
         /* Always stream the coredump to disk, if that's possible */
         r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
@@ -803,7 +819,7 @@ int main(int argc, char* argv[]) {
         }
 
         /* Vacuum again, but exclude the coredump we just created */
-        coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);
+        coredump_vacuum(coredump_fd, keep_free, max_use);
 
         /* Now, let's drop privileges to become the user who owns the
          * segfaulted process and allocate the coredump memory under
@@ -839,9 +855,10 @@ log:
         if (core_message)
                 IOVEC_SET_STRING(iovec[j++], core_message);
 
+        journal_size_max = size_parameter_evaluate(&arg_journal_size_max, available);
         /* Optionally store the entire coredump in the journal */
         if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
-            coredump_size <= (off_t) arg_journal_size_max) {
+            coredump_size <= (off_t) journal_size_max) {
                 size_t sz = 0;
 
                 /* Store the coredump itself in the journal */
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index be6a552..ac32af6 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -353,7 +353,8 @@ static int journal_file_fstat(JournalFile *f) {
 }
 
 static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
-        uint64_t old_size, new_size;
+        uint64_t old_size, new_size, max_size, min_size, keep_free, available, free;
+        struct statvfs svfs;
         int r;
 
         assert(f);
@@ -389,31 +390,32 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
 
         /* Allocate more space. */
 
-        if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
-                return -E2BIG;
-
-        if (new_size > f->metrics.min_size && f->metrics.keep_free > 0) {
-                struct statvfs svfs;
+        if (fstatvfs(f->fd, &svfs) < 0)
+                return -errno;
 
-                if (fstatvfs(f->fd, &svfs) >= 0) {
-                        uint64_t available;
+        free = svfs.f_bfree * svfs.f_bsize;
+        available = svfs.f_bsize * svfs.f_bavail;
+        max_size = size_parameter_evaluate(&f->metrics.max_size, available);
+        min_size = size_parameter_evaluate(&f->metrics.min_size, available);
+        keep_free = size_parameter_evaluate(&f->metrics.keep_free, available);
 
-                        available = svfs.f_bfree * svfs.f_bsize;
+        if (max_size > 0 && new_size > max_size)
+                return -E2BIG;
 
-                        if (available >= f->metrics.keep_free)
-                                available -= f->metrics.keep_free;
-                        else
-                                available = 0;
+        if (new_size > min_size && keep_free > 0) {
+                if (free >= keep_free)
+                        free -= keep_free;
+                else
+                        free = 0;
 
-                        if (new_size - old_size > available)
-                                return -E2BIG;
-                }
+                if (new_size - old_size > free)
+                        return -E2BIG;
         }
 
         /* Increase by larger blocks at once */
         new_size = ((new_size+FILE_SIZE_INCREASE-1) / FILE_SIZE_INCREASE) * FILE_SIZE_INCREASE;
-        if (f->metrics.max_size > 0 && new_size > f->metrics.max_size)
-                new_size = f->metrics.max_size;
+        if (max_size > 0 && new_size > max_size)
+                new_size = max_size;
 
         /* Note that the glibc fallocate() fallback is very
            inefficient, hence we try to minimize the allocation area
@@ -600,16 +602,20 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
 static int journal_file_setup_data_hash_table(JournalFile *f) {
         uint64_t s, p;
         Object *o;
+        struct statvfs ss;
         int r;
 
         assert(f);
 
+        if (fstatvfs(f->fd, &ss) < 0)
+                return -errno;
+
         /* We estimate that we need 1 hash table entry per 768 of
            journal file and we want to make sure we never get beyond
            75% fill level. Calculate the hash table size for the
            maximum file size based on these metrics. */
 
-        s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem);
+        s = (size_parameter_evaluate(&f->metrics.max_size, ss.f_bsize * ss.f_bavail) * 4 / 768 / 3) * sizeof(HashItem);
         if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
                 s = DEFAULT_DATA_HASH_TABLE_SIZE;
 
@@ -2950,78 +2956,90 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
 }
 
 void journal_default_metrics(JournalMetrics *m, int fd) {
-        uint64_t fs_size = 0;
+        uint64_t fs_size = 0, available = 0, max_use, max_size, min_size, keep_free;
         struct statvfs ss;
         char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX];
 
         assert(m);
         assert(fd >= 0);
 
-        if (fstatvfs(fd, &ss) >= 0)
+        if (fstatvfs(fd, &ss) >= 0) {
                 fs_size = ss.f_frsize * ss.f_blocks;
+                available = ss.f_bsize * ss.f_bavail;
+        }
 
-        if (m->max_use == (uint64_t) -1) {
+        max_use = size_parameter_evaluate(&m->max_use, available);
+        max_size = size_parameter_evaluate(&m->max_size, available);
+        min_size = size_parameter_evaluate(&m->min_size, available);
+        keep_free = size_parameter_evaluate(&m->keep_free, available);
+
+        if (max_use == (uint64_t) -1) {
 
                 if (fs_size > 0) {
-                        m->max_use = PAGE_ALIGN(fs_size / 10); /* 10% of file system size */
+                        max_use = PAGE_ALIGN(fs_size / 10); /* 10% of file system size */
 
-                        if (m->max_use > DEFAULT_MAX_USE_UPPER)
-                                m->max_use = DEFAULT_MAX_USE_UPPER;
+                        if (max_use > DEFAULT_MAX_USE_UPPER)
+                                max_use = DEFAULT_MAX_USE_UPPER;
 
-                        if (m->max_use < DEFAULT_MAX_USE_LOWER)
-                                m->max_use = DEFAULT_MAX_USE_LOWER;
+                        if (max_use < DEFAULT_MAX_USE_LOWER)
+                                max_use = DEFAULT_MAX_USE_LOWER;
                 } else
-                        m->max_use = DEFAULT_MAX_USE_LOWER;
+                        max_use = DEFAULT_MAX_USE_LOWER;
         } else {
-                m->max_use = PAGE_ALIGN(m->max_use);
+                max_use = PAGE_ALIGN(max_use);
 
-                if (m->max_use < JOURNAL_FILE_SIZE_MIN*2)
-                        m->max_use = JOURNAL_FILE_SIZE_MIN*2;
+                if (max_use < JOURNAL_FILE_SIZE_MIN*2)
+                        max_use = JOURNAL_FILE_SIZE_MIN*2;
         }
 
-        if (m->max_size == (uint64_t) -1) {
-                m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */
+        if (max_size == (uint64_t) -1) {
+                max_size = PAGE_ALIGN(max_use / 8); /* 8 chunks */
 
-                if (m->max_size > DEFAULT_MAX_SIZE_UPPER)
-                        m->max_size = DEFAULT_MAX_SIZE_UPPER;
+                if (max_size > DEFAULT_MAX_SIZE_UPPER)
+                        max_size = DEFAULT_MAX_SIZE_UPPER;
         } else
-                m->max_size = PAGE_ALIGN(m->max_size);
+                max_size = PAGE_ALIGN(max_size);
 
-        if (m->max_size < JOURNAL_FILE_SIZE_MIN)
-                m->max_size = JOURNAL_FILE_SIZE_MIN;
+        if (max_size < JOURNAL_FILE_SIZE_MIN)
+                max_size = JOURNAL_FILE_SIZE_MIN;
 
-        if (m->max_size*2 > m->max_use)
-                m->max_use = m->max_size*2;
+        if (max_size*2 > max_use)
+                max_use = max_size*2;
 
-        if (m->min_size == (uint64_t) -1)
-                m->min_size = JOURNAL_FILE_SIZE_MIN;
+        if (min_size == (uint64_t) -1)
+                min_size = JOURNAL_FILE_SIZE_MIN;
         else {
-                m->min_size = PAGE_ALIGN(m->min_size);
+                min_size = PAGE_ALIGN(min_size);
 
-                if (m->min_size < JOURNAL_FILE_SIZE_MIN)
-                        m->min_size = JOURNAL_FILE_SIZE_MIN;
+                if (min_size < JOURNAL_FILE_SIZE_MIN)
+                        min_size = JOURNAL_FILE_SIZE_MIN;
 
-                if (m->min_size > m->max_size)
-                        m->max_size = m->min_size;
+                if (min_size > max_size)
+                        max_size = min_size;
         }
 
-        if (m->keep_free == (uint64_t) -1) {
+        if (keep_free == (uint64_t) -1) {
 
                 if (fs_size > 0) {
-                        m->keep_free = PAGE_ALIGN(fs_size * 3 / 20); /* 15% of file system size */
+                        keep_free = PAGE_ALIGN(fs_size * 3 / 20); /* 15% of file system size */
 
-                        if (m->keep_free > DEFAULT_KEEP_FREE_UPPER)
-                                m->keep_free = DEFAULT_KEEP_FREE_UPPER;
+                        if (keep_free > DEFAULT_KEEP_FREE_UPPER)
+                                keep_free = DEFAULT_KEEP_FREE_UPPER;
 
                 } else
-                        m->keep_free = DEFAULT_KEEP_FREE;
+                        keep_free = DEFAULT_KEEP_FREE;
         }
 
+        m->max_use = (SizeParameter) {.value=max_use, .relative=false};
+        m->max_size = (SizeParameter) {.value=max_size, .relative=false};
+        m->min_size = (SizeParameter) {.value=min_size, .relative=false};
+        m->keep_free = (SizeParameter) {.value=keep_free, .relative=false};
+
         log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s",
-                  format_bytes(a, sizeof(a), m->max_use),
-                  format_bytes(b, sizeof(b), m->max_size),
-                  format_bytes(c, sizeof(c), m->min_size),
-                  format_bytes(d, sizeof(d), m->keep_free));
+                  format_bytes(a, sizeof(a), m->max_use.value),
+                  format_bytes(b, sizeof(b), m->max_size.value),
+                  format_bytes(c, sizeof(c), m->min_size.value),
+                  format_bytes(d, sizeof(d), m->keep_free.value));
 }
 
 int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) {
@@ -3144,3 +3162,13 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) {
 
         return false;
 }
+
+uint64_t size_parameter_evaluate(const SizeParameter *sp, uint64_t available) {
+        if (sp->value == (uint64_t) -1)
+                return (uint64_t) -1;
+
+        if (sp->relative)
+                return sp->value * 0.01 * available;
+
+        return sp->value;
+}
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 403c8f7..ad79536 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -35,12 +35,17 @@
 #include "mmap-cache.h"
 #include "hashmap.h"
 
+typedef struct SizeParameter {
+        uint64_t value;
+        bool relative;
+} SizeParameter;
+
 typedef struct JournalMetrics {
-        uint64_t max_use;
-        uint64_t use;
-        uint64_t max_size;
-        uint64_t min_size;
-        uint64_t keep_free;
+        SizeParameter max_use;
+        SizeParameter use;
+        SizeParameter max_size;
+        SizeParameter min_size;
+        SizeParameter keep_free;
 } JournalMetrics;
 
 typedef enum direction {
@@ -229,3 +234,5 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *
 int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to);
 
 bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
+
+uint64_t size_parameter_evaluate(const SizeParameter *sp, uint64_t available);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index b3a4b53..7c97643 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -91,7 +91,7 @@ static uint64_t available_space(Server *s, bool verbose) {
         _cleanup_free_ char *p = NULL;
         sd_id128_t machine;
         struct statvfs ss;
-        uint64_t sum = 0, ss_avail = 0, avail = 0;
+        uint64_t sum = 0, ss_avail = 0, avail = 0, max_use, keep_free;
         int r;
         _cleanup_closedir_ DIR *d = NULL;
         usec_t ts;
@@ -155,18 +155,20 @@ static uint64_t available_space(Server *s, bool verbose) {
         }
 
         ss_avail = ss.f_bsize * ss.f_bavail;
+        max_use = size_parameter_evaluate(&m->max_use, ss_avail);
+        keep_free = size_parameter_evaluate(&m->keep_free, ss_avail);
 
         /* If we reached a high mark, we will always allow this much
          * again, unless usage goes above max_use. This watermark
          * value is cached so that we don't give up space on pressure,
          * but hover below the maximum usage. */
 
-        if (m->use < sum)
-                m->use = sum;
+        if (size_parameter_evaluate(&m->use, ss_avail) < sum)
+                m->use = (SizeParameter) {.value=sum, .relative=false};
 
-        avail = LESS_BY(ss_avail, m->keep_free);
+        avail = LESS_BY(ss_avail, keep_free);
 
-        s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
+        s->cached_available_space = LESS_BY(MIN(max_use, avail), sum);
         s->cached_available_space_timestamp = ts;
 
         if (verbose) {
@@ -178,8 +180,8 @@ static uint64_t available_space(Server *s, bool verbose) {
                                       "trying to leave %s free of %s available → current limit %s).",
                                       s->system_journal ? "Permanent" : "Runtime",
                                       format_bytes(fb1, sizeof(fb1), sum),
-                                      format_bytes(fb2, sizeof(fb2), m->max_use),
-                                      format_bytes(fb3, sizeof(fb3), m->keep_free),
+                                      format_bytes(fb2, sizeof(fb2), max_use),
+                                      format_bytes(fb3, sizeof(fb3), keep_free),
                                       format_bytes(fb4, sizeof(fb4), ss_avail),
                                       format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
         }
@@ -373,13 +375,18 @@ static void do_vacuum(
                 JournalMetrics *metrics) {
 
         const char *p;
+        struct statvfs ss;
+        uint64_t max_use = 0;
         int r;
 
         if (!f)
                 return;
 
+        if (fstatvfs(f->fd, &ss) >= 0)
+                max_use = size_parameter_evaluate(&metrics->max_use, ss.f_bsize * ss.f_bavail);
+
         p = strjoina(path, id);
-        r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
+        r = journal_directory_vacuum(p, max_use, s->max_retention_usec, &s->oldest_file_usec, false);
         if (r < 0 && r != -ENOENT)
                 log_error_errno(r, "Failed to vacuum %s: %m", p);
 }
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 2c85515..ef4ac08 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -26,6 +26,7 @@
 
 #include "conf-parser.h"
 #include "conf-files.h"
+#include "journal-file.h"
 #include "util.h"
 #include "macro.h"
 #include "strv.h"
@@ -517,6 +518,27 @@ int config_parse_si_size(const char* unit,
         return 0;
 }
 
+static int parse_percent(const char *rvalue, SizeParameter *sp) {
+        char *p, *e;
+        off_t percent;
+
+        p = endswith(rvalue, "%");
+        if (!p)
+                return -ERANGE;
+
+        percent = strtoll(rvalue, &e, 10);
+        if (*e != '%' || e != p)
+                return -ERANGE;
+
+        if (percent > 100)
+                return -ERANGE;
+
+        sp->relative = true;
+        sp->value = percent;
+
+        return 0;
+}
+
 int config_parse_iec_off(const char* unit,
                            const char *filename,
                            unsigned line,
@@ -528,7 +550,7 @@ int config_parse_iec_off(const char* unit,
                            void *data,
                            void *userdata) {
 
-        off_t *bytes = data;
+        SizeParameter *sp = data;
         int r;
 
         assert(filename);
@@ -538,10 +560,13 @@ int config_parse_iec_off(const char* unit,
 
         assert_cc(sizeof(off_t) == sizeof(uint64_t));
 
-        r = parse_size(rvalue, 1024, bytes);
-        if (r < 0)
-                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
-
+        r = parse_percent(rvalue, sp);
+        if (r < 0) {
+                sp->relative = false;
+                r = parse_size(rvalue, 1024, (off_t *)&sp->value);
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
+        }
         return 0;
 }
 
-- 
2.1.0



More information about the systemd-devel mailing list