load-fragment.c revision bf500566323bbc2240d1fdd1165a8c908faf4098
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin This file is part of systemd.
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin Copyright 2010 Lennart Poettering
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin Copyright 2012 Holger Hans Peter Freyther
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin systemd is free software; you can redistribute it and/or modify it
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin under the terms of the GNU Lesser General Public License as published by
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin the Free Software Foundation; either version 2.1 of the License, or
343a568a3281a6a0a4c562407aef7b0dfc299b98minfrin (at your option) any later version.
along with systemd; If not, see <http://www.gnu.org/licenses/>.
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <grp.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#include "sd-messages.h"
#include "unit.h"
#include "strv.h"
#include "conf-parser.h"
#include "load-fragment.h"
#include "log.h"
#include "ioprio.h"
#include "securebits.h"
#include "missing.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "utf8.h"
#include "path-util.h"
#include "env-util.h"
#include "cgroup.h"
#include "bus-util.h"
#include "bus-error.h"
#include "errno-list.h"
#include "af-list.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
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) {
lvalue);
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;
char *state;
t = strndup(w, l);
return log_oom();
r = unit_name_printf(u, t, &k);
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(u);
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(u);
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(u);
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;
return log_oom();
if (!p->path) {
free(p);
return log_oom();
free(p);
free(p);
free(p);
p->socket = s;
if (s->ports) {
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;
s->bind_ipv6_only = b;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
int priority, r;
c->nice_set = true;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
int oa, r;
c->oom_score_adjust_set = true;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char *path, **n;
assert(e);
e += ltype;
*e = NULL;
size_t l;
char *state;
n = NULL;
if (rvalue[0] == 0)
ignore = true;
rvalue ++;
honour_argv0 = true;
rvalue ++;
return log_oom();
if (!path) {
r = log_oom();
goto fail;
goto fail;
c = n[k++] = cunescape_length(w, l);
r = log_oom();
goto fail;
if (!utf8_is_valid(c)) {
goto fail;
n[k] = NULL;
goto fail;
if (!path) {
if (!path) {
r = log_oom();
goto fail;
if (!nce) {
r = log_oom();
goto fail;
fail:
n[k] = NULL;
strv_free(n);
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");
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
return log_oom();
n = NULL;
s->bind_to_device = n;
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");
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
c->ioprio_set = true;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
c->ioprio_set = true;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
c->cpu_sched_policy = x;
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
c->cpu_sched_set = true;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
c->cpu_sched_priority = i;
c->cpu_sched_set = true;
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;
char *state;
if (c->cpuset)
unsigned cpu;
t = strndup(w, l);
return log_oom();
if (!c->cpuset) {
if (!c->cpuset)
return log_oom();
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
if (!cap) {
if (c->capabilities)
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;
char *state;
c->secure_bits = 0;
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;
char *state;
bool invert = false;
invert = true;
rvalue++;
t = strndup(w, l);
return log_oom();
if (invert)
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
u = (unsigned long long) RLIM_INFINITY;
if (!*rl) {
if (!*rl)
return log_oom();
#ifdef HAVE_SYSV_COMPAT
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
*priority = (int) i;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
*sig = r;
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;
char *state;
unsigned long flags = 0;
_cleanup_free_ char *t;
t = strndup(w, l);
return log_oom();
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
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) {
bool ignore;
c->selinux_context_ignore = false;
ignore = true;
rvalue++;
ignore = false;
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
c->selinux_context = k;
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) {
bool ignore;
c->apparmor_profile_ignore = false;
ignore = true;
rvalue++;
ignore = false;
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
c->apparmor_profile = k;
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;
if (b == TIMER_CALENDAR) {
rvalue);
rvalue);
return log_oom();
v->base = b;
v->value = u;
v->calendar_spec = c;
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) {
if (type < 0) {
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;
path_free_specs(p);
return log_oom();
rvalue);
if (!path_is_absolute(k)) {
return log_oom();
k = NULL;
s->type = b;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Unit *x;
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char *state, *w;
size_t l;
t = strndup(w, l);
return log_oom();
k ?: t, strerror(-r));
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(s);
s->start_timeout_defined = true;
s->start_timeout_defined = true;
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) {
Unit *x;
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
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;
return log_oom();
if (!id_str)
return log_oom();
if (!access_str) {
access_str++;
if (p->access < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
p = NULL;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
s = n ?: rvalue;
return log_oom();
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;
return log_oom();
_cleanup_free_ char *n;
n = cunescape_length(w, l);
return log_oom();
if (!env_assignment_is_valid(n)) {
return log_oom();
*env = x;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
*ip_tos = x;
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Condition *c;
if (trigger)
rvalue++;
if (negate)
rvalue++;
return log_oom();
if (!path_is_absolute(p)) {
return log_oom();
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Condition *c;
if (trigger)
rvalue++;
if (negate)
rvalue++;
return log_oom();
return log_oom();
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Condition *c;
if (trigger)
rvalue++;
if (negate)
rvalue++;
rvalue);
return log_oom();
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) {
char *state;
size_t l;
_cleanup_free_ char *n;
n = strndup(w, l);
return log_oom();
if (!utf8_is_valid(n)) {
r = unit_require_mounts_for(u, n);
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
assert(u);
for (a = b = u->documentation; a && *a; a++) {
if (is_valid_documentation_url(*a))
free(*a);
*b = NULL;
#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[] =
bool invert = false;
char *w, *state;
size_t l;
assert(u);
c->syscall_whitelist = false;
invert = true;
rvalue++;
if (!c->syscall_filter) {
if (!c->syscall_filter)
return log_oom();
if (invert)
c->syscall_whitelist = false;
c->syscall_whitelist = true;
int id;
if (id < 0)
if (r == -EEXIST)
return log_oom();
int id;
t = strndup(w, l);
return log_oom();
if (id < 0) {
if (r == -EEXIST)
return log_oom();
c->no_new_privileges = true;
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 *w, *state;
size_t l;
return log_oom();
uint32_t a;
t = strndup(w, l);
return log_oom();
r = seccomp_arch_from_string(t, &a);
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
if (r == -EEXIST)
return log_oom();
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) {
c->syscall_errno = 0;
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
c->syscall_errno = e;
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) {
bool invert = false;
char *w, *state;
size_t l;
assert(u);
c->address_families_whitelist = false;
invert = true;
rvalue++;
if (!c->address_families) {
if (!c->address_families)
return log_oom();
int af;
t = strndup(w, l);
return log_oom();
if (af <= 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
if (r == -EEXIST)
return log_oom();
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) {
assert(u);
return log_oom();
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) {
unsigned long lu;
if (r < 0 || lu <= 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) {
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 n;
while (c->device_allow)
if (!path)
return log_oom();
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
if (isempty(m))
return log_oom();
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 lu;
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 lu;
const char *weight;
size_t n;
while (c->blockio_device_weights)
if (!*weight) {
if (!path)
return log_oom();
return log_oom();
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) {
const char *bandwidth;
bool read;
size_t n;
if (!*bandwidth) {
if (!path)
return log_oom();
if (r < 0 || bytes <= 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
return log_oom();
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) {
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) {
*personality = p;
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 *n;
n = strndup(w, l);
return log_oom();
if (!filename_is_safe(n)) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
return log_oom();
n = NULL;
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;
char *state;
int val;
if (!temp)
return log_oom();
if (val > 0) {
return log_oom();
log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
return log_oom();
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 *n;
int offset;
n = strndup(w, l);
return log_oom();
if (!utf8_is_valid(n)) {
return log_oom();
n = NULL;
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) {
log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
c->no_new_privileges = !!k;
c->no_new_privileges_set = true;
int fd, r;
FILE *f;
if (c++ >= FOLLOW_MAX)
return -ELOOP;
if (!id) {
if (!id)
return -ENOMEM;
if (fd >= 0)
return -errno;
r = -errno;
*_f = f;
assert(u);
assert(*u);
r = unit_merge_by_name(*u, k);
free(k);
if (other) {
*u = other;
if (id == k)
free(k);
assert(u);
if (!symlink_names)
return -ENOMEM;
if (!filename)
return -ENOMEM;
if (r != -ENOENT)
if (!filename)
return -ENOMEM;
r = -ENOENT;
if (r != -ENOENT)
if (!filename)
merged = u;
if (merged != u) {
return -errno;
(void*) load_fragment_gperf_lookup, false, true, u);
if (u->source_path) {
u->source_mtime = 0;
Iterator i;
assert(u);
if (t == u->id)
r = load_from_path(u, t);
_cleanup_free_ char *k;
return -ENOMEM;
r = load_from_path(u, k);
if (t == u->id)
z = unit_name_template(t);
return -ENOMEM;
r = load_from_path(u, z);
const char *rvalue;
} table[] = {
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
#ifdef HAVE_SYSV_COMPAT
#ifdef HAVE_SECCOMP
#ifdef HAVE_SELINUX
assert(f);
const char *dot;
const ConfigPerfItem *p;
if (dot)
if (prev)
prev = i;