]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util-lib: various improvements to kernel command line parsing
authorLennart Poettering <lennart@poettering.net>
Mon, 12 Dec 2016 17:29:15 +0000 (18:29 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 21 Dec 2016 18:09:08 +0000 (19:09 +0100)
This improves kernel command line parsing in a number of ways:

a) An kernel option "foo_bar=xyz" is now considered equivalent to
   "foo-bar-xyz", i.e. when comparing kernel command line option names "-" and
   "_" are now considered equivalent (this only applies to the option names
   though, not the option values!). Most of our kernel options used "-" as word
   separator in kernel command line options so far, but some used "_". With
   this change, which was a source of confusion for users (well, at least of
   one user: myself, I just couldn't remember that it's systemd.debug-shell,
   not systemd.debug_shell). Considering both as equivalent is inspired how
   modern kernel module loading normalizes all kernel module names to use
   underscores now too.

b) All options previously using a dash for separating words in kernel command
   line options now use an underscore instead, in all documentation and in
   code. Since a) has been implemented this should not create any compatibility
   problems, but normalizes our documentation and our code.

c) All kernel command line options which take booleans (or are boolean-like)
   have been reworked so that "foobar" (without argument) is now equivalent to
   "foobar=1" (but not "foobar=0"), thus normalizing the handling of our
   boolean arguments. Specifically this means systemd.debug-shell and
   systemd_debug_shell=1 are now entirely equivalent.

d) All kernel command line options which take an argument, and where no
   argument is specified will now result in a log message. e.g. passing just
   "systemd.unit" will no result in a complain that it needs an argument. This
   is implemented in the proc_cmdline_missing_value() function.

e) There's now a call proc_cmdline_get_bool() similar to proc_cmdline_get_key()
   that parses booleans (following the logic explained in c).

f) The proc_cmdline_parse() call's boolean argument has been replaced by a new
   flags argument that takes a common set of bits with proc_cmdline_get_key().

g) All kernel command line APIs now begin with the same "proc_cmdline_" prefix.

h) There are now tests for much of this. Yay!

22 files changed:
man/kernel-command-line.xml
man/systemd-debug-generator.xml
man/systemd-modules-load.service.xml
man/systemd-udevd.service.xml
src/basic/cgroup-util.c
src/basic/log.c
src/basic/proc-cmdline.c
src/basic/proc-cmdline.h
src/core/main.c
src/cryptsetup/cryptsetup-generator.c
src/debug-generator/debug-generator.c
src/firstboot/firstboot.c
src/fsck/fsck.c
src/fstab-generator/fstab-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hibernate-resume/hibernate-resume-generator.c
src/journal/journald-server.c
src/modules-load/modules-load.c
src/quotacheck/quotacheck.c
src/test/test-proc-cmdline.c
src/udev/net/link-config.c
src/udev/udevd.c

index c86e45265fe946b126202e92fe1b4401c1a04904..78e45e66a97e3fdf13891f3538c92305584f3dad 100644 (file)
       <varlistentry>
         <term><varname>systemd.mask=</varname></term>
         <term><varname>systemd.wants=</varname></term>
-        <term><varname>systemd.debug-shell</varname></term>
+        <term><varname>systemd.debug_shell</varname></term>
         <listitem>
           <para>Additional parameters understood by
           <citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       </varlistentry>
 
       <varlistentry>
-        <term><varname>udev.log-priority=</varname></term>
-        <term><varname>rd.udev.log-priority=</varname></term>
-        <term><varname>udev.children-max=</varname></term>
-        <term><varname>rd.udev.children-max=</varname></term>
-        <term><varname>udev.exec-delay=</varname></term>
-        <term><varname>rd.udev.exec-delay=</varname></term>
-        <term><varname>udev.event-timeout=</varname></term>
-        <term><varname>rd.udev.event-timeout=</varname></term>
+        <term><varname>udev.log_priority=</varname></term>
+        <term><varname>rd.udev.log_priority=</varname></term>
+        <term><varname>udev.children_max=</varname></term>
+        <term><varname>rd.udev.children_max=</varname></term>
+        <term><varname>udev.exec_delay=</varname></term>
+        <term><varname>rd.udev.exec_delay=</varname></term>
+        <term><varname>udev.event_timeout=</varname></term>
+        <term><varname>rd.udev.event_timeout=</varname></term>
         <term><varname>net.ifnames=</varname></term>
 
         <listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><varname>modules-load=</varname></term>
-        <term><varname>rd.modules-load=</varname></term>
+        <term><varname>modules_load=</varname></term>
+        <term><varname>rd.modules_load=</varname></term>
 
         <listitem>
           <para>Load a specific kernel module early at boot. For
index 5c5e9fc4a1a6e892eef318b2fd9227addd0d4eb5..0a66b9bbf928793132ef40effe0d939d27d099d6 100644 (file)
@@ -70,7 +70,7 @@
     the initial transaction. This is useful to start one or more
     additional units at boot. May be specified more than once.</para>
 
-    <para>If the <option>systemd.debug-shell</option> option is
+    <para>If the <option>systemd.debug_shell</option> option is
     specified, the debug shell service
     <literal>debug-shell.service</literal> is pulled into the boot
     transaction. It will spawn a debug shell on tty9 during early
index b25929b2e409fc7891c2e17aea839fb120d8eaa7..ee097d7f5c9f6be7799eb1eba26c3cd8e09acf08 100644 (file)
@@ -73,8 +73,8 @@
     <variablelist class='kernel-commandline-options'>
 
       <varlistentry>
-        <term><varname>modules-load=</varname></term>
-        <term><varname>rd.modules-load=</varname></term>
+        <term><varname>modules_load=</varname></term>
+        <term><varname>rd.modules_load=</varname></term>
 
         <listitem><para>Takes a comma-separated list of kernel modules
         to statically load during early boot. The option prefixed with
index 243fd064710cf22ffc8d9a48406e22b50cde0038..81b957b0c813230910c5e9dd24b6b36e26291daa 100644 (file)
       <para>Parameters starting with "rd." will be read when
       <command>systemd-udevd</command> is used in an initrd.</para>
       <varlistentry>
-        <term><varname>udev.log-priority=</varname></term>
-        <term><varname>rd.udev.log-priority=</varname></term>
+        <term><varname>udev.log_priority=</varname></term>
+        <term><varname>rd.udev.log_priority=</varname></term>
         <listitem>
           <para>Set the log level.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
-        <term><varname>udev.children-max=</varname></term>
-        <term><varname>rd.udev.children-max=</varname></term>
+        <term><varname>udev.children_max=</varname></term>
+        <term><varname>rd.udev.children_max=</varname></term>
         <listitem>
           <para>Limit the number of events executed in parallel.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
-        <term><varname>udev.exec-delay=</varname></term>
-        <term><varname>rd.udev.exec-delay=</varname></term>
+        <term><varname>udev.exec_delay=</varname></term>
+        <term><varname>rd.udev.exec_delay=</varname></term>
         <listitem>
           <para>Delay the execution of <varname>RUN</varname> instructions by the given
           number of seconds. This option might be useful when
         </listitem>
       </varlistentry>
       <varlistentry>
-        <term><varname>udev.event-timeout=</varname></term>
-        <term><varname>rd.udev.event-timeout=</varname></term>
+        <term><varname>udev.event_timeout=</varname></term>
+        <term><varname>rd.udev.event_timeout=</varname></term>
         <listitem>
           <para>Wait for events to finish up to the given number
           of seconds. This option might be useful if events are
index dc13025115f6ba5129e9d7ef38810ddcd7aebc9c..d2d18f13f026f0fc11adc5737dae73501fa79560 100644 (file)
@@ -2361,6 +2361,7 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
 bool cg_is_unified_wanted(void) {
         static thread_local int wanted = -1;
         int r, unified;
+        bool b;
 
         /* If the hierarchy is already mounted, then follow whatever
          * was chosen for it. */
@@ -2374,20 +2375,11 @@ bool cg_is_unified_wanted(void) {
         if (wanted >= 0)
                 return wanted;
 
-        r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
-        if (r > 0)
-                return (wanted = true);
-        else {
-                _cleanup_free_ char *value = NULL;
-
-                r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
-                if (r < 0)
-                        return false;
-                if (r == 0)
-                        return (wanted = false);
+        r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
+        if (r < 0)
+                return false;
 
-                return (wanted = parse_boolean(value) > 0);
-        }
+        return (wanted = r > 0 ? b : false);
 }
 
 bool cg_is_legacy_wanted(void) {
@@ -2397,6 +2389,7 @@ bool cg_is_legacy_wanted(void) {
 bool cg_is_unified_systemd_controller_wanted(void) {
         static thread_local int wanted = -1;
         int r, unified;
+        bool b;
 
         /* If the unified hierarchy is requested in full, no need to
          * bother with this. */
@@ -2415,23 +2408,11 @@ bool cg_is_unified_systemd_controller_wanted(void) {
         if (wanted >= 0)
                 return wanted;
 
-        r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller", NULL);
-        if (r > 0)
-                wanted = false;
-        else {
-                _cleanup_free_ char *value = NULL;
-
-                r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller=", &value);
-                if (r < 0)
-                        return false;
-
-                if (r == 0)
-                        wanted = false;
-                else
-                        wanted = parse_boolean(value) <= 0;
-        }
+        r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
+        if (r < 0)
+                return false;
 
-        return wanted;
+        return (wanted = r > 0 ? b : false);
 }
 
 bool cg_is_legacy_systemd_controller_wanted(void) {
index 557212c02278aa4d0d0e42eed209ddf0bff18a26..1362b1c086fc33e43528ca65143ae6b3d5418551 100644 (file)
@@ -981,24 +981,30 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
         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);
         }
 
@@ -1009,10 +1015,9 @@ void log_parse_environment(void) {
         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)
index 98c94ed5e26eeb7c626ffcca5c46cd35485d8dc4..6ecb6c3f0d46a4773e55cc562e3a842fc61657c3 100644 (file)
@@ -56,9 +56,8 @@ int proc_cmdline(char **ret) {
                 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;
@@ -72,7 +71,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
         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)
@@ -80,17 +79,23 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
                 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;
         }
@@ -98,13 +103,64 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
         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)
@@ -121,21 +177,26 @@ int get_proc_cmdline_key(const char *key, char **value) {
                 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;
@@ -148,20 +209,42 @@ int get_proc_cmdline_key(const char *key, char **value) {
         }
 
         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;
 }
 
 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[] = {
index 6d6ee95c11f5508e7b3bc5e433976ba7ddb06555..ebfed355e95bfefd8887d65776b950a038e77452 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdbool.h>
+
+#include "log.h"
+
+enum {
+        PROC_CMDLINE_STRIP_RD_PREFIX = 1,
+        PROC_CMDLINE_VALUE_OPTIONAL = 2,
+};
+
+typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
+
 int proc_cmdline(char **ret);
-int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
-                       void *data,
-                       bool strip_prefix);
-int get_proc_cmdline_key(const char *parameter, char **value);
+
+int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, unsigned flags);
+
+int proc_cmdline_get_key(const char *parameter, unsigned flags, char **value);
+int proc_cmdline_get_bool(const char *key, bool *ret);
+
+char *proc_cmdline_key_startswith(const char *s, const char *prefix);
+bool proc_cmdline_key_streq(const char *x, const char *y);
 
 int shall_restore_state(void);
 const char* runlevel_to_target(const char *rl);
+
+/* A little helper call, to be used in proc_cmdline_parse_t callbacks */
+static inline bool proc_cmdline_value_missing(const char *key, const char *value) {
+        if (!value) {
+                log_warning("Missing argument for %s= kernel command line switch, ignoring.", key);
+                return true;
+        }
+
+        return false;
+}
index 6ec996577c82ad3f7d7877acf60539a48cfcc4bf..56a81ab94abbd9d73319752dc5da099f35a59497 100644 (file)
@@ -337,60 +337,73 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
         assert(key);
 
-        if (streq(key, "systemd.unit") && value) {
+        if (STR_IN_SET(key, "systemd.unit", "rd.systemd.unit")) {
 
-                if (!in_initrd())
-                        return free_and_strdup(&arg_default_unit, value);
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
-        } else if (streq(key, "rd.systemd.unit") && value) {
-
-                if (in_initrd())
-                        return free_and_strdup(&arg_default_unit, value);
+                if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
+                        log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
+                else if (in_initrd() == !!startswith(key, "rd.")) {
+                        if (free_and_strdup(&arg_default_unit, value) < 0)
+                                return log_oom();
+                }
 
-        } else if (streq(key, "systemd.dump_core") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.dump_core")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse dump core switch %s. Ignoring.", value);
                 else
                         arg_dump_core = r;
 
-        } else if (streq(key, "systemd.crash_chvt") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.crash_chvt")) {
 
-                if (parse_crash_chvt(value) < 0)
+                if (!value)
+                        arg_crash_chvt = 0; /* turn on */
+                else if (parse_crash_chvt(value) < 0)
                         log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
 
-        } else if (streq(key, "systemd.crash_shell") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.crash_shell")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse crash shell switch %s. Ignoring.", value);
                 else
                         arg_crash_shell = r;
 
-        } else if (streq(key, "systemd.crash_reboot") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.crash_reboot")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse crash reboot switch %s. Ignoring.", value);
                 else
                         arg_crash_reboot = r;
 
-        } else if (streq(key, "systemd.confirm_spawn") && value) {
-
-                arg_confirm_spawn = mfree(arg_confirm_spawn);
+        } else if (proc_cmdline_key_streq(key, "systemd.confirm_spawn")) {
+                char *s;
 
-                r = parse_confirm_spawn(value, &arg_confirm_spawn);
+                r = parse_confirm_spawn(value, &s);
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse confirm_spawn switch %s. Ignoring.", value);
+                else {
+                        free(arg_confirm_spawn);
+                        arg_confirm_spawn = s;
+                }
 
-        } else if (streq(key, "systemd.show_status") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.show_status")) {
 
-                r = parse_show_status(value, &arg_show_status);
-                if (r < 0)
-                        log_warning("Failed to parse show status switch %s. Ignoring.", value);
+                if (value) {
+                        r = parse_show_status(value, &arg_show_status);
+                        if (r < 0)
+                                log_warning("Failed to parse show status switch %s. Ignoring.", value);
+                } else
+                        arg_show_status = SHOW_STATUS_YES;
 
-        } else if (streq(key, "systemd.default_standard_output") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.default_standard_output")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 r = exec_output_from_string(value);
                 if (r < 0)
@@ -398,7 +411,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 else
                         arg_default_std_output = r;
 
-        } else if (streq(key, "systemd.default_standard_error") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.default_standard_error")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 r = exec_output_from_string(value);
                 if (r < 0)
@@ -406,24 +422,42 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 else
                         arg_default_std_error = r;
 
-        } else if (streq(key, "systemd.setenv") && value) {
+        } else if (streq(key, "systemd.setenv")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (env_assignment_is_valid(value)) {
                         char **env;
 
                         env = strv_env_set(arg_default_environment, value);
-                        if (env)
-                                arg_default_environment = env;
-                        else
-                                log_warning_errno(ENOMEM, "Setting environment variable '%s' failed, ignoring: %m", value);
+                        if (!env)
+                                return log_oom();
+
+                        arg_default_environment = env;
                 } else
                         log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
 
-        } else if (streq(key, "systemd.machine_id") && value) {
+        } else if (proc_cmdline_key_streq(key, "systemd.machine_id")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = set_machine_id(value);
+                if (r < 0)
+                        log_warning("MachineID '%s' is not valid. Ignoring.", value);
 
-               r = set_machine_id(value);
-               if (r < 0)
-                       log_warning("MachineID '%s' is not valid. Ignoring.", value);
+        } else if (proc_cmdline_key_streq(key, "systemd.default_timeout_start_sec")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = parse_sec(value, &arg_default_timeout_start_usec);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
+
+                if (arg_default_timeout_start_usec <= 0)
+                        arg_default_timeout_start_usec = USEC_INFINITY;
 
         } else if (streq(key, "quiet") && !value) {
 
@@ -445,15 +479,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 target = runlevel_to_target(key);
                 if (target)
                         return free_and_strdup(&arg_default_unit, target);
-
-        } else if (streq(key, "systemd.default_timeout_start_sec") && value) {
-
-                r = parse_sec(value, &arg_default_timeout_start_usec);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
-
-                if (arg_default_timeout_start_usec <= 0)
-                        arg_default_timeout_start_usec = USEC_INFINITY;
         }
 
         return 0;
@@ -1341,10 +1366,9 @@ static int fixup_environment(void) {
          * However if TERM was configured through the kernel
          * command line then leave it alone. */
 
-        r = get_proc_cmdline_key("TERM=", &term);
+        r = proc_cmdline_get_key("TERM", 0, &term);
         if (r < 0)
                 return r;
-
         if (r == 0) {
                 term = strdup(default_term_for_tty("/dev/console"));
                 if (!term)
@@ -1591,7 +1615,7 @@ int main(int argc, char *argv[]) {
         }
 
         if (arg_system) {
-                r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+                r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
         }
index 68029865a04e63a77b9148f967ba6ddfa617e12f..e2a43f7195f432325afa8ff914e7fac727633fee 100644 (file)
@@ -278,27 +278,30 @@ static crypto_device *get_crypto_device(const char *uuid) {
 }
 
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
-        int r;
-        crypto_device *d;
         _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
+        crypto_device *d;
+        int r;
 
-        if (streq(key, "luks") && value) {
+        if (streq(key, "luks")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : 1;
                 if (r < 0)
-                        log_warning("Failed to parse luks switch %s. Ignoring.", value);
+                        log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value);
                 else
                         arg_enabled = r;
 
-        } else if (streq(key, "luks.crypttab") && value) {
+        } else if (streq(key, "luks.crypttab")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : 1;
                 if (r < 0)
-                        log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value);
+                        log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value);
                 else
                         arg_read_crypttab = r;
 
-        } else if (streq(key, "luks.uuid") && value) {
+        } else if (streq(key, "luks.uuid")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 d = get_crypto_device(startswith(value, "luks-") ? value+5 : value);
                 if (!d)
@@ -306,7 +309,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
                 d->create = arg_whitelist = true;
 
-        } else if (streq(key, "luks.options") && value) {
+        } else if (streq(key, "luks.options")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
                 if (r == 2) {
@@ -314,13 +320,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                         if (!d)
                                 return log_oom();
 
-                        free(d->options);
-                        d->options = uuid_value;
-                        uuid_value = NULL;
+                        free_and_replace(d->options, uuid_value);
                 } else if (free_and_strdup(&arg_default_options, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "luks.key") && value) {
+        } else if (streq(key, "luks.key")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
                 if (r == 2) {
@@ -328,13 +335,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                         if (!d)
                                 return log_oom();
 
-                        free(d->keyfile);
-                        d->keyfile = uuid_value;
-                        uuid_value = NULL;
+                        free_and_replace(d->keyfile, uuid_value);
                 } else if (free_and_strdup(&arg_default_keyfile, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "luks.name") && value) {
+        } else if (streq(key, "luks.name")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
                 if (r == 2) {
@@ -478,7 +486,7 @@ int main(int argc, char *argv[]) {
         if (!arg_disks)
                 goto cleanup;
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
         if (r < 0) {
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
                 r = EXIT_FAILURE;
index 28ebe36b38752052f9f405244ae89921719fb98b..1d8bc71e571760bb3d3422b2596f12d5074ec31e 100644 (file)
@@ -39,56 +39,53 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
         assert(key);
 
         if (streq(key, "systemd.mask")) {
+                char *n;
 
-                if (!value)
-                        log_error("Missing argument for systemd.mask= kernel command line parameter.");
-                else {
-                        char *n;
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
-                        r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to glob unit name: %m");
+                r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to glob unit name: %m");
 
-                        r = strv_consume(&arg_mask, n);
-                        if (r < 0)
-                                return log_oom();
-                }
+                r = strv_consume(&arg_mask, n);
+                if (r < 0)
+                        return log_oom();
 
         } else if (streq(key, "systemd.wants")) {
+                char *n;
 
-                if (!value)
-                        log_error("Missing argument for systemd.want= kernel command line parameter.");
-                else {
-                        char *n;
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
-                        r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to glob unit name: %m");
+                r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to glob unit name: %m");
 
-                        r = strv_consume(&arg_wants, n);
-                        if (r < 0)
-                                return log_oom();
-                }
+                r = strv_consume(&arg_wants, n);
+                if (r < 0)
+                        return log_oom();
 
-        } else if (streq(key, "systemd.debug-shell")) {
+        } else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) {
 
                 if (value) {
                         r = parse_boolean(value);
                         if (r < 0)
-                                log_error("Failed to parse systemd.debug-shell= argument '%s', ignoring.", value);
+                                log_error("Failed to parse systemd.debug_shell= argument '%s', ignoring.", value);
                         else
                                 arg_debug_shell = r;
                 } else
                         arg_debug_shell = true;
+
         } else if (streq(key, "systemd.unit")) {
 
-                if (!value)
-                        log_error("Missing argument for systemd.unit= kernel command line parameter.");
-                else {
-                        r = free_and_strdup(&arg_default_unit, value);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to set default unit %s: %m", value);
-                }
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = free_and_strdup(&arg_default_unit, value);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set default unit %s: %m", value);
+
         } else if (!value) {
                 const char *target;
 
@@ -173,7 +170,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index 7c615abbc581f0ba3d95823a28c860c9a5e2e160..fd7051f21eb14b7f4916d4c96a6fccb3a0cd2e24 100644 (file)
@@ -826,7 +826,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        _cleanup_free_ char *enabled = NULL;
+        bool enabled;
         int r;
 
         r = parse_argv(argc, argv);
@@ -839,15 +839,14 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = get_proc_cmdline_key("systemd.firstboot=", &enabled);
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                r = parse_boolean(enabled);
-                if (r == 0)
-                        goto finish;
-                if (r < 0)
-                        log_warning_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %s", enabled);
+        r = proc_cmdline_get_bool("systemd.firstboot", &enabled);
+        if (r < 0) {
+                log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring.");
+                goto finish;
+        }
+        if (r > 0 && !enabled) {
+                r = 0; /* disabled */
+                goto finish;
         }
 
         r = process_locale();
index be25c6a2b29b554c6d6bce57ee370ecc7c8d1859..2100681e1773b0b9387c0648f1c36940d2a5cd82 100644 (file)
@@ -99,7 +99,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
         assert(key);
 
-        if (streq(key, "fsck.mode") && value) {
+        if (streq(key, "fsck.mode")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (streq(value, "auto"))
                         arg_force = arg_skip = false;
@@ -110,7 +113,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 else
                         log_warning("Invalid fsck.mode= parameter '%s'. Ignoring.", value);
 
-        } else if (streq(key, "fsck.repair") && value) {
+        } else if (streq(key, "fsck.repair")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (streq(value, "preen"))
                         arg_repair = "-a";
@@ -293,7 +299,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index f6a912ae06add407e212a43bdca31422969aa217..84163abbc533f29dcad8ec4aa58febd23cca791f 100644 (file)
@@ -612,27 +612,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
          * instance should take precedence.  In the case of multiple rootflags=
          * or usrflags= the arguments should be concatenated */
 
-        if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
+        if (STR_IN_SET(key, "fstab", "rd.fstab")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : 1;
                 if (r < 0)
                         log_warning("Failed to parse fstab switch %s. Ignoring.", value);
                 else
                         arg_fstab_enabled = r;
 
-        } else if (streq(key, "root") && value) {
+        } else if (streq(key, "root")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (free_and_strdup(&arg_root_what, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "rootfstype") && value) {
+        } else if (streq(key, "rootfstype")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (free_and_strdup(&arg_root_fstype, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "rootflags") && value) {
+        } else if (streq(key, "rootflags")) {
                 char *o;
 
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 o = arg_root_options ?
                         strjoin(arg_root_options, ",", value) :
                         strdup(value);
@@ -642,19 +651,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 free(arg_root_options);
                 arg_root_options = o;
 
-        } else if (streq(key, "mount.usr") && value) {
+        } else if (streq(key, "mount.usr")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (free_and_strdup(&arg_usr_what, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "mount.usrfstype") && value) {
+        } else if (streq(key, "mount.usrfstype")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (free_and_strdup(&arg_usr_fstype, value) < 0)
                         return log_oom();
 
-        } else if (streq(key, "mount.usrflags") && value) {
+        } else if (streq(key, "mount.usrflags")) {
                 char *o;
 
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 o = arg_usr_options ?
                         strjoin(arg_usr_options, ",", value) :
                         strdup(value);
@@ -689,7 +707,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index a60905de9424c22685d8dc84b603a10541c5ac6f..f94f9f782781f9360122e261a1bf5c4322f94adb 100644 (file)
@@ -912,15 +912,18 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
         assert(key);
 
-        if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
+        if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto")) {
 
-                r = parse_boolean(value);
+                r = value ? parse_boolean(value) : 1;
                 if (r < 0)
                         log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
                 else
                         arg_enabled = r;
 
-        } else if (streq(key, "root") && value) {
+        } else if (streq(key, "root")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 /* Disable root disk logic if there's a root= value
                  * specified (unless it happens to be "gpt-auto") */
@@ -1018,7 +1021,7 @@ int main(int argc, char *argv[]) {
                 return EXIT_SUCCESS;
         }
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index 9f59c04b2673acae86d30280e3214cec898b3258..a97fe668d5020355a9ecbb3571fc7fb8a789519a 100644 (file)
 #include "util.h"
 
 static const char *arg_dest = "/tmp";
-static char *arg_resume_dev = NULL;
+static char *arg_resume_device = NULL;
 
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
 
-        if (streq(key, "resume") && value) {
-                free(arg_resume_dev);
-                arg_resume_dev = fstab_node_to_udev_node(value);
-                if (!arg_resume_dev)
+        if (streq(key, "resume")) {
+                char *s;
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                s = fstab_node_to_udev_node(value);
+                if (!s)
                         return log_oom();
+
+                free(arg_resume_device);
+                arg_resume_device = s;
         }
 
         return 0;
@@ -49,10 +56,10 @@ static int process_resume(void) {
         _cleanup_free_ char *name = NULL, *lnk = NULL;
         int r;
 
-        if (!arg_resume_dev)
+        if (!arg_resume_device)
                 return 0;
 
-        r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service", &name);
+        r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", &name);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate unit name: %m");
 
@@ -88,12 +95,12 @@ int main(int argc, char *argv[]) {
         if (!in_initrd())
                 return EXIT_SUCCESS;
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
         r = process_resume();
-        free(arg_resume_dev);
+        free(arg_resume_device);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 5c6941ebd616527ae560386840344d1204de8f42..6bdb375fb7882dc66ba5f9367dfefe9b7084b70c 100644 (file)
@@ -1532,60 +1532,93 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
         assert(s);
 
-        if (streq(key, "systemd.journald.forward_to_syslog")) {
+        if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_syslog")) {
+
                 r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value);
                 else
                         s->forward_to_syslog = r;
-        } else if (streq(key, "systemd.journald.forward_to_kmsg")) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_kmsg")) {
+
                 r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value);
                 else
                         s->forward_to_kmsg = r;
-        } else if (streq(key, "systemd.journald.forward_to_console")) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_console")) {
+
                 r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value);
                 else
                         s->forward_to_console = r;
-        } else if (streq(key, "systemd.journald.forward_to_wall")) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_wall")) {
+
                 r = value ? parse_boolean(value) : true;
                 if (r < 0)
                         log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value);
                 else
                         s->forward_to_wall = r;
-        } else if (streq(key, "systemd.journald.max_level_console") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_console")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = log_level_from_string(value);
                 if (r < 0)
                         log_warning("Failed to parse max level console value \"%s\". Ignoring.", value);
                 else
                         s->max_level_console = r;
-        } else if (streq(key, "systemd.journald.max_level_store") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_store")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = log_level_from_string(value);
                 if (r < 0)
                         log_warning("Failed to parse max level store value \"%s\". Ignoring.", value);
                 else
                         s->max_level_store = r;
-        } else if (streq(key, "systemd.journald.max_level_syslog") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_syslog")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = log_level_from_string(value);
                 if (r < 0)
                         log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value);
                 else
                         s->max_level_syslog = r;
-        } else if (streq(key, "systemd.journald.max_level_kmsg") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_kmsg")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = log_level_from_string(value);
                 if (r < 0)
                         log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value);
                 else
                         s->max_level_kmsg = r;
-        } else if (streq(key, "systemd.journald.max_level_wall") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_wall")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = log_level_from_string(value);
                 if (r < 0)
                         log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value);
                 else
                         s->max_level_wall = r;
+
         } else if (startswith(key, "systemd.journald"))
                 log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
 
@@ -1898,7 +1931,10 @@ int server_init(Server *s) {
         journal_reset_metrics(&s->runtime_storage.metrics);
 
         server_parse_config_file(s);
-        parse_proc_cmdline(parse_proc_cmdline_item, s, true);
+
+        r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX);
+        if (r < 0)
+                log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
         if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) {
                 log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
index 0901fea8dc35e5f97be5d5f5baeb282222bde766..615998a6f60d679a04e2c87b0716e3e18ed9e801 100644 (file)
@@ -62,7 +62,11 @@ static int add_modules(const char *p) {
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
         int r;
 
-        if (streq(key, "modules-load") && value) {
+        if (proc_cmdline_key_streq(key, "modules_load")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = add_modules(value);
                 if (r < 0)
                         return r;
@@ -226,7 +230,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index 2714cde5c7c973b2ccb85e5441067f2166a6a808..2495bcbefde30c2168e7da1d62ced3088edbd249 100644 (file)
@@ -34,7 +34,10 @@ static bool arg_force = false;
 
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
 
-        if (streq(key, "quotacheck.mode") && value) {
+        if (streq(key, "quotacheck.mode")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
 
                 if (streq(value, "auto"))
                         arg_force = arg_skip = false;
@@ -88,7 +91,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
 
index 4101678f19d69994a177f513ba6846eeb492cfb4..12dac8585b663598fdcb3585698affd335da1a3f 100644 (file)
@@ -35,8 +35,8 @@ static int parse_item(const char *key, const char *value, void *data) {
         return 0;
 }
 
-static void test_parse_proc_cmdline(void) {
-        assert_se(parse_proc_cmdline(parse_item, &obj, true) >= 0);
+static void test_proc_cmdline_parse(void) {
+        assert_se(proc_cmdline_parse(parse_item, &obj, true) >= 0);
 }
 
 static void test_runlevel_to_target(void) {
@@ -55,11 +55,101 @@ static void test_runlevel_to_target(void) {
         assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET));
 }
 
+static void test_proc_cmdline_get_key(void) {
+        _cleanup_free_ char *value = NULL;
+
+        putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm");
+
+        assert_se(proc_cmdline_get_key("", 0, &value) == -EINVAL);
+        assert_se(proc_cmdline_get_key("abc", 0, NULL) == 0);
+        assert_se(proc_cmdline_get_key("abc", 0, &value) == 0 && value == NULL);
+        assert_se(proc_cmdline_get_key("abc", PROC_CMDLINE_VALUE_OPTIONAL, &value) == 0 && value == NULL);
+
+        assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("foo_bar", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "quux"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("foo-bar", 0, &value) > 0 && streq_ptr(value, "quux"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("foo-bar", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "quux"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("foo-bar", 0, NULL) == 0);
+        assert_se(proc_cmdline_get_key("foo-bar", PROC_CMDLINE_VALUE_OPTIONAL, NULL) == -EINVAL);
+
+        assert_se(proc_cmdline_get_key("wuff-piep", 0, &value) > 0 && streq_ptr(value, "tuet"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("wuff-piep", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "tuet"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("wuff_piep", 0, &value) > 0 && streq_ptr(value, "tuet"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("wuff_piep", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "tuet"));
+        value = mfree(value);
+        assert_se(proc_cmdline_get_key("wuff_piep", 0, NULL) == 0);
+        assert_se(proc_cmdline_get_key("wuff_piep", PROC_CMDLINE_VALUE_OPTIONAL, NULL) == -EINVAL);
+
+        assert_se(proc_cmdline_get_key("zumm", 0, &value) == 0 && value == NULL);
+        assert_se(proc_cmdline_get_key("zumm", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && value == NULL);
+        assert_se(proc_cmdline_get_key("zumm", 0, NULL) > 0);
+}
+
+static void test_proc_cmdline_get_bool(void) {
+        bool value = false;
+
+        putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep");
+
+        assert_se(proc_cmdline_get_bool("", &value) == -EINVAL);
+        assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false);
+        assert_se(proc_cmdline_get_bool("foo_bar", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("foo-bar", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("bar-waldo", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("bar_waldo", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("x_y-z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x-y-z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x-y_z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("x_y_z", &value) > 0 && value == false);
+        assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false);
+}
+
+static void test_proc_cmdline_key_streq(void) {
+
+        assert_se(proc_cmdline_key_streq("", ""));
+        assert_se(proc_cmdline_key_streq("a", "a"));
+        assert_se(!proc_cmdline_key_streq("", "a"));
+        assert_se(!proc_cmdline_key_streq("a", ""));
+        assert_se(proc_cmdline_key_streq("a", "a"));
+        assert_se(!proc_cmdline_key_streq("a", "b"));
+        assert_se(proc_cmdline_key_streq("x-y-z", "x-y-z"));
+        assert_se(proc_cmdline_key_streq("x-y-z", "x_y_z"));
+        assert_se(proc_cmdline_key_streq("x-y-z", "x-y_z"));
+        assert_se(proc_cmdline_key_streq("x-y-z", "x_y-z"));
+        assert_se(proc_cmdline_key_streq("x_y-z", "x-y_z"));
+        assert_se(!proc_cmdline_key_streq("x_y-z", "x-z_z"));
+}
+
+static void test_proc_cmdline_key_startswith(void) {
+
+        assert_se(proc_cmdline_key_startswith("", ""));
+        assert_se(proc_cmdline_key_startswith("x", ""));
+        assert_se(!proc_cmdline_key_startswith("", "x"));
+        assert_se(proc_cmdline_key_startswith("x", "x"));
+        assert_se(!proc_cmdline_key_startswith("x", "y"));
+        assert_se(!proc_cmdline_key_startswith("foo-bar", "quux"));
+        assert_se(proc_cmdline_key_startswith("foo-bar", "foo"));
+        assert_se(proc_cmdline_key_startswith("foo-bar", "foo-bar"));
+        assert_se(proc_cmdline_key_startswith("foo-bar", "foo_bar"));
+        assert_se(proc_cmdline_key_startswith("foo-bar", "foo_"));
+        assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx"));
+}
+
 int main(void) {
         log_parse_environment();
         log_open();
 
-        test_parse_proc_cmdline();
+        test_proc_cmdline_parse();
+        test_proc_cmdline_key_streq();
+        test_proc_cmdline_key_startswith();
+        test_proc_cmdline_get_key();
+        test_proc_cmdline_get_bool();
         test_runlevel_to_target();
 
         return 0;
index 1dca375279adbb699e60f1f10f59a97f74ecf2ba..3af87f13883d1f3d0c1d9c825a483023b2636a0c 100644 (file)
@@ -192,14 +192,9 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
 }
 
 static bool enable_name_policy(void) {
-        _cleanup_free_ char *value = NULL;
-        int r;
-
-        r = get_proc_cmdline_key("net.ifnames=", &value);
-        if (r > 0 && streq(value, "0"))
-            return false;
+        bool b;
 
-        return true;
+        return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
 }
 
 int link_config_load(link_config_ctx *ctx) {
index 895c6f271b54713dfaf9af2d7344602bfc4a9295..dd23054b0d7807aa96eb836a0f4fffe9da254a6c 100644 (file)
@@ -1357,10 +1357,10 @@ static int listen_fds(int *rctrl, int *rnetlink) {
 
 /*
  * read the kernel command line, in case we need to get into debug mode
- *   udev.log-priority=<level>                 syslog priority
- *   udev.children-max=<number of workers>     events are fully serialized if set to 1
- *   udev.exec-delay=<number of seconds>       delay execution of every executed program
- *   udev.event-timeout=<number of seconds>    seconds to wait before terminating an event
+ *   udev.log_priority=<level>                 syslog priority
+ *   udev.children_max=<number of workers>     events are fully serialized if set to 1
+ *   udev.exec_delay=<number of seconds>       delay execution of every executed program
+ *   udev.event_timeout=<number of seconds>    seconds to wait before terminating an event
  */
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
         int r = 0;
@@ -1370,25 +1370,46 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
         if (!value)
                 return 0;
 
-        if (streq(key, "udev.log-priority") && value) {
+        if (proc_cmdline_key_streq(key, "udev.log_priority")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = util_log_priority(value);
                 if (r >= 0)
                         log_set_max_level(r);
-        } else if (streq(key, "udev.event-timeout") && value) {
+
+        } else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = safe_atou64(value, &arg_event_timeout_usec);
                 if (r >= 0) {
                         arg_event_timeout_usec *= USEC_PER_SEC;
                         arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
                 }
-        } else if (streq(key, "udev.children-max") && value)
+
+        } else if (proc_cmdline_key_streq(key, "udev.children_max")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = safe_atou(value, &arg_children_max);
-        else if (streq(key, "udev.exec-delay") && value)
+
+        } else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
                 r = safe_atoi(value, &arg_exec_delay);
-        else if (startswith(key, "udev."))
+
+        } else if (startswith(key, "udev."))
                 log_warning("Unknown udev kernel command line option \"%s\"", key);
 
         if (r < 0)
                 log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
+
         return 0;
 }
 
@@ -1649,7 +1670,7 @@ int main(int argc, char *argv[]) {
         if (r <= 0)
                 goto exit;
 
-        r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
+        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
         if (r < 0)
                 log_warning_errno(r, "failed to parse kernel command line, ignoring: %m");