conf-parser.c revision 94d75d6423f16f1fb66d214cb640ae3a114c5c58
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen/***
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen This file is part of systemd.
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen Copyright 2010 Lennart Poettering
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen systemd is free software; you can redistribute it and/or modify it
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen under the terms of the GNU Lesser General Public License as published by
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen (at your option) any later version.
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen systemd is distributed in the hope that it will be useful, but
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen Lesser General Public License for more details.
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen You should have received a copy of the GNU Lesser General Public License
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen***/
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include <string.h>
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include <stdio.h>
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include <errno.h>
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include <stdlib.h>
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "sd-messages.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "conf-files.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "util.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "macro.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "strv.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "log.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "utf8.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "path-util.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "signal-util.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen#include "conf-parser.h"
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersenint config_item_table_lookup(
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const void *table,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const char *section,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const char *lvalue,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen ConfigParserCallback *func,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen int *ltype,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen void **data,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen void *userdata) {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const ConfigTableItem *t;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
9ee18af3a036074c4021c82ae2e67f5ccaa9ea9dTom Gundersen assert(table);
9ee18af3a036074c4021c82ae2e67f5ccaa9ea9dTom Gundersen assert(lvalue);
9ee18af3a036074c4021c82ae2e67f5ccaa9ea9dTom Gundersen assert(func);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen assert(ltype);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen assert(data);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen for (t = table; t->lvalue; t++) {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen if (!streq(lvalue, t->lvalue))
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen continue;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen if (!streq_ptr(section, t->section))
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen continue;
9ee18af3a036074c4021c82ae2e67f5ccaa9ea9dTom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen *func = t->parse;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen *ltype = t->ltype;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen *data = t->data;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen return 1;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen }
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen return 0;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen}
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersenint config_item_perf_lookup(
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const void *table,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const char *section,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen const char *lvalue,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen ConfigParserCallback *func,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen int *ltype,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen void **data,
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen void *userdata) {
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table;
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen const ConfigPerfItem *p;
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen assert(table);
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen assert(lvalue);
40862866417265ac8c20422cb44f14a8f141ce0dTom Gundersen assert(func);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen assert(ltype);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen assert(data);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen if (!section)
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen p = lookup(lvalue, strlen(lvalue));
e2acdb6b0f68d9b4152708a9f21bf9e11f8b9e7eTorstein Husebø else {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen char *key;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen key = strjoin(section, ".", lvalue, NULL);
9ee18af3a036074c4021c82ae2e67f5ccaa9ea9dTom Gundersen if (!key)
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen return -ENOMEM;
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen p = lookup(key, strlen(key));
free(key);
}
if (!p)
return 0;
*func = p->parse;
*ltype = p->ltype;
*data = (uint8_t*) userdata + p->offset;
return 1;
}
/* 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) {
ConfigParserCallback func = NULL;
int ltype = 0;
void *data = NULL;
int r;
assert(filename);
assert(line > 0);
assert(lookup);
assert(lvalue);
assert(rvalue);
r = lookup(table, section, lvalue, &func, &ltype, &data, userdata);
if (r < 0)
return r;
if (r > 0) {
if (func)
return func(unit, filename, line, section, section_line,
lvalue, ltype, rvalue, data, userdata);
return 0;
}
/* Warn about unknown non-extension fields. */
if (!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) {
char *e;
assert(filename);
assert(line > 0);
assert(lookup);
assert(l);
l = strstrip(l);
if (!*l)
return 0;
if (strchr(COMMENTS "\n", *l))
return 0;
if (startswith(l, ".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 (!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));
if (!fn)
return -ENOMEM;
return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
}
if (*l == '[') {
size_t k;
char *n;
k = strlen(l);
assert(k > 0);
if (l[k-1] != ']') {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
return -EBADMSG;
}
n = strndup(l+1, k-2);
if (!n)
return -ENOMEM;
if (sections && !nulstr_contains(sections, n)) {
if (!relaxed && !startswith(n, "X-"))
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
free(n);
*section = mfree(*section);
*section_line = 0;
*section_ignored = true;
} else {
free(*section);
*section = n;
*section_line = line;
*section_ignored = false;
}
return 0;
}
if (sections && !*section) {
if (!relaxed && !*section_ignored)
log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
return 0;
}
e = strchr(l, '=');
if (!e) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
return -EINVAL;
}
*e = 0;
e++;
return next_assignment(unit,
filename,
line,
lookup,
table,
*section,
*section_line,
strstrip(l),
strstrip(e),
relaxed,
userdata);
}
/* Go through the file and parse each line */
int config_parse(const char *unit,
const char *filename,
FILE *f,
const char *sections,
ConfigItemLookup lookup,
const void *table,
bool relaxed,
bool allow_include,
bool warn,
void *userdata) {
_cleanup_free_ char *section = NULL, *continuation = NULL;
_cleanup_fclose_ FILE *ours = NULL;
unsigned line = 0, section_line = 0;
bool section_ignored = false;
int r;
assert(filename);
assert(lookup);
if (!f) {
f = ours = fopen(filename, "re");
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);
return errno == ENOENT ? 0 : -errno;
}
}
fd_warn_permissions(filename, fileno(f));
while (!feof(f)) {
char l[LINE_MAX], *p, *c = NULL, *e;
bool escaped = false;
if (!fgets(l, sizeof(l), f)) {
if (feof(f))
break;
log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
return -errno;
}
truncate_nl(l);
if (continuation) {
c = strappend(continuation, l);
if (!c) {
if (warn)
log_oom();
return -ENOMEM;
}
continuation = mfree(continuation);
p = c;
} else
p = l;
for (e = p; *e; e++) {
if (escaped)
escaped = false;
else if (*e == '\\')
escaped = true;
}
if (escaped) {
*(e-1) = ' ';
if (c)
continuation = c;
else {
continuation = strdup(l);
if (!continuation) {
if (warn)
log_oom();
return -ENOMEM;
}
}
continue;
}
r = parse_line(unit,
filename,
++line,
sections,
lookup,
table,
relaxed,
allow_include,
&section,
&section_line,
&section_ignored,
p,
userdata);
free(c);
if (r < 0) {
if (warn)
log_warning_errno(r, "Failed to parse file '%s': %m",
filename);
return r;
}
}
return 0;
}
/* Parse each config file in the specified directories. */
int config_parse_many(const char *conf_file,
const char *conf_file_dirs,
const char *sections,
ConfigItemLookup lookup,
const void *table,
bool relaxed,
void *userdata) {
_cleanup_strv_free_ char **files = NULL;
char **fn;
int r;
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0)
return r;
if (conf_file) {
r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
if (r < 0)
return r;
}
STRV_FOREACH(fn, files) {
r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
if (r < 0)
return r;
}
return 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_PARSER(int, int, safe_atoi);
DEFINE_PARSER(long, long, safe_atoli);
DEFINE_PARSER(uint32, uint32_t, safe_atou32);
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);
DEFINE_PARSER(mode, mode_t, parse_mode);
int config_parse_iec_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;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = parse_size(rvalue, 1024, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
*sz = (size_t) v;
return 0;
}
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;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = parse_size(rvalue, 1000, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
*sz = (size_t) v;
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) {
uint64_t *bytes = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
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);
return 0;
}
int config_parse_bool(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 k;
bool *b = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
k = parse_boolean(rvalue);
if (k < 0) {
log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
*b = !!k;
return 0;
}
int config_parse_tristate(
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 k, *t = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
/* A tristate is pretty much a boolean, except that it can
* also take the special value -1, indicating "uninitialized",
* much like NULL is for a pointer type. */
k = parse_boolean(rvalue);
if (k < 0) {
log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
*t = !!k;
return 0;
}
int config_parse_string(
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 **s = data, *n;
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;
return 0;
}
int config_parse_path(
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 **s = data, *n;
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 (!path_is_absolute(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
return 0;
}
n = strdup(rvalue);
if (!n)
return log_oom();
path_kill_slashes(n);
free(*s);
*s = n;
return 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) {
char ***sv = data;
const char *word, *state;
size_t l;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
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 = strv_new(NULL, NULL);
if (!empty)
return log_oom();
strv_free(*sv);
*sv = empty;
return 0;
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
char *n;
n = strndup(word, l);
if (!n)
return log_oom();
if (!utf8_is_valid(n)) {
log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
free(n);
continue;
}
r = strv_consume(sv, n);
if (r < 0)
return log_oom();
}
if (!isempty(state))
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
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;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
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);
return 0;
}
*o = (x << 3) | LOG_PRI(*o);
return 0;
}
int config_parse_log_level(
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;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
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);
return 0;
}
*o = (*o & LOG_FACMASK) | x;
return 0;
}
int config_parse_signal(
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 *sig = data, r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(sig);
r = signal_from_string_try_harder(rvalue);
if (r <= 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
return 0;
}
*sig = r;
return 0;
}
int config_parse_personality(
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 long *personality = data, p;
assert(filename);
assert(lvalue);
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;
}
*personality = p;
return 0;
}