diff options
Diffstat (limited to 'src/core/load-fragment.c')
-rw-r--r-- | src/core/load-fragment.c | 844 |
1 files changed, 394 insertions, 450 deletions
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a48cb4029a..fc2755cb92 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -20,44 +20,43 @@ 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 "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cap-list.h" +#include "cgroup.h" #include "conf-parser.h" -#include "load-fragment.h" -#include "log.h" +#include "cpu-set-util.h" +#include "env-util.h" +#include "errno-list.h" #include "ioprio.h" -#include "securebits.h" +#include "log.h" #include "missing.h" -#include "unit-name.h" -#include "unit-printf.h" -#include "utf8.h" #include "path-util.h" -#include "env-util.h" -#include "cgroup.h" -#include "bus-util.h" -#include "bus-error.h" -#include "errno-list.h" -#include "af-list.h" -#include "cap-list.h" -#include "signal-util.h" -#include "bus-internal.h" - #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "securebits.h" +#include "signal-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "load-fragment.h" int config_parse_warn_compat( const char *unit, @@ -74,15 +73,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; }; @@ -120,18 +119,16 @@ int config_parse_unit_deps(const char *unit, r = unit_name_printf(u, t, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + 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."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } @@ -166,16 +163,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 +185,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 +216,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 +255,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 +278,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 +321,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 +332,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 +348,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 +369,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) { @@ -420,8 +416,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; } @@ -453,14 +448,12 @@ int config_parse_exec_nice(const char *unit, r = safe_atoi(rvalue, &priority); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse nice priority, ignoring: %s. ", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue); return 0; } if (priority < PRIO_MIN || priority >= PRIO_MAX) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "Nice priority out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue); return 0; } @@ -491,14 +484,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; } @@ -552,7 +543,7 @@ int config_parse_exec( 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; @@ -572,24 +563,19 @@ int config_parse_exec( 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,7 +600,7 @@ int config_parse_exec( path_kill_slashes(path); - for (;;) { + while (!isempty(p)) { _cleanup_free_ char *word = NULL; /* Check explicitly for an unquoted semicolon as @@ -627,7 +613,7 @@ int config_parse_exec( } /* 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 +628,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 +642,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; } @@ -741,8 +726,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 +757,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 +789,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 +822,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 +831,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,50 +853,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); + ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); + if (ncpus < 0) + return ncpus; - 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; - } + if (c->cpuset) + CPU_FREE(c->cpuset); - CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset); + if (ncpus == 0) + /* An empty assignment resets the CPU list */ + c->cpuset = NULL; + else { + c->cpuset = cpuset; + cpuset = NULL; } - if (!isempty(state)) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Trailing garbage, ignoring."); + c->cpuset_ncpus = ncpus; return 0; } @@ -942,8 +901,7 @@ int config_parse_exec_capabilities(const char *unit, cap = cap_from_text(rvalue); if (!cap) { - log_syntax(unit, LOG_ERR, filename, line, errno, - "Failed to parse capabilities, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue); return 0; } @@ -994,14 +952,12 @@ 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; } @@ -1048,15 +1004,14 @@ int config_parse_bounding_set(const char *unit, cap = capability_from_name(t); 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 set, ignoring: %s", t); continue; } sum |= ((uint64_t) 1ULL) << (uint64_t) cap; } 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."); if (invert) *capability_bounding_set_drop |= sum; @@ -1094,8 +1049,7 @@ int config_parse_limit(const char *unit, r = safe_atollu(rvalue, &u); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse resource value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } } @@ -1132,8 +1086,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 +1095,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, @@ -1209,12 +1133,12 @@ int config_parse_exec_mount_flags(const char *unit, 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); return 0; } } 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."); c->mount_flags = flags; return 0; @@ -1244,8 +1168,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 +1181,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 +1216,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 +1229,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 +1264,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 +1277,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; } @@ -1400,23 +1318,18 @@ 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; } 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue); 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue); return 0; } } @@ -1459,33 +1372,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 +1432,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; } @@ -1589,13 +1492,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; } @@ -1640,7 +1543,7 @@ int config_parse_service_sockets( } 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; } @@ -1653,7 +1556,7 @@ int config_parse_service_sockets( 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."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -1686,7 +1589,7 @@ 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; } @@ -1751,21 +1654,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 +1715,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 +1725,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; } @@ -1869,8 +1767,7 @@ int config_parse_bus_endpoint_policy( access_str = strpbrk(name, WHITESPACE); if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid endpoint policy value '%s'", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue); return 0; } @@ -1881,21 +1778,83 @@ int config_parse_bus_endpoint_policy( 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str); return 0; } if (!c->bus_endpoint) { r = bus_endpoint_new(&c->bus_endpoint); - if (r < 0) - return r; + return log_error_errno(r, "Failed to create bus endpoint object: %m"); } return bus_endpoint_add_policy(c->bus_endpoint, name, access); } +int config_parse_working_directory( + 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; + Unit *u = userdata; + bool missing_ok; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(c); + assert(u); + + if (rvalue[0] == '-') { + missing_ok = true; + rvalue++; + } else + missing_ok = false; + + if (streq(rvalue, "~")) { + c->working_directory_home = true; + c->working_directory = mfree(c->working_directory); + } else { + _cleanup_free_ char *k = NULL; + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue); + return 0; + } + + path_kill_slashes(k); + + if (!utf8_is_valid(k)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); + return 0; + } + + if (!path_is_absolute(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue); + return 0; + } + + free(c->working_directory); + c->working_directory = k; + k = NULL; + + c->working_directory_home = false; + } + + c->working_directory_missing_ok = missing_ok; + return 0; +} + int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, @@ -1910,7 +1869,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 +1878,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 +1925,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 +1954,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 +1966,7 @@ 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; } @@ -2034,8 +1991,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 +2039,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 +2096,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 +2145,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 +2193,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 +2231,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 +2245,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); } } @@ -2337,8 +2289,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; } @@ -2389,8 +2340,7 @@ int config_parse_syscall_filter( 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); continue; } @@ -2407,8 +2357,7 @@ int config_parse_syscall_filter( set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); } 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. */ @@ -2436,8 +2385,7 @@ int config_parse_syscall_archs( int r; if (isempty(rvalue)) { - set_free(*archs); - *archs = NULL; + *archs = set_free(*archs); return 0; } @@ -2455,8 +2403,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 +2414,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 +2446,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 +2478,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 +2506,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 +2523,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 +2542,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,29 +2551,23 @@ 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; } @@ -2649,26 +2585,19 @@ int config_parse_cpu_shares( void *data, void *userdata) { - unsigned long *shares = data, lu; + uint64_t *shares = data; int r; assert(filename); assert(lvalue); assert(rvalue); - if (isempty(rvalue)) { - *shares = (unsigned long) -1; - 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); + 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; } @@ -2697,15 +2626,12 @@ int config_parse_cpu_quota( } if (!endswith(rvalue, "%")) { - - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2727,24 +2653,51 @@ int config_parse_memory_limit( void *userdata) { CGroupContext *c = data; - off_t bytes; + uint64_t bytes; int r; - if (isempty(rvalue)) { + if (isempty(rvalue) || streq(rvalue, "infinity")) { c->memory_limit = (uint64_t) -1; return 0; } - assert_cc(sizeof(uint64_t) == sizeof(off_t)); - r = parse_size(rvalue, 1024, &bytes); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Memory limit '%s' invalid. Ignoring.", rvalue); + if (r < 0 || bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + + c->memory_limit = bytes; + return 0; +} + +int config_parse_tasks_max( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + CGroupContext *c = data; + uint64_t u; + int r; + + if (isempty(rvalue) || streq(rvalue, "infinity")) { + c->tasks_max = (uint64_t) -1; + return 0; + } + + r = safe_atou64(rvalue, &u); + if (r < 0 || u < 1) { + log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); return 0; } - c->memory_limit = (uint64_t) bytes; return 0; } @@ -2781,8 +2734,7 @@ int config_parse_device_allow( 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } @@ -2791,8 +2743,7 @@ int config_parse_device_allow( 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; } @@ -2822,26 +2773,19 @@ 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_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; } - *weight = lu; return 0; } @@ -2860,8 +2804,8 @@ int config_parse_blockio_device_weight( _cleanup_free_ char *path = NULL; CGroupBlockIODeviceWeight *w; CGroupContext *c = data; - unsigned long lu; const char *weight; + uint64_t u; size_t n; int r; @@ -2878,9 +2822,10 @@ int config_parse_blockio_device_weight( 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,19 +2834,18 @@ 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_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; } + assert(u != CGROUP_BLKIO_WEIGHT_INVALID); + w = new0(CGroupBlockIODeviceWeight, 1); if (!w) return log_oom(); @@ -2909,7 +2853,7 @@ int config_parse_blockio_device_weight( w->path = path; path = NULL; - w->weight = lu; + w->weight = u; LIST_PREPEND(device_weights, c->blockio_device_weights, w); return 0; @@ -2931,7 +2875,7 @@ int config_parse_blockio_bandwidth( CGroupBlockIODeviceBandwidth *b; CGroupContext *c = data; const char *bandwidth; - off_t bytes; + uint64_t bytes; bool read; size_t n; int r; @@ -2957,8 +2901,7 @@ int config_parse_blockio_bandwidth( bandwidth += strspn(bandwidth, WHITESPACE); if (!*bandwidth) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Expected space separated pair of device node and bandwidth. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); return 0; } @@ -2967,15 +2910,13 @@ 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); + log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2985,7 +2926,7 @@ int config_parse_blockio_bandwidth( b->path = path; path = NULL; - b->bandwidth = (uint64_t) bytes; + b->bandwidth = bytes; b->read = read; LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b); @@ -2993,9 +2934,7 @@ int config_parse_blockio_bandwidth( 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_netclass( const char *unit, const char *filename, unsigned line, @@ -3007,25 +2946,38 @@ int config_parse_job_mode_isolate( void *data, void *userdata) { - JobMode *m = data; + CGroupContext *c = data; + unsigned v; int r; assert(filename); assert(lvalue); assert(rvalue); - r = parse_boolean(rvalue); + if (streq(rvalue, "auto")) { + c->netclass_type = CGROUP_NETCLASS_TYPE_AUTO; + return 0; + } + + r = safe_atou32(rvalue, &v); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse boolean, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue); return 0; } - *m = r ? JOB_ISOLATE : JOB_REPLACE; + if (v > CGROUP_NETCLASS_FIXED_MAX) + log_syntax(unit, LOG_ERR, filename, line, 0, + "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX); + + c->netclass_id = v; + c->netclass_type = CGROUP_NETCLASS_TYPE_FIXED; + 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 +2989,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 +3019,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 +3031,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 +3060,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 +3107,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 +3125,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; } @@ -3208,8 +3159,7 @@ 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; } @@ -3222,14 +3172,13 @@ int config_parse_namespace_path_strv( 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; } offset = n[0] == '-'; if (!path_is_absolute(n + offset)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Not an absolute path, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue); continue; } @@ -3242,8 +3191,7 @@ int config_parse_namespace_path_strv( 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; } @@ -3270,8 +3218,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; } @@ -3314,8 +3261,7 @@ int config_parse_protect_home( 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } @@ -3358,8 +3304,7 @@ int config_parse_protect_system( 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); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue); return 0; } @@ -3508,9 +3453,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; } @@ -3534,9 +3477,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; @@ -3605,6 +3546,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 +3581,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 +3635,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" }, @@ -3723,7 +3667,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" }, |