diff options
Diffstat (limited to 'src/core/load-fragment.c')
-rw-r--r-- | src/core/load-fragment.c | 334 |
1 files changed, 288 insertions, 46 deletions
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d9a5094aa0..4ebe92fd45 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -34,21 +34,20 @@ #include "hexdecoct.h" #include "io-util.h" #include "ioprio.h" +#include "ip-protocol-list.h" #include "journal-util.h" #include "load-fragment.h" #include "log.h" #include "missing.h" -#include "mount-util.h" +#include "mountpoint-util.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" #if HAVE_SECCOMP #include "seccomp-util.h" #endif -#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" @@ -57,26 +56,22 @@ #include "user-util.h" #include "web-util.h" -static int supported_socket_protocol_from_string(const char *s) { +static int parse_socket_protocol(const char *s) { int r; - if (isempty(s)) - return IPPROTO_IP; - - r = socket_protocol_from_name(s); + r = parse_ip_protocol(s); if (r < 0) - return -EINVAL; + return r; if (!IN_SET(r, IPPROTO_UDPLITE, IPPROTO_SCTP)) return -EPROTONOSUPPORT; return r; } -DEFINE_CONFIG_PARSE(config_parse_socket_protocol, supported_socket_protocol_from_string, "Failed to parse socket protocol"); +DEFINE_CONFIG_PARSE(config_parse_socket_protocol, parse_socket_protocol, "Failed to parse socket protocol"); DEFINE_CONFIG_PARSE(config_parse_exec_secure_bits, secure_bits_from_string, "Failed to parse secure bits"); DEFINE_CONFIG_PARSE_ENUM(config_parse_collect_mode, collect_mode, CollectMode, "Failed to parse garbage collection mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy"); -DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier"); DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode"); @@ -135,7 +130,7 @@ int config_parse_unit_deps( continue; } - r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE); + r = unit_add_dependency_by_name(u, d, k, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } @@ -1015,6 +1010,17 @@ int config_parse_exec_output( eo = EXEC_OUTPUT_FILE; + } else if ((n = startswith(rvalue, "append:"))) { + + r = unit_full_printf(u, n, &resolved); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s: %m", n); + + r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue); + if (r < 0) + return -ENOEXEC; + + eo = EXEC_OUTPUT_FILE_APPEND; } else { eo = exec_output_from_string(rvalue); if (eo < 0) { @@ -1557,7 +1563,7 @@ int config_parse_trigger_unit( return 0; } - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE); + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, true, UNIT_DEPENDENCY_FILE); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p); return 0; @@ -1755,11 +1761,11 @@ int config_parse_service_sockets( continue; } - r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE); + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); - r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE); + r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } @@ -2861,8 +2867,8 @@ int config_parse_address_families( } af = af_from_name(word); - if (af <= 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, + if (af < 0) { + log_syntax(unit, LOG_ERR, filename, line, af, "Failed to parse address family, ignoring: %s", word); continue; } @@ -3002,13 +3008,13 @@ int config_parse_cpu_quota( return 0; } - r = parse_percent_unbounded(rvalue); + r = parse_permille_unbounded(rvalue); if (r <= 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue); return 0; } - c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U; + c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U; return 0; } @@ -3030,7 +3036,7 @@ int config_parse_memory_limit( if (!isempty(rvalue) && !streq(rvalue, "infinity")) { - r = parse_percent(rvalue); + r = parse_permille(rvalue); if (r < 0) { r = parse_size(rvalue, 1024, &bytes); if (r < 0) { @@ -3038,7 +3044,7 @@ int config_parse_memory_limit( return 0; } } else - bytes = physical_memory_scale(r, 100U); + bytes = physical_memory_scale(r, 1000U); if (bytes >= UINT64_MAX || (bytes <= 0 && !streq(lvalue, "MemorySwapMax"))) { @@ -3047,7 +3053,9 @@ int config_parse_memory_limit( } } - if (streq(lvalue, "MemoryLow")) + if (streq(lvalue, "MemoryMin")) + c->memory_min = bytes; + else if (streq(lvalue, "MemoryLow")) c->memory_low = bytes; else if (streq(lvalue, "MemoryHigh")) c->memory_high = bytes; @@ -3080,7 +3088,7 @@ int config_parse_tasks_max( int r; if (isempty(rvalue)) { - *tasks_max = u->manager->default_tasks_max; + *tasks_max = u ? u->manager->default_tasks_max : UINT64_MAX; return 0; } @@ -3089,7 +3097,7 @@ int config_parse_tasks_max( return 0; } - r = parse_percent(rvalue); + r = parse_permille(rvalue); if (r < 0) { r = safe_atou64(rvalue, &v); if (r < 0) { @@ -3097,7 +3105,7 @@ int config_parse_tasks_max( return 0; } } else - v = system_tasks_max_scale(r, 100U); + v = system_tasks_max_scale(r, 1000U); if (v <= 0 || v >= UINT64_MAX) { log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range, ignoring.", rvalue); @@ -3199,7 +3207,6 @@ int config_parse_device_allow( _cleanup_free_ char *path = NULL, *resolved = NULL; CGroupContext *c = data; - CGroupDeviceAllow *a; const char *p = rvalue; int r; @@ -3231,7 +3238,7 @@ int config_parse_device_allow( return 0; } - if (!startswith(resolved, "block-") && !startswith(resolved, "char-")) { + if (!STARTSWITH_SET(resolved, "block-", "char-")) { r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue); if (r < 0) @@ -3248,17 +3255,7 @@ int config_parse_device_allow( return 0; } - a = new0(CGroupDeviceAllow, 1); - if (!a) - return log_oom(); - - a->path = TAKE_PTR(resolved); - a->r = isempty(p) || !!strchr(p, 'r'); - a->w = isempty(p) || !!strchr(p, 'w'); - a->m = isempty(p) || !!strchr(p, 'm'); - - LIST_PREPEND(device_allow, c->device_allow, a); - return 0; + return cgroup_add_device_allow(c, resolved, p); } int config_parse_io_device_weight( @@ -3335,6 +3332,77 @@ int config_parse_io_device_weight( return 0; } +int config_parse_io_device_latency( + 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, *resolved = NULL; + CGroupIODeviceLatency *l; + CGroupContext *c = data; + const char *p = rvalue; + usec_t usec; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + while (c->io_device_latencies) + cgroup_context_free_io_device_latency(c, c->io_device_latencies); + + return 0; + } + + r = extract_first_word(&p, &path, NULL, EXTRACT_QUOTES); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0 || isempty(p)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract device path and latency from '%s', ignoring.", rvalue); + return 0; + } + + r = unit_full_printf(userdata, path, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in '%s', ignoring: %m", path); + return 0; + } + + r = path_simplify_and_warn(resolved, 0, unit, filename, line, lvalue); + if (r < 0) + return 0; + + if (parse_sec(p, &usec) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", p); + return 0; + } + + l = new0(CGroupIODeviceLatency, 1); + if (!l) + return log_oom(); + + l->path = TAKE_PTR(resolved); + l->target_usec = usec; + + LIST_PREPEND(device_latencies, c->io_device_latencies, l); + return 0; +} + int config_parse_io_limit( const char *unit, const char *filename, @@ -3904,13 +3972,9 @@ int config_parse_temporary_filesystems( if (r < 0) continue; - r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, w); - if (r == -ENOMEM) + r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, resolved, w); + if (r < 0) return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse mount options, ignoring: %s", word); - continue; - } } } @@ -4116,6 +4180,183 @@ int config_parse_job_running_timeout_sec( return 0; } +int config_parse_emergency_action( + 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) { + + Manager *m = NULL; + EmergencyAction *x = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (unit) + m = ((Unit*) userdata)->manager; + else + m = data; + + r = parse_emergency_action(rvalue, MANAGER_IS_SYSTEM(m), x); + if (r < 0) { + if (r == -EOPNOTSUPP && MANAGER_IS_USER(m)) { + /* Compat mode: remove for systemd 241. */ + + log_syntax(unit, LOG_INFO, filename, line, r, + "%s= in user mode specified as \"%s\", using \"exit-force\" instead.", + lvalue, rvalue); + *x = EMERGENCY_ACTION_EXIT_FORCE; + return 0; + } + + if (r == -EOPNOTSUPP) + log_syntax(unit, LOG_ERR, filename, line, r, + "%s= specified as %s mode action, ignoring: %s", + lvalue, MANAGER_IS_SYSTEM(m) ? "user" : "system", rvalue); + else + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse %s=, ignoring: %s", lvalue, rvalue); + return 0; + } + + return 0; +} + +int config_parse_pid_file( + 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, *n = NULL; + Unit *u = userdata; + char **s = data; + const char *e; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + 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 in '%s', ignoring: %m", rvalue); + return 0; + } + + /* If this is a relative path make it absolute by prefixing the /run */ + n = path_make_absolute(k, u->manager->prefix[EXEC_DIRECTORY_RUNTIME]); + if (!n) + return log_oom(); + + /* Check that the result is a sensible path */ + r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue); + if (r < 0) + return r; + + e = path_startswith(n, "/var/run/"); + if (e) { + char *z; + + z = strjoin("/run/", e); + if (!z) + return log_oom(); + + log_syntax(unit, LOG_NOTICE, filename, line, 0, "PIDFile= references path below legacy directory /var/run/, updating %s → %s; please update the unit file accordingly.", n, z); + + free_and_replace(*s, z); + } else + free_and_replace(*s, n); + + return 0; +} + +int config_parse_exit_status( + 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 *exit_status = data, r; + uint8_t u; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(exit_status); + + if (isempty(rvalue)) { + *exit_status = -1; + return 0; + } + + r = safe_atou8(rvalue, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse exit status '%s', ignoring: %m", rvalue); + return 0; + } + + *exit_status = u; + return 0; +} + +int config_parse_disable_controllers( + 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 r; + CGroupContext *c = data; + CGroupMask disabled_mask; + + /* 1. If empty, make all controllers eligible for use again. + * 2. If non-empty, merge all listed controllers, space separated. */ + + if (isempty(rvalue)) { + c->disable_controllers = 0; + return 0; + } + + r = cg_mask_from_string(rvalue, &disabled_mask); + if (r < 0 || disabled_mask <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid cgroup string: %s, ignoring", rvalue); + return 0; + } + + c->disable_controllers |= disabled_mask; + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { @@ -4174,7 +4415,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { free_and_replace(*filename, target); } - f = fdopen(fd, "re"); + f = fdopen(fd, "r"); if (!f) { safe_close(fd); return -errno; @@ -4290,7 +4531,6 @@ static int load_from_path(Unit *u, const char *path) { 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 @@ -4302,6 +4542,7 @@ static int load_from_path(Unit *u, const char *path) { else if (!IN_SET(r, -ENOENT, -ENOTDIR)) return r; + filename = mfree(filename); /* Empty the symlink names for the next run */ set_clear_free(symlink_names); } @@ -4524,6 +4765,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_device_policy, "POLICY" }, { config_parse_io_limit, "LIMIT" }, { config_parse_io_device_weight, "DEVICEWEIGHT" }, + { config_parse_io_device_latency, "DEVICELATENCY" }, { config_parse_blockio_bandwidth, "BANDWIDTH" }, { config_parse_blockio_weight, "WEIGHT" }, { config_parse_blockio_device_weight, "DEVICEWEIGHT" }, |