]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/conf-parser.c
Merge pull request #16678 from poettering/loop-configure
[thirdparty/systemd.git] / src / shared / conf-parser.c
index b04eb3912c19a4f51cd235b7d45993c6c0db7771..0fec79f3d7979fe60ee7ea028de1ec5faf238a6b 100644 (file)
@@ -159,7 +159,7 @@ static int parse_line(
                 char *l,
                 void *userdata) {
 
-        char *e, *include;
+        char *e;
 
         assert(filename);
         assert(line > 0);
@@ -173,35 +173,6 @@ static int parse_line(
         if (*l == '\n')
                 return 0;
 
-        include = first_word(l, ".include");
-        if (include) {
-                _cleanup_free_ char *fn = NULL;
-
-                /* .includes are a bad idea, we only support them here
-                 * for historical reasons. They create cyclic include
-                 * problems and make it difficult to detect
-                 * configuration file changes with an easy
-                 * stat(). Better approaches, such as .d/ drop-in
-                 * snippets exist.
-                 *
-                 * Support for them should be eventually removed. */
-
-                if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
-                        return 0;
-                }
-
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
-                           "Please use drop-in files instead.");
-
-                fn = file_in_same_dir(filename, strstrip(include));
-                if (!fn)
-                        return -ENOMEM;
-
-                return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
-        }
-
         if (!utf8_is_valid(l))
                 return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);
 
@@ -289,13 +260,15 @@ int config_parse(const char *unit,
                  ConfigItemLookup lookup,
                  const void *table,
                  ConfigParseFlags flags,
-                 void *userdata) {
+                 void *userdata,
+                 usec_t *ret_mtime) {
 
         _cleanup_free_ char *section = NULL, *continuation = NULL;
         _cleanup_fclose_ FILE *ours = NULL;
         unsigned line = 0, section_line = 0;
         bool section_ignored = false, bom_seen = false;
         int r, fd;
+        usec_t mtime;
 
         assert(filename);
         assert(lookup);
@@ -313,8 +286,16 @@ int config_parse(const char *unit,
         }
 
         fd = fileno(f);
-        if (fd >= 0) /* stream might not have an fd, let's be careful hence */
-                fd_warn_permissions(filename, fd);
+        if (fd >= 0) { /* stream might not have an fd, let's be careful hence */
+                struct stat st;
+
+                if (fstat(fd, &st) < 0)
+                        return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_ERR : LOG_DEBUG, errno,
+                                              "Failed to fstat(%s): %m", filename);
+
+                (void) stat_warn_permissions(filename, &st);
+                mtime = timespec_load(&st.st_mtim);
+        }
 
         for (;;) {
                 _cleanup_free_ char *buf = NULL;
@@ -331,7 +312,7 @@ int config_parse(const char *unit,
                         return r;
                 }
                 if (r < 0) {
-                        if (CONFIG_PARSE_WARN)
+                        if (FLAGS_SET(flags, CONFIG_PARSE_WARN))
                                 log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
 
                         return r;
@@ -434,6 +415,9 @@ int config_parse(const char *unit,
                 }
         }
 
+        if (ret_mtime)
+                *ret_mtime = mtime;
+
         return 0;
 }
 
@@ -444,23 +428,32 @@ static int config_parse_many_files(
                 ConfigItemLookup lookup,
                 const void *table,
                 ConfigParseFlags flags,
-                void *userdata) {
+                void *userdata,
+                usec_t *ret_mtime) {
 
+        usec_t mtime = 0;
         char **fn;
         int r;
 
         if (conf_file) {
-                r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
+                r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime);
                 if (r < 0)
                         return r;
         }
 
         STRV_FOREACH(fn, files) {
-                r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
+                usec_t t;
+
+                r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t);
                 if (r < 0)
                         return r;
+                if (t > mtime) /* Find the newest */
+                        mtime = t;
         }
 
+        if (ret_mtime)
+                *ret_mtime = mtime;
+
         return 0;
 }
 
@@ -472,7 +465,8 @@ int config_parse_many_nulstr(
                 ConfigItemLookup lookup,
                 const void *table,
                 ConfigParseFlags flags,
-                void *userdata) {
+                void *userdata,
+                usec_t *ret_mtime) {
 
         _cleanup_strv_free_ char **files = NULL;
         int r;
@@ -481,7 +475,7 @@ int config_parse_many_nulstr(
         if (r < 0)
                 return r;
 
-        return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
+        return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
 }
 
 /* Parse each config file in the directories specified as strv. */
@@ -494,7 +488,7 @@ int config_parse_many(
                 const void *table,
                 ConfigParseFlags flags,
                 void *userdata,
-                char ***ret_dropins) {
+                usec_t *ret_mtime) {
 
         _cleanup_strv_free_ char **dropin_dirs = NULL;
         _cleanup_strv_free_ char **files = NULL;
@@ -510,14 +504,7 @@ int config_parse_many(
         if (r < 0)
                 return r;
 
-        r = config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
-        if (r < 0)
-                return r;
-
-        if (ret_dropins)
-                *ret_dropins = TAKE_PTR(files);
-
-        return 0;
+        return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
 }
 
 #define DEFINE_PARSER(type, vartype, conv_func)                         \
@@ -561,7 +548,7 @@ int config_parse_iec_size(const char* unit,
         if (r >= 0 && (uint64_t) (size_t) v != v)
                 r = -ERANGE;
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
                 return 0;
         }
 
@@ -590,10 +577,8 @@ int config_parse_si_uint64(
         assert(data);
 
         r = parse_size(rvalue, 1000, sz);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
-                return 0;
-        }
+        if (r < 0)
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
 
         return 0;
 }
@@ -620,7 +605,7 @@ int config_parse_iec_uint64(
 
         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);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
 
         return 0;
 }
@@ -647,7 +632,7 @@ int config_parse_bool(const char* unit,
 
         k = parse_boolean(rvalue);
         if (k < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, k,
+                log_syntax(unit, fatal ? LOG_ERR : LOG_WARNING, filename, line, k,
                            "Failed to parse boolean value%s: %s",
                            fatal ? "" : ", ignoring", rvalue);
                 return fatal ? -ENOEXEC : 0;
@@ -677,10 +662,15 @@ int config_parse_id128(
         assert(rvalue);
 
         r = sd_id128_from_string(rvalue, &t);
-        if (r < 0)
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
-        else if (sd_id128_is_null(t))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        if (sd_id128_is_null(t)) {
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "128bit ID/UUID is all 0, ignoring: %s", rvalue);
+                return 0;
+        }
 
         *result = t;
         return 0;
@@ -711,7 +701,7 @@ int config_parse_tristate(
 
         k = parse_boolean(rvalue);
         if (k < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -806,25 +796,23 @@ int config_parse_strv(
                 return 0;
         }
 
-        for (;;) {
+        for (const char *p = rvalue;;) {
                 char *word = NULL;
 
-                r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
+                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
                 if (r == 0)
-                        break;
+                        return 0;
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
-                        break;
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+                        return 0;
                 }
 
                 r = strv_consume(sv, word);
                 if (r < 0)
                         return log_oom();
         }
-
-        return 0;
 }
 
 int config_parse_warn_compat(
@@ -883,7 +871,7 @@ int config_parse_log_facility(
 
         x = log_facility_unshifted_from_string(rvalue);
         if (x < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -913,7 +901,7 @@ int config_parse_log_level(
 
         x = log_level_from_string(rvalue);
         if (x < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -946,7 +934,7 @@ int config_parse_signal(
 
         r = signal_from_string(rvalue);
         if (r <= 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -978,7 +966,7 @@ int config_parse_personality(
         else {
                 p = personality_from_string(rvalue);
                 if (p == PERSONALITY_INVALID) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
                         return 0;
                 }
         }
@@ -1013,7 +1001,7 @@ int config_parse_ifname(
         }
 
         if (!ifname_valid(rvalue)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -1038,7 +1026,6 @@ int config_parse_ifnames(
 
         _cleanup_strv_free_ char **names = NULL;
         char ***s = data;
-        const char *p;
         int r;
 
         assert(filename);
@@ -1051,13 +1038,14 @@ int config_parse_ifnames(
                 return 0;
         }
 
-        p = rvalue;
-        for (;;) {
+        for (const char *p = rvalue;;) {
                 _cleanup_free_ char *word = NULL;
 
                 r = extract_first_word(&p, &word, NULL, 0);
+                if (r == -ENOMEM)
+                        return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r,
+                        log_syntax(unit, LOG_WARNING, filename, line, r,
                                    "Failed to extract interface name, ignoring assignment: %s",
                                    rvalue);
                         return 0;
@@ -1066,7 +1054,7 @@ int config_parse_ifnames(
                         break;
 
                 if (!ifname_valid_full(word, ltype)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
                                    "Interface name is not valid or too long, ignoring assignment: %s",
                                    word);
                         continue;
@@ -1112,7 +1100,7 @@ int config_parse_ip_port(
 
         r = parse_ip_port(rvalue, &port);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse port '%s'.", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse port '%s'.", rvalue);
                 return 0;
         }
 
@@ -1141,14 +1129,14 @@ int config_parse_mtu(
 
         r = parse_mtu(ltype, rvalue, mtu);
         if (r == -ERANGE) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s",
                            (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX,
                            rvalue);
                 return 0;
         }
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Failed to parse MTU value '%s', ignoring: %m", rvalue);
                 return 0;
         }
@@ -1180,7 +1168,7 @@ int config_parse_rlimit(
                 return 0;
         }
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -1216,7 +1204,7 @@ int config_parse_permille(const char* unit,
 
         r = parse_permille(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+                log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Failed to parse permille value, ignoring: %s", rvalue);
                 return 0;
         }
@@ -1250,7 +1238,7 @@ int config_parse_vlanprotocol(const char* unit,
         else if (STR_IN_SET(rvalue, "802.1q", "802.1Q"))
                 *vlan_protocol = ETH_P_8021Q;
         else {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
                            "Failed to parse VLAN protocol value, ignoring: %s", rvalue);
                 return 0;
         }