chiark / gitweb /
conf-parser: generate 7 parsing functions from a macro
[elogind.git] / src / shared / conf-parser.c
index 8c62fb959b8b292262e6eaa0bd5f8ab7a5bc385e..a98805e215106c91bc0692e5966b109f136624de 100644 (file)
@@ -32,6 +32,8 @@
 #include "log.h"
 #include "utf8.h"
 #include "path-util.h"
+#include "set.h"
+#include "exit-status.h"
 
 int config_item_table_lookup(
                 void *table,
@@ -90,7 +92,7 @@ int config_item_perf_lookup(
         else {
                 char *key;
 
-                key = join(section, ".", lvalue, NULL);
+                key = strjoin(section, ".", lvalue, NULL);
                 if (!key)
                         return -ENOMEM;
 
@@ -172,7 +174,7 @@ static int parse_line(
         if (!*l)
                 return 0;
 
-        if (strchr(COMMENTS, *l))
+        if (strchr(COMMENTS "\n", *l))
                 return 0;
 
         if (startswith(l, ".include ")) {
@@ -260,23 +262,19 @@ int config_parse(
                 void *userdata) {
 
         unsigned line = 0;
-        char *section = NULL;
+        char _cleanup_free_ *section = NULL, *continuation = NULL;
+        FILE _cleanup_fclose_ *ours = NULL;
         int r;
-        bool ours = false;
-        char *continuation = NULL;
 
         assert(filename);
         assert(lookup);
 
         if (!f) {
-                f = fopen(filename, "re");
+                f = ours = fopen(filename, "re");
                 if (!f) {
-                        r = -errno;
-                        log_error("Failed to open configuration file '%s': %s", filename, strerror(-r));
-                        goto finish;
+                        log_error("Failed to open configuration file '%s': %m", filename);
+                        return -errno;
                 }
-
-                ours = true;
         }
 
         while (!feof(f)) {
@@ -287,19 +285,16 @@ int config_parse(
                         if (feof(f))
                                 break;
 
-                        r = -errno;
-                        log_error("Failed to read configuration file '%s': %s", filename, strerror(-r));
-                        goto finish;
+                        log_error("Failed to read configuration file '%s': %m", filename);
+                        return -errno;
                 }
 
                 truncate_nl(l);
 
                 if (continuation) {
                         c = strappend(continuation, l);
-                        if (!c) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
+                        if (!c)
+                                return -ENOMEM;
 
                         free(continuation);
                         continuation = NULL;
@@ -321,10 +316,8 @@ int config_parse(
                                 continuation = c;
                         else {
                                 continuation = strdup(l);
-                                if (!continuation) {
-                                        r = -ENOMEM;
-                                        goto finish;
-                                }
+                                if (!continuation)
+                                        return -ENOMEM;
                         }
 
                         continue;
@@ -342,124 +335,46 @@ int config_parse(
                 free(c);
 
                 if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        free(section);
-        free(continuation);
-
-        if (f && ours)
-                fclose(f);
-
-        return r;
-}
-
-int config_parse_int(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        int *i = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoi(rvalue, i)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue);
-                return 0;
+                        return r;
         }
 
         return 0;
 }
 
-int config_parse_long(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        long *i = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atoli(rvalue, i)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-int config_parse_uint64(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        uint64_t *u = data;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atou64(rvalue, u)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue);
-                return 0;
+#define DEFINE_PARSER(type, vartype, conv_func)                         \
+        int config_parse_##type(const char *filename,                   \
+                                unsigned line,                          \
+                                const char *section,                    \
+                                const char *lvalue,                     \
+                                int ltype,                              \
+                                const char *rvalue,                     \
+                                void *data,                             \
+                                void *userdata) {                       \
+                                                                        \
+                vartype *i = data;                                      \
+                int r;                                                  \
+                                                                        \
+                assert(filename);                                       \
+                assert(lvalue);                                         \
+                assert(rvalue);                                         \
+                assert(data);                                           \
+                                                                        \
+                r = conv_func(rvalue, i);                               \
+                if (r < 0)                                              \
+                        log_error("[%s:%u] Failed to parse %s value, ignoring: %s", \
+                                  filename, line, #vartype, rvalue);    \
+                                                                        \
+                return 0;                                               \
         }
 
-        return 0;
-}
-
-int config_parse_unsigned(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        unsigned *u = data;
-        int r;
+DEFINE_PARSER(int, int, safe_atoi)
+DEFINE_PARSER(long, long, safe_atoli)
+DEFINE_PARSER(uint64, uint64_t, safe_atou64)
+DEFINE_PARSER(unsigned, unsigned, safe_atou)
+DEFINE_PARSER(double, double, safe_atod)
+DEFINE_PARSER(nsec, nsec_t, parse_nsec)
+DEFINE_PARSER(sec, usec_t, parse_sec)
 
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if ((r = safe_atou(rvalue, u)) < 0) {
-                log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
-                return r;
-        }
-
-        return 0;
-}
 
 int config_parse_bytes_size(
                 const char *filename,
@@ -591,9 +506,9 @@ int config_parse_string(
         assert(rvalue);
         assert(data);
 
-        n = cunescape(rvalue);
+        n = strdup(rvalue);
         if (!n)
-                return -ENOMEM;
+                return log_oom();
 
         if (!utf8_is_valid(n)) {
                 log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
@@ -642,7 +557,7 @@ int config_parse_path(
 
         n = strdup(rvalue);
         if (!n)
-                return -ENOMEM;
+                return log_oom();
 
         path_kill_slashes(n);
 
@@ -662,12 +577,8 @@ int config_parse_strv(
                 void *data,
                 void *userdata) {
 
-        char*** sv = data;
-        char **n;
-        char *w;
-        unsigned k;
+        char *** sv = data, *w, *state;
         size_t l;
-        char *state;
         int r;
 
         assert(filename);
@@ -675,48 +586,40 @@ int config_parse_strv(
         assert(rvalue);
         assert(data);
 
-        k = strv_length(*sv);
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
+        if (isempty(rvalue)) {
+                char **empty;
 
-        n = new(char*, k+1);
-        if (!n)
-                return -ENOMEM;
+                /* Empty assignment resets the list. As a special rule
+                 * we actually fill in a real empty array here rather
+                 * than NULL, since some code wants to know if
+                 * something was set at all... */
+                empty = strv_new(NULL, NULL);
+                if (!empty)
+                        return log_oom();
 
-        if (*sv)
-                for (k = 0; (*sv)[k]; k++)
-                        n[k] = (*sv)[k];
-        else
-                k = 0;
+                strv_free(*sv);
+                *sv = empty;
+                return 0;
+        }
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                n[k] = cunescape_length(w, l);
-                if (!n[k]) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
+                _cleanup_free_ char *n;
+
+                n = cunescape_length(w, l);
+                if (!n)
+                        return log_oom();
 
-                if (!utf8_is_valid(n[k])) {
-                        log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
-                        free(n[k]);
+                if (!utf8_is_valid(n)) {
+                        log_error("[%s:%u] String is not UTF-8 clean, ignoring: %s", filename, line, rvalue);
                         continue;
                 }
 
-                k++;
+                r = strv_extend(sv, n);
+                if (r < 0)
+                        return log_oom();
         }
 
-        n[k] = NULL;
-        free(*sv);
-        *sv = n;
-
         return 0;
-
-fail:
-        for (; k > 0; k--)
-                free(n[k-1]);
-        free(n);
-
-        return r;
 }
 
 int config_parse_path_strv(
@@ -729,12 +632,8 @@ int config_parse_path_strv(
                 void *data,
                 void *userdata) {
 
-        char*** sv = data;
-        char **n;
-        char *w;
-        unsigned k;
+        char*** sv = data, *w, *state;
         size_t l;
-        char *state;
         int r;
 
         assert(filename);
@@ -742,101 +641,34 @@ int config_parse_path_strv(
         assert(rvalue);
         assert(data);
 
-        k = strv_length(*sv);
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
-
-        n = new(char*, k+1);
-        if (!n)
-                return -ENOMEM;
-
-        k = 0;
-        if (*sv)
-                for (; (*sv)[k]; k++)
-                        n[k] = (*sv)[k];
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                strv_free(*sv);
+                *sv = NULL;
+                return 0;
+        }
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                n[k] = strndup(w, l);
-                if (!n[k]) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
+                _cleanup_free_ char *n;
 
-                if (!utf8_is_valid(n[k])) {
+                n = strndup(w, l);
+                if (!n)
+                        return log_oom();
+
+                if (!utf8_is_valid(n)) {
                         log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
-                        free(n[k]);
                         continue;
                 }
 
-                if (!path_is_absolute(n[k])) {
+                if (!path_is_absolute(n)) {
                         log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
-                        free(n[k]);
                         continue;
                 }
 
-                path_kill_slashes(n[k]);
-                k++;
-        }
-
-        n[k] = NULL;
-        free(*sv);
-        *sv = n;
-
-        return 0;
-
-fail:
-        for (; k > 0; k--)
-                free(n[k-1]);
-        free(n);
-
-        return r;
-}
-
-int config_parse_usec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        usec_t *usec = data;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (parse_usec(rvalue, usec) < 0) {
-                log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
-                return 0;
-        }
-
-        return 0;
-}
-
-int config_parse_nsec(
-                const char *filename,
-                unsigned line,
-                const char *section,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        nsec_t *nsec = data;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        if (parse_nsec(rvalue, nsec) < 0) {
-                log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
-                return 0;
+                path_kill_slashes(n);
+                r = strv_extend(sv, n);
+                if (r < 0)
+                        return log_oom();
         }
 
         return 0;
@@ -863,7 +695,7 @@ int config_parse_mode(
 
         errno = 0;
         l = strtol(rvalue, &x, 8);
-        if (!x || *x || errno) {
+        if (!x || x == rvalue || *x || errno) {
                 log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
                 return 0;
         }
@@ -933,3 +765,83 @@ int config_parse_level(
         *o = (*o & LOG_FACMASK) | x;
         return 0;
 }
+
+int config_parse_set_status(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char *w;
+        size_t l;
+        char *state;
+        int r;
+        ExitStatusSet *status_set = data;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+
+                set_free(status_set->signal);
+                set_free(status_set->code);
+
+                status_set->signal = status_set->code = NULL;
+                return 0;
+        }
+
+        FOREACH_WORD(w, l, rvalue, state) {
+                int val;
+                char *temp;
+
+                temp = strndup(w, l);
+                if (!temp)
+                        return log_oom();
+
+                r = safe_atoi(temp, &val);
+                if (r < 0) {
+                        val = signal_from_string_try_harder(temp);
+                        free(temp);
+
+                        if (val > 0) {
+                                r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
+                                if (r < 0)
+                                        return log_oom();
+
+                                r = set_put(status_set->signal, INT_TO_PTR(val));
+                                if (r < 0) {
+                                        log_error("[%s:%u] Unable to store: %s", filename, line, w);
+                                        return r;
+                                }
+                        } else {
+                                log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w);
+                                return 0;
+                        }
+                } else {
+                        free(temp);
+
+                        if (val < 0 || val > 255)
+                                log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val);
+                        else {
+                                r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
+                                if (r < 0)
+                                        return log_oom();
+
+                                r = set_put(status_set->code, INT_TO_PTR(val));
+                                if (r < 0) {
+                                        log_error("[%s:%u] Unable to store: %s", filename, line, w);
+                                        return r;
+                                }
+                        }
+                }
+        }
+
+        return 0;
+}