]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/load-fragment.c
creds: Add ImportCredential=
[thirdparty/systemd.git] / src / core / load-fragment.c
index 6c55bc5187c1527fb36850567ee29ff088cb4181..6d129af7b2aec4f1139970d8fcac87c2179be9ce 100644 (file)
@@ -138,7 +138,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to pa
 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");
@@ -146,12 +146,13 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_time
 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");
@@ -201,7 +202,7 @@ bool contains_instance_specifier_superset(const char *s) {
                 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) {
@@ -209,7 +210,6 @@ bool contains_instance_specifier_superset(const char *s) {
                                 return true;
                         percent = false;
                 }
-        }
 
         return false;
 }
@@ -680,7 +680,7 @@ int config_parse_socket_listen(
         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;
@@ -800,7 +800,7 @@ int config_parse_exec_coredump_filter(
         }
 
         c->coredump_filter |= f;
-        c->oom_score_adjust_set = true;
+        c->coredump_filter_set = true;
         return 0;
 }
 
@@ -1886,7 +1886,7 @@ int config_parse_capability_set(
                 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;
 
@@ -1899,9 +1899,11 @@ int config_parse_capability_set(
                 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) {
@@ -1909,7 +1911,7 @@ int config_parse_capability_set(
                 return 0;
         }
 
-        if (sum == 0 || *capability_set == initial)
+        if (sum == 0 || *capability_set == def)
                 /* "", "~" or uninitialized data -> replace */
                 *capability_set = invert ? ~sum : sum;
         else {
@@ -2741,6 +2743,16 @@ int config_parse_environ(
                 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;
 
@@ -2755,10 +2767,10 @@ int config_parse_environ(
                 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);
@@ -3813,6 +3825,7 @@ int config_parse_memory_limit(
         if (isempty(rvalue) && STR_IN_SET(lvalue, "DefaultMemoryLow",
                                                   "DefaultMemoryMin",
                                                   "MemoryLow",
+                                                  "StartupMemoryLow",
                                                   "MemoryMin"))
                 bytes = CGROUP_LIMIT_MIN;
         else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
@@ -3828,7 +3841,17 @@ int config_parse_memory_limit(
                         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;
                 }
@@ -3837,6 +3860,9 @@ int config_parse_memory_limit(
         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;
@@ -3846,15 +3872,30 @@ int config_parse_memory_limit(
         } 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;
@@ -3936,12 +3977,12 @@ int config_parse_delegate(
                 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;
@@ -3988,6 +4029,42 @@ int config_parse_delegate(
         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,
@@ -4340,15 +4417,13 @@ int config_parse_io_limit(
                 }
 
         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);
         }
@@ -4606,7 +4681,7 @@ int config_parse_exec_directories(
                 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;
                 }
@@ -4765,6 +4840,46 @@ int config_parse_set_credential(
         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,
@@ -4779,7 +4894,6 @@ int config_parse_load_credential(
 
         _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;
@@ -4832,35 +4946,54 @@ int config_parse_load_credential(
                 }
         }
 
-        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;
 }
 
@@ -5583,7 +5716,7 @@ int config_parse_emergency_action(
                 void *userdata) {
 
         EmergencyAction *x = ASSERT_PTR(data);
-        bool is_system;
+        RuntimeScope runtime_scope;
         int r;
 
         assert(filename);
@@ -5592,16 +5725,16 @@ int config_parse_emergency_action(
 
         /* 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);
@@ -6098,10 +6231,14 @@ int unit_load_fragment(Unit *u) {
          * 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. */
@@ -6172,8 +6309,10 @@ void unit_dump_config_items(FILE *f) {
                 { 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" },