summaryrefslogtreecommitdiff
path: root/src/core/load-fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/load-fragment.c')
-rw-r--r--src/core/load-fragment.c2057
1 files changed, 1271 insertions, 786 deletions
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index a48cb4029a..06c156a623 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1,5 +1,3 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
@@ -20,44 +18,55 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <linux/oom.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
-#include <sched.h>
#include <linux/fs.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-
+#include <linux/oom.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
+#include <sched.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
-#include "unit.h"
-#include "strv.h"
+#include "af-list.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "cap-list.h"
+#include "capability-util.h"
+#include "cgroup.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
+#include "env-util.h"
+#include "errno-list.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "ioprio.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 "parse-util.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"
-#include "cap-list.h"
-#include "signal-util.h"
-#include "bus-internal.h"
-
+#include "process-util.h"
+#include "rlimit-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "securebits.h"
+#include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "user-util.h"
+#include "utf8.h"
+#include "web-util.h"
int config_parse_warn_compat(
const char *unit,
@@ -74,15 +83,15 @@ int config_parse_warn_compat(
switch(reason) {
case DISABLED_CONFIGURATION:
- log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
+ log_syntax(unit, LOG_DEBUG, filename, line, 0,
"Support for option %s= has been disabled at compile time and it is ignored", lvalue);
break;
case DISABLED_LEGACY:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has been removed and it is ignored", lvalue);
break;
case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has not yet been enabled and it is ignored", lvalue);
break;
};
@@ -90,52 +99,73 @@ int config_parse_warn_compat(
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) {
+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;
Unit *u = userdata;
- const char *word, *state;
- size_t l;
+ const char *p;
assert(filename);
assert(lvalue);
assert(rvalue);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
int r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(u, t, &k);
+ r = unit_name_printf(u, word, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
r = unit_add_dependency_by_name(u, d, k, NULL, true);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
return 0;
}
+int config_parse_obsolete_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) {
+
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
+
+ return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
+}
+
int config_parse_unit_string_printf(
const char *unit,
const char *filename,
@@ -166,16 +196,17 @@ int config_parse_unit_string_printf(
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_strv_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_strv_printf(
+ 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 = userdata;
_cleanup_free_ char *k = NULL;
@@ -187,24 +218,25 @@ int config_parse_unit_strv_printf(const char *unit,
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: %s", rvalue, strerror(-r));
+ 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 ? k : rvalue, data, userdata);
+ return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_path_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_path_printf(
+ 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;
@@ -217,7 +249,7 @@ int config_parse_unit_path_printf(const char *unit,
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));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
@@ -256,17 +288,17 @@ int config_parse_unit_path_strv_printf(
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: %s", t, strerror(-r));
+ 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)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k);
return 0;
}
@@ -279,7 +311,7 @@ int config_parse_unit_path_strv_printf(
k = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -322,12 +354,8 @@ int config_parse_socket_listen(const char *unit,
p->type = ltype;
r = unit_full_printf(UNIT(s), rvalue, &p->path);
if (r < 0) {
- p->path = strdup(rvalue);
- if (!p->path)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ 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);
@@ -337,14 +365,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
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));
+ 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 ?: rvalue);
+ 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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -353,14 +381,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
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));
+ 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 ? k : rvalue);
+ 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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -374,13 +402,14 @@ int config_parse_socket_listen(const char *unit,
}
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
- log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
- "Address family not supported, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
return 0;
}
}
p->fd = -1;
+ p->auxiliary_fds = NULL;
+ p->n_auxiliary_fds = 0;
p->socket = s;
if (s->ports) {
@@ -393,6 +422,37 @@ int config_parse_socket_listen(const char *unit,
return 0;
}
+int config_parse_socket_protocol(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;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ s = SOCKET(data);
+
+ if (streq(rvalue, "udplite"))
+ s->socket_protocol = IPPROTO_UDPLITE;
+ else if (streq(rvalue, "sctp"))
+ s->socket_protocol = IPPROTO_SCTP;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
int config_parse_socket_bind(const char *unit,
const char *filename,
unsigned line,
@@ -420,8 +480,7 @@ int config_parse_socket_bind(const char *unit,
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
return 0;
}
@@ -432,16 +491,17 @@ int config_parse_socket_bind(const char *unit,
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) {
+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;
@@ -451,16 +511,13 @@ int config_parse_exec_nice(const char *unit,
assert(rvalue);
assert(data);
- r = safe_atoi(rvalue, &priority);
+ r = parse_nice(rvalue, &priority);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse nice priority, ignoring: %s. ", rvalue);
- return 0;
- }
+ if (r == -ERANGE)
+ log_syntax(unit, LOG_ERR, filename, line, r, "Nice priority out of range, ignoring: %s", rvalue);
+ else
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
- if (priority < PRIO_MIN || priority >= PRIO_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Nice priority out of range, ignoring: %s", rvalue);
return 0;
}
@@ -491,14 +548,12 @@ int config_parse_exec_oom_score_adjust(const char* unit,
r = safe_atoi(rvalue, &oa);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0;
}
if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "OOM score adjust value out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
return 0;
}
@@ -531,9 +586,7 @@ int config_parse_exec(
assert(e);
e += ltype;
-
rvalue += strspn(rvalue, WHITESPACE);
- p = rvalue;
if (isempty(rvalue)) {
/* An empty assignment resets the list */
@@ -541,55 +594,55 @@ int config_parse_exec(
return 0;
}
+ p = rvalue;
do {
- int i;
+ _cleanup_free_ char *path = NULL, *firstword = NULL;
+ bool separate_argv0 = false, ignore = false, privileged = false;
+ _cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
- _cleanup_free_ ExecCommand *nce = NULL;
- _cleanup_free_ char *path = NULL, *firstword = NULL;
char *f;
- bool separate_argv0 = false, ignore = false;
+ int i;
semicolon = false;
- r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
+ 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]. */
+ for (i = 0; i < 3; i++) {
+ /* We accept an absolute path as first argument.
+ * If it's prefixed with - and the path doesn't exist,
+ * we ignore it instead of erroring out;
+ * if it's prefixed with @, we allow overriding of argv[0];
+ * and if it's prefixed with !, it will be run with full privileges */
if (*f == '-' && !ignore)
ignore = true;
else if (*f == '@' && !separate_argv0)
separate_argv0 = true;
+ else if (*f == '+' && !privileged)
+ privileged = true;
else
break;
- f ++;
+ f++;
}
if (isempty(f)) {
/* First word is either "-" or "@" with no command. */
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty path in command line, ignoring: \"%s\"", rvalue);
+ 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, EINVAL,
- "Executable path contains special characters, ignoring: %s", rvalue);
+ 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, EINVAL,
- "Executable path is not absolute, ignoring: %s", rvalue);
+ 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, EINVAL,
- "Executable path specifies a directory, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
return 0;
}
@@ -614,20 +667,20 @@ int config_parse_exec(
path_kill_slashes(path);
- for (;;) {
+ while (!isempty(p)) {
_cleanup_free_ char *word = NULL;
/* Check explicitly for an unquoted semicolon as
* command separator token. */
if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
- p ++;
+ p++;
p += strspn(p, WHITESPACE);
semicolon = true;
break;
}
/* Check for \; explicitly, to not confuse it with \\;
- * or "\;" or "\\;" etc. unquote_first_word would
+ * or "\;" or "\\;" etc. extract_first_word would
* return the same for all of those. */
if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
p += 2;
@@ -642,7 +695,7 @@ int config_parse_exec(
continue;
}
- r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
+ 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)
@@ -656,8 +709,7 @@ int config_parse_exec(
}
if (!n || !n[0]) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
return 0;
}
@@ -668,6 +720,7 @@ int config_parse_exec(
nce->argv = n;
nce->path = path;
nce->ignore = ignore;
+ nce->privileged = privileged;
exec_command_append_list(e, nce);
@@ -685,16 +738,17 @@ int config_parse_exec(
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) {
+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) {
Socket *s = data;
char *n;
@@ -705,6 +759,11 @@ int config_parse_socket_bindtodevice(const char* unit,
assert(data);
if (rvalue[0] && !streq(rvalue, "*")) {
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
+ return 0;
+ }
+
n = strdup(rvalue);
if (!n)
return log_oom();
@@ -741,8 +800,7 @@ int config_parse_exec_io_class(const char *unit,
x = ioprio_class_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IO scheduling class, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
return 0;
}
@@ -773,8 +831,7 @@ int config_parse_exec_io_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse IO priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
return 0;
}
@@ -806,8 +863,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
x = sched_policy_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -x,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -840,8 +896,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -850,8 +905,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
max = sched_get_priority_max(c->cpu_sched_policy);
if (i < min || i > max) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "CPU scheduling priority is out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
return 0;
}
@@ -873,83 +927,29 @@ int config_parse_exec_cpu_affinity(const char *unit,
void *userdata) {
ExecContext *c = data;
- const char *word, *state;
- size_t l;
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ int ncpus;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- if (isempty(rvalue)) {
- /* An empty assignment resets the CPU list */
- if (c->cpuset)
- CPU_FREE(c->cpuset);
- c->cpuset = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int r;
- unsigned cpu;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = safe_atou(t, &cpu);
-
- if (!c->cpuset) {
- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
- if (!c->cpuset)
- return log_oom();
- }
-
- if (r < 0 || cpu >= c->cpuset_ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
- return 0;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
- }
- if (!isempty(state))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
+ if (ncpus < 0)
+ return ncpus;
-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) {
+ if (c->cpuset)
+ CPU_FREE(c->cpuset);
- ExecContext *c = data;
- cap_t cap;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- cap = cap_from_text(rvalue);
- if (!cap) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse capabilities, ignoring: %s", rvalue);
- return 0;
+ if (ncpus == 0)
+ /* An empty assignment resets the CPU list */
+ c->cpuset = NULL;
+ else {
+ c->cpuset = cpuset;
+ cpuset = NULL;
}
-
- if (c->capabilities)
- cap_free(c->capabilities);
- c->capabilities = cap;
+ c->cpuset_ncpus = ncpus;
return 0;
}
@@ -994,34 +994,32 @@ int config_parse_exec_secure_bits(const char *unit,
else if (first_word(word, "noroot-locked"))
c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse secure bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid syntax, garbage at the end, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
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) {
+int config_parse_capability_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) {
- uint64_t *capability_bounding_set_drop = data;
- const char *word, *state;
- size_t l;
+ uint64_t *capability_set = data;
+ uint64_t sum = 0, initial = 0;
bool invert = false;
- uint64_t sum = 0;
+ const char *p;
assert(filename);
assert(lvalue);
@@ -1033,80 +1031,84 @@ int config_parse_bounding_set(const char *unit,
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. */
+ if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
+ initial = CAP_ALL; /* initialized to all bits on */
+ /* else "AmbientCapabilities" initialized to all bits off */
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int cap;
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ int cap, r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
+ break;
+ }
- cap = capability_from_name(t);
+ cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
continue;
}
- sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+ sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
- if (invert)
- *capability_bounding_set_drop |= sum;
+ sum = invert ? ~sum : sum;
+
+ if (sum == 0 || *capability_set == initial)
+ /* "" or uninitialized data -> replace */
+ *capability_set = sum;
else
- *capability_bounding_set_drop |= ~sum;
+ /* previous data -> merge */
+ *capability_set |= sum;
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) {
+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) {
- struct rlimit **rl = data;
- unsigned long long u;
+ struct rlimit **rl = data, d = {};
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- rl += ltype;
-
- if (streq(rvalue, "infinity"))
- 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;
- }
+ r = rlimit_parse(ltype, rvalue, &d);
+ if (r == -EILSEQ) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
}
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
+ if (rl[ltype])
+ *rl[ltype] = d;
+ else {
+ rl[ltype] = newdup(struct rlimit, &d, 1);
+ if (!rl[ltype])
return log_oom();
}
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
return 0;
}
@@ -1132,8 +1134,7 @@ int config_parse_sysv_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse SysV start priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
return 0;
}
@@ -1142,38 +1143,9 @@ int config_parse_sysv_priority(const char *unit,
}
#endif
+DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
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,
- void *data,
- void *userdata) {
-
- int *sig = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(sig);
-
- r = signal_from_string_try_harder(rvalue);
- if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse kill signal, ignoring: %s", rvalue);
- return 0;
- }
-
- *sig = r;
- return 0;
-}
-
int config_parse_exec_mount_flags(const char *unit,
const char *filename,
unsigned line,
@@ -1185,38 +1157,28 @@ int config_parse_exec_mount_flags(const char *unit,
void *data,
void *userdata) {
- ExecContext *c = data;
- const char *word, *state;
- size_t l;
+
unsigned long flags = 0;
+ ExecContext *c = data;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
- _cleanup_free_ char *t;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- if (streq(t, "shared"))
- flags = MS_SHARED;
- else if (streq(t, "slave"))
- flags = MS_SLAVE;
- else if (streq(t, "private"))
- flags = MS_PRIVATE;
- else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
- return 0;
- }
+ if (streq(rvalue, "shared"))
+ flags = MS_SHARED;
+ else if (streq(rvalue, "slave"))
+ flags = MS_SLAVE;
+ else if (streq(rvalue, "private"))
+ flags = MS_PRIVATE;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
+ return 0;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
c->mount_flags = flags;
+
return 0;
}
@@ -1244,8 +1206,7 @@ int config_parse_exec_selinux_context(
assert(data);
if (isempty(rvalue)) {
- free(c->selinux_context);
- c->selinux_context = NULL;
+ c->selinux_context = mfree(c->selinux_context);
c->selinux_context_ignore = false;
return 0;
}
@@ -1258,8 +1219,7 @@ int config_parse_exec_selinux_context(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1294,8 +1254,7 @@ int config_parse_exec_apparmor_profile(
assert(data);
if (isempty(rvalue)) {
- free(c->apparmor_profile);
- c->apparmor_profile = NULL;
+ c->apparmor_profile = mfree(c->apparmor_profile);
c->apparmor_profile_ignore = false;
return 0;
}
@@ -1308,8 +1267,7 @@ int config_parse_exec_apparmor_profile(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1344,8 +1302,7 @@ int config_parse_exec_smack_process_label(
assert(data);
if (isempty(rvalue)) {
- free(c->smack_process_label);
- c->smack_process_label = NULL;
+ c->smack_process_label = mfree(c->smack_process_label);
c->smack_process_label_ignore = false;
return 0;
}
@@ -1358,8 +1315,7 @@ int config_parse_exec_smack_process_label(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1382,10 +1338,13 @@ int config_parse_timer(const char *unit,
void *userdata) {
Timer *t = data;
- usec_t u = 0;
+ usec_t usec = 0;
TimerValue *v;
TimerBase b;
CalendarSpec *c = NULL;
+ Unit *u = userdata;
+ _cleanup_free_ char *k = NULL;
+ int r;
assert(filename);
assert(lvalue);
@@ -1400,23 +1359,24 @@ int config_parse_timer(const char *unit,
b = timer_base_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b,
- "Failed to parse timer base, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
+ return 0;
+ }
+
+ r = unit_full_printf(u, rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
if (b == TIMER_CALENDAR) {
- if (calendar_spec_from_string(rvalue, &c) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse calendar specification, ignoring: %s",
- rvalue);
+ if (calendar_spec_from_string(k, &c) < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
return 0;
}
} else {
- if (parse_sec(rvalue, &u) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse timer value, ignoring: %s",
- rvalue);
+ if (parse_sec(k, &usec) < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
return 0;
}
}
@@ -1428,7 +1388,7 @@ int config_parse_timer(const char *unit,
}
v->base = b;
- v->value = u;
+ v->value = usec;
v->calendar_spec = c;
LIST_PREPEND(value, t->values, v);
@@ -1459,33 +1419,30 @@ int config_parse_trigger_unit(
assert(data);
if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Multiple units to trigger specified, ignoring: %s", rvalue);
+ 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)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ return 0;
+ }
- type = unit_name_to_type(p ?: rvalue);
+ type = unit_name_to_type(p);
if (type < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit type not valid, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
return 0;
}
if (type == u->type) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trigger cannot be of same type, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
return 0;
}
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
}
@@ -1522,25 +1479,18 @@ int config_parse_path_spec(const char *unit,
b = path_type_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse path type, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
return 0;
}
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, -r,
- "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.", rvalue);
+ return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path is not absolute, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
return 0;
}
@@ -1571,11 +1521,11 @@ int config_parse_socket_service(
void *data,
void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *p = NULL;
Socket *s = data;
- int r;
Unit *x;
- _cleanup_free_ char *p = NULL;
+ int r;
assert(filename);
assert(lvalue);
@@ -1589,13 +1539,13 @@ int config_parse_socket_service(
}
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, 0, "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, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1604,6 +1554,50 @@ int config_parse_socket_service(
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;
+ Socket *s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ s->fdname = mfree(s->fdname);
+ return 0;
+ }
+
+ 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 (!fdname_is_valid(p)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
+ return 0;
+ }
+
+ free(s->fdname);
+ s->fdname = p;
+ p = NULL;
+
+ return 0;
+}
+
int config_parse_service_sockets(
const char *unit,
const char *filename,
@@ -1617,8 +1611,7 @@ int config_parse_service_sockets(
void *userdata) {
Service *s = data;
- const char *word, *state;
- size_t l;
+ const char *p;
int r;
assert(filename);
@@ -1626,21 +1619,28 @@ int config_parse_service_sockets(
assert(rvalue);
assert(data);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(UNIT(s), t, &k);
+ r = unit_name_printf(UNIT(s), word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
if (!endswith(k, ".socket")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
continue;
}
@@ -1652,8 +1652,6 @@ int config_parse_service_sockets(
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
return 0;
}
@@ -1686,25 +1684,27 @@ int config_parse_bus_name(
}
if (!service_name_is_valid(k)) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", 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 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) {
Service *s = userdata;
+ usec_t usec;
int r;
assert(filename);
@@ -1712,16 +1712,180 @@ int config_parse_service_timeout(const char *unit,
assert(rvalue);
assert(s);
- r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
- rvalue, data, userdata);
- if (r < 0)
- return r;
+ /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
- if (streq(lvalue, "TimeoutSec")) {
- s->start_timeout_defined = true;
- s->timeout_stop_usec = s->timeout_start_usec;
- } else if (streq(lvalue, "TimeoutStartSec"))
+ r = parse_sec(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
+ * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
+ * all other timeouts. */
+ if (usec <= 0)
+ usec = USEC_INFINITY;
+
+ if (!streq(lvalue, "TimeoutStopSec")) {
s->start_timeout_defined = true;
+ s->timeout_start_usec = usec;
+ }
+
+ if (!streq(lvalue, "TimeoutStartSec"))
+ s->timeout_stop_usec = usec;
+
+ return 0;
+}
+
+int config_parse_sec_fix_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) {
+
+ usec_t *usec = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(usec);
+
+ /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
+ * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
+ * timeout. */
+
+ r = parse_sec(rvalue, usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (*usec <= 0)
+ *usec = USEC_INFINITY;
+
+ return 0;
+}
+
+int config_parse_user_group(
+ 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 **user = data, *n;
+ Unit *u = userdata;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(u);
+
+ if (isempty(rvalue))
+ n = NULL;
+ 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 %s, ignoring: %m", rvalue);
+ return 0;
+ }
+
+ if (!valid_user_group_name_or_id(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
+ return 0;
+ }
+
+ n = k;
+ k = NULL;
+ }
+
+ free(*user);
+ *user = n;
+
+ return 0;
+}
+
+int config_parse_user_group_strv(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char ***users = data;
+ Unit *u = userdata;
+ const char *p;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(u);
+
+ if (isempty(rvalue)) {
+ char **empty;
+
+ empty = new0(char*, 1);
+ if (!empty)
+ return log_oom();
+
+ strv_free(*users);
+ *users = empty;
+
+ return 0;
+ }
+
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
+
+ r = extract_first_word(&p, &word, WHITESPACE, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ break;
+ }
+
+ r = unit_full_printf(u, word, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word);
+ continue;
+ }
+
+ if (!valid_user_group_name_or_id(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID, ignoring: %s", k);
+ continue;
+ }
+
+ r = strv_push(users, k);
+ if (r < 0)
+ return log_oom();
+
+ k = NULL;
+ }
return 0;
}
@@ -1738,7 +1902,7 @@ int config_parse_busname_service(
void *data,
void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
BusName *n = data;
int r;
Unit *x;
@@ -1751,21 +1915,18 @@ int config_parse_busname_service(
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);
+ 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, 0, "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));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1815,8 +1976,7 @@ int config_parse_bus_policy(
access_str = strpbrk(id_str, WHITESPACE);
if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy value '%s'", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
return 0;
}
@@ -1826,8 +1986,7 @@ int config_parse_bus_policy(
p->access = bus_policy_access_from_string(access_str);
if (p->access < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy access type '%s'", access_str);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
return 0;
}
@@ -1840,7 +1999,7 @@ int config_parse_bus_policy(
return 0;
}
-int config_parse_bus_endpoint_policy(
+int config_parse_working_directory(
const char *unit,
const char *filename,
unsigned line,
@@ -1852,48 +2011,56 @@ int config_parse_bus_endpoint_policy(
void *data,
void *userdata) {
- _cleanup_free_ char *name = NULL;
- BusPolicyAccess access;
ExecContext *c = data;
- char *access_str;
+ Unit *u = userdata;
+ bool missing_ok;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
+ assert(c);
+ assert(u);
- name = strdup(rvalue);
- if (!name)
- return log_oom();
+ if (rvalue[0] == '-') {
+ missing_ok = true;
+ rvalue++;
+ } else
+ missing_ok = false;
- access_str = strpbrk(name, WHITESPACE);
- if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy value '%s'", rvalue);
- return 0;
- }
+ if (streq(rvalue, "~")) {
+ c->working_directory_home = true;
+ c->working_directory = mfree(c->working_directory);
+ } else {
+ _cleanup_free_ char *k = NULL;
- *access_str = '\0';
- access_str++;
- access_str += strspn(access_str, WHITESPACE);
+ 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;
+ }
- access = bus_policy_access_from_string(access_str);
- if (access <= _BUS_POLICY_ACCESS_INVALID ||
- access >= _BUS_POLICY_ACCESS_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy access type '%s'", access_str);
- return 0;
- }
+ path_kill_slashes(k);
- if (!c->bus_endpoint) {
- r = bus_endpoint_new(&c->bus_endpoint);
+ if (!utf8_is_valid(k)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ return 0;
+ }
- if (r < 0)
- return r;
+ 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 bus_endpoint_add_policy(c->bus_endpoint, name, access);
+ c->working_directory_missing_ok = missing_ok;
+ return 0;
}
int config_parse_unit_env_file(const char *unit,
@@ -1910,7 +2077,6 @@ int config_parse_unit_env_file(const char *unit,
char ***env = data;
Unit *u = userdata;
_cleanup_free_ char *n = NULL;
- const char *s;
int r;
assert(filename);
@@ -1920,24 +2086,22 @@ int config_parse_unit_env_file(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment frees the list */
- strv_free(*env);
- *env = NULL;
+ *env = strv_free(*env);
return 0;
}
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);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
- 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);
+ if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
return 0;
}
- r = strv_extend(env, s);
+ r = strv_extend(env, n);
if (r < 0)
return log_oom();
@@ -1969,24 +2133,26 @@ int config_parse_environ(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- strv_free(*env);
- *env = NULL;
+ *env = strv_free(*env);
return 0;
}
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 (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
}
- if (!k)
+ if (!k) {
k = strdup(rvalue);
- if (!k)
- return log_oom();
+ if (!k)
+ return log_oom();
+ }
FOREACH_WORD_QUOTED(word, l, k, state) {
- _cleanup_free_ char *n;
+ _cleanup_free_ char *n = NULL;
char **x;
r = cunescape_length(word, l, 0, &n);
@@ -1996,7 +2162,7 @@ int config_parse_environ(const char *unit,
}
if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
continue;
}
@@ -2008,8 +2174,71 @@ int config_parse_environ(const char *unit,
*env = x;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
+
+ return 0;
+}
+
+int config_parse_pass_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) {
+
+ const char *whole_rvalue = rvalue;
+ char*** passenv = data;
+ _cleanup_strv_free_ char **n = NULL;
+ size_t nlen = 0, nbufsize = 0;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ *passenv = strv_free(*passenv);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+ break;
+ }
+
+ if (!env_name_is_valid(word)) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid environment name for %s, ignoring: %s", lvalue, word);
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
+ return log_oom();
+ n[nlen++] = word;
+ n[nlen] = NULL;
+ word = NULL;
+ }
+
+ if (n) {
+ r = strv_extend_strv(passenv, n, true);
+ if (r < 0)
+ return r;
+ }
return 0;
}
@@ -2034,8 +2263,7 @@ int config_parse_ip_tos(const char *unit,
x = ip_tos_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IP TOS value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
return 0;
}
@@ -2083,12 +2311,12 @@ int config_parse_unit_condition_path(
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
return 0;
}
@@ -2140,7 +2368,7 @@ int config_parse_unit_condition_string(
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
@@ -2189,7 +2417,7 @@ int config_parse_unit_condition_null(
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);
+ log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
return 0;
}
@@ -2237,20 +2465,18 @@ int config_parse_unit_requires_mounts_for(
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
continue;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2277,8 +2503,7 @@ int config_parse_documentation(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- strv_free(u->documentation);
- u->documentation = NULL;
+ u->documentation = strv_free(u->documentation);
return 0;
}
@@ -2292,8 +2517,7 @@ int config_parse_documentation(const char *unit,
if (documentation_url_is_valid(*a))
*(b++) = *a;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid URL, ignoring: %s", *a);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
free(*a);
}
}
@@ -2304,6 +2528,55 @@ int config_parse_documentation(const char *unit,
}
#ifdef HAVE_SECCOMP
+static int syscall_filter_parse_one(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ ExecContext *c,
+ bool invert,
+ const char *t,
+ bool warn) {
+ int r;
+
+ if (*t == '@') {
+ const SystemCallFilterSet *set;
+
+ for (set = syscall_filter_sets; set->set_name; set++)
+ if (streq(set->set_name, t)) {
+ const char *sys;
+
+ NULSTR_FOREACH(sys, set->value) {
+ r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false);
+ if (r < 0)
+ return r;
+ }
+ break;
+ }
+ } else {
+ int id;
+
+ id = seccomp_syscall_resolve_name(t);
+ if (id == __NR_SCMP_ERROR) {
+ if (warn)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
+ return 0;
+ }
+
+ /* 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 == 0)
+ return 0;
+ if (r < 0)
+ return log_oom();
+ } else
+ set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
+ }
+ return 0;
+}
+
int config_parse_syscall_filter(
const char *unit,
const char *filename,
@@ -2316,13 +2589,6 @@ int config_parse_syscall_filter(
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;
@@ -2337,8 +2603,7 @@ int config_parse_syscall_filter(
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- set_free(c->syscall_filter);
- c->syscall_filter = NULL;
+ c->syscall_filter = set_free(c->syscall_filter);
c->syscall_whitelist = false;
return 0;
}
@@ -2357,62 +2622,33 @@ int config_parse_syscall_filter(
/* 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 */
- 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 == 0)
- continue;
- if (r < 0)
- return log_oom();
- }
+ r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
+ if (r < 0)
+ return r;
}
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
_cleanup_free_ char *t = NULL;
- int id;
t = strndup(word, l);
if (!t)
return log_oom();
- id = seccomp_syscall_resolve_name(t);
- if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call, ignoring: %s", t);
- 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) {
- r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == 0)
- continue;
- if (r < 0)
- return log_oom();
- } else
- set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
+ r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true);
+ if (r < 0)
+ return r;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
- if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
+ if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager))
c->no_new_privileges = true;
return 0;
@@ -2436,8 +2672,7 @@ int config_parse_syscall_archs(
int r;
if (isempty(rvalue)) {
- set_free(*archs);
- *archs = NULL;
+ *archs = set_free(*archs);
return 0;
}
@@ -2455,8 +2690,7 @@ int config_parse_syscall_archs(
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);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
continue;
}
@@ -2467,8 +2701,7 @@ int config_parse_syscall_archs(
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2500,8 +2733,7 @@ int config_parse_syscall_errno(
e = errno_from_name(rvalue);
if (e < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse error number, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
return 0;
}
@@ -2533,8 +2765,7 @@ int config_parse_address_families(
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- set_free(c->address_families);
- c->address_families = NULL;
+ c->address_families = set_free(c->address_families);
c->address_families_whitelist = false;
return 0;
}
@@ -2562,8 +2793,7 @@ int config_parse_address_families(
af = af_from_name(t);
if (af <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse address family, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
continue;
}
@@ -2580,8 +2810,7 @@ int config_parse_address_families(
set_remove(c->address_families, INT_TO_PTR(af));
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2600,7 +2829,7 @@ int config_parse_unit_slice(
void *userdata) {
_cleanup_free_ char *k = NULL;
- Unit *u = userdata, *slice;
+ Unit *u = userdata, *slice = NULL;
int r;
assert(filename);
@@ -2609,35 +2838,29 @@ int config_parse_unit_slice(
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();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ return 0;
}
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);
+ 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);
+ 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;
}
- 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(
+int config_parse_cpu_weight(
const char *unit,
const char *filename,
unsigned line,
@@ -2649,26 +2872,47 @@ int config_parse_cpu_shares(
void *data,
void *userdata) {
- unsigned long *shares = data, lu;
+ uint64_t *weight = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- if (isempty(rvalue)) {
- *shares = (unsigned long) -1;
+ r = cg_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "CPU weight '%s' invalid. Ignoring.", rvalue);
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;
+}
+
+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) {
+
+ uint64_t *shares = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = cg_cpu_shares_parse(rvalue, shares);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
return 0;
}
- *shares = lu;
return 0;
}
@@ -2685,7 +2929,7 @@ int config_parse_cpu_quota(
void *userdata) {
CGroupContext *c = data;
- double percent;
+ int r;
assert(filename);
assert(lvalue);
@@ -2696,25 +2940,67 @@ int config_parse_cpu_quota(
return 0;
}
- if (!endswith(rvalue, "%")) {
-
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
+ r = parse_percent_unbounded(rvalue);
+ if (r <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
return 0;
}
- if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' invalid. Ignoring.", rvalue);
- return 0;
+ c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
+ 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;
+ uint64_t bytes = CGROUP_LIMIT_MAX;
+ int r;
+
+ if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
+
+ r = parse_percent(rvalue);
+ if (r < 0) {
+ r = parse_size(rvalue, 1024, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ } else
+ bytes = physical_memory_scale(r, 100U);
+
+ if (bytes <= 0 || bytes >= UINT64_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
+ return 0;
+ }
}
- c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
+ if (streq(lvalue, "MemoryLow"))
+ c->memory_low = bytes;
+ else if (streq(lvalue, "MemoryHigh"))
+ c->memory_high = bytes;
+ else if (streq(lvalue, "MemoryMax"))
+ c->memory_max = bytes;
+ else if (streq(lvalue, "MemorySwapMax"))
+ c->memory_swap_max = bytes;
+ else if (streq(lvalue, "MemoryLimit"))
+ c->memory_limit = bytes;
+ else
+ return -EINVAL;
return 0;
}
-int config_parse_memory_limit(
+int config_parse_tasks_max(
const char *unit,
const char *filename,
unsigned line,
@@ -2726,25 +3012,36 @@ int config_parse_memory_limit(
void *data,
void *userdata) {
- CGroupContext *c = data;
- off_t bytes;
+ uint64_t *tasks_max = data, v;
+ Unit *u = userdata;
int r;
if (isempty(rvalue)) {
- c->memory_limit = (uint64_t) -1;
+ *tasks_max = u->manager->default_tasks_max;
return 0;
}
- assert_cc(sizeof(uint64_t) == sizeof(off_t));
+ if (streq(rvalue, "infinity")) {
+ *tasks_max = CGROUP_LIMIT_MAX;
+ return 0;
+ }
- r = parse_size(rvalue, 1024, &bytes);
+ r = parse_percent(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Memory limit '%s' invalid. Ignoring.", rvalue);
+ r = safe_atou64(rvalue, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ } else
+ v = system_tasks_max_scale(r, 100U);
+
+ if (v <= 0 || v >= UINT64_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
return 0;
}
- c->memory_limit = (uint64_t) bytes;
+ *tasks_max = v;
return 0;
}
@@ -2760,11 +3057,12 @@ int config_parse_device_allow(
void *data,
void *userdata) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *path = NULL, *t = NULL;
CGroupContext *c = data;
CGroupDeviceAllow *a;
- const char *m;
+ const char *m = NULL;
size_t n;
+ int r;
if (isempty(rvalue)) {
while (c->device_allow)
@@ -2773,26 +3071,30 @@ int config_parse_device_allow(
return 0;
}
- n = strcspn(rvalue, WHITESPACE);
- path = strndup(rvalue, n);
+ r = unit_full_printf(userdata, rvalue, &t);
+ if(r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve specifiers in %s, ignoring: %m",
+ rvalue);
+ }
+
+ n = strcspn(t, WHITESPACE);
+
+ path = strndup(t, n);
if (!path)
return log_oom();
- if (!startswith(path, "/dev/") &&
- !startswith(path, "block-") &&
- !startswith(path, "char-")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ if (!is_deviceallow_pattern(path)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
- m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ m = t + n + strspn(t + 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);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
return 0;
}
@@ -2810,7 +3112,7 @@ int config_parse_device_allow(
return 0;
}
-int config_parse_blockio_weight(
+int config_parse_io_weight(
const char *unit,
const char *filename,
unsigned line,
@@ -2822,30 +3124,23 @@ int config_parse_blockio_weight(
void *data,
void *userdata) {
- unsigned long *weight = data, lu;
+ uint64_t *weight = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- if (isempty(rvalue)) {
- *weight = (unsigned long) -1;
- 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);
+ r = cg_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
return 0;
}
- *weight = lu;
return 0;
}
-int config_parse_blockio_device_weight(
+int config_parse_io_device_weight(
const char *unit,
const char *filename,
unsigned line,
@@ -2858,10 +3153,10 @@ int config_parse_blockio_device_weight(
void *userdata) {
_cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceWeight *w;
+ CGroupIODeviceWeight *w;
CGroupContext *c = data;
- unsigned long lu;
const char *weight;
+ uint64_t u;
size_t n;
int r;
@@ -2870,17 +3165,18 @@ int config_parse_blockio_device_weight(
assert(rvalue);
if (isempty(rvalue)) {
- while (c->blockio_device_weights)
- cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_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.");
+ weight += strspn(weight, WHITESPACE);
+
+ if (isempty(weight)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
return 0;
}
@@ -2889,33 +3185,32 @@ int config_parse_blockio_device_weight(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "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);
+ r = cg_weight_parse(weight, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
return 0;
}
- w = new0(CGroupBlockIODeviceWeight, 1);
+ assert(u != CGROUP_WEIGHT_INVALID);
+
+ w = new0(CGroupIODeviceWeight, 1);
if (!w)
return log_oom();
w->path = path;
path = NULL;
- w->weight = lu;
+ w->weight = u;
- LIST_PREPEND(device_weights, c->blockio_device_weights, w);
+ LIST_PREPEND(device_weights, c->io_device_weights, w);
return 0;
}
-int config_parse_blockio_bandwidth(
+int config_parse_io_limit(
const char *unit,
const char *filename,
unsigned line,
@@ -2928,11 +3223,11 @@ int config_parse_blockio_bandwidth(
void *userdata) {
_cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceBandwidth *b;
+ CGroupIODeviceLimit *l = NULL, *t;
CGroupContext *c = data;
- const char *bandwidth;
- off_t bytes;
- bool read;
+ CGroupIOLimitType type;
+ const char *limit;
+ uint64_t num;
size_t n;
int r;
@@ -2940,25 +3235,135 @@ int config_parse_blockio_bandwidth(
assert(lvalue);
assert(rvalue);
- read = streq("BlockIOReadBandwidth", lvalue);
+ type = cgroup_io_limit_type_from_string(lvalue);
+ assert(type >= 0);
if (isempty(rvalue)) {
- CGroupBlockIODeviceBandwidth *next;
+ LIST_FOREACH(device_limits, l, c->io_device_limits)
+ l->limits[type] = cgroup_io_limit_defaults[type];
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ limit = rvalue + n;
+ limit += strspn(limit, WHITESPACE);
+
+ if (!*limit) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ if (streq("infinity", limit)) {
+ num = CGROUP_LIMIT_MAX;
+ } else {
+ r = parse_size(limit, 1000, &num);
+ if (r < 0 || num <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ }
+
+ LIST_FOREACH(device_limits, t, c->io_device_limits) {
+ if (path_equal(path, t->path)) {
+ l = t;
+ break;
+ }
+ }
+
+ if (!l) {
+ CGroupIOLimitType ttype;
+
+ l = new0(CGroupIODeviceLimit, 1);
+ if (!l)
+ return log_oom();
+
+ l->path = path;
+ path = NULL;
+ for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
+ l->limits[ttype] = cgroup_io_limit_defaults[ttype];
+
+ LIST_PREPEND(device_limits, c->io_device_limits, l);
+ }
+
+ l->limits[type] = num;
+
+ 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) {
+
+ uint64_t *weight = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = cg_blkio_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ 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;
+ const char *weight;
+ uint64_t u;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
- LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
- if (b->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, b);
+ 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);
- bandwidth = rvalue + n;
- bandwidth += strspn(bandwidth, WHITESPACE);
+ weight = rvalue + n;
+ weight += strspn(weight, WHITESPACE);
- if (!*bandwidth) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected space separated pair of device node and bandwidth. Ignoring.");
+ if (isempty(weight)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
return 0;
}
@@ -2967,35 +3372,32 @@ int config_parse_blockio_bandwidth(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
- r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0 || bytes <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ r = cg_blkio_weight_parse(weight, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
return 0;
}
- b = new0(CGroupBlockIODeviceBandwidth, 1);
- if (!b)
+ assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
+
+ w = new0(CGroupBlockIODeviceWeight, 1);
+ if (!w)
return log_oom();
- b->path = path;
+ w->path = path;
path = NULL;
- b->bandwidth = (uint64_t) bytes;
- b->read = read;
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ w->weight = u;
+ LIST_PREPEND(device_weights, c->blockio_device_weights, w);
return 0;
}
-DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
-
-int config_parse_job_mode_isolate(
+int config_parse_blockio_bandwidth(
const char *unit,
const char *filename,
unsigned line,
@@ -3007,25 +3409,84 @@ int config_parse_job_mode_isolate(
void *data,
void *userdata) {
- JobMode *m = data;
+ _cleanup_free_ char *path = NULL;
+ CGroupBlockIODeviceBandwidth *b = NULL, *t;
+ CGroupContext *c = data;
+ const char *bandwidth;
+ uint64_t bytes;
+ bool read;
+ size_t n;
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);
+ read = streq("BlockIOReadBandwidth", lvalue);
+
+ if (isempty(rvalue)) {
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+ }
return 0;
}
- *m = r ? JOB_ISOLATE : JOB_REPLACE;
+ n = strcspn(rvalue, WHITESPACE);
+ bandwidth = rvalue + n;
+ bandwidth += strspn(bandwidth, WHITESPACE);
+
+ if (!*bandwidth) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = parse_size(bandwidth, 1000, &bytes);
+ if (r < 0 || bytes <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
+ if (path_equal(path, t->path)) {
+ b = t;
+ break;
+ }
+ }
+
+ if (!t) {
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
+
+ b->path = path;
+ path = NULL;
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+
+ LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ }
+
+ if (read)
+ b->rbps = bytes;
+ else
+ b->wbps = bytes;
+
return 0;
}
-int config_parse_personality(
+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,
@@ -3037,21 +3498,20 @@ int config_parse_personality(
void *data,
void *userdata) {
- unsigned long *personality = data, p;
+ JobMode *m = data;
+ int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(personality);
- p = personality_from_string(rvalue);
- if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse personality, ignoring: %s", rvalue);
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
return 0;
}
- *personality = p;
+ *m = r ? JOB_ISOLATE : JOB_REPLACE;
return 0;
}
@@ -3068,6 +3528,7 @@ int config_parse_runtime_directory(
void *userdata) {
char***rt = data;
+ Unit *u = userdata;
const char *word, *state;
size_t l;
int r;
@@ -3079,21 +3540,25 @@ int config_parse_runtime_directory(
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- strv_free(*rt);
- *rt = NULL;
+ *rt = strv_free(*rt);
return 0;
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ _cleanup_free_ char *t = NULL, *n = NULL;
- n = strndup(word, l);
- if (!n)
+ t = strndup(word, l);
+ if (!t)
return log_oom();
+ r = unit_name_printf(u, t, &n);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ continue;
+ }
+
if (!filename_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Runtime directory is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
continue;
}
@@ -3104,8 +3569,7 @@ int config_parse_runtime_directory(
n = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3152,15 +3616,13 @@ int config_parse_set_status(
val = signal_from_string_try_harder(temp);
if (val <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -val,
- "Failed to parse value, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
continue;
}
set = &status_set->signal;
} else {
if (val < 0 || val > 255) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Value %d is outside range 0-255, ignoring", val);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
continue;
}
set = &status_set->status;
@@ -3172,14 +3634,12 @@ int config_parse_set_status(
r = set_put(*set, INT_TO_PTR(val));
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Unable to store: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
return r;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3197,8 +3657,8 @@ int config_parse_namespace_path_strv(
void *userdata) {
char*** sv = data;
- const char *word, *state;
- size_t l;
+ const char *prev;
+ const char *cur;
int r;
assert(filename);
@@ -3208,42 +3668,47 @@ int config_parse_namespace_path_strv(
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- strv_free(*sv);
- *sv = NULL;
+ *sv = strv_free(*sv);
return 0;
}
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ prev = cur = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
int offset;
- n = strndup(word, l);
- if (!n)
+ r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
+ return 0;
+ }
- if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ if (!utf8_is_valid(word)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
+ prev = cur;
continue;
}
- offset = n[0] == '-';
- if (!path_is_absolute(n + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not an absolute path, ignoring: %s", rvalue);
+ offset = word[0] == '-';
+ if (!path_is_absolute(word + offset)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
+ prev = cur;
continue;
}
- path_kill_slashes(n);
+ path_kill_slashes(word + offset);
- r = strv_push(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
- n = NULL;
+ prev = cur;
+ word = NULL;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
return 0;
}
@@ -3270,8 +3735,7 @@ int config_parse_no_new_privileges(
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -3302,7 +3766,7 @@ int config_parse_protect_home(
assert(data);
/* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
+ * to parse as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
@@ -3313,9 +3777,8 @@ int config_parse_protect_home(
ProtectHome h;
h = protect_home_from_string(rvalue);
- if (h < 0){
- log_syntax(unit, LOG_ERR, filename, line, -h,
- "Failed to parse protect home value, ignoring: %s", rvalue);
+ if (h < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
return 0;
}
@@ -3346,7 +3809,7 @@ int config_parse_protect_system(
assert(data);
/* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
+ * to parse as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
@@ -3357,9 +3820,8 @@ int config_parse_protect_system(
ProtectSystem s;
s = protect_system_from_string(rvalue);
- if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s,
- "Failed to parse protect system value, ignoring: %s", rvalue);
+ if (s < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
return 0;
}
@@ -3372,10 +3834,10 @@ int config_parse_protect_system(
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
+ char *id = NULL;
unsigned c = 0;
int fd, r;
FILE *f;
- char *id = NULL;
assert(filename);
assert(*filename);
@@ -3397,7 +3859,6 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
* the names of this unit, but only if it is a valid
* unit name. */
name = basename(*filename);
-
if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
id = set_get(names, name);
@@ -3437,6 +3898,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
*_f = f;
*_final = id;
+
return 0;
}
@@ -3461,7 +3923,19 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
* ours? Then let's try it the other way
* round */
- other = manager_get_unit((*u)->manager, k);
+ /* If the symlink name we are looking at is unit template, then
+ we must search for instance of this template */
+ if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
+ _cleanup_free_ char *instance = NULL;
+
+ r = unit_name_replace_instance(k, (*u)->instance, &instance);
+ if (r < 0)
+ return r;
+
+ other = manager_get_unit((*u)->manager, instance);
+ } else
+ other = manager_get_unit((*u)->manager, k);
+
free(k);
if (other) {
@@ -3485,13 +3959,13 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
}
static int load_from_path(Unit *u, const char *path) {
- int r;
_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;
+ int r;
assert(u);
assert(path);
@@ -3508,9 +3982,7 @@ static int load_from_path(Unit *u, const char *path) {
r = open_follow(&filename, &f, symlink_names, &id);
if (r < 0) {
- free(filename);
- filename = NULL;
-
+ filename = mfree(filename);
if (r != -ENOENT)
return r;
}
@@ -3518,7 +3990,7 @@ static int load_from_path(Unit *u, const char *path) {
} else {
char **p;
- STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+ STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit
@@ -3532,20 +4004,22 @@ static int load_from_path(Unit *u, const char *path) {
r = -ENOENT;
else
r = open_follow(&filename, &f, symlink_names, &id);
+ if (r >= 0)
+ break;
+ filename = mfree(filename);
+
+ /* ENOENT means that the file is missing or is a dangling symlink.
+ * ENOTDIR means that one of paths we expect to be is a directory
+ * is not a directory, we should just ignore that.
+ * EACCES means that the directory or file permissions are wrong.
+ */
+ if (r == -EACCES)
+ log_debug_errno(r, "Cannot access \"%s\": %m", filename);
+ else if (!IN_SET(r, -ENOENT, -ENOTDIR))
+ return r;
- if (r < 0) {
- free(filename);
- filename = NULL;
-
- if (r != -ENOENT)
- return r;
-
- /* Empty the symlink names for the next run */
- set_clear_free(symlink_names);
- continue;
- }
-
- break;
+ /* Empty the symlink names for the next run */
+ set_clear_free(symlink_names);
}
}
@@ -3553,6 +4027,11 @@ static int load_from_path(Unit *u, const char *path) {
/* Hmm, no suitable file found? */
return 0;
+ if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
+ log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
+ return -ELOOP;
+ }
+
merged = u;
r = merge_by_names(&merged, symlink_names, id);
if (r < 0)
@@ -3566,10 +4045,12 @@ static int load_from_path(Unit *u, const char *path) {
if (fstat(fileno(f), &st) < 0)
return -errno;
- if (null_or_empty(&st))
+ if (null_or_empty(&st)) {
u->load_state = UNIT_MASKED;
- else {
+ u->fragment_mtime = 0;
+ } else {
u->load_state = UNIT_LOADED;
+ u->fragment_mtime = timespec_load(&st.st_mtim);
/* Now, parse the file contents */
r = config_parse(u->id, filename, f,
@@ -3584,8 +4065,6 @@ static int load_from_path(Unit *u, const char *path) {
u->fragment_path = filename;
filename = NULL;
- u->fragment_mtime = timespec_load(&st.st_mtim);
-
if (u->source_path) {
if (stat(u->source_path, &st) >= 0)
u->source_mtime = timespec_load(&st.st_mtim);
@@ -3605,6 +4084,11 @@ int unit_load_fragment(Unit *u) {
assert(u->load_state == UNIT_STUB);
assert(u->id);
+ 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
* to override things by placing things in /etc/systemd/system */
@@ -3635,13 +4119,11 @@ int unit_load_fragment(Unit *u) {
if (r < 0)
return r;
- if (u->load_state == UNIT_STUB) {
+ 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. */
- free(u->fragment_path);
- u->fragment_path = NULL;
- }
+ u->fragment_path = mfree(u->fragment_path);
}
/* Look for a template */
@@ -3691,7 +4173,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_int, "INTEGER" },
{ config_parse_unsigned, "UNSIGNED" },
{ config_parse_iec_size, "SIZE" },
- { config_parse_iec_off, "SIZE" },
+ { config_parse_iec_uint64, "SIZE" },
{ config_parse_si_size, "SIZE" },
{ config_parse_bool, "BOOLEAN" },
{ config_parse_string, "STRING" },
@@ -3711,9 +4193,8 @@ void unit_dump_config_items(FILE *f) {
{ 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_capability_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
{ config_parse_unit_deps, "UNIT [...]" },
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
@@ -3723,7 +4204,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_sysv_priority, "SYSVPRIORITY" },
#endif
{ config_parse_kill_mode, "KILLMODE" },
- { config_parse_kill_signal, "SIGNAL" },
+ { config_parse_signal, "SIGNAL" },
{ config_parse_socket_listen, "SOCKET [...]" },
{ config_parse_socket_bind, "SOCKETBIND" },
{ config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
@@ -3755,9 +4236,13 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_address_families, "FAMILIES" },
#endif
{ config_parse_cpu_shares, "SHARES" },
+ { config_parse_cpu_weight, "WEIGHT" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
+ { config_parse_io_limit, "LIMIT" },
+ { config_parse_io_weight, "WEIGHT" },
+ { config_parse_io_device_weight, "DEVICEWEIGHT" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },