X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbasic%2Fproc-cmdline.c;h=895e21570b5eaacbf8250ddb68f81fcb03f5019c;hb=6357ed92bd48120109f246b34e0fa8977a2caedc;hp=62c801fe49ffa7d8f52c6ee2be2e16069f701f93;hpb=07045a1a92c839fd2af80bd0c060a595021bc3b3;p=elogind.git diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 62c801fe4..895e21570 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -34,15 +34,30 @@ #include "virt.h" int proc_cmdline(char **ret) { + const char *e; assert(ret); + /* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */ + e = secure_getenv("SYSTEMD_PROC_CMDLINE"); + if (e) { + char *m; + + m = strdup(e); + if (!m) + return -ENOMEM; + + *ret = m; + return 0; + } + if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); } -int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { +int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) { + _cleanup_free_ char *line = NULL; const char *p; int r; @@ -56,7 +71,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { p = line; for (;;) { _cleanup_free_ char *word = NULL; - char *value = NULL; + char *value, *key, *q; r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) @@ -64,16 +79,23 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { if (r == 0) break; - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; + key = word; + + /* Filter out arguments that are intended only for the initrd */ + q = startswith(word, "rd."); + if (q) { + if (!in_initrd()) + continue; - value = strchr(word, '='); + if (flags & PROC_CMDLINE_STRIP_RD_PREFIX) + key = q; + } + + value = strchr(key, '='); if (value) *(value++) = 0; - r = parse_item(word, value); + r = parse_item(key, value, data); if (r < 0) return r; } @@ -81,13 +103,64 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { 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 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) @@ -104,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; @@ -131,21 +209,43 @@ 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; } #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[] = { @@ -161,17 +261,29 @@ static const char * const rlmap[] = { "3", SPECIAL_MULTI_USER_TARGET, "4", SPECIAL_MULTI_USER_TARGET, "5", SPECIAL_GRAPHICAL_TARGET, + NULL +}; + +static const char * const rlmap_initrd[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + NULL }; const char* runlevel_to_target(const char *word) { size_t i; + const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd + : rlmap; if (!word) return NULL; - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) - return rlmap[i+1]; + if (in_initrd() && (word = startswith(word, "rd.")) == NULL) + return NULL; + + for (i = 0; rlmap_ptr[i] != NULL; i += 2) + if (streq(word, rlmap_ptr[i])) + return rlmap_ptr[i+1]; return NULL; }