DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_home, protect_home, ProtectHome, "Failed to parse protect home value");
DEFINE_CONFIG_PARSE_ENUM(config_parse_protect_system, protect_system, ProtectSystem, "Failed to parse protect system value");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse resource preserve mode");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_preference, ManagedOOMPreference, "Failed to parse ManagedOOMPreference=");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_memory_pressure_watch, cgroup_pressure_watch, CGroupPressureWatch, "Failed to parse memory pressure watch setting");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
static DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares_internal, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
-DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flag_from_string, unsigned long, "Failed to parse mount flag");
+DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_propagation_flag, mount_propagation_flag_from_string, unsigned long, "Failed to parse mount propagation flag");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_status_unit_format, status_unit_format, StatusUnitFormat, "Failed to parse status unit format");
DEFINE_CONFIG_PARSE_ENUM_FULL(config_parse_socket_timestamping, socket_timestamping_from_string_harder, SocketTimestamping, "Failed to parse timestamping precision");
return false;
/* %i, %n and %N all expand to the instance or a superset of it. */
- for (; p < q; p++) {
+ for (; p < q; p++)
if (*p == '%')
percent = !percent;
else if (percent) {
return true;
percent = false;
}
- }
return false;
}
p->n_auxiliary_fds = 0;
p->socket = s;
- LIST_FIND_TAIL(port, s->ports, tail);
+ tail = LIST_FIND_TAIL(port, s->ports);
LIST_INSERT_AFTER(port, s->ports, tail, p);
p = NULL;
}
c->coredump_filter |= f;
- c->oom_score_adjust_set = true;
+ c->coredump_filter_set = true;
return 0;
}
void *userdata) {
uint64_t *capability_set = ASSERT_PTR(data);
- uint64_t sum = 0, initial = 0;
+ uint64_t sum = 0, initial, def;
bool invert = false;
int r;
rvalue++;
}
- if (streq(lvalue, "CapabilityBoundingSet"))
- initial = CAP_ALL; /* initialized to all bits on */
- /* else "AmbientCapabilities" initialized to all bits off */
+ if (streq(lvalue, "CapabilityBoundingSet")) {
+ initial = CAP_MASK_ALL; /* initialized to all bits on */
+ def = CAP_MASK_UNSET; /* not set */
+ } else
+ def = initial = 0; /* All bits off */
r = capability_set_from_string(rvalue, &sum);
if (r < 0) {
return 0;
}
- if (sum == 0 || *capability_set == initial)
+ if (sum == 0 || *capability_set == def)
/* "", "~" or uninitialized data -> replace */
*capability_set = invert ? ~sum : sum;
else {
return 0;
}
+ /* If 'u' is set, we operate on the regular unit specifier table. Otherwise we use a manager-specific
+ * specifier table (in which case ltype must contain the runtime scope). */
+ const Specifier *table = u ? NULL : (const Specifier[]) {
+ COMMON_SYSTEM_SPECIFIERS,
+ COMMON_TMP_SPECIFIERS,
+ COMMON_CREDS_SPECIFIERS(ltype),
+ { 'h', specifier_user_home, NULL },
+ { 's', specifier_user_shell, NULL },
+ };
+
for (const char *p = rvalue;; ) {
_cleanup_free_ char *word = NULL, *resolved = NULL;
if (r == 0)
return 0;
- if (u)
- r = unit_env_printf(u, word, &resolved);
+ if (table)
+ r = specifier_printf(word, sc_arg_max(), table, NULL, NULL, &resolved);
else
- r = specifier_printf(word, sc_arg_max(), system_and_tmp_specifier_table, NULL, NULL, &resolved);
+ r = unit_env_printf(u, word, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to resolve specifiers in %s, ignoring: %m", word);
if (isempty(rvalue) && STR_IN_SET(lvalue, "DefaultMemoryLow",
"DefaultMemoryMin",
"MemoryLow",
+ "StartupMemoryLow",
"MemoryMin"))
bytes = CGROUP_LIMIT_MIN;
else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
bytes = physical_memory_scale(r, 10000U);
if (bytes >= UINT64_MAX ||
- (bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryZSwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) {
+ (bytes <= 0 && !STR_IN_SET(lvalue,
+ "MemorySwapMax",
+ "StartupMemorySwapMax",
+ "MemoryZSwapMax",
+ "StartupMemoryZSwapMax",
+ "MemoryLow",
+ "StartupMemoryLow",
+ "MemoryMin",
+ "DefaultMemoryLow",
+ "DefaultstartupMemoryLow",
+ "DefaultMemoryMin"))) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
return 0;
}
if (streq(lvalue, "DefaultMemoryLow")) {
c->default_memory_low = bytes;
c->default_memory_low_set = true;
+ } else if (streq(lvalue, "DefaultStartupMemoryLow")) {
+ c->default_startup_memory_low = bytes;
+ c->default_startup_memory_low_set = true;
} else if (streq(lvalue, "DefaultMemoryMin")) {
c->default_memory_min = bytes;
c->default_memory_min_set = true;
} else if (streq(lvalue, "MemoryLow")) {
c->memory_low = bytes;
c->memory_low_set = true;
+ } else if (streq(lvalue, "StartupMemoryLow")) {
+ c->startup_memory_low = bytes;
+ c->startup_memory_low_set = true;
} else if (streq(lvalue, "MemoryHigh"))
c->memory_high = bytes;
- else if (streq(lvalue, "MemoryMax"))
+ else if (streq(lvalue, "StartupMemoryHigh")) {
+ c->startup_memory_high = bytes;
+ c->startup_memory_high_set = true;
+ } else if (streq(lvalue, "MemoryMax"))
c->memory_max = bytes;
- else if (streq(lvalue, "MemorySwapMax"))
+ else if (streq(lvalue, "StartupMemoryMax")) {
+ c->startup_memory_max = bytes;
+ c->startup_memory_max_set = true;
+ } else if (streq(lvalue, "MemorySwapMax"))
c->memory_swap_max = bytes;
- else if (streq(lvalue, "MemoryZSwapMax"))
+ else if (streq(lvalue, "StartupMemorySwapMax")) {
+ c->startup_memory_swap_max = bytes;
+ c->startup_memory_swap_max_set = true;
+ } else if (streq(lvalue, "MemoryZSwapMax"))
c->memory_zswap_max = bytes;
- else if (streq(lvalue, "MemoryLimit")) {
+ else if (streq(lvalue, "StartupMemoryZSwapMax")) {
+ c->startup_memory_zswap_max = bytes;
+ c->startup_memory_zswap_max_set = true;
+ } else if (streq(lvalue, "MemoryLimit")) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Unit uses MemoryLimit=; please use MemoryMax= instead. Support for MemoryLimit= will be removed soon.");
c->memory_limit = bytes;
return 0;
}
- /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or turn it
- * off for all. Or it takes a list of controller names, in which case we add the specified controllers to the
- * mask to delegate. */
+ /* We either accept a boolean value, which may be used to turn on delegation for all controllers, or
+ * turn it off for all. Or it takes a list of controller names, in which case we add the specified
+ * controllers to the mask to delegate. Delegate= enables delegation without any controllers. */
if (isempty(rvalue)) {
- /* An empty string resets controllers and set Delegate=yes. */
+ /* An empty string resets controllers and sets Delegate=yes. */
c->delegate = true;
c->delegate_controllers = 0;
return 0;
return 0;
}
+int config_parse_delegate_subgroup(
+ 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 = ASSERT_PTR(data);
+ UnitType t;
+
+ t = unit_name_to_type(unit);
+ assert(t >= 0);
+
+ if (!unit_vtable[t]->can_delegate) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "DelegateSubgroup= setting not supported for this unit type, ignoring.");
+ return 0;
+ }
+
+ if (isempty(rvalue)) {
+ c->delegate_subgroup = mfree(c->delegate_subgroup);
+ return 0;
+ }
+
+ if (cg_needs_escape(rvalue)) { /* Insist that specified names don't need escaping */
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid control group name, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return free_and_strdup_warn(&c->delegate_subgroup, rvalue);
+}
+
int config_parse_managed_oom_mode(
const char *unit,
const char *filename,
}
if (!l) {
- CGroupIOLimitType ttype;
-
l = new0(CGroupIODeviceLimit, 1);
if (!l)
return log_oom();
l->path = TAKE_PTR(resolved);
- for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
- l->limits[ttype] = cgroup_io_limit_defaults[ttype];
+ for (CGroupIOLimitType i = 0; i < _CGROUP_IO_LIMIT_TYPE_MAX; i++)
+ l->limits[i] = cgroup_io_limit_defaults[i];
LIST_PREPEND(device_limits, c->io_device_limits, l);
}
if (r == -ENOMEM)
return log_oom();
if (r <= 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r ?: SYNTHETIC_ERRNO(EINVAL),
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid syntax in %s=, ignoring: %s", lvalue, tuple);
return 0;
}
return 0;
}
+int hashmap_put_credential(Hashmap **h, const char *id, const char *path, bool encrypted) {
+ ExecLoadCredential *old;
+ int r;
+
+ assert(h);
+ assert(id);
+ assert(path);
+
+ old = hashmap_get(*h, id);
+ if (old) {
+ r = free_and_strdup(&old->path, path);
+ if (r < 0)
+ return r;
+
+ old->encrypted = encrypted;
+ } else {
+ _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+
+ lc = new(ExecLoadCredential, 1);
+ if (!lc)
+ return log_oom();
+
+ *lc = (ExecLoadCredential) {
+ .id = strdup(id),
+ .path = strdup(path),
+ .encrypted = encrypted,
+ };
+ if (!lc->id || !lc->path)
+ return -ENOMEM;
+
+ r = hashmap_ensure_put(h, &exec_load_credential_hash_ops, lc->id, lc);
+ if (r < 0)
+ return r;
+
+ TAKE_PTR(lc);
+ }
+
+ return 0;
+}
+
int config_parse_load_credential(
const char *unit,
const char *filename,
_cleanup_free_ char *word = NULL, *k = NULL, *q = NULL;
ExecContext *context = ASSERT_PTR(data);
- ExecLoadCredential *old;
bool encrypted = ltype;
Unit *u = userdata;
const char *p;
}
}
- old = hashmap_get(context->load_credentials, k);
- if (old) {
- free_and_replace(old->path, q);
- old->encrypted = encrypted;
- } else {
- _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
+ r = hashmap_put_credential(&context->load_credentials, k, q, encrypted);
+ if (r < 0)
+ return log_error_errno(r, "Failed to store load credential '%s': %m", rvalue);
- lc = new(ExecLoadCredential, 1);
- if (!lc)
- return log_oom();
+ return 0;
+}
- *lc = (ExecLoadCredential) {
- .id = TAKE_PTR(k),
- .path = TAKE_PTR(q),
- .encrypted = encrypted,
- };
+int config_parse_import_credential(
+ 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) {
- r = hashmap_ensure_put(&context->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Duplicated credential value '%s', ignoring assignment: %s", lc->id, rvalue);
- return 0;
- }
+ _cleanup_free_ char *s = NULL;
+ Set** import_credentials = ASSERT_PTR(data);
+ Unit *u = userdata;
+ int r;
- TAKE_PTR(lc);
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ *import_credentials = set_free(*import_credentials);
+ return 0;
}
+ r = unit_cred_printf(u, rvalue, &s);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
+ return 0;
+ }
+ if (!filename_is_valid(s)) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", s);
+ return 0;
+ }
+
+ r = set_put_strdup(import_credentials, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to store credential name '%s': %m", rvalue);
+
return 0;
}
void *userdata) {
EmergencyAction *x = ASSERT_PTR(data);
- bool is_system;
+ RuntimeScope runtime_scope;
int r;
assert(filename);
/* If we have a unit determine the scope based on it */
if (unit)
- is_system = MANAGER_IS_SYSTEM(((Unit*) ASSERT_PTR(userdata))->manager);
+ runtime_scope = ((Unit*) ASSERT_PTR(userdata))->manager->runtime_scope;
else
- is_system = ltype; /* otherwise, assume the scope is passed in via ltype */
+ runtime_scope = ltype; /* otherwise, assume the scope is passed in via ltype */
- r = parse_emergency_action(rvalue, is_system, x);
+ r = parse_emergency_action(rvalue, runtime_scope, x);
if (r < 0) {
if (r == -EOPNOTSUPP)
log_syntax(unit, LOG_WARNING, filename, line, r,
"%s= specified as %s mode action, ignoring: %s",
- lvalue, is_system ? "user" : "system", rvalue);
+ lvalue, runtime_scope_to_string(runtime_scope), rvalue);
else
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring: %s", lvalue, rvalue);
* declared in the file system. In particular, this is true (and frequent) for device and swap units.
*/
const char *id = u->id;
- _cleanup_free_ char *free_id = NULL;
+ _cleanup_free_ char *filename = NULL, *free_id = NULL;
if (fragment) {
- id = basename(fragment);
+ r = path_extract_filename(fragment, &filename);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to extract filename from fragment '%s': %m", fragment);
+ id = filename;
+
if (unit_name_is_valid(id, UNIT_NAME_TEMPLATE)) {
assert(u->instance); /* If we're not trying to use a template for non-instanced unit,
* this must be set. */
{ config_parse_nsec, "NANOSECONDS" },
{ config_parse_namespace_path_strv, "PATH [...]" },
{ config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" },
- { config_parse_unit_requires_mounts_for, "PATH [...]" },
- { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
+ { config_parse_unit_requires_mounts_for,
+ "PATH [...]" },
+ { config_parse_exec_mount_propagation_flag,
+ "MOUNTFLAG" },
{ config_parse_unit_string_printf, "STRING" },
{ config_parse_trigger_unit, "UNIT" },
{ config_parse_timer, "TIMER" },