diff --git a/man/systemctl.xml b/man/systemctl.xml
index 2a542ba466..8b8d106555 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -2795,6 +2795,21 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
+
+
+
+
+ When used with kexec, append the specified string to the kernel command
+ line options of the kexec kernel. The kernel command line is taken from the boot loader entry of
+ the currently booted kernel (as selected automatically when no kexec kernel is preloaded, see
+ kexec above). This string is appended verbatim, separated from the existing
+ options by a single space. systemctl kexec will fail if this option is specified
+ when a kexec kernel is already loaded.
+
+
+
+
+
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index c34c7fb10e..9f52115b73 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -137,7 +137,7 @@ _systemctl () {
--show-transaction -T --mkdir --read-only'
[ARG]='--host -H --kill-whom --property -p -P --signal -s --type -t --state --job-mode --root
--preset-mode -n --lines -o --output -M --machine --message --timestamp --check-inhibitors --what
- --image --boot-loader-menu --boot-loader-entry --reboot-argument --drop-in'
+ --image --boot-loader-menu --boot-loader-entry --reboot-argument --kernel-cmdline --drop-in'
)
if __contains_word "--user" ${COMP_WORDS[*]}; then
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
index b7d10eb891..fd38c678ea 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -28,6 +28,9 @@ static int load_kexec_kernel(void) {
int r;
if (kexec_loaded()) {
+ if (arg_kernel_cmdline)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--kernel-cmdline= specified but kexec kernel already loaded");
log_debug("Kexec kernel already loaded.");
return 0;
}
@@ -78,6 +81,9 @@ static int load_kexec_kernel(void) {
if (!options)
return log_oom();
+ if (!isempty(arg_kernel_cmdline) && !strextend_with_separator(&options, " ", arg_kernel_cmdline))
+ return log_oom();
+
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
"%s %s kernel=\"%s\" cmdline=\"%s\"%s%s%s",
arg_dry_run ? "Would call" : "Calling",
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 3d3ed98fcd..5c9a24b119 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -27,6 +27,7 @@
#include "systemctl-compat-shutdown.h"
#include "systemctl-logind.h"
#include "time-util.h"
+#include "utf8.h"
char **arg_types = NULL;
char **arg_states = NULL;
@@ -68,6 +69,7 @@ char *arg_image = NULL;
usec_t arg_when = 0;
bool arg_stdin = false;
const char *arg_reboot_argument = NULL;
+char *arg_kernel_cmdline = NULL;
enum action arg_action = ACTION_SYSTEMCTL;
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
const char *arg_host = NULL;
@@ -98,6 +100,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_kill_whom, unsetp);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_reboot_argument, unsetp);
+STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
STATIC_DESTRUCTOR_REGISTER(arg_host, unsetp);
STATIC_DESTRUCTOR_REGISTER(arg_boot_loader_entry, unsetp);
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
@@ -305,6 +308,9 @@ static int systemctl_help(void) {
" Boot into a specific boot loader entry on next boot\n"
" --reboot-argument=ARG\n"
" Specify argument string to pass to reboot()\n"
+ " --kernel-cmdline=CMDLINE\n"
+ " Append to the kernel command line when loading the\n"
+ " kernel from the booted boot loader entry\n"
" --plain Print unit dependencies as a list instead of a tree\n"
" --timestamp=FORMAT Change format of printed timestamps (pretty, unix,\n"
" us, utc, us+utc)\n"
@@ -434,6 +440,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_WAIT,
ARG_WHAT,
ARG_REBOOT_ARG,
+ ARG_KERNEL_CMDLINE,
ARG_TIMESTAMP_STYLE,
ARG_READ_ONLY,
ARG_MKDIR,
@@ -505,6 +512,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "show-transaction", no_argument, NULL, 'T' },
{ "what", required_argument, NULL, ARG_WHAT },
{ "reboot-argument", required_argument, NULL, ARG_REBOOT_ARG },
+ { "kernel-cmdline", required_argument, NULL, ARG_KERNEL_CMDLINE },
{ "timestamp", required_argument, NULL, ARG_TIMESTAMP_STYLE },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "mkdir", no_argument, NULL, ARG_MKDIR },
@@ -960,6 +968,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_reboot_argument = optarg;
break;
+ case ARG_KERNEL_CMDLINE:
+ if (!utf8_is_valid(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--kernel-cmdline= argument is not valid UTF-8: %s", optarg);
+ if (string_has_cc(optarg, NULL))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--kernel-cmdline= argument contains control characters: %s", optarg);
+
+ r = free_and_strdup_warn(&arg_kernel_cmdline, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case ARG_TIMESTAMP_STYLE:
if (streq(optarg, "help"))
return DUMP_STRING_TABLE(timestamp_style, TimestampStyle, _TIMESTAMP_STYLE_MAX);
diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h
index 8d4b1a614d..bc52e96fe3 100644
--- a/src/systemctl/systemctl.h
+++ b/src/systemctl/systemctl.h
@@ -76,6 +76,7 @@ extern char *arg_image;
extern usec_t arg_when;
extern bool arg_stdin;
extern const char *arg_reboot_argument;
+extern char *arg_kernel_cmdline;
extern enum action arg_action;
extern BusTransport arg_transport;
extern const char *arg_host;