systemctl: add --kernel-cmdline-reuse option
kexec-tools has a --reuse-cmdline option which is very convenient when doing a lot of reboots, add the same to systemctl. Dedup options, letting the last one wins in case of duplicates, so that 'systemctl kexec --reuse-cmdline' can be chained many times without continuosly expanding the cmdline with duplicates from the boot entry.
This commit is contained in:
+32
-3
@@ -2795,14 +2795,43 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
<para>When used with <command>kexec</command>, 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
|
||||
<command>kexec</command> above). This string is appended verbatim, separated from the existing
|
||||
options by a single space. <command>systemctl kexec</command> will fail if this option is specified
|
||||
when a kexec kernel is already loaded.</para>
|
||||
<command>kexec</command> above). This string is appended, separated from the existing
|
||||
options by a single space. This option may be specified more than once, in which case the
|
||||
strings are appended in the order given. <command>systemctl kexec</command> will fail if this
|
||||
option is specified when a kexec kernel is already loaded.</para>
|
||||
|
||||
<para>The kexec kernel command line is assembled in a fixed order, independent of the order in
|
||||
which the options are specified on the command line: first the command line from the boot loader
|
||||
entry, then the command line of the currently running kernel (if
|
||||
<option>--kernel-cmdline-reuse</option> is used), and finally the strings specified with
|
||||
<option>--kernel-cmdline=</option>. Afterwards, arguments that are exactly identical and appear
|
||||
more than once are removed, keeping the last occurrence. Note that only byte-for-byte identical
|
||||
arguments are deduplicated: for example <literal>foo=bar</literal> and
|
||||
<literal>foo=quux</literal> are both kept, as they are not identical (the latter takes effect, as
|
||||
the kernel uses the last assignment of a given parameter).</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--kernel-cmdline-reuse</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>Like <option>--kernel-cmdline=</option>, but instead of taking the string to append as an
|
||||
argument, the command line of the currently running kernel is reused. This is useful to boot the
|
||||
kexec kernel with the same command line options the running system was booted with, including any
|
||||
modifications applied at boot time.
|
||||
As with <option>--kernel-cmdline=</option>, the reused command line is added to the command line
|
||||
taken from the boot loader entry, and <command>systemctl kexec</command> will fail if this option
|
||||
is specified when a kexec kernel is already loaded. This option may be combined with
|
||||
<option>--kernel-cmdline=</option>; see <option>--kernel-cmdline=</option> above for the order in
|
||||
which the various command line sources are combined and deduplicated.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v262"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--plain</option></term>
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ _systemctl () {
|
||||
--help -h --no-ask-password --no-block --legend=no --no-pager --no-reload --no-wall --now
|
||||
--quiet -q --system --user --version --runtime --recursive -r --firmware-setup
|
||||
--show-types --plain --failed --value --fail --dry-run --wait --no-warn --with-dependencies
|
||||
--show-transaction -T --mkdir --read-only'
|
||||
--show-transaction -T --mkdir --read-only --kernel-cmdline-reuse'
|
||||
[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 --kernel-cmdline --drop-in --when'
|
||||
|
||||
@@ -543,4 +543,5 @@ _arguments -s \
|
||||
'--failed[Show failed units]' \
|
||||
'--timestamp=[Change format of printed timestamps]:style:_systemctl_timestamp' \
|
||||
'--when=[Schedule halt/power-off/reboot/kexec action after a certain timestamp]:timestamp:(show cancel auto)' \
|
||||
'--kernel-cmdline-reuse[Reuse the current kernel command line when loading the kexec kernel]' \
|
||||
'*::systemctl command:_systemctl_commands'
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "efivars.h"
|
||||
#include "extract-word.h"
|
||||
#include "fd-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
@@ -24,13 +25,38 @@
|
||||
#include "systemctl-trivial-method.h"
|
||||
#include "systemctl-util.h"
|
||||
|
||||
static int deduplicate_kernel_cmdline(char **cmdline) {
|
||||
int r;
|
||||
|
||||
assert(cmdline);
|
||||
|
||||
/* Split, reverse, deduplicate, reverse again: the last occurrence of each identical argument wins. */
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
r = strv_split_full(&l, *cmdline, /* separators= */ NULL,
|
||||
EXTRACT_KEEP_QUOTE | EXTRACT_RETAIN_ESCAPE | EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
strv_reverse(l);
|
||||
strv_uniq(l);
|
||||
strv_reverse(l);
|
||||
|
||||
_cleanup_free_ char *joined = strv_join(l, " ");
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(*cmdline, joined);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_kexec_kernel(void) {
|
||||
int r;
|
||||
|
||||
if (kexec_loaded()) {
|
||||
if (arg_kernel_cmdline)
|
||||
if (arg_kernel_cmdline || arg_reuse_kernel_cmdline)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--kernel-cmdline= specified but kexec kernel already loaded");
|
||||
"--kernel-cmdline=/--kernel-cmdline-reuse specified but kexec kernel already loaded");
|
||||
log_debug("Kexec kernel already loaded.");
|
||||
return 0;
|
||||
}
|
||||
@@ -81,9 +107,19 @@ static int load_kexec_kernel(void) {
|
||||
if (!options)
|
||||
return log_oom();
|
||||
|
||||
/* Assemble in a fixed order: UKI -> current cmdline -> appended cmdline, and dedup at the end */
|
||||
if (!isempty(arg_reuse_kernel_cmdline) && !strextend_with_separator(&options, " ", arg_reuse_kernel_cmdline))
|
||||
return log_oom();
|
||||
|
||||
if (!isempty(arg_kernel_cmdline) && !strextend_with_separator(&options, " ", arg_kernel_cmdline))
|
||||
return log_oom();
|
||||
|
||||
if (!isempty(arg_reuse_kernel_cmdline) || !isempty(arg_kernel_cmdline)) {
|
||||
r = deduplicate_kernel_cmdline(&options);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deduplicate kernel command line: %m");
|
||||
}
|
||||
|
||||
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
|
||||
"%s %s kernel=\"%s\" cmdline=\"%s\"%s%s%s",
|
||||
arg_dry_run ? "Would call" : "Calling",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "static-destruct.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
@@ -71,6 +72,7 @@ usec_t arg_when = 0;
|
||||
bool arg_stdin = false;
|
||||
const char *arg_reboot_argument = NULL;
|
||||
char *arg_kernel_cmdline = NULL;
|
||||
char *arg_reuse_kernel_cmdline = NULL;
|
||||
enum action arg_action = ACTION_SYSTEMCTL;
|
||||
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
|
||||
const char *arg_host = NULL;
|
||||
@@ -102,6 +104,7 @@ 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_reuse_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);
|
||||
@@ -764,10 +767,31 @@ static int systemctl_parse_argv(int argc, char *argv[], int log_level_shift, cha
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--kernel-cmdline= argument contains invalid characters: %s", opts.arg);
|
||||
|
||||
r = free_and_strdup_warn(&arg_kernel_cmdline, opts.arg);
|
||||
if (!strextend_with_separator(&arg_kernel_cmdline, " ", opts.arg))
|
||||
return log_oom();
|
||||
break;
|
||||
|
||||
OPTION_LONG("kernel-cmdline-reuse", NULL,
|
||||
"Like --kernel-cmdline=, but reuse the current kernel command line"): {
|
||||
_cleanup_free_ char *cmdline = NULL;
|
||||
|
||||
r = proc_cmdline(&cmdline);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read current kernel command line: %m");
|
||||
|
||||
const char *stripped = empty_to_null(strstrip(cmdline));
|
||||
if (!stripped)
|
||||
break;
|
||||
|
||||
if (!string_is_safe(stripped, STRING_ALLOW_GLOBS|STRING_ALLOW_BACKSLASHES|STRING_ALLOW_QUOTES))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Current kernel command line contains invalid characters: %s", stripped);
|
||||
|
||||
r = free_and_strdup_warn(&arg_reuse_kernel_cmdline, stripped);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
}
|
||||
|
||||
OPTION_LONG("plain", NULL, "Print unit dependencies as a list instead of a tree"):
|
||||
arg_plain = true;
|
||||
|
||||
@@ -77,6 +77,7 @@ extern usec_t arg_when;
|
||||
extern bool arg_stdin;
|
||||
extern const char *arg_reboot_argument;
|
||||
extern char *arg_kernel_cmdline;
|
||||
extern char *arg_reuse_kernel_cmdline;
|
||||
extern enum action arg_action;
|
||||
extern BusTransport arg_transport;
|
||||
extern const char *arg_host;
|
||||
|
||||
Reference in New Issue
Block a user