diff options
Diffstat (limited to 'src/shared/conf-parser.c')
-rw-r--r-- | src/shared/conf-parser.c | 665 |
1 files changed, 446 insertions, 219 deletions
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 7b3ac8999..e65fee5bc 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -1,21 +1,4 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include <errno.h> #include <limits.h> @@ -28,21 +11,29 @@ #include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" +#include "def.h" #include "extract-word.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" +//#include "rlimit-util.h" #include "signal-util.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "syslog-util.h" #include "time-util.h" #include "utf8.h" +/// Additional includes needed by elogind +#include "def.h" +#include "fileio.h" + int config_item_table_lookup( const void *table, const char *section, @@ -118,17 +109,18 @@ int config_item_perf_lookup( } /* Run the user supplied parser for an assignment */ -static int next_assignment(const char *unit, - const char *filename, - unsigned line, - ConfigItemLookup lookup, - const void *table, - const char *section, - unsigned section_line, - const char *lvalue, - const char *rvalue, - bool relaxed, - void *userdata) { +static int next_assignment( + const char *unit, + const char *filename, + unsigned line, + ConfigItemLookup lookup, + const void *table, + const char *section, + unsigned section_line, + const char *lvalue, + const char *rvalue, + ConfigParseFlags flags, + void *userdata) { ConfigParserCallback func = NULL; int ltype = 0; @@ -154,28 +146,28 @@ static int next_assignment(const char *unit, } /* Warn about unknown non-extension fields. */ - if (!relaxed && !startswith(lvalue, "X-")) + if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section); return 0; } -/* Parse a variable assignment line */ -static int parse_line(const char* unit, - const char *filename, - unsigned line, - const char *sections, - ConfigItemLookup lookup, - const void *table, - bool relaxed, - bool allow_include, - char **section, - unsigned *section_line, - bool *section_ignored, - char *l, - void *userdata) { +/* Parse a single logical line */ +static int parse_line( + const char* unit, + const char *filename, + unsigned line, + const char *sections, + ConfigItemLookup lookup, + const void *table, + ConfigParseFlags flags, + char **section, + unsigned *section_line, + bool *section_ignored, + char *l, + void *userdata) { - char *e; + char *e, *include; assert(filename); assert(line > 0); @@ -183,14 +175,14 @@ static int parse_line(const char* unit, assert(l); l = strstrip(l); - if (!*l) return 0; if (strchr(COMMENTS "\n", *l)) return 0; - if (startswith(l, ".include ")) { + include = first_word(l, ".include"); + if (include) { _cleanup_free_ char *fn = NULL; /* .includes are a bad idea, we only support them here @@ -202,18 +194,25 @@ static int parse_line(const char* unit, * * Support for them should be eventually removed. */ - if (!allow_include) { + if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) { log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring."); return 0; } - fn = file_in_same_dir(filename, strstrip(l+9)); + log_syntax(unit, LOG_WARNING, filename, line, 0, + ".include directives are deprecated, and support for them will be removed in a future version of elogind. " + "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, relaxed, false, false, userdata); + 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); + if (*l == '[') { size_t k; char *n; @@ -232,7 +231,7 @@ static int parse_line(const char* unit, if (sections && !nulstr_contains(sections, n)) { - if (!relaxed && !startswith(n, "X-")) + if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n); free(n); @@ -240,8 +239,7 @@ static int parse_line(const char* unit, *section_line = 0; *section_ignored = true; } else { - free(*section); - *section = n; + free_and_replace(*section, n); *section_line = line; *section_ignored = false; } @@ -251,7 +249,7 @@ static int parse_line(const char* unit, if (sections && !*section) { - if (!relaxed && !*section_ignored) + if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored) log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring."); return 0; @@ -275,7 +273,7 @@ static int parse_line(const char* unit, *section_line, strstrip(l), strstrip(e), - relaxed, + flags, userdata); } @@ -286,15 +284,13 @@ int config_parse(const char *unit, const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, - bool allow_include, - bool warn, + ConfigParseFlags flags, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; - bool section_ignored = false, allow_bom = true; + bool section_ignored = false; int r; assert(filename); @@ -305,9 +301,9 @@ int config_parse(const char *unit, if (!f) { /* Only log on request, except for ENOENT, * since we return 0 to the caller. */ - if (warn || errno == ENOENT) - log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, - "Failed to open configuration file '%s': %m", filename); + if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT) + log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, + "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; } } @@ -315,33 +311,51 @@ int config_parse(const char *unit, fd_warn_permissions(filename, fileno(f)); for (;;) { - char buf[LINE_MAX], *l, *p, *c = NULL, *e; + _cleanup_free_ char *buf = NULL; bool escaped = false; + char *l, *p, *e; - if (!fgets(buf, sizeof buf, f)) { - if (feof(f)) - break; + r = read_line(f, LONG_LINE_MAX, &buf); + if (r == 0) + break; + if (r == -ENOBUFS) { + if (flags & CONFIG_PARSE_WARN) + log_error_errno(r, "%s:%u: Line too long", filename, line); - return log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); + return r; + } + if (r < 0) { + if (CONFIG_PARSE_WARN) + log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); + + return r; } l = buf; - if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK)) - l += strlen(UTF8_BYTE_ORDER_MARK); - allow_bom = false; + if (!(flags & CONFIG_PARSE_REFUSE_BOM)) { + char *q; - truncate_nl(l); + q = startswith(buf, UTF8_BYTE_ORDER_MARK); + if (q) { + l = q; + flags |= CONFIG_PARSE_REFUSE_BOM; + } + } if (continuation) { - c = strappend(continuation, l); - if (!c) { - if (warn) + if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) { + if (flags & CONFIG_PARSE_WARN) + log_error("%s:%u: Continuation line too long", filename, line); + return -ENOBUFS; + } + + if (!strextend(&continuation, l, NULL)) { + if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } - continuation = mfree(continuation); - p = c; + p = continuation; } else p = l; @@ -355,12 +369,10 @@ int config_parse(const char *unit, if (escaped) { *(e-1) = ' '; - if (c) - continuation = c; - else { + if (!continuation) { continuation = strdup(l); if (!continuation) { - if (warn) + if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } @@ -375,19 +387,37 @@ int config_parse(const char *unit, sections, lookup, table, - relaxed, - allow_include, + flags, §ion, §ion_line, §ion_ignored, p, userdata); - free(c); + if (r < 0) { + if (flags & CONFIG_PARSE_WARN) + log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); + return r; + } + + continuation = mfree(continuation); + } + if (continuation) { + r = parse_line(unit, + filename, + ++line, + sections, + lookup, + table, + flags, + §ion, + §ion_line, + §ion_ignored, + continuation, + userdata); if (r < 0) { - if (warn) - log_warning_errno(r, "Failed to parse file '%s': %m", - filename); + if (flags & CONFIG_PARSE_WARN) + log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); return r; } } @@ -401,20 +431,20 @@ static int config_parse_many_files( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { char **fn; int r; if (conf_file) { - r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata); + r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata); if (r < 0) return r; } STRV_FOREACH(fn, files) { - r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata); + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata); if (r < 0) return r; } @@ -429,18 +459,17 @@ int config_parse_many_nulstr( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { _cleanup_strv_free_ char **files = NULL; int r; - r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs); + r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs); if (r < 0) return r; - return config_parse_many_files(conf_file, files, - sections, lookup, table, relaxed, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); } #if 0 /// UNNEEDED by elogind @@ -452,7 +481,7 @@ int config_parse_many( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { _cleanup_strv_free_ char **dropin_dirs = NULL; @@ -465,45 +494,16 @@ int config_parse_many( if (r < 0) return r; - r = conf_files_list_strv(&files, ".conf", NULL, (const char* const*) dropin_dirs); + r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs); if (r < 0) return r; - return config_parse_many_files(conf_file, files, - sections, lookup, table, relaxed, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); } #endif // 0 #define DEFINE_PARSER(type, vartype, conv_func) \ - int config_parse_##type( \ - const char *unit, \ - const char *filename, \ - unsigned line, \ - const char *section, \ - unsigned section_line, \ - 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_syntax(unit, LOG_ERR, filename, line, r, \ - "Failed to parse %s value, ignoring: %s", \ - #type, rvalue); \ - \ - return 0; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ + DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value") DEFINE_PARSER(int, int, safe_atoi); DEFINE_PARSER(long, long, safe_atoli); @@ -519,6 +519,7 @@ DEFINE_PARSER(double, double, safe_atod); DEFINE_PARSER(nsec, nsec_t, parse_nsec); #endif // 0 DEFINE_PARSER(sec, usec_t, parse_sec); +#if 0 /// UNNEEDED by elogind DEFINE_PARSER(mode, mode_t, parse_mode); int config_parse_iec_size(const char* unit, @@ -551,17 +552,17 @@ int config_parse_iec_size(const char* unit, return 0; } -#if 0 /// UNNEEDED by elogind -int config_parse_si_size(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_si_size( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { size_t *sz = data; uint64_t v; @@ -582,16 +583,17 @@ int config_parse_si_size(const char* unit, return 0; } -int config_parse_iec_uint64(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_iec_uint64( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { uint64_t *bytes = data; int r; @@ -637,7 +639,7 @@ int config_parse_bool(const char* unit, return fatal ? -ENOEXEC : 0; } - *b = !!k; + *b = k; return 0; } @@ -688,32 +690,20 @@ int config_parse_string( void *data, void *userdata) { - char **s = data, *n; + char **s = data; assert(filename); assert(lvalue); assert(rvalue); assert(data); - if (!utf8_is_valid(rvalue)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); - return 0; - } - - if (isempty(rvalue)) - n = NULL; - else { - n = strdup(rvalue); - if (!n) - return log_oom(); - } - - free(*s); - *s = n; + if (free_and_strdup(s, empty_to_null(rvalue)) < 0) + return log_oom(); return 0; } +#if 0 /// UNNEEDED by elogind int config_parse_path( const char *unit, const char *filename, @@ -726,48 +716,43 @@ int config_parse_path( void *data, void *userdata) { - char **s = data, *n; + _cleanup_free_ char *n = NULL; bool fatal = ltype; + char **s = data; + int r; assert(filename); assert(lvalue); assert(rvalue); assert(data); - if (!utf8_is_valid(rvalue)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); - return fatal ? -ENOEXEC : 0; - } - - if (!path_is_absolute(rvalue)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Not an absolute path%s: %s", - fatal ? "" : ", ignoring", rvalue); - return fatal ? -ENOEXEC : 0; - } + if (isempty(rvalue)) + goto finalize; n = strdup(rvalue); if (!n) return log_oom(); - path_kill_slashes(n); - - free(*s); - *s = n; + r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue); + if (r < 0) + return fatal ? -ENOEXEC : 0; - return 0; +finalize: + return free_and_replace(*s, n); } +#endif // 0 -int config_parse_strv(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_strv( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { char ***sv = data; int r; @@ -778,19 +763,7 @@ int config_parse_strv(const char *unit, assert(data); if (isempty(rvalue)) { - char **empty; - - /* 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 = new0(char*, 1); - if (!empty) - return log_oom(); - - strv_free(*sv); - *sv = empty; - + *sv = strv_free(*sv); return 0; } @@ -807,11 +780,6 @@ int config_parse_strv(const char *unit, break; } - if (!utf8_is_valid(word)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word); - free(word); - continue; - } r = strv_consume(sv, word); if (r < 0) return log_oom(); @@ -821,7 +789,7 @@ int config_parse_strv(const char *unit, } #if 0 /// UNNEEDED by elogind -int config_parse_log_facility( +int config_parse_warn_compat( const char *unit, const char *filename, unsigned line, @@ -833,6 +801,40 @@ int config_parse_log_facility( void *data, void *userdata) { + Disabled reason = ltype; + + switch(reason) { + + case DISABLED_CONFIGURATION: + log_syntax(unit, LOG_DEBUG, filename, line, 0, + "Support for option %s= has been disabled at compile time and it is ignored", lvalue); + break; + + case DISABLED_LEGACY: + log_syntax(unit, LOG_INFO, filename, line, 0, + "Support for option %s= has been removed and it is ignored", lvalue); + break; + + case DISABLED_EXPERIMENTAL: + log_syntax(unit, LOG_INFO, filename, line, 0, + "Support for option %s= has not yet been enabled and it is ignored", lvalue); + break; + } + + return 0; +} + +int config_parse_log_facility( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { int *o = data, x; @@ -851,7 +853,6 @@ int config_parse_log_facility( return 0; } -#endif // 0 int config_parse_log_level( const char *unit, @@ -865,7 +866,6 @@ int config_parse_log_level( void *data, void *userdata) { - int *o = data, x; assert(filename); @@ -879,7 +879,11 @@ int config_parse_log_level( return 0; } - *o = (*o & LOG_FACMASK) | x; + if (*o < 0) /* if it wasn't initialized so far, assume zero facility */ + *o = x; + else + *o = (*o & LOG_FACMASK) | x; + return 0; } @@ -902,7 +906,7 @@ int config_parse_signal( assert(rvalue); assert(sig); - r = signal_from_string_try_harder(rvalue); + r = signal_from_string(rvalue); if (r <= 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue); return 0; @@ -912,7 +916,6 @@ int config_parse_signal( return 0; } -#if 0 /// UNNEEDED by elogind int config_parse_personality( const char *unit, const char *filename, @@ -932,10 +935,14 @@ int config_parse_personality( assert(rvalue); assert(personality); - p = personality_from_string(rvalue); - if (p == PERSONALITY_INVALID) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue); - return 0; + if (isempty(rvalue)) + p = PERSONALITY_INVALID; + 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); + return 0; + } } *personality = p; @@ -1015,4 +1022,224 @@ int config_parse_ip_port( return 0; } + +int config_parse_join_controllers( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ****ret = data; + const char *whole_rvalue = rvalue; + unsigned n = 0; + _cleanup_(strv_free_freep) char ***controllers = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(ret); + + for (;;) { + _cleanup_free_ char *word = NULL; + char **l; + int r; + + r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); + return r; + } + if (r == 0) + break; + + l = strv_split(word, ","); + if (!l) + return log_oom(); + strv_uniq(l); + + if (strv_length(l) <= 1) { + strv_free(l); + continue; + } + + if (!controllers) { + controllers = new(char**, 2); + if (!controllers) { + strv_free(l); + return log_oom(); + } + + controllers[0] = l; + controllers[1] = NULL; + + n = 1; + } else { + char ***a; + char ***t; + + t = new0(char**, n+2); + if (!t) { + strv_free(l); + return log_oom(); + } + + n = 0; + + for (a = controllers; *a; a++) + if (strv_overlap(*a, l)) { + if (strv_extend_strv(&l, *a, false) < 0) { + strv_free(l); + strv_free_free(t); + return log_oom(); + } + + } else { + char **c; + + c = strv_copy(*a); + if (!c) { + strv_free(l); + strv_free_free(t); + return log_oom(); + } + + t[n++] = c; + } + + t[n++] = strv_uniq(l); + + strv_free_free(controllers); + controllers = t; + } + } + if (!isempty(rvalue)) + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); + + /* As a special case, return a single empty strv, to override the default */ + if (!controllers) { + controllers = new(char**, 2); + if (!controllers) + return log_oom(); + controllers[0] = strv_new(NULL, NULL); + if (!controllers[0]) + return log_oom(); + controllers[1] = NULL; + } + + strv_free_free(*ret); + *ret = TAKE_PTR(controllers); + + return 0; +} + +int config_parse_mtu( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint32_t *mtu = data; + int r; + + assert(rvalue); + assert(mtu); + + r = parse_mtu(ltype, rvalue, mtu); + if (r == -ERANGE) { + log_syntax(unit, LOG_ERR, 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, + "Failed to parse MTU value '%s', ignoring: %m", rvalue); + return 0; + } + + return 0; +} + +int config_parse_rlimit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data, d = {}; + int r; + + assert(rvalue); + assert(rl); + + r = rlimit_parse(ltype, rvalue, &d); + if (r == -EILSEQ) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue); + return 0; + } + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + if (rl[ltype]) + *rl[ltype] = d; + else { + rl[ltype] = newdup(struct rlimit, &d, 1); + if (!rl[ltype]) + return log_oom(); + } + + return 0; +} + +int config_parse_permille(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + unsigned *permille = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(permille); + + r = parse_permille(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse permille value, ignoring: %s", rvalue); + return 0; + } + + *permille = (unsigned) r; + + return 0; +} #endif // 0 |