mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
Merge pull request #26887 from yuwata/proc-cmdline-filter-arguments
proc-cmdline: filter PID1 arguments on container
This commit is contained in:
commit
ddd43f31e3
|
@ -347,6 +347,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
|
@ -108,6 +108,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
|
|
||||||
/* Note the asymmetry: the long option --echo= allows an optional argument, the short option does
|
/* Note the asymmetry: the long option --echo= allows an optional argument, the short option does
|
||||||
* not. */
|
* not. */
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+hen", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+hen", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
75
src/basic/getopt-defs.h
Normal file
75
src/basic/getopt-defs.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#define SYSTEMD_GETOPT_SHORT_OPTIONS "hDbsz:"
|
||||||
|
|
||||||
|
#define COMMON_GETOPT_ARGS \
|
||||||
|
ARG_LOG_LEVEL = 0x100, \
|
||||||
|
ARG_LOG_TARGET, \
|
||||||
|
ARG_LOG_COLOR, \
|
||||||
|
ARG_LOG_LOCATION, \
|
||||||
|
ARG_LOG_TIME
|
||||||
|
|
||||||
|
#define SYSTEMD_GETOPT_ARGS \
|
||||||
|
ARG_UNIT, \
|
||||||
|
ARG_SYSTEM, \
|
||||||
|
ARG_USER, \
|
||||||
|
ARG_TEST, \
|
||||||
|
ARG_NO_PAGER, \
|
||||||
|
ARG_VERSION, \
|
||||||
|
ARG_DUMP_CONFIGURATION_ITEMS, \
|
||||||
|
ARG_DUMP_BUS_PROPERTIES, \
|
||||||
|
ARG_BUS_INTROSPECT, \
|
||||||
|
ARG_DUMP_CORE, \
|
||||||
|
ARG_CRASH_CHVT, \
|
||||||
|
ARG_CRASH_SHELL, \
|
||||||
|
ARG_CRASH_REBOOT, \
|
||||||
|
ARG_CONFIRM_SPAWN, \
|
||||||
|
ARG_SHOW_STATUS, \
|
||||||
|
ARG_DESERIALIZE, \
|
||||||
|
ARG_SWITCHED_ROOT, \
|
||||||
|
ARG_DEFAULT_STD_OUTPUT, \
|
||||||
|
ARG_DEFAULT_STD_ERROR, \
|
||||||
|
ARG_MACHINE_ID, \
|
||||||
|
ARG_SERVICE_WATCHDOGS
|
||||||
|
|
||||||
|
#define SHUTDOWN_GETOPT_ARGS \
|
||||||
|
ARG_EXIT_CODE, \
|
||||||
|
ARG_TIMEOUT
|
||||||
|
|
||||||
|
#define COMMON_GETOPT_OPTIONS \
|
||||||
|
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL }, \
|
||||||
|
{ "log-target", required_argument, NULL, ARG_LOG_TARGET }, \
|
||||||
|
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR }, \
|
||||||
|
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, \
|
||||||
|
{ "log-time", optional_argument, NULL, ARG_LOG_TIME }
|
||||||
|
|
||||||
|
#define SYSTEMD_GETOPT_OPTIONS \
|
||||||
|
{ "unit", required_argument, NULL, ARG_UNIT }, \
|
||||||
|
{ "system", no_argument, NULL, ARG_SYSTEM }, \
|
||||||
|
{ "user", no_argument, NULL, ARG_USER }, \
|
||||||
|
{ "test", no_argument, NULL, ARG_TEST }, \
|
||||||
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER }, \
|
||||||
|
{ "help", no_argument, NULL, 'h' }, \
|
||||||
|
{ "version", no_argument, NULL, ARG_VERSION }, \
|
||||||
|
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, \
|
||||||
|
{ "dump-bus-properties", no_argument, NULL, ARG_DUMP_BUS_PROPERTIES }, \
|
||||||
|
{ "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT }, \
|
||||||
|
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, \
|
||||||
|
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, \
|
||||||
|
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, \
|
||||||
|
{ "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, \
|
||||||
|
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, \
|
||||||
|
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, \
|
||||||
|
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE }, \
|
||||||
|
{ "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT }, \
|
||||||
|
{ "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, }, \
|
||||||
|
{ "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, }, \
|
||||||
|
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID }, \
|
||||||
|
{ "service-watchdogs", required_argument, NULL, ARG_SERVICE_WATCHDOGS }
|
||||||
|
|
||||||
|
#define SHUTDOWN_GETOPT_OPTIONS \
|
||||||
|
{ "exit-code", required_argument, NULL, ARG_EXIT_CODE }, \
|
||||||
|
{ "timeout", required_argument, NULL, ARG_TIMEOUT }
|
|
@ -7,15 +7,76 @@
|
||||||
#include "efivars.h"
|
#include "efivars.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "getopt-defs.h"
|
||||||
#include "initrd-util.h"
|
#include "initrd-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "proc-cmdline.h"
|
#include "proc-cmdline.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "special.h"
|
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
#include "virt.h"
|
#include "virt.h"
|
||||||
|
|
||||||
|
int proc_cmdline_filter_pid1_args(
|
||||||
|
char **argv, /* input, may be reordered by this function. */
|
||||||
|
char ***ret) {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
COMMON_GETOPT_ARGS,
|
||||||
|
SYSTEMD_GETOPT_ARGS,
|
||||||
|
SHUTDOWN_GETOPT_ARGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option options[] = {
|
||||||
|
COMMON_GETOPT_OPTIONS,
|
||||||
|
SYSTEMD_GETOPT_OPTIONS,
|
||||||
|
SHUTDOWN_GETOPT_OPTIONS,
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int saved_optind, saved_opterr, saved_optopt, argc;
|
||||||
|
char *saved_optarg;
|
||||||
|
char **filtered;
|
||||||
|
size_t idx;
|
||||||
|
|
||||||
|
assert(argv);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
/* Backup global variables. */
|
||||||
|
saved_optind = optind;
|
||||||
|
saved_opterr = opterr;
|
||||||
|
saved_optopt = optopt;
|
||||||
|
saved_optarg = optarg;
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). Here, we do not use
|
||||||
|
* the GNU extensions, but might be used previously. Hence, we need to always reset it. */
|
||||||
|
optind = 0;
|
||||||
|
|
||||||
|
/* Do not print an error message. */
|
||||||
|
opterr = 0;
|
||||||
|
|
||||||
|
/* Filter out all known options. */
|
||||||
|
argc = strv_length(argv);
|
||||||
|
while (getopt_long(argc, argv, SYSTEMD_GETOPT_SHORT_OPTIONS, options, NULL) >= 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
idx = optind;
|
||||||
|
|
||||||
|
/* Restore global variables. */
|
||||||
|
optind = saved_optind;
|
||||||
|
opterr = saved_opterr;
|
||||||
|
optopt = saved_optopt;
|
||||||
|
optarg = saved_optarg;
|
||||||
|
|
||||||
|
filtered = strv_copy(strv_skip(argv, idx));
|
||||||
|
if (!filtered)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = filtered;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int proc_cmdline(char **ret) {
|
int proc_cmdline(char **ret) {
|
||||||
const char *e;
|
const char *e;
|
||||||
|
|
||||||
|
@ -40,71 +101,86 @@ int proc_cmdline(char **ret) {
|
||||||
return read_one_line_file("/proc/cmdline", ret);
|
return read_one_line_file("/proc/cmdline", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int proc_cmdline_extract_first(const char **p, char **ret_word, ProcCmdlineFlags flags) {
|
static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
|
||||||
const char *q = *p;
|
const char *e;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
for (;;) {
|
assert(ret);
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
const char *c;
|
|
||||||
|
|
||||||
r = extract_first_word(&q, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
/* 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)
|
||||||
|
return strv_split_full(ret, e, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
|
||||||
|
if (detect_container() > 0) {
|
||||||
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
|
|
||||||
|
r = get_process_cmdline_strv(1, /* flags = */ 0, &args);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Filter out arguments that are intended only for the initrd */
|
if (filter_pid1_args)
|
||||||
|
return proc_cmdline_filter_pid1_args(args, ret);
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(args);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
|
||||||
|
r = read_one_line_file("/proc/cmdline", &s);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return strv_split_full(ret, s, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_cmdline_strv(char ***ret) {
|
||||||
|
return proc_cmdline_strv_internal(ret, /* filter_pid1_args = */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *mangle_word(const char *word, ProcCmdlineFlags flags) {
|
||||||
|
char *c;
|
||||||
|
|
||||||
c = startswith(word, "rd.");
|
c = startswith(word, "rd.");
|
||||||
if (c) {
|
if (c) {
|
||||||
if (!in_initrd())
|
/* Filter out arguments that are intended only for the initrd */
|
||||||
continue;
|
|
||||||
|
|
||||||
if (FLAGS_SET(flags, PROC_CMDLINE_STRIP_RD_PREFIX)) {
|
if (!in_initrd())
|
||||||
r = free_and_strdup(&word, c);
|
return NULL;
|
||||||
if (r < 0)
|
|
||||||
return r;
|
if (FLAGS_SET(flags, PROC_CMDLINE_STRIP_RD_PREFIX))
|
||||||
}
|
return c;
|
||||||
|
|
||||||
} else if (FLAGS_SET(flags, PROC_CMDLINE_RD_STRICT) && in_initrd())
|
} else if (FLAGS_SET(flags, PROC_CMDLINE_RD_STRICT) && in_initrd())
|
||||||
continue; /* And optionally filter out arguments that are intended only for the host */
|
/* And optionally filter out arguments that are intended only for the host */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
*p = q;
|
return (char*) word;
|
||||||
*ret_word = TAKE_PTR(word);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = q;
|
static int proc_cmdline_parse_strv(char **args, proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) {
|
||||||
*ret_word = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) {
|
|
||||||
const char *p;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(parse_item);
|
assert(parse_item);
|
||||||
|
|
||||||
/* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_parse(), let's make this
|
/* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_parse(), let's
|
||||||
* clear. */
|
* make this clear. */
|
||||||
assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL));
|
assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL));
|
||||||
|
|
||||||
p = line;
|
STRV_FOREACH(word, args) {
|
||||||
for (;;) {
|
char *key, *value;
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
char *value;
|
|
||||||
|
|
||||||
r = proc_cmdline_extract_first(&p, &word, flags);
|
key = mangle_word(*word, flags);
|
||||||
if (r < 0)
|
if (!key)
|
||||||
return r;
|
continue;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
value = strchr(word, '=');
|
value = strchr(key, '=');
|
||||||
if (value)
|
if (value)
|
||||||
*(value++) = 0;
|
*(value++) = '\0';
|
||||||
|
|
||||||
r = parse_item(word, value, data);
|
r = parse_item(key, value, data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +189,7 @@ static int proc_cmdline_parse_given(const char *line, proc_cmdline_parse_t parse
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) {
|
int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineFlags flags) {
|
||||||
_cleanup_free_ char *line = NULL;
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(parse_item);
|
assert(parse_item);
|
||||||
|
@ -121,24 +197,30 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF
|
||||||
/* We parse the EFI variable first, because later settings have higher priority. */
|
/* We parse the EFI variable first, because later settings have higher priority. */
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
|
if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
|
||||||
|
_cleanup_free_ char *line = NULL;
|
||||||
|
|
||||||
r = systemd_efi_options_variable(&line);
|
r = systemd_efi_options_variable(&line);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENODATA)
|
if (r != -ENODATA)
|
||||||
log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
|
log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
|
||||||
} else {
|
} else {
|
||||||
r = proc_cmdline_parse_given(line, parse_item, data, flags);
|
r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
line = mfree(line);
|
r = proc_cmdline_parse_strv(args, parse_item, data, flags);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r = proc_cmdline(&line);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return proc_cmdline_parse_given(line, parse_item, data, flags);
|
args = strv_free(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return proc_cmdline_parse_strv(args, parse_item, data, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool relaxed_equal_char(char a, char b) {
|
static bool relaxed_equal_char(char a, char b) {
|
||||||
|
@ -173,24 +255,19 @@ bool proc_cmdline_key_streq(const char *x, const char *y) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmdline_get_key(const char *line, const char *key, ProcCmdlineFlags flags, char **ret_value) {
|
static int cmdline_get_key(char **args, const char *key, ProcCmdlineFlags flags, char **ret_value) {
|
||||||
_cleanup_free_ char *v = NULL;
|
_cleanup_free_ char *v = NULL;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const char *p;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(line);
|
|
||||||
assert(key);
|
assert(key);
|
||||||
|
|
||||||
p = line;
|
STRV_FOREACH(p, args) {
|
||||||
for (;;) {
|
const char *word;
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
|
|
||||||
r = proc_cmdline_extract_first(&p, &word, flags);
|
word = mangle_word(*p, flags);
|
||||||
if (r < 0)
|
if (!word)
|
||||||
return r;
|
continue;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ret_value) {
|
if (ret_value) {
|
||||||
const char *e;
|
const char *e;
|
||||||
|
@ -224,6 +301,7 @@ static int cmdline_get_key(const char *line, const char *key, ProcCmdlineFlags f
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) {
|
int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) {
|
||||||
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
_cleanup_free_ char *line = NULL, *v = NULL;
|
_cleanup_free_ char *line = NULL, *v = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -247,14 +325,14 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
|
||||||
if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
|
if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
r = proc_cmdline(&line);
|
r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) /* Shortcut */
|
if (FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) /* Shortcut */
|
||||||
return cmdline_get_key(line, key, flags, ret_value);
|
return cmdline_get_key(args, key, flags, ret_value);
|
||||||
|
|
||||||
r = cmdline_get_key(line, key, flags, ret_value ? &v : NULL);
|
r = cmdline_get_key(args, key, flags, ret_value ? &v : NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
|
@ -264,7 +342,6 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
line = mfree(line);
|
|
||||||
r = systemd_efi_options_variable(&line);
|
r = systemd_efi_options_variable(&line);
|
||||||
if (r == -ENODATA) {
|
if (r == -ENODATA) {
|
||||||
if (ret_value)
|
if (ret_value)
|
||||||
|
@ -275,7 +352,12 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return cmdline_get_key(line, key, flags, ret_value);
|
args = strv_free(args);
|
||||||
|
r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return cmdline_get_key(args, key, flags, ret_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_cmdline_get_bool(const char *key, bool *ret) {
|
int proc_cmdline_get_bool(const char *key, bool *ret) {
|
||||||
|
@ -303,51 +385,9 @@ int proc_cmdline_get_bool(const char *key, bool *ret) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
|
static int cmdline_get_key_ap(ProcCmdlineFlags flags, char* const* args, va_list ap) {
|
||||||
_cleanup_free_ char *line = NULL;
|
|
||||||
bool processing_efi = true;
|
|
||||||
const char *p;
|
|
||||||
va_list ap;
|
|
||||||
int r, ret = 0;
|
int r, ret = 0;
|
||||||
|
|
||||||
/* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_get_key_many(), let's make
|
|
||||||
* this clear. */
|
|
||||||
assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL));
|
|
||||||
|
|
||||||
/* This call may clobber arguments on failure! */
|
|
||||||
|
|
||||||
if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
|
|
||||||
r = systemd_efi_options_variable(&line);
|
|
||||||
if (r < 0 && r != -ENODATA)
|
|
||||||
log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
|
|
||||||
}
|
|
||||||
|
|
||||||
p = line;
|
|
||||||
for (;;) {
|
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
|
|
||||||
r = proc_cmdline_extract_first(&p, &word, flags);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r == 0) {
|
|
||||||
/* We finished with this command line. If this was the EFI one, then let's proceed with the regular one */
|
|
||||||
if (processing_efi) {
|
|
||||||
processing_efi = false;
|
|
||||||
|
|
||||||
line = mfree(line);
|
|
||||||
r = proc_cmdline(&line);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
p = line;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(ap, flags);
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char **v;
|
char **v;
|
||||||
const char *k, *e;
|
const char *k, *e;
|
||||||
|
@ -358,20 +398,69 @@ int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
|
||||||
|
|
||||||
assert_se(v = va_arg(ap, char**));
|
assert_se(v = va_arg(ap, char**));
|
||||||
|
|
||||||
|
STRV_FOREACH(p, args) {
|
||||||
|
const char *word;
|
||||||
|
|
||||||
|
word = mangle_word(*p, flags);
|
||||||
|
if (!word)
|
||||||
|
continue;
|
||||||
|
|
||||||
e = proc_cmdline_key_startswith(word, k);
|
e = proc_cmdline_key_startswith(word, k);
|
||||||
if (e && *e == '=') {
|
if (e && *e == '=') {
|
||||||
r = free_and_strdup(v, e + 1);
|
r = free_and_strdup(v, e + 1);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
va_end(ap);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
|
||||||
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
|
int r, ret = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* The PROC_CMDLINE_VALUE_OPTIONAL flag doesn't really make sense for proc_cmdline_get_key_many(), let's make
|
||||||
|
* this clear. */
|
||||||
|
assert(!FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL));
|
||||||
|
|
||||||
|
/* This call may clobber arguments on failure! */
|
||||||
|
|
||||||
|
if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
|
||||||
|
_cleanup_free_ char *line = NULL;
|
||||||
|
|
||||||
|
r = systemd_efi_options_variable(&line);
|
||||||
|
if (r < 0 && r != -ENODATA)
|
||||||
|
log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
|
||||||
|
if (r >= 0) {
|
||||||
|
r = strv_split_full(&args, line, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
va_start(ap, flags);
|
||||||
|
r = cmdline_get_key_ap(flags, args, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
ret = r;
|
||||||
|
args = strv_free(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = proc_cmdline_strv(&args);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
va_start(ap, flags);
|
||||||
|
r = cmdline_get_key_ap(flags, args, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return ret + r;
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,10 @@ typedef enum ProcCmdlineFlags {
|
||||||
|
|
||||||
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
|
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
|
||||||
|
|
||||||
|
int proc_cmdline_filter_pid1_args(char **argv, char ***ret);
|
||||||
|
|
||||||
int proc_cmdline(char **ret);
|
int proc_cmdline(char **ret);
|
||||||
|
int proc_cmdline_strv(char ***ret);
|
||||||
|
|
||||||
int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, ProcCmdlineFlags flags);
|
int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, ProcCmdlineFlags flags);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 1);
|
assert(argc >= 1);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "-hkalM:u::xc", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "-hkalM:u::xc", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "getopt-defs.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "hostname-setup.h"
|
#include "hostname-setup.h"
|
||||||
#include "ima-setup.h"
|
#include "ima-setup.h"
|
||||||
|
@ -818,62 +819,13 @@ static void set_manager_settings(Manager *m) {
|
||||||
|
|
||||||
static int parse_argv(int argc, char *argv[]) {
|
static int parse_argv(int argc, char *argv[]) {
|
||||||
enum {
|
enum {
|
||||||
ARG_LOG_LEVEL = 0x100,
|
COMMON_GETOPT_ARGS,
|
||||||
ARG_LOG_TARGET,
|
SYSTEMD_GETOPT_ARGS,
|
||||||
ARG_LOG_COLOR,
|
|
||||||
ARG_LOG_LOCATION,
|
|
||||||
ARG_LOG_TIME,
|
|
||||||
ARG_UNIT,
|
|
||||||
ARG_SYSTEM,
|
|
||||||
ARG_USER,
|
|
||||||
ARG_TEST,
|
|
||||||
ARG_NO_PAGER,
|
|
||||||
ARG_VERSION,
|
|
||||||
ARG_DUMP_CONFIGURATION_ITEMS,
|
|
||||||
ARG_DUMP_BUS_PROPERTIES,
|
|
||||||
ARG_BUS_INTROSPECT,
|
|
||||||
ARG_DUMP_CORE,
|
|
||||||
ARG_CRASH_CHVT,
|
|
||||||
ARG_CRASH_SHELL,
|
|
||||||
ARG_CRASH_REBOOT,
|
|
||||||
ARG_CONFIRM_SPAWN,
|
|
||||||
ARG_SHOW_STATUS,
|
|
||||||
ARG_DESERIALIZE,
|
|
||||||
ARG_SWITCHED_ROOT,
|
|
||||||
ARG_DEFAULT_STD_OUTPUT,
|
|
||||||
ARG_DEFAULT_STD_ERROR,
|
|
||||||
ARG_MACHINE_ID,
|
|
||||||
ARG_SERVICE_WATCHDOGS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
COMMON_GETOPT_OPTIONS,
|
||||||
{ "log-target", required_argument, NULL, ARG_LOG_TARGET },
|
SYSTEMD_GETOPT_OPTIONS,
|
||||||
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR },
|
|
||||||
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
|
|
||||||
{ "log-time", optional_argument, NULL, ARG_LOG_TIME },
|
|
||||||
{ "unit", required_argument, NULL, ARG_UNIT },
|
|
||||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
|
||||||
{ "user", no_argument, NULL, ARG_USER },
|
|
||||||
{ "test", no_argument, NULL, ARG_TEST },
|
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
|
||||||
{ "help", no_argument, NULL, 'h' },
|
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
|
||||||
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
|
|
||||||
{ "dump-bus-properties", no_argument, NULL, ARG_DUMP_BUS_PROPERTIES },
|
|
||||||
{ "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
|
|
||||||
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
|
|
||||||
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT },
|
|
||||||
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
|
|
||||||
{ "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT },
|
|
||||||
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN },
|
|
||||||
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
|
|
||||||
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE },
|
|
||||||
{ "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT },
|
|
||||||
{ "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, },
|
|
||||||
{ "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, },
|
|
||||||
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID },
|
|
||||||
{ "service-watchdogs", required_argument, NULL, ARG_SERVICE_WATCHDOGS },
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -886,7 +838,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
if (getpid_cached() == 1)
|
if (getpid_cached() == 1)
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, SYSTEMD_GETOPT_SHORT_OPTIONS, options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
|
@ -210,6 +210,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
|
@ -2720,6 +2720,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
static const char option_string[] = "-hp:als:H:M:qn:o:E:";
|
static const char option_string[] = "-hp:als:H:M:qn:o:E:";
|
||||||
|
|
||||||
|
|
|
@ -815,6 +815,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:P", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:P", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
|
|
|
@ -242,6 +242,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tPqGdSu:", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tPqGdSu:", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
|
@ -106,35 +106,28 @@ Condition* condition_free_list_type(Condition *head, ConditionType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int condition_test_kernel_command_line(Condition *c, char **env) {
|
static int condition_test_kernel_command_line(Condition *c, char **env) {
|
||||||
_cleanup_free_ char *line = NULL;
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(c);
|
assert(c);
|
||||||
assert(c->parameter);
|
assert(c->parameter);
|
||||||
assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
|
assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
|
||||||
|
|
||||||
r = proc_cmdline(&line);
|
r = proc_cmdline_strv(&args);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
bool equal = strchr(c->parameter, '=');
|
bool equal = strchr(c->parameter, '=');
|
||||||
|
|
||||||
for (const char *p = line;;) {
|
STRV_FOREACH(word, args) {
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (equal)
|
if (equal)
|
||||||
found = streq(word, c->parameter);
|
found = streq(*word, c->parameter);
|
||||||
else {
|
else {
|
||||||
const char *f;
|
const char *f;
|
||||||
|
|
||||||
f = startswith(word, c->parameter);
|
f = startswith(*word, c->parameter);
|
||||||
found = f && IN_SET(*f, 0, '=');
|
found = f && IN_SET(*f, 0, '=');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "getopt-defs.h"
|
||||||
#include "initrd-util.h"
|
#include "initrd-util.h"
|
||||||
#include "killall.h"
|
#include "killall.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
@ -50,23 +51,13 @@ static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
|
||||||
|
|
||||||
static int parse_argv(int argc, char *argv[]) {
|
static int parse_argv(int argc, char *argv[]) {
|
||||||
enum {
|
enum {
|
||||||
ARG_LOG_LEVEL = 0x100,
|
COMMON_GETOPT_ARGS,
|
||||||
ARG_LOG_TARGET,
|
SHUTDOWN_GETOPT_ARGS,
|
||||||
ARG_LOG_COLOR,
|
|
||||||
ARG_LOG_LOCATION,
|
|
||||||
ARG_LOG_TIME,
|
|
||||||
ARG_EXIT_CODE,
|
|
||||||
ARG_TIMEOUT,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
COMMON_GETOPT_OPTIONS,
|
||||||
{ "log-target", required_argument, NULL, ARG_LOG_TARGET },
|
SHUTDOWN_GETOPT_OPTIONS,
|
||||||
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR },
|
|
||||||
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
|
|
||||||
{ "log-time", optional_argument, NULL, ARG_LOG_TIME },
|
|
||||||
{ "exit-code", required_argument, NULL, ARG_EXIT_CODE },
|
|
||||||
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +66,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 1);
|
assert(argc >= 1);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
|
|
||||||
/* "-" prevents getopt from permuting argv[] and moving the verb away
|
/* "-" prevents getopt from permuting argv[] and moving the verb away
|
||||||
* from argv[1]. Our interface to initrd promises it'll be there. */
|
* from argv[1]. Our interface to initrd promises it'll be there. */
|
||||||
while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
|
||||||
|
|
|
@ -6,9 +6,12 @@
|
||||||
#include "initrd-util.h"
|
#include "initrd-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "nulstr-util.h"
|
||||||
#include "proc-cmdline.h"
|
#include "proc-cmdline.h"
|
||||||
|
#include "process-util.h"
|
||||||
#include "special.h"
|
#include "special.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
static int obj;
|
static int obj;
|
||||||
|
@ -27,6 +30,7 @@ TEST(proc_cmdline_parse) {
|
||||||
|
|
||||||
TEST(proc_cmdline_override) {
|
TEST(proc_cmdline_override) {
|
||||||
_cleanup_free_ char *line = NULL, *value = NULL;
|
_cleanup_free_ char *line = NULL, *value = NULL;
|
||||||
|
_cleanup_strv_free_ char **args = NULL;
|
||||||
|
|
||||||
assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0);
|
assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\"") == 0);
|
||||||
assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=different") == 0);
|
assert_se(putenv((char*) "SYSTEMD_EFI_OPTIONS=different") == 0);
|
||||||
|
@ -35,6 +39,9 @@ TEST(proc_cmdline_override) {
|
||||||
assert_se(proc_cmdline(&line) >= 0);
|
assert_se(proc_cmdline(&line) >= 0);
|
||||||
assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\""));
|
assert_se(streq(line, "foo_bar=quux wuff-piep=tuet zumm some_arg_with_space='foo bar' and_one_more=\"zzz aaa\""));
|
||||||
line = mfree(line);
|
line = mfree(line);
|
||||||
|
assert_se(proc_cmdline_strv(&args) >= 0);
|
||||||
|
assert_se(strv_equal(args, STRV_MAKE("foo_bar=quux", "wuff-piep=tuet", "zumm", "some_arg_with_space=foo bar", "and_one_more=zzz aaa")));
|
||||||
|
args = strv_free(args);
|
||||||
|
|
||||||
/* Test if parsing makes uses of the override */
|
/* Test if parsing makes uses of the override */
|
||||||
assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
||||||
|
@ -52,6 +59,9 @@ TEST(proc_cmdline_override) {
|
||||||
assert_se(proc_cmdline(&line) >= 0);
|
assert_se(proc_cmdline(&line) >= 0);
|
||||||
assert_se(streq(line, "hoge"));
|
assert_se(streq(line, "hoge"));
|
||||||
line = mfree(line);
|
line = mfree(line);
|
||||||
|
assert_se(proc_cmdline_strv(&args) >= 0);
|
||||||
|
assert_se(strv_equal(args, STRV_MAKE("hoge")));
|
||||||
|
args = strv_free(args);
|
||||||
|
|
||||||
assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
||||||
value = mfree(value);
|
value = mfree(value);
|
||||||
|
@ -256,6 +266,48 @@ TEST(proc_cmdline_key_startswith) {
|
||||||
assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx"));
|
assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define test_proc_cmdline_filter_pid1_args_one(nulstr, expected) \
|
||||||
|
({ \
|
||||||
|
_cleanup_strv_free_ char **a = NULL, **b = NULL; \
|
||||||
|
const char s[] = (nulstr); \
|
||||||
|
\
|
||||||
|
/* This emulates get_process_cmdline_strv(). */ \
|
||||||
|
assert_se(a = strv_parse_nulstr_full(s, ELEMENTSOF(s), \
|
||||||
|
/* drop_trailing_nuls = */ true)); \
|
||||||
|
assert_se(proc_cmdline_filter_pid1_args(a, &b) >= 0); \
|
||||||
|
assert_se(strv_equal(b, expected)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
TEST(proc_cmdline_filter_pid1_args) {
|
||||||
|
test_proc_cmdline_filter_pid1_args_one("systemd\0",
|
||||||
|
STRV_MAKE_EMPTY);
|
||||||
|
|
||||||
|
test_proc_cmdline_filter_pid1_args_one("systemd\0"
|
||||||
|
"hoge\0"
|
||||||
|
"-x\0"
|
||||||
|
"foo\0"
|
||||||
|
"--aaa\0"
|
||||||
|
"var\0",
|
||||||
|
STRV_MAKE("hoge", "foo", "var"));
|
||||||
|
|
||||||
|
test_proc_cmdline_filter_pid1_args_one("/usr/lib/systemd/systemd\0"
|
||||||
|
"--switched-root\0"
|
||||||
|
"--system\0"
|
||||||
|
"--deserialize\030\0" /* followed with space */
|
||||||
|
"--deserialize=31\0" /* followed with '=' */
|
||||||
|
"--exit-code=42\0"
|
||||||
|
"\0\0\0"
|
||||||
|
"systemd.log_level=debug\0"
|
||||||
|
"--unit\0foo.target\0"
|
||||||
|
" ' quoted '\0"
|
||||||
|
"systemd.log_target=console\0"
|
||||||
|
"\t\0"
|
||||||
|
" arg with space \0"
|
||||||
|
"3\0"
|
||||||
|
"\0\0\0",
|
||||||
|
STRV_MAKE("", "", "", "systemd.log_level=debug", " ' quoted '", "systemd.log_target=console", "\t", " arg with space ", "3"));
|
||||||
|
}
|
||||||
|
|
||||||
static int intro(void) {
|
static int intro(void) {
|
||||||
if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
|
if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
|
||||||
return log_tests_skipped("can't read /proc/cmdline");
|
return log_tests_skipped("can't read /proc/cmdline");
|
||||||
|
|
|
@ -75,6 +75,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, arg_print ? "hVd:b:t:p" : "+hVd:b:t:p", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, arg_print ? "hVd:b:t:p" : "+hVd:b:t:p", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
|
@ -62,6 +62,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
|
|
|
@ -1150,6 +1150,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_services = l;
|
arg_services = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||||
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
||||||
|
optind = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue