Merge pull request #31442 from YHNdnzj/towards-cgroup-v1-deprecation

core: refuse cgroupv1 unless SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE
This commit is contained in:
Luca Boccassi
2024-02-27 19:21:35 +00:00
committed by GitHub
11 changed files with 204 additions and 178 deletions
+7
View File
@@ -7,6 +7,13 @@ CHANGES WITH 256 in spe:
* Support for flushing of the nscd user/group database caches will be
dropped in a future release.
* Support for cgroup v1 ('legacy' and 'hybrid' hierarchies) is now
considered obsolete and systemd by default will refuse to boot under it.
To forcibly reenable cgroup v1 support, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1
must be set on kernel command line. The meson option 'default-hierarchy='
is also deprecated, i.e. only cgroup v2 ('unified' hierarchy) can be
selected as build-time default.
* Previously, systemd-networkd did not explicitly remove any bridge VLAN
IDs assigned on bridge master and ports. Since v256, if a .network
file for an interface has at least one valid settings in [BridgeVLAN]
-12
View File
@@ -761,17 +761,6 @@ if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0
endif
conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname)
default_hierarchy = get_option('default-hierarchy')
conf.set_quoted('DEFAULT_HIERARCHY_NAME', default_hierarchy,
description : 'default cgroup hierarchy as string')
if default_hierarchy == 'legacy'
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_NONE')
elif default_hierarchy == 'hybrid'
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_SYSTEMD')
else
conf.set('DEFAULT_HIERARCHY', 'CGROUP_UNIFIED_ALL')
endif
extra_net_naming_schemes = []
extra_net_naming_map = []
foreach scheme: get_option('extra-net-naming-schemes').split(',')
@@ -2768,7 +2757,6 @@ summary({
'default LLMNR mode' : default_llmnr,
'default DNS servers' : dns_servers.split(' '),
'default NTP servers' : ntp_servers.split(' '),
'default cgroup hierarchy' : default_hierarchy,
'default net.naming-scheme value' : default_net_naming_scheme,
'default KillUserProcesses value' : kill_user_processes,
'default locale' : default_locale,
+2 -2
View File
@@ -227,8 +227,8 @@ option('configfiledir', type : 'string', value : '',
option('fallback-hostname', type : 'string', value : 'localhost',
description : 'the hostname used if none configured')
option('default-hierarchy', type : 'combo',
choices : ['legacy', 'hybrid', 'unified'], value : 'unified',
description : 'default cgroup hierarchy')
choices : ['legacy', 'hybrid', 'unified'], deprecated : true,
description : '''This option is deprecated and will be removed in a future release''')
option('extra-net-naming-schemes', type : 'string',
description : 'comma-separated list of extra net.naming-scheme= definitions')
option('default-net-naming-scheme', type : 'string', value : 'latest',
-1
View File
@@ -244,7 +244,6 @@ const char* const systemd_features =
" -LIBARCHIVE"
#endif
" default-hierarchy=" DEFAULT_HIERARCHY_NAME
;
static char *systemd_features_with_color(void) {
+1 -1
View File
@@ -4783,7 +4783,7 @@ static int unit_get_io_accounting_raw(Unit *u, uint64_t ret[static _CGROUP_IO_AC
r = cg_all_unified();
if (r < 0)
return r;
if (r == 0) /* TODO: support cgroupv1 */
if (r == 0)
return -ENODATA;
if (!FLAGS_SET(crt->cgroup_realized_mask, CGROUP_MASK_IO))
+19 -7
View File
@@ -666,7 +666,7 @@ static int parse_config_file(void) {
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
{ "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type },
{ "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy },
{ "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL },
{ "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_LEGACY, NULL },
{ "Manager", "RuntimeWatchdogSec", config_parse_watchdog_sec, 0, &arg_runtime_watchdog },
{ "Manager", "RuntimeWatchdogPreSec", config_parse_watchdog_sec, 0, &arg_pretimeout_watchdog },
{ "Manager", "RebootWatchdogSec", config_parse_watchdog_sec, 0, &arg_reboot_watchdog },
@@ -2290,12 +2290,6 @@ static int initialize_runtime(
install_crash_handler();
if (!skip_setup) {
r = mount_cgroup_controllers();
if (r < 0) {
*ret_error_message = "Failed to mount cgroup hierarchies";
return r;
}
/* Pull credentials from various sources into a common credential directory (we do
* this here, before setting up the machine ID, so that we can use credential info
* for setting up the machine ID) */
@@ -3022,6 +3016,24 @@ int main(int argc, char *argv[]) {
goto finish;
}
if (!skip_setup) {
/* Before we actually start deleting cgroup v1 code, make it harder to boot
* in cgroupv1 mode first. See also #30852. */
r = mount_cgroup_legacy_controllers(loaded_policy);
if (r < 0) {
if (r == -ERFKILL)
error_message = "Refusing to run under cgroup v1, SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 not specified on kernel command line";
else
error_message = "Failed to mount cgroup v1 hierarchy";
goto finish;
}
if (r > 0) {
log_full(LOG_CRIT, "Legacy cgroup v1 support selected. This is no longer supported. Will proceed anyway after 30s.");
(void) usleep_safe(30 * USEC_PER_SEC);
}
}
/* The efivarfs is now mounted, let's lock down the system token. */
lock_down_efi_variables();
+29 -16
View File
@@ -81,9 +81,6 @@ static int cg_any_controller_used_for_v1(void) {
bool cg_is_unified_wanted(void) {
static thread_local int wanted = -1;
bool b;
const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
_cleanup_free_ char *c = NULL;
int r;
/* If we have a cached value, return that. */
@@ -96,21 +93,20 @@ bool cg_is_unified_wanted(void) {
return (wanted = r >= CGROUP_UNIFIED_ALL);
/* If we were explicitly passed systemd.unified_cgroup_hierarchy, respect that. */
bool b;
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", /* flags = */ 0, &b);
if (r > 0)
return (wanted = b);
/* If we passed cgroup_no_v1=all with no other instructions, it seems highly unlikely that we want to
* use hybrid or legacy hierarchy. */
_cleanup_free_ char *c = NULL;
r = proc_cmdline_get_key("cgroup_no_v1", 0, &c);
if (r > 0 && streq_ptr(c, "all"))
return (wanted = true);
/* If any controller is in use as v1, don't use unified. */
if (cg_any_controller_used_for_v1() > 0)
return (wanted = false);
return (wanted = is_default);
return (wanted = cg_any_controller_used_for_v1() <= 0);
}
bool cg_is_legacy_wanted(void) {
@@ -132,10 +128,6 @@ bool cg_is_legacy_wanted(void) {
bool cg_is_hybrid_wanted(void) {
static thread_local int wanted = -1;
int r;
bool b;
const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
/* We default to true if the default is "hybrid", obviously, but also when the default is "unified",
* because if we get called, it means that unified hierarchy was not mounted. */
/* If we have a cached value, return that. */
if (wanted >= 0)
@@ -146,12 +138,33 @@ bool cg_is_hybrid_wanted(void) {
return (wanted = false);
/* Otherwise, let's see what the kernel command line has to say. Since checking is expensive, cache
* a non-error result. */
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", /* flags = */ 0, &b);
/* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
* a non-error result.
* The meaning of the kernel option is reversed wrt. to the return value of this function, hence the
* negation. */
return (wanted = r > 0 ? !b : is_default);
bool b;
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", /* flags = */ 0, &b);
if (r > 0)
return (wanted = !b);
/* The default hierarchy is "unified". But if this is reached, it means that unified hierarchy was
* not mounted, so return true too. */
return (wanted = true);
}
bool cg_is_legacy_force_enabled(void) {
bool force;
if (!cg_is_legacy_wanted())
return false;
/* If in container, we have to follow host's cgroup hierarchy. */
if (detect_container() > 0)
return true;
if (proc_cmdline_get_bool("SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE", /* flags = */ 0, &force) < 0)
return false;
return force;
}
int cg_weight_parse(const char *s, uint64_t *ret) {
+1
View File
@@ -10,6 +10,7 @@
bool cg_is_unified_wanted(void);
bool cg_is_legacy_wanted(void);
bool cg_is_hybrid_wanted(void);
bool cg_is_legacy_force_enabled(void);
int cg_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_weight_parse(const char *s, uint64_t *ret);
+140 -132
View File
@@ -107,16 +107,6 @@ static const MountPoint mount_table[] = {
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
#if ENABLE_PSTORE
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
@@ -167,8 +157,11 @@ static int mount_one(const MountPoint *p, bool relabel) {
int r, priority;
assert(p);
assert(p->what);
assert(p->where);
assert(p->type);
priority = (p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
priority = FLAGS_SET(p->mode, MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
if (p->condition_fn && !p->condition_fn())
return 0;
@@ -180,13 +173,13 @@ static int mount_one(const MountPoint *p, bool relabel) {
r = path_is_mount_point_full(p->where, /* root = */ NULL, AT_SYMLINK_FOLLOW);
if (r < 0 && r != -ENOENT) {
log_full_errno(priority, r, "Failed to determine whether %s is a mount point: %m", p->where);
return (p->mode & MNT_FATAL) ? r : 0;
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
}
if (r > 0)
return 0;
/* Skip securityfs in a container */
if (!(p->mode & MNT_IN_CONTAINER) && detect_container() > 0)
if (!FLAGS_SET(p->mode, MNT_IN_CONTAINER) && detect_container() > 0)
return 0;
/* The access mode here doesn't really matter too much, since
@@ -207,39 +200,35 @@ static int mount_one(const MountPoint *p, bool relabel) {
else
r = mount_nofollow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
if (r < 0)
return (p->mode & MNT_FATAL) ? r : 0;
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
/* Relabel again, since we now mounted something fresh here */
if (relabel)
(void) label_fix(p->where, 0);
if (p->mode & MNT_CHECK_WRITABLE) {
if (FLAGS_SET(p->mode, MNT_CHECK_WRITABLE))
if (access(p->where, W_OK) < 0) {
r = -errno;
(void) umount2(p->where, UMOUNT_NOFOLLOW);
(void) rmdir(p->where);
log_full_errno(priority, r, "Mount point %s not writable after mounting, undoing: %m", p->where);
return (p->mode & MNT_FATAL) ? r : 0;
log_full_errno(priority, r, "Mount point '%s' not writable after mounting, undoing: %m", p->where);
return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
}
}
return 1;
}
static int mount_points_setup(size_t n, bool loaded_policy) {
int ret = 0, r;
int r = 0;
assert(n <= ELEMENTSOF(mount_table));
FOREACH_ARRAY(mp, mount_table, n) {
r = mount_one(mp, loaded_policy);
if (r != 0 && ret >= 0)
ret = r;
}
FOREACH_ARRAY(mp, mount_table, n)
RET_GATHER(r, mount_one(mp, loaded_policy));
return ret;
return r;
}
int mount_setup_early(void) {
@@ -297,81 +286,6 @@ static int symlink_controller(const char *target, const char *alias) {
return 0;
}
int mount_cgroup_controllers(void) {
_cleanup_set_free_ Set *controllers = NULL;
int r;
if (!cg_is_legacy_wanted())
return 0;
/* Mount all available cgroup controllers that are built into the kernel. */
r = cg_kernel_controllers(&controllers);
if (r < 0)
return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
for (;;) {
_cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
const char *other_controller;
MountPoint p = {
.what = "cgroup",
.type = "cgroup",
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
.mode = MNT_IN_CONTAINER,
};
controller = set_steal_first(controllers);
if (!controller)
break;
/* Check if we shall mount this together with another controller */
other_controller = join_with(controller);
if (other_controller) {
_cleanup_free_ char *c = NULL;
/* Check if the other controller is actually available in the kernel too */
c = set_remove(controllers, other_controller);
if (c) {
/* Join the two controllers into one string, and maintain a stable ordering */
if (strcmp(controller, other_controller) < 0)
options = strjoin(controller, ",", other_controller);
else
options = strjoin(other_controller, ",", controller);
if (!options)
return log_oom();
}
}
/* The simple case, where there's only one controller to mount together */
if (!options)
options = TAKE_PTR(controller);
where = path_join("/sys/fs/cgroup", options);
if (!where)
return log_oom();
p.where = where;
p.options = options;
r = mount_one(&p, true);
if (r < 0)
return r;
/* Create symlinks from the individual controller names, in case we have a joined mount */
if (controller)
(void) symlink_controller(options, controller);
if (other_controller)
(void) symlink_controller(options, other_controller);
}
/* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
(void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
"mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
return 0;
}
#if HAVE_SELINUX || ENABLE_SMACK
static int relabel_cb(
RecurseDirEvent event,
@@ -415,34 +329,6 @@ static int relabel_tree(const char *path) {
return r;
}
static int relabel_cgroup_filesystems(void) {
int r;
struct statfs st;
r = cg_all_unified();
if (r == 0) {
/* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
only when the filesystem has been already populated by a previous instance of systemd
running from initrd. Otherwise don't remount anything and leave the filesystem read-write
for the cgroup filesystems to be mounted inside. */
if (statfs("/sys/fs/cgroup", &st) < 0)
return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
if (st.f_flags & ST_RDONLY)
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
(void) label_fix("/sys/fs/cgroup", 0);
(void) relabel_tree("/sys/fs/cgroup");
if (st.f_flags & ST_RDONLY)
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
} else if (r < 0)
return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
return 0;
}
static int relabel_extra(void) {
_cleanup_strv_free_ char **files = NULL;
int r, c = 0;
@@ -533,14 +419,12 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
FOREACH_STRING(i, "/dev", "/dev/shm", "/run")
(void) relabel_tree(i);
(void) relabel_cgroup_filesystems();
n_extra = relabel_extra();
after_relabel = now(CLOCK_MONOTONIC);
log_info("Relabeled /dev, /dev/shm, /run, /sys/fs/cgroup%s in %s.",
n_extra > 0 ? ", additional files" : "",
log_info("Relabeled /dev/, /dev/shm/, /run/%s in %s.",
n_extra > 0 ? ", and additional files" : "",
FORMAT_TIMESPAN(after_relabel - before_relabel, 0));
}
#endif
@@ -589,3 +473,127 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
return 0;
}
static const MountPoint cgroupv1_mount_table[] = {
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
};
static void relabel_cgroup_legacy_hierarchy(void) {
#if HAVE_SELINUX || ENABLE_SMACK
struct statfs st;
assert(cg_is_legacy_wanted());
/* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
only when the filesystem has been already populated by a previous instance of systemd
running from initrd. Otherwise don't remount anything and leave the filesystem read-write
for the cgroup filesystems to be mounted inside. */
if (statfs("/sys/fs/cgroup", &st) < 0)
return (void) log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup/: %m");
if (st.f_flags & ST_RDONLY)
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
(void) label_fix("/sys/fs/cgroup", 0);
(void) relabel_tree("/sys/fs/cgroup");
if (st.f_flags & ST_RDONLY)
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
#endif
}
int mount_cgroup_legacy_controllers(bool loaded_policy) {
_cleanup_set_free_ Set *controllers = NULL;
int r;
if (!cg_is_legacy_wanted())
return 0;
if (!cg_is_legacy_force_enabled())
return -ERFKILL;
FOREACH_ARRAY(mp, cgroupv1_mount_table, ELEMENTSOF(cgroupv1_mount_table)) {
r = mount_one(mp, loaded_policy);
if (r < 0)
return r;
}
if (loaded_policy)
relabel_cgroup_legacy_hierarchy();
/* Mount all available cgroup controllers that are built into the kernel. */
r = cg_kernel_controllers(&controllers);
if (r < 0)
return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
for (;;) {
_cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
const char *other_controller;
MountPoint p = {
.what = "cgroup",
.type = "cgroup",
.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
.mode = MNT_IN_CONTAINER,
};
controller = set_steal_first(controllers);
if (!controller)
break;
/* Check if we shall mount this together with another controller */
other_controller = join_with(controller);
if (other_controller) {
_cleanup_free_ char *c = NULL;
/* Check if the other controller is actually available in the kernel too */
c = set_remove(controllers, other_controller);
if (c) {
/* Join the two controllers into one string, and maintain a stable ordering */
if (strcmp(controller, other_controller) < 0)
options = strjoin(controller, ",", other_controller);
else
options = strjoin(other_controller, ",", controller);
if (!options)
return log_oom();
}
}
/* The simple case, where there's only one controller to mount together */
if (!options)
options = TAKE_PTR(controller);
where = path_join("/sys/fs/cgroup", options);
if (!where)
return log_oom();
p.where = where;
p.options = options;
r = mount_one(&p, true);
if (r < 0)
return r;
/* Create symlinks from the individual controller names, in case we have a joined mount */
if (controller)
(void) symlink_controller(options, controller);
if (other_controller)
(void) symlink_controller(options, other_controller);
}
/* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
(void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
"mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
return 1;
}
+4 -4
View File
@@ -3,10 +3,10 @@
#include <stdbool.h>
bool mount_point_is_api(const char *path);
bool mount_point_ignore(const char *path);
int mount_setup_early(void);
int mount_setup(bool loaded_policy, bool leave_propagation);
int mount_cgroup_controllers(void);
bool mount_point_is_api(const char *path);
bool mount_point_ignore(const char *path);
int mount_cgroup_legacy_controllers(bool loaded_policy);
+1 -3
View File
@@ -16,10 +16,8 @@ static void test_is_wanted_print_one(bool header) {
log_info("-- %s --", __func__);
assert_se(proc_cmdline(&cmdline) >= 0);
log_info("cmdline: %s", cmdline);
if (header) {
log_info("default-hierarchy=" DEFAULT_HIERARCHY_NAME);
if (header)
(void) system("findmnt -n /sys/fs/cgroup");
}
log_info("is_unified_wanted() → %s", yes_no(cg_is_unified_wanted()));
log_info("is_hybrid_wanted() → %s", yes_no(cg_is_hybrid_wanted()));