if (de->d_type != DT_DIR)
                         continue;
 
-                if (dot_or_dot_dot(de->d_name))
+                if (streq(de->d_name, ".") ||
+                    streq(de->d_name, ".."))
                         continue;
 
                 b = strdup(de->d_name);
         if (r < 0 && errno != ENOENT)
                 return -errno;
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                r = cg_rmdir(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to remove compat systemd cgroup %s: %m", path);
-        }
-
         return 0;
 }
 
          * just cuts off the name= prefixed used for named
          * hierarchies, if it is specified. */
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                if (cg_hybrid_unified())
-                        controller = SYSTEMD_CGROUP_CONTROLLER_HYBRID;
-                else
-                        controller = SYSTEMD_CGROUP_CONTROLLER_LEGACY;
-        }
-
         e = startswith(controller, "name=");
         if (e)
                 return e;
 }
 
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
-        int r;
+        int unified, r;
 
         assert(fs);
 
         if (!cg_controller_is_valid(controller))
                 return -EINVAL;
 
-        if (cg_all_unified())
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+
+        if (unified > 0)
                 r = join_path_unified(path, suffix, fs);
         else
                 r = join_path_legacy(controller, path, suffix, fs);
 }
 
 static int controller_is_accessible(const char *controller) {
+        int unified;
 
         assert(controller);
 
         if (!cg_controller_is_valid(controller))
                 return -EINVAL;
 
-        if (cg_all_unified()) {
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0) {
                 /* We don't support named hierarchies if we are using
                  * the unified hierarchy. */
 
 
 int cg_trim(const char *controller, const char *path, bool delete_root) {
         _cleanup_free_ char *fs = NULL;
-        int r = 0, q;
+        int r = 0;
 
         assert(path);
 
                         return -errno;
         }
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
-                if (q < 0)
-                        log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
-        }
-
         return r;
 }
 
                 return -errno;
         }
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                r = cg_create(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to create compat systemd cgroup %s: %m", path);
-        }
-
         return 1;
 }
 
 
         xsprintf(c, PID_FMT "\n", pid);
 
-        r = write_string_file(fs, c, 0);
-        if (r < 0)
-                return r;
-
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                r = cg_attach(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, pid);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to attach %d to compat systemd cgroup %s: %m", pid, path);
-        }
-
-        return 0;
+        return write_string_file(fs, c, 0);
 }
 
 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
         if (r < 0)
                 return r;
 
-        r = chmod_and_chown(fs, mode, uid, gid);
-        if (r < 0)
-                return r;
-
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to set group access on compat systemd cgroup %s: %m", path);
-        }
-
-        return 0;
+        return chmod_and_chown(fs, mode, uid, gid);
 }
 
 int cg_set_task_access(
                 gid_t gid) {
 
         _cleanup_free_ char *fs = NULL, *procs = NULL;
-        int r;
+        int r, unified;
 
         assert(path);
 
         if (r < 0)
                 return r;
 
-        if (!cg_unified(controller)) {
-                /* Compatibility, Always keep values for "tasks" in sync with
-                 * "cgroup.procs" */
-                if (cg_get_path(controller, path, "tasks", &procs) >= 0)
-                        (void) chmod_and_chown(procs, mode, uid, gid);
-        }
+        unified = cg_unified(controller);
+        if (unified < 0)
+                return unified;
+        if (unified)
+                return 0;
 
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && cg_hybrid_unified()) {
-                r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to set task access on compat systemd cgroup %s: %m", path);
-        }
+        /* Compatibility, Always keep values for "tasks" in sync with
+         * "cgroup.procs" */
+        if (cg_get_path(controller, path, "tasks", &procs) >= 0)
+                (void) chmod_and_chown(procs, mode, uid, gid);
 
         return 0;
 }
 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
         _cleanup_fclose_ FILE *f = NULL;
         char line[LINE_MAX];
-        const char *fs, *controller_str;
+        const char *fs;
         size_t cs = 0;
-        bool unified;
+        int unified;
 
         assert(path);
         assert(pid >= 0);
                 controller = SYSTEMD_CGROUP_CONTROLLER;
 
         unified = cg_unified(controller);
-        if (!unified) {
-                if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
-                        controller_str = SYSTEMD_CGROUP_CONTROLLER_LEGACY;
-                else
-                        controller_str = controller;
-
-                cs = strlen(controller_str);
-        }
+        if (unified < 0)
+                return unified;
+        if (unified == 0)
+                cs = strlen(controller);
 
         fs = procfs_file_alloca(pid, "cgroup");
         log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
 
                         *e = 0;
                         FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
-                                if (k == cs && memcmp(word, controller_str, cs) == 0) {
+                                if (k == cs && memcmp(word, controller, cs) == 0) {
                                         found = true;
                                         break;
                                 }
 int cg_install_release_agent(const char *controller, const char *agent) {
         _cleanup_free_ char *fs = NULL, *contents = NULL;
         const char *sc;
-        int r;
+        int r, unified;
 
         assert(agent);
 
-        if (cg_unified(controller)) /* doesn't apply to unified hierarchy */
+        unified = cg_unified(controller);
+        if (unified < 0)
+                return unified;
+        if (unified) /* doesn't apply to unified hierarchy */
                 return -EOPNOTSUPP;
 
         r = cg_get_path(controller, NULL, "release_agent", &fs);
 
 int cg_uninstall_release_agent(const char *controller) {
         _cleanup_free_ char *fs = NULL;
-        int r;
+        int r, unified;
 
-        if (cg_unified(controller)) /* Doesn't apply to unified hierarchy */
+        unified = cg_unified(controller);
+        if (unified < 0)
+                return unified;
+        if (unified) /* Doesn't apply to unified hierarchy */
                 return -EOPNOTSUPP;
 
         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
 }
 
 int cg_is_empty_recursive(const char *controller, const char *path) {
-        int r;
+        int unified, r;
 
         assert(path);
 
         if (controller && (isempty(path) || path_equal(path, "/")))
                 return false;
 
-        if (cg_unified(controller)) {
+        unified = cg_unified(controller);
+        if (unified < 0)
+                return unified;
+
+        if (unified > 0) {
                 _cleanup_free_ char *t = NULL;
 
                 /* On the unified hierarchy we can check empty state
         if (!p)
                 return false;
 
-        if (streq(p, SYSTEMD_CGROUP_CONTROLLER))
-                return true;
-
         s = startswith(p, "name=");
         if (s)
                 p = s;
 
 int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
         CGroupController c;
-        int r;
+        int r, unified;
 
         /* This one will create a cgroup in our private tree, but also
          * duplicate it in the trees specified in mask, and remove it
                 return r;
 
         /* If we are in the unified hierarchy, we are done now */
-        if (cg_all_unified())
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
                 return 0;
 
         /* Otherwise, do the same in the other hierarchies */
 
 int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
         CGroupController c;
-        int r;
+        int r, unified;
 
         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
         if (r < 0)
                 return r;
 
-        if (cg_all_unified())
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
                 return 0;
 
         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
 
 int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
         CGroupController c;
-        int r = 0;
+        int r = 0, unified;
 
         if (!path_equal(from, to))  {
                 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
                         return r;
         }
 
-        if (cg_all_unified())
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
                 return r;
 
         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
 
 int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
         CGroupController c;
-        int r;
+        int r, unified;
 
         r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
         if (r < 0)
                 return r;
 
-        if (cg_all_unified())
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0)
                 return r;
 
         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
 
 int cg_mask_supported(CGroupMask *ret) {
         CGroupMask mask = 0;
-        int r;
+        int r, unified;
 
         /* Determines the mask of supported cgroup controllers. Only
          * includes controllers we can make sense of and that are
          * actually accessible. */
 
-        if (cg_all_unified()) {
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (unified > 0) {
                 _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
                 const char *c;
 
 
 static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
 
-/* The hybrid mode was initially implemented in v232 and simply mounted
- * cgroup v2 on /sys/fs/cgroup/systemd.  This unfortunately broke other
- * tools (such as docker) which expected the v1 "name=systemd" hierarchy
- * on /sys/fs/cgroup/systemd.  From v233 and on, the hybrid mode mountnbs
- * v2 on /sys/fs/cgroup/unified and maintains "name=systemd" hierarchy
- * on /sys/fs/cgroup/systemd for compatibility with other tools.
- *
- * To keep live upgrade working, we detect and support v232 layout.  When
- * v232 layout is detected, to keep cgroup v2 process management but
- * disable the compat dual layout, we return %true on
- * cg_unified(SYSTEMD_CGROUP_CONTROLLER) and %false on cg_hybrid_unified().
- */
-static thread_local bool unified_systemd_v232;
-
 static int cg_update_unified(void) {
 
         struct statfs fs;
         if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
                 unified_cache = CGROUP_UNIFIED_ALL;
         else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
-                if (statfs("/sys/fs/cgroup/unified/", &fs) == 0 &&
-                    F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) {
-                        unified_cache = CGROUP_UNIFIED_SYSTEMD;
-                        unified_systemd_v232 = false;
-                } else if (statfs("/sys/fs/cgroup/systemd/", &fs) == 0 &&
-                           F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) {
-                        unified_cache = CGROUP_UNIFIED_SYSTEMD;
-                        unified_systemd_v232 = true;
-                } else {
-                        if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
-                                return -errno;
-                        if (!F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
-                                return -ENOMEDIUM;
-                        unified_cache = CGROUP_UNIFIED_NONE;
-                }
+                if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
+                        return -errno;
+
+                unified_cache = F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC) ?
+                        CGROUP_UNIFIED_SYSTEMD : CGROUP_UNIFIED_NONE;
         } else
                 return -ENOMEDIUM;
 #else
         return 0;
 }
 
-bool cg_unified(const char *controller) {
+int cg_unified(const char *controller) {
+
+        int r;
 
-        assert(cg_update_unified() >= 0);
+        r = cg_update_unified();
+        if (r < 0)
+                return r;
 
         if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
                 return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
                 return unified_cache >= CGROUP_UNIFIED_ALL;
 }
 
-bool cg_all_unified(void) {
+int cg_all_unified(void) {
 
         return cg_unified(NULL);
 }
 
 #if 0 /// UNNEEDED by elogind
-bool cg_hybrid_unified(void) {
-
-        assert(cg_update_unified() >= 0);
-
-        return unified_cache == CGROUP_UNIFIED_SYSTEMD && !unified_systemd_v232;
-}
-
-int cg_unified_flush(void) {
+void cg_unified_flush(void) {
         unified_cache = CGROUP_UNIFIED_UNKNOWN;
-
-        return cg_update_unified();
 }
 
 int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
         _cleanup_free_ char *fs = NULL;
         CGroupController c;
-        int r;
+        int r, unified;
 
         assert(p);
 
         if (supported == 0)
                 return 0;
 
-        if (!cg_all_unified()) /* on the legacy hiearchy there's no joining of controllers defined */
+        unified = cg_all_unified();
+        if (unified < 0)
+                return unified;
+        if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
                 return 0;
 
         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
 
 bool cg_is_unified_wanted(void) {
         static thread_local int wanted = -1;
-        int r;
+        int r, unified;
         bool b;
 
         /* If the hierarchy is already mounted, then follow whatever
          * was chosen for it. */
-        if (cg_unified_flush() >= 0)
-                return cg_all_unified();
+        unified = cg_all_unified();
+        if (unified >= 0)
+                return unified;
 
         /* Otherwise, let's see what the kernel command line has to
          * say. Since checking that is expensive, let's cache the
 
 bool cg_is_unified_systemd_controller_wanted(void) {
         static thread_local int wanted = -1;
-        int r;
+        int r, unified;
         bool b;
 
         /* If the unified hierarchy is requested in full, no need to
 
         /* If the hierarchy is already mounted, then follow whatever
          * was chosen for it. */
-        if (cg_unified_flush() >= 0)
-                return cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+        unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
+        if (unified >= 0)
+                return unified;
 
         /* Otherwise, let's see what the kernel command line has to
          * say. Since checking that is expensive, let's cache the
 
                 return 0;
         }
 
-        if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
+        if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) ||
             getpid() == 1 ||
             isatty(STDERR_FILENO) <= 0) {
 
 #if 0 /// elogind does not support logging to systemd-journald
-                if (log_target == LOG_TARGET_AUTO ||
-                    log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
-                    log_target == LOG_TARGET_JOURNAL) {
+                if (IN_SET(log_target, LOG_TARGET_AUTO,
+                                       LOG_TARGET_JOURNAL_OR_KMSG,
+                                       LOG_TARGET_JOURNAL)) {
                         r = log_open_journal();
                         if (r >= 0) {
                                 log_close_syslog();
                 }
 #endif // 0
 
-                if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-                    log_target == LOG_TARGET_SYSLOG) {
+                if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
+                                       LOG_TARGET_SYSLOG)) {
                         r = log_open_syslog();
                         if (r >= 0) {
                                 log_close_journal();
                         }
                 }
 
-                if (log_target == LOG_TARGET_AUTO ||
-                    log_target == LOG_TARGET_SAFE ||
-                    log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
-                    log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-                    log_target == LOG_TARGET_KMSG) {
+                if (IN_SET(log_target, LOG_TARGET_AUTO,
+                                       LOG_TARGET_SAFE,
+                                       LOG_TARGET_JOURNAL_OR_KMSG,
+                                       LOG_TARGET_SYSLOG_OR_KMSG,
+                                       LOG_TARGET_KMSG)) {
                         r = log_open_kmsg();
                         if (r >= 0) {
                                 log_close_journal();
                         *(e++) = 0;
 
 #if 0 /// elogind does not support logging to systemd-journald
-                if (log_target == LOG_TARGET_AUTO ||
-                    log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
-                    log_target == LOG_TARGET_JOURNAL) {
+                if (IN_SET(log_target, LOG_TARGET_AUTO,
+                                       LOG_TARGET_JOURNAL_OR_KMSG,
+                                       LOG_TARGET_JOURNAL)) {
 
                         k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
                         if (k < 0) {
                 }
 #endif // 0
 
-                if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-                    log_target == LOG_TARGET_SYSLOG) {
+                if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
+                                       LOG_TARGET_SYSLOG)) {
 
                         k = write_to_syslog(level, error, file, line, func, buffer);
                         if (k < 0) {
                 }
 
                 if (k <= 0 &&
-                    (log_target == LOG_TARGET_AUTO ||
-                     log_target == LOG_TARGET_SAFE ||
-                     log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
-                     log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
-                     log_target == LOG_TARGET_KMSG)) {
+                    IN_SET(log_target, LOG_TARGET_AUTO,
+                                       LOG_TARGET_SAFE,
+                                       LOG_TARGET_SYSLOG_OR_KMSG,
+                                       LOG_TARGET_JOURNAL_OR_KMSG,
+                                       LOG_TARGET_KMSG)) {
 
                         k = write_to_kmsg(level, error, file, line, func, buffer);
                         if (k < 0) {
                 level = log_facility | LOG_PRI(level);
 
 #if 0 /// elogind does not support logging to systemd-journald
-        if ((log_target == LOG_TARGET_AUTO ||
-             log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
-             log_target == LOG_TARGET_JOURNAL) &&
+        if (IN_SET(log_target, LOG_TARGET_AUTO,
+                               LOG_TARGET_JOURNAL_OR_KMSG,
+                               LOG_TARGET_JOURNAL) &&
             journal_fd >= 0) {
                 char header[LINE_MAX];
                 struct iovec iovec[17] = {};
         if (streq(key, "debug") && !value)
                 log_set_max_level(LOG_DEBUG);
 
-        else if (streq(key, "systemd.log_target") && value) {
+        else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (log_set_target_from_string(value) < 0)
                         log_warning("Failed to parse log target '%s'. Ignoring.", value);
 
-        } else if (streq(key, "systemd.log_level") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (log_set_max_level_from_string(value) < 0)
                         log_warning("Failed to parse log level '%s'. Ignoring.", value);
 
-        } else if (streq(key, "systemd.log_color") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
 
-                if (log_show_color_from_string(value) < 0)
+                if (log_show_color_from_string(value ?: "1") < 0)
                         log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
 
-        } else if (streq(key, "systemd.log_location") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
 
-                if (log_show_location_from_string(value) < 0)
+                if (log_show_location_from_string(value ?: "1") < 0)
                         log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
         }
 
         const char *e;
 
         if (get_ctty_devnr(0, NULL) < 0)
-                /* Only try to read the command line in daemons.
-                   We assume that anything that has a controlling
-                   tty is user stuff. */
-                (void) parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
+                /* Only try to read the command line in daemons.  We assume that anything that has a controlling tty is
+                   user stuff. */
+                (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
 
         e = secure_getenv("SYSTEMD_LOG_TARGET");
         if (e && log_set_target_from_string(e) < 0)
 }
 
 bool log_on_console(void) {
-        if (log_target == LOG_TARGET_CONSOLE ||
-            log_target == LOG_TARGET_CONSOLE_PREFIXED)
+        if (IN_SET(log_target, LOG_TARGET_CONSOLE,
+                               LOG_TARGET_CONSOLE_PREFIXED))
                 return true;
 
         return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
 
                 return read_one_line_file("/proc/cmdline", ret);
 }
 
-int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
-                       void *data,
-                       bool strip_prefix) {
+int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {
+
         _cleanup_free_ char *line = NULL;
         const char *p;
         int r;
         p = line;
         for (;;) {
                 _cleanup_free_ char *word = NULL;
-                char *value = NULL, *unprefixed;
+                char *value, *key, *q;
 
                 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
                 if (r == 0)
                         break;
 
-                /* Filter out arguments that are intended only for the
-                 * initrd */
-                unprefixed = startswith(word, "rd.");
-                if (unprefixed && !in_initrd())
-                        continue;
+                key = word;
+
+                /* Filter out arguments that are intended only for the initrd */
+                q = startswith(word, "rd.");
+                if (q) {
+                        if (!in_initrd())
+                                continue;
+
+                        if (flags & PROC_CMDLINE_STRIP_RD_PREFIX)
+                                key = q;
+                }
 
-                value = strchr(word, '=');
+                value = strchr(key, '=');
                 if (value)
                         *(value++) = 0;
 
-                r = parse_item(strip_prefix && unprefixed ? unprefixed : word, value, data);
+                r = parse_item(key, value, data);
                 if (r < 0)
                         return r;
         }
         return 0;
 }
 
-int get_proc_cmdline_key(const char *key, char **value) {
+static bool relaxed_equal_char(char a, char b) {
+
+        return a == b ||
+                (a == '_' && b == '-') ||
+                (a == '-' && b == '_');
+}
+
+char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
+
+        assert(s);
+        assert(prefix);
+
+        /* Much like startswith(), but considers "-" and "_" the same */
+
+        for (; *prefix != 0; s++, prefix++)
+                if (!relaxed_equal_char(*s, *prefix))
+                        return NULL;
+
+        return (char*) s;
+}
+
+bool proc_cmdline_key_streq(const char *x, const char *y) {
+        assert(x);
+        assert(y);
+
+        /* Much like streq(), but considers "-" and "_" the same */
+
+        for (; *x != 0 || *y != 0; x++, y++)
+                if (!relaxed_equal_char(*x, *y))
+                        return false;
+
+        return true;
+}
+
+int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
         _cleanup_free_ char *line = NULL, *ret = NULL;
         bool found = false;
         const char *p;
         int r;
 
-        assert(key);
+        /* Looks for a specific key on the kernel command line. Supports two modes:
+         *
+         * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
+         *    is searched, and the value following this is returned in "value".
+         *
+         * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the the key is found as a
+         *    separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
+         *    this is also accepted, and "value" is returned as NULL.
+         *
+         * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
+         *
+         * In all three cases, > 0 is returned if the key is found, 0 if not.*/
+
+        if (isempty(key))
+                return -EINVAL;
+
+        if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
+                return -EINVAL;
 
         r = proc_cmdline(&line);
         if (r < 0)
                 if (r == 0)
                         break;
 
-                /* Filter out arguments that are intended only for the
-                 * initrd */
+                /* Automatically filter out arguments that are intended only for the initrd, if we are not in the
+                 * initrd. */
                 if (!in_initrd() && startswith(word, "rd."))
                         continue;
 
                 if (value) {
-                        e = startswith(word, key);
+                        e = proc_cmdline_key_startswith(word, key);
                         if (!e)
                                 continue;
 
-                        r = free_and_strdup(&ret, e);
-                        if (r < 0)
-                                return r;
+                        if (*e == '=') {
+                                r = free_and_strdup(&ret, e+1);
+                                if (r < 0)
+                                        return r;
+
+                                found = true;
+
+                        } else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
+                                found = true;
 
-                        found = true;
                 } else {
                         if (streq(word, key))
                                 found = true;
         }
 
         return found;
+}
+
+int proc_cmdline_get_bool(const char *key, bool *ret) {
+        _cleanup_free_ char *v = NULL;
+        int r;
+
+        assert(ret);
+
+        r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                *ret = false;
+                return 0;
+        }
+
+        if (v) { /* parameter passed */
+                r = parse_boolean(v);
+                if (r < 0)
+                        return r;
+                *ret = r;
+        } else /* no parameter passed */
+                *ret = true;
 
+        return 1;
 }
 
 #if 0 /// UNNEEDED by elogind
 int shall_restore_state(void) {
-        _cleanup_free_ char *value = NULL;
+        bool ret;
         int r;
 
-        r = get_proc_cmdline_key("systemd.restore_state=", &value);
+        r = proc_cmdline_get_bool("systemd.restore_state", &ret);
         if (r < 0)
                 return r;
-        if (r == 0)
-                return true;
 
-        return parse_boolean(value);
+        return r > 0 ? ret : true;
 }
 
 static const char * const rlmap[] = {