#include "securebits.h"
#include "securebits-util.h"
#include "signal-util.h"
+#include "socket-protocol-list.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "web-util.h"
-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) {
- Disabled reason = ltype;
-
- switch(reason) {
- case DISABLED_CONFIGURATION:
- 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, 0,
- "Support for option %s= has been removed and it is ignored", lvalue);
- break;
- case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, 0,
- "Support for option %s= has not yet been enabled and it is ignored", lvalue);
- break;
- };
-
- return 0;
-}
-
DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode");
int config_parse_unit_deps(
assert(rvalue);
assert(u);
+ /* Let's not bother with anything that is too long */
+ if (strlen(rvalue) >= PATH_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "%s value too long%s.",
+ lvalue, fatal ? "" : ", ignoring");
+ return fatal ? -ENAMETOOLONG : 0;
+ }
+
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%s: %m",
- fatal ? "" : ", ignoring", rvalue);
+ "Failed to resolve unit specifiers in \"%s\"%s: %m",
+ rvalue, fatal ? "" : ", ignoring");
return fatal ? -ENOEXEC : 0;
}
if (r < 0) {
if (r != -EAFNOSUPPORT)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
-
return 0;
}
p->n_auxiliary_fds = 0;
p->socket = s;
- if (s->ports) {
- LIST_FIND_TAIL(port, s->ports, tail);
- LIST_INSERT_AFTER(port, s->ports, tail, p);
- } else
- LIST_PREPEND(port, s->ports, p);
+ LIST_FIND_TAIL(port, s->ports, tail);
+ LIST_INSERT_AFTER(port, s->ports, tail, p);
+
p = NULL;
return 0;
void *data,
void *userdata) {
Socket *s;
+ int r;
assert(filename);
assert(lvalue);
s = SOCKET(data);
- if (streq(rvalue, "udplite"))
- s->socket_protocol = IPPROTO_UDPLITE;
- else if (streq(rvalue, "sctp"))
- s->socket_protocol = IPPROTO_SCTP;
- else {
+ r = socket_protocol_from_name(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid socket protocol, ignoring: %s", rvalue);
+ return 0;
+ } else if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
return 0;
}
+ s->socket_protocol = r;
+
return 0;
}
s = SOCKET(data);
- b = socket_address_bind_ipv6_only_from_string(rvalue);
+ b = parse_socket_address_bind_ipv6_only_or_bool(rvalue);
if (b < 0) {
- int r;
-
- r = parse_boolean(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
- return 0;
- }
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
+ return 0;
+ }
- s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
- } else
- s->bind_ipv6_only = b;
+ s->bind_ipv6_only = b;
return 0;
}
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = resolved;
+
+ n[nlen++] = TAKE_PTR(resolved);
n[nlen] = NULL;
- resolved = NULL;
}
if (!n || !n[0]) {
if (!nce)
return log_oom();
- nce->argv = n;
- nce->path = path;
+ nce->argv = TAKE_PTR(n);
+ nce->path = TAKE_PTR(path);
nce->flags = flags;
exec_command_append_list(e, nce);
/* Do not _cleanup_free_ these. */
- n = NULL;
- path = NULL;
nce = NULL;
rvalue = p;
void *data,
void *userdata) {
- _cleanup_free_ char *cleaned = NULL;
_cleanup_free_ void *p = NULL;
ExecContext *c = data;
size_t sz;
return 0;
}
- /* Be tolerant to whitespace. Remove it all before decoding */
- cleaned = strdup(rvalue);
- if (!cleaned)
- return log_oom();
- delete_chars(cleaned, WHITESPACE);
-
- r = unbase64mem(cleaned, (size_t) -1, &p, &sz);
+ r = unbase64mem(rvalue, (size_t) -1, &p, &sz);
if (r < 0)
- return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", cleaned);
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue);
assert(sz > 0);
if (ncpus < 0)
return ncpus;
- if (c->cpuset)
- CPU_FREE(c->cpuset);
-
- if (ncpus == 0)
+ if (ncpus == 0) {
/* An empty assignment resets the CPU list */
- c->cpuset = NULL;
- else {
- c->cpuset = cpuset;
- cpuset = NULL;
+ c->cpuset = cpu_set_mfree(c->cpuset);
+ c->cpuset_ncpus = 0;
+ return 0;
+ }
+
+ if (!c->cpuset) {
+ c->cpuset = TAKE_PTR(cpuset);
+ c->cpuset_ncpus = (unsigned) ncpus;
+ return 0;
+ }
+
+ if (c->cpuset_ncpus < (unsigned) ncpus) {
+ CPU_OR_S(CPU_ALLOC_SIZE(c->cpuset_ncpus), cpuset, c->cpuset, cpuset);
+ CPU_FREE(c->cpuset);
+ c->cpuset = TAKE_PTR(cpuset);
+ c->cpuset_ncpus = (unsigned) ncpus;
+ return 0;
}
- c->cpuset_ncpus = ncpus;
+
+ CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), c->cpuset, c->cpuset, cpuset);
return 0;
}
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, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
+ if (unit_has_name(u, p)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Units cannot trigger themselves, ignoring: %s", rvalue);
return 0;
}
return -ENOEXEC;
}
- unit_ref_set(&s->service, x);
+ unit_ref_set(&s->service, UNIT(s), x);
return 0;
}
return -ENOEXEC;
}
- n = k;
- k = NULL;
+ n = TAKE_PTR(k);
}
free(*user);
"Failed to resolve specifiers, ignoring: %s", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_assignment_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"Failed to resolve specifiers, ignoring: %s", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_name_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = k;
+ n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
- k = NULL;
}
if (n) {
for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
- r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
+ r = extract_first_word(&rvalue, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_QUOTES);
if (r == 0)
break;
if (r == -ENOMEM)
"Failed to resolve specifiers, ignoring: %s", word);
continue;
}
- } else {
- k = word;
- word = NULL;
- }
+ } else
+ k = TAKE_PTR(word);
if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = k;
+ n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
- k = NULL;
}
if (n) {
continue;
}
- t = realloc_multiply(c->log_extra_fields, sizeof(struct iovec), c->n_log_extra_fields+1);
+ t = reallocarray(c->log_extra_fields, c->n_log_extra_fields+1, sizeof(struct iovec));
if (!t)
return log_oom();
}
#if 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 errno_num) {
- int r;
-
- if (t[0] == '@') {
- const SyscallFilterSet *set;
- const char *i;
-
- set = syscall_filter_set_find(t);
- if (!set) {
- if (warn)
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Don't know system call group, ignoring: %s", t);
- return 0;
- }
-
- NULSTR_FOREACH(i, set->value) {
- r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false, errno_num);
- if (r < 0)
- return r;
- }
- } else {
- int id;
-
- id = seccomp_syscall_resolve_name(t);
- if (id == __NR_SCMP_ERROR) {
- if (warn)
- log_syntax(unit, LOG_WARNING, 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 = hashmap_put(c->syscall_filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
- if (r == 0)
- return 0;
- if (r < 0)
- return log_oom();
- } else
- (void) hashmap_remove(c->syscall_filter, INT_TO_PTR(id + 1));
- }
-
- return 0;
-}
-
int config_parse_syscall_filter(
const char *unit,
const char *filename,
c->syscall_whitelist = true;
/* Accept default syscalls if we are on a whitelist */
- r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false, -1);
+ r = seccomp_parse_syscall_filter("@default", -1, c->syscall_filter, SECCOMP_PARSE_WHITELIST);
if (r < 0)
return r;
}
continue;
}
- r = syscall_filter_parse_one(unit, filename, line, c, invert, name, true, num);
+ r = seccomp_parse_syscall_filter_full(name, num, c->syscall_filter,
+ SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|(invert ? SECCOMP_PARSE_INVERT : 0)|(c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
+ unit, filename, line);
if (r < 0)
return r;
}
} else
bytes = physical_memory_scale(r, 100U);
- if (bytes <= 0 || bytes >= UINT64_MAX) {
+ if (bytes >= UINT64_MAX ||
+ (bytes <= 0 && !streq(lvalue, "MemorySwapMax"))) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
return 0;
}
}
r = unit_full_printf(userdata, rvalue, &t);
- if(r < 0) {
+ if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve specifiers in %s, ignoring: %m",
rvalue);
+ return 0;
}
n = strcspn(t, WHITESPACE);
if (!path)
return log_oom();
- if (!is_deviceallow_pattern(path)) {
+ if (!is_deviceallow_pattern(path) &&
+ !path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
if (!a)
return log_oom();
- a->path = path;
- path = NULL;
+ a->path = TAKE_PTR(path);
a->r = !!strchr(m, 'r');
a->w = !!strchr(m, 'w');
a->m = !!strchr(m, 'm');
if (!path)
return log_oom();
- if (!path_startswith(path, "/dev")) {
+ if (!path_startswith(path, "/dev") &&
+ !path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
if (!w)
return log_oom();
- w->path = path;
- path = NULL;
+ w->path = TAKE_PTR(path);
w->weight = u;
if (!path)
return log_oom();
- if (!path_startswith(path, "/dev")) {
+ if (!path_startswith(path, "/dev") &&
+ !path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
if (!l)
return log_oom();
- l->path = path;
- path = NULL;
+ l->path = TAKE_PTR(path);
for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
l->limits[ttype] = cgroup_io_limit_defaults[ttype];
if (!path)
return log_oom();
- if (!path_startswith(path, "/dev")) {
+ if (!path_startswith(path, "/dev") &&
+ !path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
if (!w)
return log_oom();
- w->path = path;
- path = NULL;
+ w->path = TAKE_PTR(path);
w->weight = u;
if (!path)
return log_oom();
- if (!path_startswith(path, "/dev")) {
+ if (!path_startswith(path, "/dev") &&
+ !path_startswith(path, "/run/systemd/inaccessible/")) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
if (!b)
return log_oom();
- b->path = path;
- path = NULL;
+ b->path = TAKE_PTR(path);
b->rbps = CGROUP_LIMIT_MAX;
b->wbps = CGROUP_LIMIT_MAX;
return 0;
}
+ log_notice("%s is deprecated. Please use OnFailureJobMode= instead", lvalue);
+
*m = r ? JOB_ISOLATE : JOB_REPLACE;
return 0;
}
return 0;
}
+int config_parse_temporary_filesystems(
+ 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;
+ ExecContext *c = data;
+ const char *cur;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
+ c->temporary_filesystems = NULL;
+ c->n_temporary_filesystems = 0;
+ return 0;
+ }
+
+ cur = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *path = NULL, *resolved = NULL;
+ const char *w;
+
+ 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, "Failed to extract first word, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ w = word;
+ r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+
+ r = unit_full_printf(u, path, &resolved);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers in %s, ignoring: %m", word);
+ continue;
+ }
+
+ if (!path_is_absolute(resolved)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", resolved);
+ continue;
+ }
+
+ path_kill_slashes(resolved);
+
+ r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, w);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse mount options, ignoring: %s", word);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
int config_parse_bind_paths(
const char *unit,
const char *filename,
void *userdata) {
ExecContext *c = data;
- int k;
+ ProtectHome h;
assert(filename);
assert(lvalue);
/* Our enum shall be a superset of booleans, hence first try
* to parse as boolean, and then as enum */
- k = parse_boolean(rvalue);
- if (k > 0)
- c->protect_home = PROTECT_HOME_YES;
- else if (k == 0)
- c->protect_home = PROTECT_HOME_NO;
- else {
- ProtectHome h;
-
- h = protect_home_from_string(rvalue);
- if (h < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_home = h;
+ h = parse_protect_home_or_bool(rvalue);
+ if (h < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
+ return 0;
}
+ c->protect_home = h;
+
return 0;
}
void *userdata) {
ExecContext *c = data;
- int k;
+ ProtectSystem s;
assert(filename);
assert(lvalue);
/* Our enum shall be a superset of booleans, hence first try
* to parse as boolean, and then as enum */
- k = parse_boolean(rvalue);
- if (k > 0)
- c->protect_system = PROTECT_SYSTEM_YES;
- else if (k == 0)
- c->protect_system = PROTECT_SYSTEM_NO;
- else {
- ProtectSystem s;
-
- s = protect_system_from_string(rvalue);
- if (s < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_system = s;
+ s = parse_protect_system_or_bool(rvalue);
+ if (s < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
+ return 0;
}
+ c->protect_system = s;
+
return 0;
}
return r;
}
- free(u->fragment_path);
- u->fragment_path = filename;
- filename = NULL;
+ free_and_replace(u->fragment_path, filename);
if (u->source_path) {
if (stat(u->source_path, &st) >= 0)