diff --git a/TODO b/TODO index 63b8635a01..d0807a4386 100644 --- a/TODO +++ b/TODO @@ -66,10 +66,16 @@ Features: * In journalctl add a way how "-o verbose" and suchlike can be tweaked to show only a specific set of properties +* beef up pam_systemd to take unit file settings such as cgroups properties as + parameters + * export UID ranges nspawns's --private-user and DynamicUser= uses in the systemd.pc pkg-config file, the same way we already expose the system user boundary there +* a new "systemd-analyze security" tool outputting a checklist of security + features a service does and does not implement + * Whenever we check a UID against the system UID range, also check for the dynamic UID range diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 62dad57748..761a6056de 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -711,13 +711,30 @@ Delegate= - Turns on delegation of further resource control - partitioning to processes of the unit. For unprivileged - services (i.e. those using the User= - setting), this allows processes to create a subhierarchy - beneath its control group path. For privileged services and - scopes, this ensures the processes will have all control - group controllers enabled. + Turns on delegation of further resource control partitioning to processes of the unit. Units where this + is enabled may create and manage their own private subhierarchy of control groups below the control group of + the unit itself. For unprivileged services (i.e. those using the User= setting) the unit's + control group will be made accessible to the relevant user. When enabled the service manager will refrain + from manipulating control groups or moving processes below the unit's control group, so that a clear concept + of ownership is established: the control group tree above the unit's control group (i.e. towards the root + control group) is owned and managed by the service manager of the host, while the control group tree below + the unit's control group is owned and managed by the unit itself. Takes either a boolean argument or a list + of control group controller names. If true, delegation is turned on, and all supported controllers are + enabled for the unit, making them available to the unit's processes for management. If false, delegation is + turned off entirely (and no additional controllers are enabled). If set to a list of controllers, delegation + is turned on, and the specified controllers are enabled for the unit. Note that assigning the empty string + will enable delegation, but not enable any additional controllers. Defaults to false. + + Note that controller delegation to less privileged code is only safe on the unified control group + hierarchy. Accordingly, access to the specified controllers will not be granted to unprivileged services on + the legacy hierarchy, even when requested. + + The following controller names may be specified: , , + , , , , + . Not all of these controllers are available on all kernels however, and some are + specific to the unified hierarchy while others are specific to the legacy hierarchy. Also note that the + kernel might support further controllers, which aren't covered here yet as delegation is either not supported + at all for them or not defined cleanly. diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f5fed2a927..0100fc6dbf 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2244,10 +2244,10 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) } int cg_mask_to_string(CGroupMask mask, char **ret) { - const char *controllers[_CGROUP_CONTROLLER_MAX + 1]; + _cleanup_free_ char *s = NULL; + size_t n = 0, allocated = 0; + bool space = false; CGroupController c; - int i = 0; - char *s; assert(ret); @@ -2257,19 +2257,32 @@ int cg_mask_to_string(CGroupMask mask, char **ret) { } for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { + const char *k; + size_t l; if (!(mask & CGROUP_CONTROLLER_TO_MASK(c))) continue; - controllers[i++] = cgroup_controller_to_string(c); - controllers[i] = NULL; + k = cgroup_controller_to_string(c); + l = strlen(k); + + if (!GREEDY_REALLOC(s, allocated, n + space + l + 1)) + return -ENOMEM; + + if (space) + s[n] = ' '; + memcpy(s + n + space, k, l); + n += space + l; + + space = true; } - s = strv_join((char **)controllers, NULL); - if (!s) - return -ENOMEM; + assert(s); + s[n] = 0; *ret = s; + s = NULL; + return 0; } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index c16a33723c..c549aa4024 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -34,11 +34,11 @@ /* An enum of well known cgroup controllers */ typedef enum CGroupController { CGROUP_CONTROLLER_CPU, - CGROUP_CONTROLLER_CPUACCT, - CGROUP_CONTROLLER_IO, - CGROUP_CONTROLLER_BLKIO, + CGROUP_CONTROLLER_CPUACCT, /* v1 only */ + CGROUP_CONTROLLER_IO, /* v2 only */ + CGROUP_CONTROLLER_BLKIO, /* v1 only */ CGROUP_CONTROLLER_MEMORY, - CGROUP_CONTROLLER_DEVICES, + CGROUP_CONTROLLER_DEVICES, /* v1 only */ CGROUP_CONTROLLER_PIDS, _CGROUP_CONTROLLER_MAX, _CGROUP_CONTROLLER_INVALID = -1, diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 0ae330541d..9e4c5af975 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1527,9 +1527,7 @@ int mkdtemp_malloc(const char *template, char **ret) { return 0; } -static inline void funlockfilep(FILE **f) { - funlockfile(*f); -} +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); int read_line(FILE *f, size_t limit, char **ret) { _cleanup_free_ char *buffer = NULL; diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 6fb4134ae9..be2613ca9e 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -278,6 +278,9 @@ char *strjoin_real(const char *x, ...) { char *strstrip(char *s) { char *e; + if (!s) + return NULL; + /* Drops trailing whitespace. Modifies the string in * place. Returns pointer to first non-space character */ @@ -295,7 +298,13 @@ char *strstrip(char *s) { char *delete_chars(char *s, const char *bad) { char *f, *t; - /* Drops all whitespace, regardless where in the string */ + /* Drops all specified bad characters, regardless where in the string */ + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; for (f = s, t = s; *f; f++) { if (strchr(bad, *f)) @@ -309,6 +318,26 @@ char *delete_chars(char *s, const char *bad) { return s; } +char *delete_trailing_chars(char *s, const char *bad) { + char *p, *c = s; + + /* Drops all specified bad characters, at the end of the string */ + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; + + for (p = s; *p; p++) + if (!strchr(bad, *p)) + c = p + 1; + + *c = 0; + + return s; +} + char *truncate_nl(char *s) { assert(s); diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 4c94b182c1..d2040ebd12 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -133,8 +133,20 @@ char *strjoin_real(const char *x, ...) _sentinel_; char *strstrip(char *s); char *delete_chars(char *s, const char *bad); +char *delete_trailing_chars(char *s, const char *bad); char *truncate_nl(char *s); +static inline char *skip_leading_chars(const char *s, const char *bad) { + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; + + return (char*) s + strspn(s, bad); +} + char ascii_tolower(char x); char *ascii_strlower(char *s); char *ascii_strlower_n(char *s, size_t n); diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index ba9928375e..27ce432197 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -382,19 +382,14 @@ int unit_name_path_escape(const char *f, char **ret) { if (STR_IN_SET(p, "/", "")) s = strdup("-"); else { - char *e; - if (!path_is_safe(p)) return -EINVAL; /* Truncate trailing slashes */ - e = endswith(p, "/"); - if (e) - *e = 0; + delete_trailing_chars(p, "/"); /* Truncate leading slashes */ - if (p[0] == '/') - p++; + p = skip_leading_chars(p, "/"); s = unit_name_escape(p); } diff --git a/src/core/cgroup.c b/src/core/cgroup.c index dff7d1dddc..6872da1f89 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -209,6 +209,16 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, cgroup_device_policy_to_string(c->device_policy), prefix, yes_no(c->delegate)); + if (c->delegate) { + _cleanup_free_ char *t = NULL; + + (void) cg_mask_to_string(c->delegate_controllers, &t); + + fprintf(f, "%sDelegateController=%s\n", + prefix, + strempty(t)); + } + LIST_FOREACH(device_allow, a, c->device_allow) fprintf(f, "%sDeviceAllow=%s %s%s%s\n", @@ -1062,37 +1072,47 @@ CGroupMask unit_get_own_mask(Unit *u) { if (!c) return 0; - /* If delegation is turned on, then turn on all cgroups, - * unless we are on the legacy hierarchy and the process we - * fork into it is known to drop privileges, and hence - * shouldn't get access to the controllers. - * - * Note that on the unified hierarchy it is safe to delegate - * controllers to unprivileged services. */ + return cgroup_context_get_mask(c); +} - if (c->delegate) { +CGroupMask unit_get_delegate_mask(Unit *u) { + CGroupContext *c; + + /* If delegation is turned on, then turn on selected controllers, unless we are on the legacy hierarchy and the + * process we fork into is known to drop privileges, and hence shouldn't get access to the controllers. + * + * Note that on the unified hierarchy it is safe to delegate controllers to unprivileged services. */ + + if (u->type == UNIT_SLICE) + return 0; + + c = unit_get_cgroup_context(u); + if (!c) + return 0; + + if (!c->delegate) + return 0; + + if (cg_all_unified() <= 0) { ExecContext *e; e = unit_get_exec_context(u); - if (!e || - exec_context_maintains_privileges(e) || - cg_all_unified() > 0) - return _CGROUP_MASK_ALL; + if (e && !exec_context_maintains_privileges(e)) + return 0; } - return cgroup_context_get_mask(c); + return c->delegate_controllers; } CGroupMask unit_get_members_mask(Unit *u) { assert(u); - /* Returns the mask of controllers all of the unit's children - * require, merged */ + /* Returns the mask of controllers all of the unit's children require, merged */ if (u->cgroup_members_mask_valid) return u->cgroup_members_mask; - u->cgroup_members_mask = 0; + u->cgroup_members_mask = unit_get_delegate_mask(u); if (u->type == UNIT_SLICE) { void *v; @@ -1107,9 +1127,7 @@ CGroupMask unit_get_members_mask(Unit *u) { if (UNIT_DEREF(member->slice) != u) continue; - u->cgroup_members_mask |= - unit_get_own_mask(member) | - unit_get_members_mask(member); + u->cgroup_members_mask |= unit_get_subtree_mask(member); /* note that this calls ourselves again, for the children */ } } @@ -1127,7 +1145,7 @@ CGroupMask unit_get_siblings_mask(Unit *u) { if (UNIT_ISSET(u->slice)) return unit_get_members_mask(UNIT_DEREF(u->slice)); - return unit_get_own_mask(u) | unit_get_members_mask(u); + return unit_get_subtree_mask(u); } CGroupMask unit_get_subtree_mask(Unit *u) { @@ -1946,11 +1964,9 @@ int manager_setup_cgroup(Manager *m) { if (e) *e = 0; - /* And make sure to store away the root value without trailing - * slash, even for the root dir, so that we can easily prepend - * it everywhere. */ - while ((e = endswith(m->cgroup_root, "/"))) - *e = 0; + /* And make sure to store away the root value without trailing slash, even for the root dir, so that we can + * easily prepend it everywhere. */ + delete_trailing_chars(m->cgroup_root, "/"); /* 2. Show data */ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path); diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 65245fbc43..a75be38044 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -126,6 +126,7 @@ struct CGroupContext { uint64_t tasks_max; bool delegate; + CGroupMask delegate_controllers; }; /* Used when querying IP accounting data */ @@ -153,8 +154,9 @@ void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODe void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b); CGroupMask unit_get_own_mask(Unit *u); -CGroupMask unit_get_siblings_mask(Unit *u); +CGroupMask unit_get_delegate_mask(Unit *u); CGroupMask unit_get_members_mask(Unit *u); +CGroupMask unit_get_siblings_mask(Unit *u); CGroupMask unit_get_subtree_mask(Unit *u); CGroupMask unit_get_target_mask(Unit *u); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index a99d727f4d..bef70b6f84 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -32,6 +32,42 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); +static int property_get_delegate_controllers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupController cc; + int r; + + assert(bus); + assert(reply); + assert(c); + + if (!c->delegate) + return sd_bus_message_append(reply, "as", 0); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + for (cc = 0; cc < _CGROUP_CONTROLLER_MAX; cc++) { + if ((c->delegate_controllers & CGROUP_CONTROLLER_TO_MASK(cc)) == 0) + continue; + + r = sd_bus_message_append(reply, "s", cgroup_controller_to_string(cc)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + static int property_get_io_device_weight( sd_bus *bus, const char *path, @@ -255,6 +291,7 @@ static int property_get_ip_address_access( const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0), + SD_BUS_PROPERTY("DelegateControllers", "as", property_get_delegate_controllers, 0, 0), SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), SD_BUS_PROPERTY("CPUWeight", "t", NULL, offsetof(CGroupContext, cpu_weight), 0), SD_BUS_PROPERTY("StartupCPUWeight", "t", NULL, offsetof(CGroupContext, startup_cpu_weight), 0), @@ -315,9 +352,54 @@ static int bus_cgroup_set_transient_property( if (mode != UNIT_CHECK) { c->delegate = b; + c->delegate_controllers = b ? _CGROUP_MASK_ALL : 0; + unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no"); } + return 1; + + } else if (streq(name, "DelegateControllers")) { + CGroupMask mask = 0; + + r = sd_bus_message_enter_container(message, 'a', "s"); + if (r < 0) + return r; + + for (;;) { + CGroupController cc; + const char *t; + + r = sd_bus_message_read(message, "s", &t); + if (r < 0) + return r; + if (r == 0) + break; + + cc = cgroup_controller_from_string(t); + if (cc < 0) + return sd_bus_error_set_errnof(error, EINVAL, "Unknown cgroup contoller '%s'", t); + + mask |= CGROUP_CONTROLLER_TO_MASK(cc); + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *t = NULL; + + r = cg_mask_to_string(mask, &t); + if (r < 0) + return r; + + c->delegate = true; + c->delegate_controllers |= mask; + + unit_write_drop_in_private_format(u, mode, name, "Delegate=%s", t); + } + return 1; } diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 948d1bc248..062060a3b3 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -117,8 +117,8 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE); if (r < 0) - log_unit_error_errno(u, r, "cannot add %s dependency on %s, ignoring: %m", - unit_dependency_to_string(dependency), entry); + log_unit_warning_errno(u, r, "Cannot add %s dependency on %s, ignoring: %m", + unit_dependency_to_string(dependency), entry); } return 0; @@ -154,12 +154,11 @@ int unit_load_dropin(Unit *u) { return log_oom(); } - STRV_FOREACH(f, u->dropin_paths) { - config_parse(u->id, *f, NULL, - UNIT_VTABLE(u)->sections, - config_item_perf_lookup, load_fragment_gperf_lookup, - false, false, false, u); - } + STRV_FOREACH(f, u->dropin_paths) + (void) config_parse(u->id, *f, NULL, + UNIT_VTABLE(u)->sections, + config_item_perf_lookup, load_fragment_gperf_lookup, + 0, u); u->dropin_mtime = now(CLOCK_REALTIME); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 0f6372e8a3..42c2dbb9e4 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -174,7 +174,7 @@ $1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) $1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting) $1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max) -$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate) +$1.Delegate, config_parse_delegate, 0, offsetof($1, cgroup_context) $1.IPAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.ip_accounting) $1.IPAddressAllow, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_allow) $1.IPAddressDeny, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_deny) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 84f2931b63..02d507f7b2 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3202,6 +3202,67 @@ int config_parse_tasks_max( return 0; } +int config_parse_delegate( + 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; + int r; + + /* 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. */ + + r = parse_boolean(rvalue); + if (r < 0) { + const char *p = rvalue; + CGroupMask mask = 0; + + for (;;) { + _cleanup_free_ char *word = NULL; + CGroupController cc; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + return r; + } + + cc = cgroup_controller_from_string(word); + if (cc < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid controller name '%s', ignoring", rvalue); + continue; + } + + mask |= CGROUP_CONTROLLER_TO_MASK(cc); + } + + c->delegate = true; + c->delegate_controllers |= mask; + + } else if (r > 0) { + c->delegate = true; + c->delegate_controllers = _CGROUP_MASK_ALL; + } else { + c->delegate = false; + c->delegate_controllers = 0; + } + + return 0; +} + int config_parse_device_allow( const char *unit, const char *filename, @@ -4450,7 +4511,7 @@ static int load_from_path(Unit *u, const char *path) { r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, load_fragment_gperf_lookup, - false, true, false, u); + CONFIG_PARSE_ALLOW_INCLUDE, u); if (r < 0) return r; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 1353b0a9d0..0bd6ec15d6 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -85,6 +85,7 @@ int config_parse_cpu_weight(const char *unit, const char *filename, unsigned lin int config_parse_cpu_shares(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_memory_limit(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_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); +int config_parse_delegate(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_device_policy(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_device_allow(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_io_weight(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); diff --git a/src/core/main.c b/src/core/main.c index 3e766f0645..96cac1cd9e 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -768,7 +768,7 @@ static int parse_config_file(void) { CONF_PATHS_NULSTR("systemd/system.conf.d") : CONF_PATHS_NULSTR("systemd/user.conf.d"); - config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL); + (void) config_parse_many_nulstr(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL); /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY * like everywhere else. */ diff --git a/src/core/namespace.c b/src/core/namespace.c index 33349f288e..f1ab6f9736 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1152,10 +1152,6 @@ int setup_namespace( } } - /* Try to set up the new root directory before mounting anything there */ - if (root) - (void) base_filesystem_create(root, UID_INVALID, GID_INVALID); - if (root_image) { /* A root image is specified, mount it to the right place */ r = dissected_image_mount(dissected_image, root, dissect_image_flags); @@ -1192,6 +1188,10 @@ int setup_namespace( } } + /* Try to set up the new root directory before mounting anything else there. */ + if (root_image || root_directory) + (void) base_filesystem_create(root, UID_INVALID, GID_INVALID); + if (n_mounts > 0) { _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; char **blacklist; diff --git a/src/core/unit.c b/src/core/unit.c index 7d95f9db0b..e2446804e7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1057,8 +1057,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { timespan[FORMAT_TIMESPAN_MAX]; Unit *following; _cleanup_set_free_ Set *following_set = NULL; - int r; const char *n; + CGroupMask m; + int r; assert(u); assert(u->type >= 0); @@ -1105,11 +1106,23 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->cgroup_realized_mask != 0) { _cleanup_free_ char *s = NULL; (void) cg_mask_to_string(u->cgroup_realized_mask, &s); - fprintf(f, "%s\tCGroup mask: %s\n", prefix, strnull(s)); + fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s)); } - if (u->cgroup_members_mask != 0) { + if (u->cgroup_enabled_mask != 0) { _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(u->cgroup_members_mask, &s); + (void) cg_mask_to_string(u->cgroup_enabled_mask, &s); + fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s)); + } + m = unit_get_own_mask(u); + if (m != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(m, &s); + fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s)); + } + m = unit_get_members_mask(u); + if (m != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(m, &s); fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s)); } diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 300d647903..ee258a1219 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -147,7 +147,7 @@ static int parse_config(void) { CONF_PATHS_NULSTR("systemd/coredump.conf.d"), "Coredump\0", config_item_table_lookup, items, - false, NULL); + CONFIG_PARSE_WARN, NULL); } static inline uint64_t storage_size_max(void) { diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index e045e9a842..90cd4447d7 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -1254,7 +1254,7 @@ static int parse_config(void) { return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf", CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), "Remote\0", config_item_table_lookup, items, - false, NULL); + CONFIG_PARSE_WARN, NULL); } static void help(void) { diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index ea264989ab..1e3e541998 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -543,7 +543,7 @@ static int parse_config(void) { return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-upload.conf", CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), "Upload\0", config_item_table_lookup, items, - false, NULL); + CONFIG_PARSE_WARN, NULL); } static void help(void) { diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 00ad168286..e719fae007 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1398,7 +1398,7 @@ static int server_parse_config_file(Server *s) { CONF_PATHS_NULSTR("systemd/journald.conf.d"), "Journal\0", config_item_perf_lookup, journald_gperf_lookup, - false, s); + CONFIG_PARSE_WARN, s); } static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) { diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 52c5075110..818da8465e 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -138,7 +138,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," int util_log_priority(const char *priority); size_t util_path_encode(const char *src, char *dest, size_t size); -void util_remove_trailing_chars(char *path, char c); int util_replace_whitespace(const char *str, char *to, size_t len); int util_replace_chars(char *str, const char *white); unsigned int util_string_hash32(const char *key); diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index 1d73d8f090..ae809d85e1 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -150,17 +150,6 @@ size_t util_path_encode(const char *src, char *dest, size_t size) return j; } -void util_remove_trailing_chars(char *path, char c) -{ - size_t len; - - if (path == NULL) - return; - len = strlen(path); - while (len > 0 && path[len-1] == c) - path[--len] = '\0'; -} - /* * Copy from 'str' to 'to', while removing all leading and trailing whitespace, * and replacing each run of consecutive whitespace with a single underscore. diff --git a/src/login/logind.c b/src/login/logind.c index 6046596684..cdd1710fd3 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1072,7 +1072,7 @@ static int manager_parse_config_file(Manager *m) { CONF_PATHS_NULSTR("systemd/logind.conf.d"), "Login\0", config_item_perf_lookup, logind_gperf_lookup, - false, m); + CONFIG_PARSE_WARN, m); } static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 0e1a7d1335..2ec526e636 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -630,7 +630,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { r = config_parse_many(filename, network_dirs, dropin_dirname, "Match\0NetDev\0", config_item_perf_lookup, network_netdev_gperf_lookup, - true, netdev_raw); + CONFIG_PARSE_WARN, netdev_raw); if (r < 0) return r; @@ -671,7 +671,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { r = config_parse(NULL, filename, file, NETDEV_VTABLE(netdev)->sections, config_item_perf_lookup, network_netdev_gperf_lookup, - false, false, false, netdev); + CONFIG_PARSE_WARN, netdev); if (r < 0) return r; diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 025662437b..25ec160df8 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -35,7 +35,7 @@ int manager_parse_config_file(Manager *m) { CONF_PATHS_NULSTR("systemd/networkd.conf.d"), "DHCP\0", config_item_perf_lookup, networkd_gperf_lookup, - false, m); + CONFIG_PARSE_WARN, m); } static const char* const duid_type_table[_DUID_TYPE_MAX] = { diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 29f1586d13..3ed82ca3f9 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -280,7 +280,7 @@ static int network_load_one(Manager *manager, const char *filename) { "IPv6PrefixDelegation\0" "IPv6Prefix\0", config_item_perf_lookup, network_network_gperf_lookup, - false, network); + CONFIG_PARSE_WARN, network); if (r < 0) return r; diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 285e22820f..5f9c1f5ea4 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -59,9 +59,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) { "Network\0" "Files\0", config_item_perf_lookup, nspawn_gperf_lookup, - false, - false, - true, + CONFIG_PARSE_WARN, s); if (r < 0) return r; diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 3cf4261ff0..39dc358a48 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -236,7 +236,7 @@ int manager_parse_config_file(Manager *m) { CONF_PATHS_NULSTR("systemd/resolved.conf.d"), "Resolve\0", config_item_perf_lookup, resolved_gperf_lookup, - false, m); + CONFIG_PARSE_WARN, m); if (r < 0) return r; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 57de9975c7..529bc62886 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -183,6 +183,51 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", field, "t", bytes); goto finish; + + } else if (streq(field, "Delegate")) { + + r = parse_boolean(eq); + if (r < 0) { + const char *p = eq; + + r = sd_bus_message_append(m, "s", "DelegateControllers"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + goto finish; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + return log_error_errno(r, "Invalid syntax: %s", eq); + + r = sd_bus_message_append(m, "s", word); + if (r < 0) + goto finish; + } + + r = sd_bus_message_close_container(m); + if (r < 0) + goto finish; + + r = sd_bus_message_close_container(m); + } else + r = sd_bus_message_append(m, "sv", "Delegate", "b", r); + + goto finish; + } else if (streq(field, "TasksMax")) { uint64_t t; @@ -238,7 +283,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", - "NoNewPrivileges", "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", + "NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse", "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality")) { diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index c304ae3334..10a26d45aa 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -121,17 +121,18 @@ int config_item_perf_lookup( } /* Run the user supplied parser for an assignment */ -static int next_assignment(const char *unit, - const char *filename, - unsigned line, - ConfigItemLookup lookup, - const void *table, - const char *section, - unsigned section_line, - const char *lvalue, - const char *rvalue, - bool relaxed, - void *userdata) { +static int next_assignment( + const char *unit, + const char *filename, + unsigned line, + ConfigItemLookup lookup, + const void *table, + const char *section, + unsigned section_line, + const char *lvalue, + const char *rvalue, + ConfigParseFlags flags, + void *userdata) { ConfigParserCallback func = NULL; int ltype = 0; @@ -157,26 +158,26 @@ static int next_assignment(const char *unit, } /* Warn about unknown non-extension fields. */ - if (!relaxed && !startswith(lvalue, "X-")) + if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section); return 0; } /* Parse a variable assignment line */ -static int parse_line(const char* unit, - const char *filename, - unsigned line, - const char *sections, - ConfigItemLookup lookup, - const void *table, - bool relaxed, - bool allow_include, - char **section, - unsigned *section_line, - bool *section_ignored, - char *l, - void *userdata) { +static int parse_line( + const char* unit, + const char *filename, + unsigned line, + const char *sections, + ConfigItemLookup lookup, + const void *table, + ConfigParseFlags flags, + char **section, + unsigned *section_line, + bool *section_ignored, + char *l, + void *userdata) { char *e; @@ -186,7 +187,6 @@ static int parse_line(const char* unit, assert(l); l = strstrip(l); - if (!*l) return 0; @@ -205,7 +205,7 @@ static int parse_line(const char* unit, * * Support for them should be eventually removed. */ - if (!allow_include) { + if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) { log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring."); return 0; } @@ -214,7 +214,7 @@ static int parse_line(const char* unit, if (!fn) return -ENOMEM; - return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata); + return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata); } if (*l == '[') { @@ -235,7 +235,7 @@ static int parse_line(const char* unit, if (sections && !nulstr_contains(sections, n)) { - if (!relaxed && !startswith(n, "X-")) + if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-")) log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n); free(n); @@ -254,7 +254,7 @@ static int parse_line(const char* unit, if (sections && !*section) { - if (!relaxed && !*section_ignored) + if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored) log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring."); return 0; @@ -278,7 +278,7 @@ static int parse_line(const char* unit, *section_line, strstrip(l), strstrip(e), - relaxed, + flags, userdata); } @@ -289,15 +289,13 @@ int config_parse(const char *unit, const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, - bool allow_include, - bool warn, + ConfigParseFlags flags, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; - bool section_ignored = false, allow_bom = true; + bool section_ignored = false; int r; assert(filename); @@ -308,7 +306,7 @@ int config_parse(const char *unit, if (!f) { /* Only log on request, except for ENOENT, * since we return 0 to the caller. */ - if (warn || errno == ENOENT) + if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT) log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; @@ -319,52 +317,50 @@ int config_parse(const char *unit, for (;;) { _cleanup_free_ char *buf = NULL; - char *l, *p, *c = NULL, *e; bool escaped = false; + char *l, *p, *e; r = read_line(f, LONG_LINE_MAX, &buf); if (r == 0) break; if (r == -ENOBUFS) { - if (warn) + if (flags & CONFIG_PARSE_WARN) log_error_errno(r, "%s:%u: Line too long", filename, line); return r; } if (r < 0) { - if (warn) + if (CONFIG_PARSE_WARN) log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); return r; } l = buf; - if (allow_bom) { + if (!(flags & CONFIG_PARSE_REFUSE_BOM)) { char *q; q = startswith(buf, UTF8_BYTE_ORDER_MARK); if (q) { l = q; - allow_bom = false; + flags |= CONFIG_PARSE_REFUSE_BOM; } } if (continuation) { if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) { - if (warn) + if (flags & CONFIG_PARSE_WARN) log_error("%s:%u: Continuation line too long", filename, line); return -ENOBUFS; } - c = strappend(continuation, l); - if (!c) { - if (warn) + if (!strextend(&continuation, l, NULL)) { + if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } - continuation = mfree(continuation); - p = c; + p = continuation; } else p = l; @@ -378,12 +374,10 @@ int config_parse(const char *unit, if (escaped) { *(e-1) = ' '; - if (c) - continuation = c; - else { + if (!continuation) { continuation = strdup(l); if (!continuation) { - if (warn) + if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } @@ -398,20 +392,20 @@ int config_parse(const char *unit, sections, lookup, table, - relaxed, - allow_include, + flags, §ion, §ion_line, §ion_ignored, p, userdata); - free(c); - if (r < 0) { - if (warn) + if (flags & CONFIG_PARSE_WARN) log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); return r; + } + + continuation = mfree(continuation); } return 0; @@ -423,20 +417,20 @@ static int config_parse_many_files( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { char **fn; int r; if (conf_file) { - r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata); + r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata); if (r < 0) return r; } STRV_FOREACH(fn, files) { - r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata); + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata); if (r < 0) return r; } @@ -451,7 +445,7 @@ int config_parse_many_nulstr( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { _cleanup_strv_free_ char **files = NULL; @@ -461,8 +455,7 @@ int config_parse_many_nulstr( if (r < 0) return r; - return config_parse_many_files(conf_file, files, - sections, lookup, table, relaxed, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); } /* Parse each config file in the directories specified as strv. */ @@ -473,7 +466,7 @@ int config_parse_many( const char *sections, ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata) { _cleanup_strv_free_ char **dropin_dirs = NULL; @@ -490,8 +483,7 @@ int config_parse_many( if (r < 0) return r; - return config_parse_many_files(conf_file, files, - sections, lookup, table, relaxed, userdata); + return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata); } #define DEFINE_PARSER(type, vartype, conv_func) \ @@ -567,16 +559,17 @@ int config_parse_iec_size(const char* unit, return 0; } -int config_parse_si_size(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_si_size( + 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) { size_t *sz = data; uint64_t v; @@ -597,16 +590,17 @@ int config_parse_si_size(const char* unit, return 0; } -int config_parse_iec_uint64(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_iec_uint64( + 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) { uint64_t *bytes = data; int r; diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index ce1113485d..a270488c23 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -29,8 +29,14 @@ #include "log.h" #include "macro.h" -/* An abstract parser for simple, line based, shallow configuration - * files consisting of variable assignments only. */ +/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */ + +typedef enum ConfigParseFlags { + CONFIG_PARSE_RELAXED = 1U << 0, + CONFIG_PARSE_ALLOW_INCLUDE = 1U << 1, + CONFIG_PARSE_WARN = 1U << 2, + CONFIG_PARSE_REFUSE_BOM = 1U << 3, +} ConfigParseFlags; /* Prototype for a parser for a specific configuration setting */ typedef int (*ConfigParserCallback)(const char *unit, @@ -91,9 +97,7 @@ int config_parse( const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, - bool relaxed, - bool allow_include, - bool warn, + ConfigParseFlags flags, void *userdata); int config_parse_many_nulstr( @@ -102,7 +106,7 @@ int config_parse_many_nulstr( const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata); int config_parse_many( @@ -112,7 +116,7 @@ int config_parse_many( const char *sections, /* nulstr */ ConfigItemLookup lookup, const void *table, - bool relaxed, + ConfigParseFlags flags, void *userdata); /* Generic parsers */ diff --git a/src/shared/install.c b/src/shared/install.c index 6a31e62c44..5516799e6b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1308,7 +1308,7 @@ static int unit_file_load( r = config_parse(info->name, path, f, NULL, config_item_table_lookup, items, - true, true, false, info); + CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info); if (r < 0) return log_debug_errno(r, "Failed to parse %s: %m", info->name); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 8c1624ff46..b4c3037f0c 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -58,10 +58,10 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { {} }; - config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf", - CONF_PATHS_NULSTR("systemd/sleep.conf.d"), - "Sleep\0", config_item_table_lookup, items, - false, NULL); + (void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf", + CONF_PATHS_NULSTR("systemd/sleep.conf.d"), + "Sleep\0", config_item_table_lookup, items, + CONFIG_PARSE_WARN, NULL); if (streq(verb, "suspend")) { /* empty by default */ diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 6fd35c81dc..4415bc7b9d 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -22,6 +22,7 @@ #include "macro.h" #include "manager.h" #include "rm-rf.h" +#include "string-util.h" #include "test-helper.h" #include "tests.h" #include "unit.h" @@ -117,10 +118,38 @@ static int test_cgroup_mask(void) { return 0; } +static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) { + _cleanup_free_ char *b = NULL; + + assert_se(cg_mask_to_string(mask, &b) >= 0); + assert_se(streq_ptr(b, t)); +} + +static void test_cg_mask_to_string(void) { + test_cg_mask_to_string_one(0, NULL); + test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct io blkio memory devices pids"); + test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct"); + test_cg_mask_to_string_one(CGROUP_MASK_IO, "io"); + test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio"); + test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory"); + test_cg_mask_to_string_one(CGROUP_MASK_DEVICES, "devices"); + test_cg_mask_to_string_one(CGROUP_MASK_PIDS, "pids"); + test_cg_mask_to_string_one(CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT, "cpu cpuacct"); + test_cg_mask_to_string_one(CGROUP_MASK_CPU|CGROUP_MASK_PIDS, "cpu pids"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT|CGROUP_MASK_PIDS, "cpuacct pids"); + test_cg_mask_to_string_one(CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, "devices pids"); + test_cg_mask_to_string_one(CGROUP_MASK_IO|CGROUP_MASK_BLKIO, "io blkio"); +} + int main(int argc, char* argv[]) { int rc = 0; + log_parse_environment(); + log_open(); + TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); + test_cg_mask_to_string(); return rc; } diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 7a7de98bec..2974d533c3 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -311,7 +311,7 @@ static void test_config_parse(unsigned i, const char *s) { r = config_parse(NULL, name, f, "Section\0", config_item_table_lookup, items, - false, false, true, NULL); + CONFIG_PARSE_WARN, NULL); switch (i) { case 0 ... 3: diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 604701ff7a..5d97080d2c 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -288,11 +288,47 @@ static void test_endswith_no_case(void) { } static void test_delete_chars(void) { - char *r; - char input[] = " hello, waldo. abc"; + char *s, input[] = " hello, waldo. abc"; - r = delete_chars(input, WHITESPACE); - assert_se(streq(r, "hello,waldo.abc")); + s = delete_chars(input, WHITESPACE); + assert_se(streq(s, "hello,waldo.abc")); + assert_se(s == input); +} + +static void test_delete_trailing_chars(void) { + + char *s, + input1[] = " \n \r k \n \r ", + input2[] = "kkkkthiskkkiskkkaktestkkk", + input3[] = "abcdef"; + + s = delete_trailing_chars(input1, WHITESPACE); + assert_se(streq(s, " \n \r k")); + assert_se(s == input1); + + s = delete_trailing_chars(input2, "kt"); + assert_se(streq(s, "kkkkthiskkkiskkkaktes")); + assert_se(s == input2); + + s = delete_trailing_chars(input3, WHITESPACE); + assert_se(streq(s, "abcdef")); + assert_se(s == input3); + + s = delete_trailing_chars(input3, "fe"); + assert_se(streq(s, "abcd")); + assert_se(s == input3); +} + +static void test_skip_leading_chars(void) { + char input1[] = " \n \r k \n \r ", + input2[] = "kkkkthiskkkiskkkaktestkkk", + input3[] = "abcdef"; + + assert_se(streq(skip_leading_chars(input1, WHITESPACE), "k \n \r ")); + assert_se(streq(skip_leading_chars(input2, "k"), "thiskkkiskkkaktestkkk")); + assert_se(streq(skip_leading_chars(input2, "tk"), "hiskkkiskkkaktestkkk")); + assert_se(streq(skip_leading_chars(input3, WHITESPACE), "abcdef")); + assert_se(streq(skip_leading_chars(input3, "bcaef"), "def")); } static void test_in_charset(void) { @@ -361,6 +397,8 @@ int main(int argc, char *argv[]) { test_endswith(); test_endswith_no_case(); test_delete_chars(); + test_delete_trailing_chars(); + test_skip_leading_chars(); test_in_charset(); test_split_pair(); test_first_word(); diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index b62e20c287..333f81a948 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -114,7 +114,7 @@ int manager_parse_config_file(Manager *m) { CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), "Time\0", config_item_perf_lookup, timesyncd_gperf_lookup, - false, m); + CONFIG_PARSE_WARN, m); if (r < 0) return r; diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 495ae464b4..9dd7ea1811 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -310,7 +310,7 @@ static int parse_password(const char *filename, char **wall) { r = config_parse(NULL, filename, NULL, NULL, config_item_table_lookup, items, - true, false, true, NULL); + CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL); if (r < 0) return r; diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index a5f3b1a1b0..fcbadf3e79 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -175,7 +175,7 @@ static int load_link(link_config_ctx *ctx, const char *filename) { r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup, link_config_gperf_lookup, - false, false, true, link); + CONFIG_PARSE_WARN, link); if (r < 0) return r; else diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 9aaec72baf..b061210c7c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1967,7 +1967,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules, } else { int count; - util_remove_trailing_chars(result, '\n'); + delete_trailing_chars(result, "\n"); if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) { count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); if (count > 0) diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index b5662be5c2..3bcd09061a 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -85,7 +85,7 @@ static int adm_builtin(struct udev *udev, int argc, char *argv[]) { strscpyl(filename, sizeof(filename), "/sys", syspath, NULL); else strscpy(filename, sizeof(filename), syspath); - util_remove_trailing_chars(filename, '/'); + delete_trailing_chars(filename, "/"); dev = udev_device_new_from_syspath(udev, filename); if (dev == NULL) { diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index e8ffe2f309..b180e24369 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -116,7 +116,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) { strscpyl(filename, sizeof(filename), "/sys", syspath, NULL); else strscpy(filename, sizeof(filename), syspath); - util_remove_trailing_chars(filename, '/'); + delete_trailing_chars(filename, "/"); dev = udev_device_new_from_synthetic_event(udev, filename, action); if (dev == NULL) {