#include <sys/time.h>
#include <sys/resource.h>
-#include <systemd/sd-messages.h>
+#ifdef HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+#include "sd-messages.h"
#include "unit.h"
#include "strv.h"
#include "conf-parser.h"
#include "missing.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "dbus-common.h"
#include "utf8.h"
#include "path-util.h"
-#include "syscall-list.h"
#include "env-util.h"
+#include "cgroup.h"
+#include "bus-util.h"
+#include "bus-error.h"
+#include "errno-list.h"
-#ifndef HAVE_SYSV_COMPAT
-int config_parse_warn_compat(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+#ifdef HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
+
+#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
+int config_parse_warn_compat(
+ 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_DEBUG, filename, line, EINVAL,
"Support for option %s= has been disabled at compile time and is ignored",
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
if (!t)
return log_oom();
- k = unit_name_printf(u, t);
- if (!k)
- return log_oom();
+ r = unit_name_printf(u, t, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ continue;
+ }
r = unit_add_dependency_by_name(u, d, k, NULL, true);
if (r < 0)
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(u);
- k = unit_full_printf(u, rvalue);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ 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: %s", rvalue, strerror(-r));
- return config_parse_string(unit, filename, line, section, lvalue, ltype,
+ return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
k ? k : rvalue, data, userdata);
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(u);
- k = unit_full_printf(u, rvalue);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ 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: %s", rvalue, strerror(-r));
- return config_parse_strv(unit, filename, line, section, lvalue, ltype,
+ return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
k ? k : rvalue, data, userdata);
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(u);
- k = unit_full_printf(u, rvalue);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ 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: %s", rvalue, strerror(-r));
- return config_parse_path(unit, filename, line, section, lvalue, ltype,
+ return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
k ? k : rvalue, data, userdata);
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
SocketPort *p, *tail;
Socket *s;
+ int r;
assert(filename);
assert(lvalue);
if (ltype != SOCKET_SOCKET) {
p->type = ltype;
- p->path = unit_full_printf(UNIT(s), rvalue);
- if (!p->path) {
+ r = unit_full_printf(UNIT(s), rvalue, &p->path);
+ if (r < 0) {
p->path = strdup(rvalue);
if (!p->path) {
free(p);
return log_oom();
} else
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
}
path_kill_slashes(p->path);
} else if (streq(lvalue, "ListenNetlink")) {
_cleanup_free_ char *k = NULL;
- int r;
p->type = SOCKET_SOCKET;
- k = unit_full_printf(UNIT(s), rvalue);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ r = unit_full_printf(UNIT(s), rvalue, &k);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to parse address value, ignoring: %s", rvalue);
free(p);
return 0;
} else {
_cleanup_free_ char *k = NULL;
- int r;
p->type = SOCKET_SOCKET;
- k = unit_full_printf(UNIT(s), rvalue);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ r = unit_full_printf(UNIT(s), rvalue, &k);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
r = socket_address_parse(&p->address, k ? k : rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to parse address value, ignoring: %s", rvalue);
free(p);
return 0;
}
p->fd = -1;
+ p->socket = s;
if (s->ports) {
- LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
- LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
+ LIST_FIND_TAIL(port, s->ports, tail);
+ LIST_INSERT_AFTER(port, s->ports, tail, p);
} else
- LIST_PREPEND(SocketPort, port, s->ports, p);
+ LIST_PREPEND(port, s->ports, p);
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
return 0;
}
-int config_parse_unit_cgroup(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *w;
- size_t l;
- char *state;
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the list */
- cgroup_bonding_free_list(u->cgroup_bondings, false);
- u->cgroup_bondings = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
- int r;
-
- t = strndup(w, l);
- if (!t)
- return log_oom();
-
- k = unit_full_printf(u, t);
- if (!k)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- t);
-
- ku = cunescape(k ? k : t);
- if (!ku)
- return log_oom();
-
- r = unit_add_cgroup_from_text(u, ku, true, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup value %s, ignoring: %s",
- k, rvalue);
- return 0;
- }
- }
-
- 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,
}
#endif
-int config_parse_fsck_passno(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *passno = data;
- int i, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atoi(rvalue, &i);
- if (r || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse fsck pass number, ignoring: %s", rvalue);
- return 0;
- }
-
- *passno = (int) i;
- return 0;
-}
-
DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
int config_parse_kill_signal(const char *unit,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
v->value = u;
v->calendar_spec = c;
- LIST_PREPEND(TimerValue, value, t->values, v);
+ LIST_PREPEND(value, t->values, v);
return 0;
}
-int config_parse_timer_unit(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_trigger_unit(
+ 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) {
- Timer *t = data;
- int r;
- DBusError error;
- Unit *u;
_cleanup_free_ char *p = NULL;
+ Unit *u = data;
+ UnitType type;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- dbus_error_init(&error);
+ if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Multiple units to trigger specified, ignoring: %s", rvalue);
+ return 0;
+ }
- p = unit_name_printf(UNIT(t), rvalue);
- if (!p)
- return log_oom();
+ r = unit_name_printf(u, rvalue, &p);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+
+ type = unit_name_to_type(p ?: rvalue);
+ if (type < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Unit type not valid, ignoring: %s", rvalue);
+ return 0;
+ }
- if (endswith(p, ".timer")) {
+ if (type == u->type) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit cannot be of type timer, ignoring: %s", rvalue);
+ "Trigger cannot be of same type, ignoring: %s", rvalue);
return 0;
}
- r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to load unit %s, ignoring: %s",
- rvalue, bus_error(&error, r));
- dbus_error_free(&error);
+ "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
return 0;
}
- unit_ref_set(&t->unit, u);
-
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
PathSpec *s;
PathType b;
_cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
return 0;
}
- k = unit_full_printf(UNIT(p), rvalue);
- if (!k) {
+ r = unit_full_printf(UNIT(p), rvalue, &k);
+ if (r < 0) {
k = strdup(rvalue);
if (!k)
return log_oom();
else
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to resolve unit specifiers on %s. Ignoring.",
rvalue);
}
if (!s)
return log_oom();
+ s->unit = UNIT(p);
s->path = path_kill_slashes(k);
k = NULL;
s->type = b;
s->inotify_fd = -1;
- LIST_PREPEND(PathSpec, spec, p->specs, s);
-
- return 0;
-}
-
-int config_parse_path_unit(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Path *t = data;
- int r;
- DBusError error;
- Unit *u;
- _cleanup_free_ char *p = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- dbus_error_init(&error);
-
- p = unit_name_printf(UNIT(t), rvalue);
- if (!p)
- return log_oom();
-
- if (endswith(p, ".path")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit cannot be of type path, ignoring: %s", p);
- return 0;
- }
-
- r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to load unit %s, ignoring: %s",
- p, bus_error(&error, r));
- dbus_error_free(&error);
- return 0;
- }
-
- unit_ref_set(&t->unit, u);
+ LIST_PREPEND(spec, p->specs, s);
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
Socket *s = data;
int r;
- DBusError error;
Unit *x;
_cleanup_free_ char *p = NULL;
assert(rvalue);
assert(data);
- dbus_error_init(&error);
-
- p = unit_name_printf(UNIT(s), rvalue);
- if (!p)
- return log_oom();
+ r = unit_name_printf(UNIT(s), rvalue, &p);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit must be of type service, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
return 0;
}
r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to load unit %s, ignoring: %s",
- rvalue, bus_error(&error, r));
- dbus_error_free(&error);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
if (!t)
return log_oom();
- k = unit_name_printf(UNIT(s), t);
- if (!k)
- return log_oom();
+ r = unit_name_printf(UNIT(s), t, &k);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", strerror(-r));
- if (!endswith(k, ".socket")) {
+ if (!endswith(k ?: t, ".socket")) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit must be of type socket, ignoring: %s", k);
+ "Unit must be of type socket, ignoring: %s", k ?: t);
continue;
}
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to add dependency on %s, ignoring: %s",
- k, strerror(-r));
+ k ?: t, strerror(-r));
- r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
if (r < 0)
return r;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
assert(rvalue);
assert(s);
- r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
+ r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
rvalue, data, userdata);
if (r < 0)
return r;
return 0;
}
+int config_parse_busname_service(
+ 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_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ BusName *n = data;
+ int r;
+ Unit *x;
+ _cleanup_free_ char *p = NULL;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = unit_name_printf(UNIT(n), rvalue, &p);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!endswith(p, ".service")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
+ 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;
+}
+
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,
char ***env = data;
Unit *u = userdata;
- _cleanup_free_ char *s = NULL;
+ _cleanup_free_ char *n = NULL;
+ const char *s;
int r;
assert(filename);
return 0;
}
- s = unit_full_printf(u, rvalue);
- if (!s)
- return log_oom();
+ r = unit_full_printf(u, rvalue, &n);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to resolve specifiers, ignoring: %s", rvalue);
+ s = n ?: rvalue;
if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Path '%s' is not absolute, ignoring.", s);
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
char*** env = data, *w, *state;
size_t l;
_cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(u);
+ assert(data);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
return 0;
}
- k = unit_full_printf(u, rvalue);
+ if (u) {
+ r = unit_full_printf(u, rvalue, &k);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", rvalue);
+ }
+
+ if (!k)
+ k = strdup(rvalue);
if (!k)
return log_oom();
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
bool trigger, negate;
Condition *c;
_cleanup_free_ char *p = NULL;
+ int r;
assert(filename);
assert(lvalue);
if (negate)
rvalue++;
- p = unit_full_printf(u, rvalue);
- if (!p)
- return log_oom();
+ r = unit_full_printf(u, rvalue, &p);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (!p) {
+ p = strdup(rvalue);
+ if (!p)
+ return log_oom();
+ }
if (!path_is_absolute(p)) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
if (!c)
return log_oom();
- LIST_PREPEND(Condition, conditions, u->conditions, c);
+ LIST_PREPEND(conditions, u->conditions, c);
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
bool trigger, negate;
Condition *c;
_cleanup_free_ char *s = NULL;
+ int r;
assert(filename);
assert(lvalue);
if (negate)
rvalue++;
- s = unit_full_printf(u, rvalue);
- if (!s)
- return log_oom();
+ r = unit_full_printf(u, rvalue, &s);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (!s) {
+ s = strdup(rvalue);
+ if (!s)
+ return log_oom();
+ }
c = condition_new(cond, s, trigger, negate);
if (!c)
return log_oom();
- LIST_PREPEND(Condition, conditions, u->conditions, c);
+ LIST_PREPEND(conditions, u->conditions, c);
return 0;
}
const char *filename,
unsigned line,
const char *section,
+ unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
if (!c)
return log_oom();
- LIST_PREPEND(Condition, conditions, u->conditions, c);
+ LIST_PREPEND(conditions, u->conditions, c);
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_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
-int config_parse_unit_cgroup_attr(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_requires_mounts_for(
+ 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 *u = data;
- size_t a, b;
- _cleanup_free_ char *n = NULL, *v = NULL;
- const CGroupSemantics *s;
- int r;
+ Unit *u = userdata;
+ char *state;
+ size_t l;
+ char *w;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- if (isempty(rvalue)) {
- /* Empty assignment clears the list */
- cgroup_attribute_free_list(u->cgroup_attributes);
- u->cgroup_attributes = NULL;
- return 0;
- }
+ FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ int r;
+ _cleanup_free_ char *n;
- a = strcspn(rvalue, WHITESPACE);
- b = strspn(rvalue + a, WHITESPACE);
- if (a <= 0 || b <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- n = strndup(rvalue, a);
- if (!n)
- return log_oom();
-
- r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_cgroup_attr_pretty(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- _cleanup_free_ char *v = NULL;
- const CGroupSemantics *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
+ n = strndup(w, l);
+ if (!n)
+ return log_oom();
- r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse cgroup attribute value, ignoring: %s",
- rvalue);
- return 0;
- } else if (r == 0) {
- log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
- "Unknown or unsupported cgroup attribute %s, ignoring: %s",
- lvalue, rvalue);
- return 0;
- }
+ if (!utf8_is_valid(n)) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
+ continue;
+ }
- r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add cgroup attribute value, ignoring: %s", rvalue);
- return 0;
+ 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_unit_requires_mounts_for(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- int r;
- bool empty_before;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- empty_before = !u->requires_mounts_for;
-
- r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
- rvalue, data, userdata);
-
- /* Make it easy to find units with requires_mounts set */
- if (empty_before && u->requires_mounts_for)
- LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
-
- return r;
-}
-
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,
return 0;
}
- r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
+ r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
rvalue, data, userdata);
if (r < 0)
return r;
free(*a);
}
}
- *b = NULL;
+ if (b)
+ *b = NULL;
return r;
}
-static void syscall_set(uint32_t *p, int nr) {
- nr = SYSCALL_TO_INDEX(nr);
- p[nr >> 4] |= 1 << (nr & 31);
-}
-
-static void syscall_unset(uint32_t *p, int nr) {
- nr = SYSCALL_TO_INDEX(nr);
- p[nr >> 4] &= ~(1 << (nr & 31));
-}
-
-int config_parse_syscall_filter(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+#ifdef HAVE_SECCOMP
+int config_parse_syscall_filter(
+ 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;
Unit *u = userdata;
bool invert = false;
- char *w;
+ char *w, *state;
size_t l;
- char *state;
+ int r;
assert(filename);
assert(lvalue);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- free(c->syscall_filter);
+ set_free(c->syscall_filter);
c->syscall_filter = NULL;
+ c->syscall_whitelist = false;
return 0;
}
}
if (!c->syscall_filter) {
- size_t n;
-
- n = (syscall_max() + 31) >> 4;
- c->syscall_filter = new(uint32_t, n);
+ c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
if (!c->syscall_filter)
return log_oom();
- memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
+ if (invert)
+ /* Allow everything but the ones listed */
+ c->syscall_whitelist = false;
+ else {
+ const char *i;
- /* Add these by default */
- syscall_set(c->syscall_filter, __NR_execve);
- syscall_set(c->syscall_filter, __NR_rt_sigreturn);
-#ifdef __NR_sigreturn
- syscall_set(c->syscall_filter, __NR_sigreturn);
-#endif
- syscall_set(c->syscall_filter, __NR_exit_group);
- syscall_set(c->syscall_filter, __NR_exit);
+ /* Allow nothing but the ones listed */
+ c->syscall_whitelist = true;
+
+ /* Accept default syscalls if we are on a whitelist */
+ NULSTR_FOREACH(i, default_syscalls) {
+ int id;
+
+ id = seccomp_syscall_resolve_name(i);
+ if (id < 0)
+ continue;
+
+ r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return log_oom();
+ }
+ }
}
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- int id;
_cleanup_free_ char *t = NULL;
+ int id;
t = strndup(w, l);
if (!t)
return log_oom();
- id = syscall_from_name(t);
+ id = seccomp_syscall_resolve_name(t);
if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse syscall, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
continue;
}
- if (invert)
- syscall_unset(c->syscall_filter, id);
- else
- syscall_set(c->syscall_filter, id);
+ /* 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) {
+ r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return log_oom();
+ } else
+ set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
}
c->no_new_privileges = true;
return 0;
}
+int config_parse_syscall_archs(
+ 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) {
+
+ Set **archs = data;
+ char *w, *state;
+ size_t l;
+ int r;
+
+ if (isempty(rvalue)) {
+ set_free(*archs);
+ *archs = NULL;
+ return 0;
+ }
+
+ r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
+ if (r < 0)
+ return log_oom();
+
+ FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+ _cleanup_free_ char *t = NULL;
+ uint32_t a;
+
+ t = strndup(w, l);
+ if (!t)
+ return log_oom();
+
+ r = seccomp_arch_from_string(t, &a);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
+ continue;
+ }
+
+ r = set_put(*archs, UINT32_TO_PTR(a + 1));
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
+
+int config_parse_syscall_errno(
+ 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;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets to KILL */
+ c->syscall_errno = 0;
+ return 0;
+ }
+
+ e = errno_from_name(rvalue);
+ if (e < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ c->syscall_errno = e;
+ return 0;
+}
+#endif
+
+int config_parse_unit_slice(
+ 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;
+ Unit *u = userdata, *slice;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ 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);
+ if (!k) {
+ k = strdup(rvalue);
+ if (!k)
+ return log_oom();
+ }
+
+ r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to load slice unit %s. Ignoring.", k);
+ return 0;
+ }
+
+ if (slice->type != UNIT_SLICE) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Slice unit %s is not a slice. Ignoring.", k);
+ return 0;
+ }
+
+ unit_ref_set(&u->slice, slice);
+ return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
+
+int config_parse_cpu_shares(
+ 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 long lu;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->cpu_shares = 1024;
+ return 0;
+ }
+
+ r = safe_atolu(rvalue, &lu);
+ if (r < 0 || lu <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "CPU shares '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->cpu_shares = lu;
+ return 0;
+}
+
+int config_parse_memory_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) {
+
+ CGroupContext *c = data;
+ off_t bytes;
+ int r;
+
+ if (isempty(rvalue)) {
+ c->memory_limit = (uint64_t) -1;
+ return 0;
+ }
+
+ assert_cc(sizeof(uint64_t) == sizeof(off_t));
+
+ r = parse_bytes(rvalue, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->memory_limit = (uint64_t) bytes;
+ return 0;
+}
+
+int config_parse_device_allow(
+ 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 *path = NULL;
+ CGroupContext *c = data;
+ CGroupDeviceAllow *a;
+ const char *m;
+ size_t n;
+
+ if (isempty(rvalue)) {
+ while (c->device_allow)
+ cgroup_context_free_device_allow(c, c->device_allow);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ if (isempty(m))
+ m = "rwm";
+
+ if (!in_charset(m, "rwm")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device rights '%s'. Ignoring.", m);
+ return 0;
+ }
+
+ a = new0(CGroupDeviceAllow, 1);
+ if (!a)
+ return log_oom();
+
+ a->path = path;
+ path = NULL;
+ a->r = !!strchr(m, 'r');
+ a->w = !!strchr(m, 'w');
+ a->m = !!strchr(m, 'm');
+
+ LIST_PREPEND(device_allow, c->device_allow, a);
+ return 0;
+}
+
+int config_parse_blockio_weight(
+ 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 long lu;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ c->blockio_weight = 1000;
+ return 0;
+ }
+
+ r = safe_atolu(rvalue, &lu);
+ if (r < 0 || lu < 10 || lu > 1000) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ c->blockio_weight = lu;
+
+ return 0;
+}
+
+int config_parse_blockio_device_weight(
+ 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 *path = NULL;
+ CGroupBlockIODeviceWeight *w;
+ CGroupContext *c = data;
+ unsigned long lu;
+ const char *weight;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->blockio_device_weights)
+ cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ weight = rvalue + n;
+ if (!*weight) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Expected block device and device weight. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ weight += strspn(weight, WHITESPACE);
+ r = safe_atolu(weight, &lu);
+ if (r < 0 || lu < 10 || lu > 1000) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+
+ w = new0(CGroupBlockIODeviceWeight, 1);
+ if (!w)
+ return log_oom();
+
+ w->path = path;
+ path = NULL;
+
+ w->weight = lu;
+
+ LIST_PREPEND(device_weights, c->blockio_device_weights, w);
+ return 0;
+}
+
+int config_parse_blockio_bandwidth(
+ 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 *path = NULL;
+ CGroupBlockIODeviceBandwidth *b;
+ CGroupContext *c = data;
+ const char *bandwidth;
+ off_t bytes;
+ bool read;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ read = streq("BlockIOReadBandwidth", lvalue);
+
+ if (isempty(rvalue)) {
+ CGroupBlockIODeviceBandwidth *next;
+
+ LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
+ if (b->read == read)
+ cgroup_context_free_blockio_device_bandwidth(c, b);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ bandwidth = rvalue + n;
+ bandwidth += strspn(bandwidth, WHITESPACE);
+
+ if (!*bandwidth) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Expected space separated pair of device node and bandwidth. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = parse_bytes(bandwidth, &bytes);
+ if (r < 0 || bytes <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
+
+ b->path = path;
+ path = NULL;
+ b->bandwidth = (uint64_t) bytes;
+ b->read = read;
+
+ LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+
+ return 0;
+}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
+
+int config_parse_job_mode_isolate(
+ 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) {
+
+ JobMode *m = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *m = r ? JOB_ISOLATE : JOB_REPLACE;
+ return 0;
+}
+
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
/* Add the file name we are currently looking at to
* the names of this unit, but only if it is a valid
* unit name. */
- name = path_get_file_name(*filename);
+ name = basename(*filename);
- if (unit_name_is_valid(name, true)) {
+ if (unit_name_is_valid(name, TEMPLATE_VALID)) {
id = set_get(names, name);
if (!id) {
if (!id)
return -ENOMEM;
- r = set_put(names, id);
- if (r < 0) {
- free(id);
+ r = set_consume(names, id);
+ if (r < 0)
return r;
- }
}
}
static int load_from_path(Unit *u, const char *path) {
int r;
- Set *symlink_names;
- FILE *f = NULL;
- char *filename = NULL, *id = NULL;
+ _cleanup_set_free_free_ Set *symlink_names = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *filename = NULL;
+ char *id = NULL;
Unit *merged;
struct stat st;
if (path_is_absolute(path)) {
filename = strdup(path);
- if (!filename) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!filename)
+ return -ENOMEM;
r = open_follow(&filename, &f, symlink_names, &id);
if (r < 0) {
filename = NULL;
if (r != -ENOENT)
- goto finish;
+ return r;
}
} else {
* follow all symlinks and add their name to our unit
* name set while doing so */
filename = path_make_absolute(path, *p);
- if (!filename) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!filename)
+ return -ENOMEM;
if (u->manager->unit_path_cache &&
!set_get(u->manager->unit_path_cache, filename))
filename = NULL;
if (r != -ENOENT)
- goto finish;
+ return r;
/* Empty the symlink names for the next run */
set_clear_free(symlink_names);
}
}
- if (!filename) {
+ if (!filename)
/* Hmm, no suitable file found? */
- r = 0;
- goto finish;
- }
+ return 0;
merged = u;
r = merge_by_names(&merged, symlink_names, id);
if (r < 0)
- goto finish;
+ return r;
if (merged != u) {
u->load_state = UNIT_MERGED;
- r = 0;
- goto finish;
+ return 0;
}
- if (fstat(fileno(f), &st) < 0) {
- r = -errno;
- goto finish;
- }
+ if (fstat(fileno(f), &st) < 0)
+ return -errno;
if (null_or_empty(&st))
u->load_state = UNIT_MASKED;
else {
+ u->load_state = UNIT_LOADED;
+
/* Now, parse the file contents */
r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
config_item_perf_lookup,
- (void*) load_fragment_gperf_lookup, false, u);
+ (void*) load_fragment_gperf_lookup, false, true, u);
if (r < 0)
- goto finish;
-
- u->load_state = UNIT_LOADED;
+ return r;
}
free(u->fragment_path);
u->source_mtime = 0;
}
- r = 0;
-
-finish:
- set_free_free(symlink_names);
- free(filename);
-
- if (f)
- fclose(f);
-
- return r;
+ return 0;
}
int unit_load_fragment(Unit *u) {
/* Look for a template */
if (u->load_state == UNIT_STUB && u->instance) {
- char *k;
+ _cleanup_free_ char *k;
k = unit_name_template(u->id);
if (!k)
return -ENOMEM;
r = load_from_path(u, k);
- free(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;
- k = unit_name_template(t);
- if (!k)
+ z = unit_name_template(t);
+ if (!z)
return -ENOMEM;
- r = load_from_path(u, k);
- free(k);
-
+ r = load_from_path(u, z);
if (r < 0)
return r;
const ConfigParserCallback callback;
const char *rvalue;
} table[] = {
+#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP)
+ { config_parse_warn_compat, "NOTSUPPORTED" },
+#endif
{ config_parse_int, "INTEGER" },
{ config_parse_unsigned, "UNSIGNED" },
{ config_parse_bytes_size, "SIZE" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_bounding_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
- { config_parse_unit_cgroup, "CGROUP [...]" },
{ 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" },
-#else
- { config_parse_warn_compat, "NOTSUPPORTED" },
#endif
{ config_parse_kill_mode, "KILLMODE" },
{ config_parse_kill_signal, "SIGNAL" },
{ 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_timer_unit, "NAME" },
{ config_parse_path_spec, "PATH" },
- { config_parse_path_unit, "UNIT" },
{ 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_start_limit_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_errno, "ERRNO" },
+#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" },
};
const char *prev = NULL;