diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c
index 9731aef5c4..09f8d74092 100644
--- a/src/core/emergency-action.c
+++ b/src/core/emergency-action.c
@@ -47,7 +47,7 @@ void emergency_action(
case EMERGENCY_ACTION_REBOOT:
log_and_status(m, warn, "Rebooting", reason);
- (void) update_reboot_parameter_and_warn(reboot_arg);
+ (void) update_reboot_parameter_and_warn(reboot_arg, true);
(void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
break;
@@ -55,7 +55,7 @@ void emergency_action(
case EMERGENCY_ACTION_REBOOT_FORCE:
log_and_status(m, warn, "Forcibly rebooting", reason);
- (void) update_reboot_parameter_and_warn(reboot_arg);
+ (void) update_reboot_parameter_and_warn(reboot_arg, true);
m->objective = MANAGER_REBOOT;
break;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 003ab45461..5f82b21995 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -32,6 +32,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "reboot-util.h"
#include "selinux-util.h"
#include "sleep-config.h"
#include "special.h"
@@ -42,6 +43,7 @@
#include "unit-name.h"
#include "user-util.h"
#include "utmp-wtmp.h"
+#include "virt.h"
static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
@@ -168,6 +170,32 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char
return 0;
}
+static int return_test_polkit(
+ sd_bus_message *message,
+ int capability,
+ const char *action,
+ const char **details,
+ uid_t good_user,
+ sd_bus_error *e) {
+
+ const char *result;
+ bool challenge;
+ int r;
+
+ r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e);
+ if (r < 0)
+ return r;
+
+ if (r > 0)
+ result = "yes";
+ else if (challenge)
+ result = "challenge";
+ else
+ result = "no";
+
+ return sd_bus_reply_method_return(message, "s", result);
+}
+
static int property_get_idle_hint(
sd_bus *bus,
const char *path,
@@ -2382,6 +2410,97 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user
error);
}
+static int property_get_reboot_parameter(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+ _cleanup_free_ char *parameter = NULL;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(userdata);
+
+ r = read_reboot_parameter(¶meter);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_append(reply, "s", parameter);
+}
+
+static int method_set_reboot_parameter(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ const char *arg;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &arg);
+ if (r < 0)
+ return r;
+
+ r = detect_container();
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+ "Reboot parameter not supported in containers, refusing.");
+
+ r = bus_verify_polkit_async(message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.set-reboot-parameter",
+ NULL,
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ r = update_reboot_parameter_and_warn(arg, false);
+ if (r < 0)
+ return r;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_parameter(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = detect_container();
+ if (r < 0)
+ return r;
+ if (r > 0) /* Inside containers, specifying a reboot parameter, doesn't make much sense */
+ return sd_bus_reply_method_return(message, "s", "na");
+
+ return return_test_polkit(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.set-reboot-parameter",
+ NULL,
+ UID_INVALID,
+ error);
+}
+
static int property_get_reboot_to_firmware_setup(
sd_bus *bus,
const char *path,
@@ -2488,32 +2607,6 @@ static int method_set_reboot_to_firmware_setup(
return sd_bus_reply_method_return(message, NULL);
}
-static int return_test_polkit(
- sd_bus_message *message,
- int capability,
- const char *action,
- const char **details,
- uid_t good_user,
- sd_bus_error *e) {
-
- const char *result;
- bool challenge;
- int r;
-
- r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e);
- if (r < 0)
- return r;
-
- if (r > 0)
- result = "yes";
- else if (challenge)
- result = "challenge";
- else
- result = "no";
-
- return sd_bus_reply_method_return(message, "s", result);
-}
-
static int method_can_reboot_to_firmware_setup(
sd_bus_message *message,
void *userdata,
@@ -3137,6 +3230,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RebootParameter", "s", property_get_reboot_parameter, 0, 0),
SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0),
SD_BUS_PROPERTY("RebootToBootLoaderMenu", "t", property_get_reboot_to_boot_loader_menu, 0, 0),
SD_BUS_PROPERTY("RebootToBootLoaderEntry", "s", property_get_reboot_to_boot_loader_entry, 0, 0),
@@ -3213,6 +3307,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CanRebootParameter", NULL, "s", method_can_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetRebootParameter", "s", NULL, method_set_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanRebootToBootLoaderMenu", NULL, "s", method_can_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 5677c15b8a..f3c13ad89a 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -190,6 +190,14 @@
send_interface="org.freedesktop.login1.Manager"
send_member="CancelScheduledShutdown"/>
+
+
+
+
diff --git a/src/login/org.freedesktop.login1.policy b/src/login/org.freedesktop.login1.policy
index 671384d34e..6ad6512f5a 100644
--- a/src/login/org.freedesktop.login1.policy
+++ b/src/login/org.freedesktop.login1.policy
@@ -337,6 +337,17 @@
+
+ Configure reboot parameter for kernel's reboot reason driver
+ Authentication is required to configure reboot parameter for kernel's reboot reason driver.
+
+ auth_admin_keep
+ auth_admin_keep
+ yes
+
+ org.freedesktop.login1.reboot
+
+
Indicate to the firmware to boot to setup interface
Authentication is required to indicate to the firmware to boot to setup interface.
diff --git a/src/shared/reboot-util.c b/src/shared/reboot-util.c
index ca40159b96..08569e8bf3 100644
--- a/src/shared/reboot-util.c
+++ b/src/shared/reboot-util.c
@@ -12,10 +12,13 @@
#include "umask-util.h"
#include "virt.h"
-int update_reboot_parameter_and_warn(const char *parameter) {
+int update_reboot_parameter_and_warn(const char *parameter, bool keep) {
int r;
if (isempty(parameter)) {
+ if (keep)
+ return 0;
+
if (unlink("/run/systemd/reboot-param") < 0) {
if (errno == ENOENT)
return 0;
@@ -36,6 +39,18 @@ int update_reboot_parameter_and_warn(const char *parameter) {
return 0;
}
+int read_reboot_parameter(char **parameter) {
+ int r;
+
+ assert(parameter);
+
+ r = read_one_line_file("/run/systemd/reboot-param", parameter);
+ if (r < 0 && r != -ENOENT)
+ return log_debug_errno(r, "Failed to read /run/systemd/reboot-param: %m");
+
+ return 0;
+}
+
int reboot_with_parameter(RebootFlags flags) {
int r;
diff --git a/src/shared/reboot-util.h b/src/shared/reboot-util.h
index d459333efc..7bddc91ea6 100644
--- a/src/shared/reboot-util.h
+++ b/src/shared/reboot-util.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-int update_reboot_parameter_and_warn(const char *parameter);
+int update_reboot_parameter_and_warn(const char *parameter, bool keep);
typedef enum RebootFlags {
REBOOT_LOG = 1 << 0, /* log about what we are going to do and all errors */
@@ -9,4 +9,5 @@ typedef enum RebootFlags {
REBOOT_FALLBACK = 1 << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */
} RebootFlags;
+int read_reboot_parameter(char **parameter);
int reboot_with_parameter(RebootFlags flags);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 9d2115b712..948dacd190 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3734,7 +3734,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
return r;
if (a == ACTION_REBOOT && argc > 1) {
- r = update_reboot_parameter_and_warn(argv[1]);
+ r = update_reboot_parameter_and_warn(argv[1], false);
if (r < 0)
return r;
@@ -8455,7 +8455,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
}
if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
- r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
+ r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
if (r < 0)
return r;
} else if (optind < argc)