--- /dev/null
+/* 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 }
#include "efivars.h"
#include "extract-word.h"
#include "fileio.h"
+#include "getopt-defs.h"
#include "initrd-util.h"
#include "macro.h"
#include "parse-util.h"
#include "strv.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) {
const char *e;
return read_one_line_file("/proc/cmdline", ret);
}
-int proc_cmdline_strv(char ***ret) {
+static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
const char *e;
int r;
if (e)
return strv_split_full(ret, e, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
- if (detect_container() > 0)
- return get_process_cmdline_strv(1, /* flags = */ 0, ret);
- else {
+ if (detect_container() > 0) {
+ _cleanup_strv_free_ char **args = NULL;
+
+ r = get_process_cmdline_strv(1, /* flags = */ 0, &args);
+ if (r < 0)
+ return r;
+
+ 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);
}
}
+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;
}
}
- r = proc_cmdline_strv(&args);
+ r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
if (r < 0)
return r;
if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
return -EINVAL;
- r = proc_cmdline_strv(&args);
+ r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
if (r < 0)
return r;
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_strv(char ***ret);
#include "fileio.h"
#include "format-util.h"
#include "fs-util.h"
+#include "getopt-defs.h"
#include "hexdecoct.h"
#include "hostname-setup.h"
#include "ima-setup.h"
static int parse_argv(int argc, char *argv[]) {
enum {
- ARG_LOG_LEVEL = 0x100,
- ARG_LOG_TARGET,
- 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,
+ COMMON_GETOPT_ARGS,
+ SYSTEMD_GETOPT_ARGS,
};
static const struct option 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 },
- { "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 },
+ COMMON_GETOPT_OPTIONS,
+ SYSTEMD_GETOPT_OPTIONS,
{}
};
if (getpid_cached() == 1)
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) {
#include "exec-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "getopt-defs.h"
#include "initrd-util.h"
#include "killall.h"
#include "log.h"
static int parse_argv(int argc, char *argv[]) {
enum {
- ARG_LOG_LEVEL = 0x100,
- ARG_LOG_TARGET,
- ARG_LOG_COLOR,
- ARG_LOG_LOCATION,
- ARG_LOG_TIME,
- ARG_EXIT_CODE,
- ARG_TIMEOUT,
+ COMMON_GETOPT_ARGS,
+ SHUTDOWN_GETOPT_ARGS,
};
static const struct option 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 },
- { "exit-code", required_argument, NULL, ARG_EXIT_CODE },
- { "timeout", required_argument, NULL, ARG_TIMEOUT },
+ COMMON_GETOPT_OPTIONS,
+ SHUTDOWN_GETOPT_OPTIONS,
{}
};
#include "initrd-util.h"
#include "log.h"
#include "macro.h"
+#include "nulstr-util.h"
#include "proc-cmdline.h"
+#include "process-util.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
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) {
if (access("/proc/cmdline", R_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
return log_tests_skipped("can't read /proc/cmdline");