load-fragment.c revision 0245cf8167d34e483955b90da7f5d5f154ca57ef
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
Copyright 2012 Holger Hans Peter Freyther
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/>.
***/
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
#include <sched.h>
#include <string.h>
#include <sys/resource.h>
#include "af-list.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
#include "cap-list.h"
#include "cgroup.h"
#include "conf-parser.h"
#include "cpu-set-util.h"
#include "env-util.h"
#include "errno-list.h"
#include "ioprio.h"
#include "log.h"
#include "missing.h"
#include "path-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "securebits.h"
#include "signal-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "unit.h"
#include "utf8.h"
#include "load-fragment.h"
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) {
switch(reason) {
case DISABLED_CONFIGURATION:
"Support for option %s= has been disabled at compile time and it is ignored", lvalue);
break;
case DISABLED_LEGACY:
"Support for option %s= has been removed and it is ignored", lvalue);
break;
case DISABLED_EXPERIMENTAL:
"Support for option %s= has not yet been enabled and it is ignored", lvalue);
break;
};
return 0;
}
int config_parse_unit_deps(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) {
UnitDependency d = ltype;
size_t l;
int r;
if (!t)
return log_oom();
r = unit_name_printf(u, t, &k);
if (r < 0) {
continue;
}
r = unit_add_dependency_by_name(u, d, k, NULL, true);
if (r < 0)
}
return 0;
}
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) {
_cleanup_free_ char *k = NULL;
int r;
assert(u);
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
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) {
_cleanup_free_ char *k = NULL;
int r;
assert(u);
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
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) {
_cleanup_free_ char *k = NULL;
int r;
assert(u);
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
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 ***x = data;
size_t l;
int r;
assert(u);
_cleanup_free_ char *k = NULL;
char t[l+1];
t[l] = 0;
r = unit_full_printf(u, t, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t);
return 0;
}
if (!utf8_is_valid(k)) {
return 0;
}
if (!path_is_absolute(k)) {
return 0;
}
r = strv_push(x, k);
if (r < 0)
return log_oom();
k = NULL;
}
return 0;
}
int config_parse_socket_listen(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) {
Socket *s;
int r;
/* An empty assignment removes all ports */
return 0;
}
if (!p)
return log_oom();
if (ltype != SOCKET_SOCKET) {
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
path_kill_slashes(p->path);
_cleanup_free_ char *k = NULL;
p->type = SOCKET_SOCKET;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
r = socket_address_parse_netlink(&p->address, k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
} else {
_cleanup_free_ char *k = NULL;
p->type = SOCKET_SOCKET;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
r = socket_address_parse_and_warn(&p->address, k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
else {
}
return 0;
}
}
p->fd = -1;
p->auxiliary_fds = NULL;
p->n_auxiliary_fds = 0;
p->socket = s;
if (s->ports) {
} else
p = NULL;
return 0;
}
int config_parse_socket_bind(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) {
Socket *s;
if (b < 0) {
int r;
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
return 0;
}
} else
s->bind_ipv6_only = b;
return 0;
}
int config_parse_exec_nice(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) {
ExecContext *c = data;
int priority, r;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
return 0;
}
return 0;
}
c->nice_set = true;
return 0;
}
int config_parse_exec_oom_score_adjust(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) {
ExecContext *c = data;
int oa, r;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0;
}
log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
return 0;
}
c->oom_score_adjust = oa;
c->oom_score_adjust_set = true;
return 0;
}
int config_parse_exec(
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) {
ExecCommand **e = data;
const char *p;
bool semicolon;
int r;
assert(e);
e += ltype;
p = rvalue;
/* An empty assignment resets the list */
*e = exec_command_free_list(*e);
return 0;
}
do {
int i;
_cleanup_strv_free_ char **n = NULL;
char *f;
bool separate_argv0 = false, ignore = false;
semicolon = false;
r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
if (r <= 0)
return 0;
f = firstword;
for (i = 0; i < 2; i++) {
/* We accept an absolute path as first argument, or
* alternatively an absolute prefixed with @ to allow
* overriding of argv[0]. */
if (*f == '-' && !ignore)
ignore = true;
else if (*f == '@' && !separate_argv0)
separate_argv0 = true;
else
break;
f ++;
}
if (isempty(f)) {
/* First word is either "-" or "@" with no command. */
log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
return 0;
}
if (!string_is_safe(f)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
return 0;
}
if (!path_is_absolute(f)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
return 0;
}
if (endswith(f, "/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
return 0;
}
if (f == firstword) {
} else {
if (!path)
return log_oom();
}
if (!separate_argv0) {
return log_oom();
if (!f)
return log_oom();
n[nlen++] = f;
}
while (!isempty(p)) {
/* Check explicitly for an unquoted semicolon as
* command separator token. */
p ++;
p += strspn(p, WHITESPACE);
semicolon = true;
break;
}
/* Check for \; explicitly, to not confuse it with \\;
* or "\;" or "\\;" etc. extract_first_word would
* return the same for all of those. */
p += 2;
p += strspn(p, WHITESPACE);
return log_oom();
f = strdup(";");
if (!f)
return log_oom();
n[nlen++] = f;
continue;
}
r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
if (r == 0)
break;
else if (r < 0)
return 0;
return log_oom();
}
if (!n || !n[0]) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
return 0;
}
if (!nce)
return log_oom();
/* Do not _cleanup_free_ these. */
n = NULL;
rvalue = p;
} while (semicolon);
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
int config_parse_socket_bindtodevice(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 *n;
if (!n)
return log_oom();
} else
n = NULL;
free(s->bind_to_device);
s->bind_to_device = n;
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
int config_parse_exec_io_class(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) {
ExecContext *c = data;
int x;
if (x < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
return 0;
}
c->ioprio_set = true;
return 0;
}
int config_parse_exec_io_priority(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) {
ExecContext *c = data;
int i, r;
if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
return 0;
}
c->ioprio_set = true;
return 0;
}
int config_parse_exec_cpu_sched_policy(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) {
ExecContext *c = data;
int x;
if (x < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
c->cpu_sched_policy = x;
/* Moving to or from real-time policy? We need to adjust the priority */
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
c->cpu_sched_set = true;
return 0;
}
int config_parse_exec_cpu_sched_prio(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) {
ExecContext *c = data;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
return 0;
}
c->cpu_sched_priority = i;
c->cpu_sched_set = true;
return 0;
}
int config_parse_exec_cpu_affinity(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) {
ExecContext *c = data;
int ncpus;
if (ncpus < 0)
return ncpus;
if (c->cpuset)
if (ncpus == 0)
/* An empty assignment resets the CPU list */
else {
}
c->cpuset_ncpus = ncpus;
return 0;
}
int config_parse_exec_capabilities(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) {
ExecContext *c = data;
if (!cap) {
log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue);
return 0;
}
if (c->capabilities)
cap_free(c->capabilities);
c->capabilities = cap;
return 0;
}
int config_parse_exec_secure_bits(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) {
ExecContext *c = data;
size_t l;
/* An empty assignment resets the field */
c->secure_bits = 0;
return 0;
}
else {
return 0;
}
}
return 0;
}
int config_parse_bounding_set(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 l;
bool invert = false;
if (rvalue[0] == '~') {
invert = true;
rvalue++;
}
/* Note that we store this inverted internally, since the
* kernel wants it like this. But we actually expose it
* non-inverted everywhere to have a fully normalized
* interface. */
_cleanup_free_ char *t = NULL;
int cap;
if (!t)
return log_oom();
cap = capability_from_name(t);
if (cap < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t);
continue;
}
}
if (invert)
else
return 0;
}
int config_parse_limit(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 long u;
u = (unsigned long long) RLIM_INFINITY;
else {
int r;
r = safe_atollu(rvalue, &u);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
}
if (!*rl) {
if (!*rl)
return log_oom();
}
return 0;
}
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(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 i, r;
if (r < 0 || i < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
return 0;
}
*priority = (int) i;
return 0;
}
#endif
DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
int config_parse_exec_mount_flags(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) {
ExecContext *c = data;
size_t l;
unsigned long flags = 0;
_cleanup_free_ char *t;
if (!t)
return log_oom();
if (streq(t, "shared"))
else if (streq(t, "slave"))
else if (streq(t, "private"))
flags = MS_PRIVATE;
else {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
return 0;
}
}
c->mount_flags = flags;
return 0;
}
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) {
ExecContext *c = data;
bool ignore;
char *k;
int r;
c->selinux_context_ignore = false;
return 0;
}
if (rvalue[0] == '-') {
ignore = true;
rvalue++;
} else
ignore = false;
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
return 0;
}
free(c->selinux_context);
c->selinux_context = k;
c->selinux_context_ignore = ignore;
return 0;
}
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) {
ExecContext *c = data;
bool ignore;
char *k;
int r;
c->apparmor_profile_ignore = false;
return 0;
}
if (rvalue[0] == '-') {
ignore = true;
rvalue++;
} else
ignore = false;
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
return 0;
}
free(c->apparmor_profile);
c->apparmor_profile = k;
return 0;
}
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) {
ExecContext *c = data;
bool ignore;
char *k;
int r;
c->smack_process_label_ignore = false;
return 0;
}
if (rvalue[0] == '-') {
ignore = true;
rvalue++;
} else
ignore = false;
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
return 0;
}
free(c->smack_process_label);
c->smack_process_label = k;
return 0;
}
int config_parse_timer(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) {
usec_t u = 0;
TimerValue *v;
TimerBase b;
CalendarSpec *c = NULL;
/* Empty assignment resets list */
return 0;
}
b = timer_base_from_string(lvalue);
if (b < 0) {
return 0;
}
if (b == TIMER_CALENDAR) {
if (calendar_spec_from_string(rvalue, &c) < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue);
return 0;
}
} else {
return 0;
}
}
if (!v) {
return log_oom();
}
v->base = b;
v->value = u;
v->calendar_spec = c;
return 0;
}
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) {
_cleanup_free_ char *p = NULL;
int r;
log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
return 0;
}
r = unit_name_printf(u, rvalue, &p);
if (r < 0) {
return 0;
}
type = unit_name_to_type(p);
if (type < 0) {
return 0;
}
log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
return 0;
}
if (r < 0) {
return 0;
}
return 0;
}
int config_parse_path_spec(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) {
PathSpec *s;
PathType b;
_cleanup_free_ char *k = NULL;
int r;
/* Empty assignment clears list */
path_free_specs(p);
return 0;
}
b = path_type_from_string(lvalue);
if (b < 0) {
return 0;
}
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
return 0;
}
if (!path_is_absolute(k)) {
return 0;
}
if (!s)
return log_oom();
s->path = path_kill_slashes(k);
k = NULL;
s->type = b;
s->inotify_fd = -1;
return 0;
}
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) {
_cleanup_free_ char *p = NULL;
Unit *x;
int r;
if (r < 0) {
return 0;
}
if (!endswith(p, ".service")) {
return 0;
}
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
unit_ref_set(&s->service, x);
return 0;
}
int config_parse_fdname(
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) {
_cleanup_free_ char *p = NULL;
int r;
return 0;
}
if (r < 0) {
return 0;
}
if (!fdname_is_valid(p)) {
return 0;
}
s->fdname = p;
p = NULL;
return 0;
}
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 l;
int r;
if (!t)
return log_oom();
r = unit_name_printf(UNIT(s), t, &k);
if (r < 0) {
continue;
}
if (!endswith(k, ".socket")) {
continue;
}
if (r < 0)
if (r < 0)
}
return 0;
}
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) {
_cleanup_free_ char *k = NULL;
int r;
assert(u);
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
if (!service_name_is_valid(k)) {
return 0;
}
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
int config_parse_service_timeout(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 r;
assert(s);
if (r < 0)
return r;
s->start_timeout_defined = true;
s->timeout_stop_usec = s->timeout_start_usec;
s->start_timeout_defined = true;
return 0;
}
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 r;
Unit *x;
_cleanup_free_ char *p = NULL;
if (r < 0) {
return 0;
}
if (!endswith(p, ".service")) {
return 0;
}
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
unit_ref_set(&n->service, x);
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
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 *access_str;
if (!p)
return log_oom();
p->type = BUSNAME_POLICY_TYPE_USER;
else
assert_not_reached("Unknown lvalue");
if (!id_str)
return log_oom();
if (!access_str) {
return 0;
}
*access_str = '\0';
access_str++;
if (p->access < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
return 0;
}
p = NULL;
return 0;
}
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) {
ExecContext *c = data;
char *access_str;
int r;
if (!name)
return log_oom();
if (!access_str) {
return 0;
}
*access_str = '\0';
access_str++;
if (access <= _BUS_POLICY_ACCESS_INVALID ||
access >= _BUS_POLICY_ACCESS_MAX) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str);
return 0;
}
if (!c->bus_endpoint) {
r = bus_endpoint_new(&c->bus_endpoint);
if (r < 0)
return log_error_errno(r, "Failed to create bus endpoint object: %m");
}
}
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) {
ExecContext *c = data;
bool missing_ok;
int r;
assert(c);
assert(u);
if (rvalue[0] == '-') {
missing_ok = true;
rvalue++;
} else
missing_ok = false;
c->working_directory_home = true;
} else {
_cleanup_free_ char *k = NULL;
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
return 0;
}
if (!utf8_is_valid(k)) {
return 0;
}
if (!path_is_absolute(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
return 0;
}
free(c->working_directory);
c->working_directory = k;
k = NULL;
c->working_directory_home = false;
}
return 0;
}
int config_parse_unit_env_file(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) {
_cleanup_free_ char *n = NULL;
int r;
/* Empty assignment frees the list */
return 0;
}
r = unit_full_printf(u, rvalue, &n);
if (r < 0) {
return 0;
}
return 0;
}
r = strv_extend(env, n);
if (r < 0)
return log_oom();
return 0;
}
int config_parse_environ(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 l;
_cleanup_free_ char *k = NULL;
int r;
/* Empty assignment resets the list */
return 0;
}
if (u) {
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
return 0;
}
}
if (!k) {
if (!k)
return log_oom();
}
_cleanup_free_ char *n = NULL;
char **x;
r = cunescape_length(word, l, 0, &n);
if (r < 0) {
continue;
}
if (!env_assignment_is_valid(n)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
continue;
}
x = strv_env_set(*env, n);
if (!x)
return log_oom();
*env = x;
}
return 0;
}
int config_parse_ip_tos(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) {
x = ip_tos_from_string(rvalue);
if (x < 0) {
return 0;
}
*ip_tos = x;
return 0;
}
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) {
_cleanup_free_ char *p = NULL;
ConditionType t = ltype;
int r;
/* Empty assignment resets the list */
return 0;
}
if (trigger)
rvalue++;
if (negate)
rvalue++;
r = unit_full_printf(u, rvalue, &p);
if (r < 0) {
return 0;
}
if (!path_is_absolute(p)) {
return 0;
}
if (!c)
return log_oom();
return 0;
}
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) {
_cleanup_free_ char *s = NULL;
ConditionType t = ltype;
int r;
/* Empty assignment resets the list */
return 0;
}
if (trigger)
rvalue++;
if (negate)
rvalue++;
r = unit_full_printf(u, rvalue, &s);
if (r < 0) {
return 0;
}
if (!c)
return log_oom();
return 0;
}
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 b;
/* Empty assignment resets the list */
return 0;
}
if (trigger)
rvalue++;
if (negate)
rvalue++;
b = parse_boolean(rvalue);
if (b < 0) {
log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
return 0;
}
if (!b)
if (!c)
return log_oom();
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
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 l;
int r;
_cleanup_free_ char *n;
if (!n)
return log_oom();
if (!utf8_is_valid(n)) {
continue;
}
r = unit_require_mounts_for(u, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
continue;
}
}
return 0;
}
int config_parse_documentation(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 r;
char **a, **b;
assert(u);
/* Empty assignment resets the list */
return 0;
}
if (r < 0)
return r;
for (a = b = u->documentation; a && *a; a++) {
if (documentation_url_is_valid(*a))
*(b++) = *a;
else {
free(*a);
}
}
if (b)
*b = NULL;
return r;
}
#ifdef HAVE_SECCOMP
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) {
static const char default_syscalls[] =
"execve\0"
"exit\0"
"exit_group\0"
"rt_sigreturn\0"
"sigreturn\0";
ExecContext *c = data;
bool invert = false;
size_t l;
int r;
assert(u);
/* Empty assignment resets the list */
c->syscall_whitelist = false;
return 0;
}
if (rvalue[0] == '~') {
invert = true;
rvalue++;
}
if (!c->syscall_filter) {
if (!c->syscall_filter)
return log_oom();
if (invert)
/* Allow everything but the ones listed */
c->syscall_whitelist = false;
else {
const char *i;
/* Allow nothing but the ones listed */
c->syscall_whitelist = true;
/* Accept default syscalls if we are on a whitelist */
int id;
if (id < 0)
continue;
if (r == 0)
continue;
if (r < 0)
return log_oom();
}
}
}
_cleanup_free_ char *t = NULL;
int id;
if (!t)
return log_oom();
if (id < 0) {
continue;
}
/* If we previously wanted to forbid a syscall and now
* we want to allow it, then remove it from the list
*/
if (!invert == c->syscall_whitelist) {
if (r == 0)
continue;
if (r < 0)
return log_oom();
} else
}
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
c->no_new_privileges = true;
return 0;
}
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 l;
int r;
return 0;
}
if (r < 0)
return log_oom();
_cleanup_free_ char *t = NULL;
uint32_t a;
if (!t)
return log_oom();
r = seccomp_arch_from_string(t, &a);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
continue;
}
if (r == 0)
continue;
if (r < 0)
return log_oom();
}
return 0;
}
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) {
ExecContext *c = data;
int e;
/* Empty assignment resets to KILL */
c->syscall_errno = 0;
return 0;
}
e = errno_from_name(rvalue);
if (e < 0) {
return 0;
}
c->syscall_errno = e;
return 0;
}
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) {
ExecContext *c = data;
bool invert = false;
size_t l;
int r;
/* Empty assignment resets the list */
c->address_families_whitelist = false;
return 0;
}
if (rvalue[0] == '~') {
invert = true;
rvalue++;
}
if (!c->address_families) {
if (!c->address_families)
return log_oom();
c->address_families_whitelist = !invert;
}
_cleanup_free_ char *t = NULL;
int af;
if (!t)
return log_oom();
af = af_from_name(t);
if (af <= 0) {
continue;
}
/* If we previously wanted to forbid an address family and now
* we want to allow it, then remove it from the list
*/
if (!invert == c->address_families_whitelist) {
if (r == 0)
continue;
if (r < 0)
return log_oom();
} else
}
return 0;
}
#endif
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) {
_cleanup_free_ char *k = NULL;
int r;
assert(u);
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
return 0;
}
if (r < 0) {
return 0;
}
r = unit_set_slice(u, slice);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
return 0;
}
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
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 r;
if (r < 0) {
return 0;
}
return 0;
}
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) {
CGroupContext *c = data;
double percent;
return 0;
}
log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
return 0;
}
return 0;
}
return 0;
}
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) {
CGroupContext *c = data;
int r;
return 0;
}
if (r < 0 || bytes < 1) {
return 0;
}
c->memory_limit = bytes;
return 0;
}
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) {
CGroupContext *c = data;
uint64_t u;
int r;
return 0;
}
r = safe_atou64(rvalue, &u);
if (r < 0 || u < 1) {
log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
return 0;
}
c->tasks_max = u;
return 0;
}
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) {
CGroupContext *c = data;
const char *m;
size_t n;
while (c->device_allow)
return 0;
}
if (!path)
return log_oom();
return 0;
}
if (isempty(m))
m = "rwm";
if (!in_charset(m, "rwm")) {
return 0;
}
if (!a)
return log_oom();
a->r = !!strchr(m, 'r');
a->w = !!strchr(m, 'w');
a->m = !!strchr(m, 'm');
return 0;
}
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 r;
if (r < 0) {
return 0;
}
return 0;
}
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) {
CGroupContext *c = data;
const char *weight;
uint64_t u;
size_t n;
int r;
while (c->blockio_device_weights)
return 0;
}
return 0;
}
if (!path)
return log_oom();
return 0;
}
r = cg_blkio_weight_parse(weight, &u);
if (r < 0) {
return 0;
}
if (!w)
return log_oom();
w->weight = u;
return 0;
}
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) {
CGroupContext *c = data;
const char *bandwidth;
bool read;
size_t n;
int r;
return 0;
}
if (!*bandwidth) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
return 0;
}
if (!path)
return log_oom();
return 0;
}
if (r < 0 || bytes <= 0) {
return 0;
}
if (!b)
return log_oom();
return 0;
}
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) {
CGroupContext *c = data;
unsigned v;
int r;
return 0;
}
r = safe_atou32(rvalue, &v);
if (r < 0) {
return 0;
}
if (v > CGROUP_NETCLASS_FIXED_MAX)
"Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX);
c->netclass_id = v;
return 0;
}
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 r;
r = parse_boolean(rvalue);
if (r < 0) {
return 0;
}
*m = r ? JOB_ISOLATE : JOB_REPLACE;
return 0;
}
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 l;
int r;
/* Empty assignment resets the list */
return 0;
}
if (!t)
return log_oom();
r = unit_name_printf(u, t, &n);
if (r < 0) {
continue;
}
if (!filename_is_valid(n)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
continue;
}
if (r < 0)
return log_oom();
n = NULL;
}
return 0;
}
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 l;
int r;
/* Empty assignment resets the list */
return 0;
}
_cleanup_free_ char *temp;
int val;
if (!temp)
return log_oom();
if (r < 0) {
if (val <= 0) {
continue;
}
} else {
continue;
}
}
if (r < 0)
return log_oom();
if (r < 0) {
return r;
}
}
return 0;
}
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 l;
int r;
/* Empty assignment resets the list */
return 0;
}
_cleanup_free_ char *n;
int offset;
if (!n)
return log_oom();
if (!utf8_is_valid(n)) {
continue;
}
offset = n[0] == '-';
if (!path_is_absolute(n + offset)) {
continue;
}
if (r < 0)
return log_oom();
n = NULL;
}
return 0;
}
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) {
ExecContext *c = data;
int k;
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;
}
c->no_new_privileges = !!k;
c->no_new_privileges_set = true;
return 0;
}
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) {
ExecContext *c = data;
int k;
/* Our enum shall be a superset of booleans, hence first try
* to parse as as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
c->protect_home = PROTECT_HOME_YES;
else if (k == 0)
c->protect_home = PROTECT_HOME_NO;
else {
ProtectHome h;
if (h < 0){
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
return 0;
}
c->protect_home = h;
}
return 0;
}
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) {
ExecContext *c = data;
int k;
/* Our enum shall be a superset of booleans, hence first try
* to parse as as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
else if (k == 0)
else {
if (s < 0){
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
return 0;
}
c->protect_system = s;
}
return 0;
}
#define FOLLOW_MAX 8
unsigned c = 0;
int fd, r;
FILE *f;
/* This will update the filename pointer if the loaded file is
* reached by a symlink. The old string will be freed. */
for (;;) {
if (c++ >= FOLLOW_MAX)
return -ELOOP;
/* Add the file name we are currently looking at to
* the names of this unit, but only if it is a valid
* unit name. */
if (!id) {
if (!id)
return -ENOMEM;
if (r < 0)
return r;
}
}
/* Try to open the file name, but don't if its a symlink */
if (fd >= 0)
break;
return -errno;
/* Hmm, so this is a symlink. Let's read the name, and follow it manually */
if (r < 0)
return r;
}
if (!f) {
safe_close(fd);
return -errno;
}
*_f = f;
return 0;
}
char *k;
int r;
assert(u);
assert(*u);
/* Let's try to add in all symlink names we found */
while ((k = set_steal_first(names))) {
/* First try to merge in the other name into our
* unit */
r = unit_merge_by_name(*u, k);
if (r < 0) {
/* Hmm, we couldn't merge the other unit into
* ours? Then let's try it the other way
* round */
free(k);
if (other) {
r = unit_merge(other, *u);
if (r >= 0) {
*u = other;
}
}
return r;
}
if (id == k)
unit_choose_id(*u, id);
free(k);
}
return 0;
}
int r;
assert(u);
if (!symlink_names)
return -ENOMEM;
if (path_is_absolute(path)) {
if (!filename)
return -ENOMEM;
if (r < 0) {
if (r != -ENOENT)
return r;
}
} else {
char **p;
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit
* name set while doing so */
if (!filename)
return -ENOMEM;
if (u->manager->unit_path_cache &&
r = -ENOENT;
else
if (r < 0) {
if (r != -ENOENT)
return r;
/* Empty the symlink names for the next run */
continue;
}
break;
}
}
if (!filename)
/* Hmm, no suitable file found? */
return 0;
merged = u;
if (r < 0)
return r;
if (merged != u) {
u->load_state = UNIT_MERGED;
return 0;
}
return -errno;
if (null_or_empty(&st))
u->load_state = UNIT_MASKED;
else {
u->load_state = UNIT_LOADED;
/* Now, parse the file contents */
UNIT_VTABLE(u)->sections,
false, true, false, u);
if (r < 0)
return r;
}
free(u->fragment_path);
u->fragment_path = filename;
if (u->source_path) {
else
u->source_mtime = 0;
}
return 0;
}
int unit_load_fragment(Unit *u) {
int r;
Iterator i;
const char *t;
assert(u);
if (u->transient) {
u->load_state = UNIT_LOADED;
return 0;
}
/* First, try to find the unit under its id. We always look
* for unit files in the default directories, to make it easy
r = load_from_path(u, u->id);
if (r < 0)
return r;
/* Try to find an alias we can load this with */
if (u->load_state == UNIT_STUB) {
SET_FOREACH(t, u->names, i) {
if (t == u->id)
continue;
r = load_from_path(u, t);
if (r < 0)
return r;
if (u->load_state != UNIT_STUB)
break;
}
}
/* And now, try looking for it under the suggested (originally linked) path */
r = load_from_path(u, u->fragment_path);
if (r < 0)
return r;
if (u->load_state == UNIT_STUB)
/* Hmm, this didn't work? Then let's get rid
* of the fragment path stored for us, so that
* we don't point to an invalid location. */
}
/* Look for a template */
_cleanup_free_ char *k = NULL;
r = unit_name_template(u->id, &k);
if (r < 0)
return r;
r = load_from_path(u, k);
if (r < 0)
return r;
if (u->load_state == UNIT_STUB) {
SET_FOREACH(t, u->names, i) {
_cleanup_free_ char *z = NULL;
if (t == u->id)
continue;
r = unit_name_template(t, &z);
if (r < 0)
return r;
r = load_from_path(u, z);
if (r < 0)
return r;
if (u->load_state != UNIT_STUB)
break;
}
}
}
return 0;
}
void unit_dump_config_items(FILE *f) {
static const struct {
const ConfigParserCallback callback;
const char *rvalue;
} table[] = {
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
{ config_parse_warn_compat, "NOTSUPPORTED" },
#endif
{ config_parse_int, "INTEGER" },
{ config_parse_unsigned, "UNSIGNED" },
{ config_parse_iec_size, "SIZE" },
{ config_parse_iec_uint64, "SIZE" },
{ config_parse_si_size, "SIZE" },
{ config_parse_bool, "BOOLEAN" },
{ config_parse_string, "STRING" },
{ config_parse_path, "PATH" },
{ config_parse_unit_path_printf, "PATH" },
{ config_parse_strv, "STRING [...]" },
{ config_parse_exec_nice, "NICE" },
{ config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
{ config_parse_exec_io_class, "IOCLASS" },
{ config_parse_exec_io_priority, "IOPRIORITY" },
{ config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
{ config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
{ config_parse_exec_cpu_affinity, "CPUAFFINITY" },
{ config_parse_mode, "MODE" },
{ config_parse_unit_env_file, "FILE" },
{ config_parse_output, "OUTPUT" },
{ config_parse_input, "INPUT" },
{ config_parse_log_facility, "FACILITY" },
{ config_parse_log_level, "LEVEL" },
{ config_parse_exec_capabilities, "CAPABILITIES" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_bounding_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
#ifdef HAVE_SYSV_COMPAT
{ config_parse_sysv_priority, "SYSVPRIORITY" },
#endif
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" },
{ config_parse_socket_bind, "SOCKETBIND" },
{ config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
{ config_parse_sec, "SECONDS" },
{ config_parse_nsec, "NANOSECONDS" },
{ config_parse_namespace_path_strv, "PATH [...]" },
{ config_parse_unit_requires_mounts_for, "PATH [...]" },
{ config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
{ config_parse_unit_string_printf, "STRING" },
{ config_parse_trigger_unit, "UNIT" },
{ config_parse_timer, "TIMER" },
{ config_parse_path_spec, "PATH" },
{ config_parse_notify_access, "ACCESS" },
{ config_parse_ip_tos, "TOS" },
{ config_parse_unit_condition_path, "CONDITION" },
{ config_parse_unit_condition_string, "CONDITION" },
{ config_parse_unit_condition_null, "CONDITION" },
{ config_parse_unit_slice, "SLICE" },
{ config_parse_documentation, "URL" },
{ config_parse_service_timeout, "SECONDS" },
{ config_parse_failure_action, "ACTION" },
{ config_parse_set_status, "STATUS" },
{ config_parse_service_sockets, "SOCKETS" },
{ config_parse_environ, "ENVIRON" },
#ifdef HAVE_SECCOMP
{ config_parse_syscall_filter, "SYSCALLS" },
{ config_parse_syscall_archs, "ARCHS" },
{ config_parse_syscall_errno, "ERRNO" },
{ config_parse_address_families, "FAMILIES" },
#endif
{ config_parse_cpu_shares, "SHARES" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },
{ config_parse_long, "LONG" },
{ config_parse_socket_service, "SERVICE" },
#ifdef HAVE_SELINUX
{ config_parse_exec_selinux_context, "LABEL" },
#endif
{ config_parse_job_mode, "MODE" },
{ config_parse_job_mode_isolate, "BOOLEAN" },
{ config_parse_personality, "PERSONALITY" },
};
const char *i;
assert(f);
unsigned j;
const char *dot;
const ConfigPerfItem *p;
prefix_len = dot-i;
if (dot)
if (prev)
fputc('\n', f);
}
for (j = 0; j < ELEMENTSOF(table); j++)
break;
}
prev = i;
}
}