#include "glyph-util.h"
#include "json-util.h"
#include "manager.h"
+#include "path-util.h"
#include "pidref.h"
#include "selinux-access.h"
#include "set.h"
return ret;
}
+
+static int manager_do_set_objective(sd_varlink *link, sd_json_variant *parameters, ManagerObjective objective, const char *selinux_permission, bool can_do_root) {
+ Manager *m = ASSERT_PTR(sd_varlink_get_userdata(link));
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ _cleanup_free_ char *rt = NULL;
+ const char *root = NULL;
+ int r;
+
+ assert(link);
+ assert(parameters);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return sd_varlink_error(link, SD_VARLINK_ERROR_METHOD_NOT_IMPLEMENTED, NULL);
+
+ if (can_do_root) {
+ static const sd_json_dispatch_field dispatch_table[] = {
+ { "root", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
+ {}
+ };
+
+ r = sd_varlink_dispatch(link, parameters, dispatch_table, &root);
+ } else
+ r = sd_varlink_dispatch(link, parameters, /* dispatch_table= */ NULL, /* userdata= */ NULL);
+ if (r != 0)
+ return r;
+
+ r = mac_selinux_access_check_varlink(link, selinux_permission);
+ if (r < 0)
+ return r;
+
+ /* dbus uses SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT) in its checking. We cannot do the same
+ * because reading capabilities from /proc is racy (TOCTOU). So we use the stricter check
+ * TODO: figure out a way to check for CAP_SYS_BOOT */
+ r = varlink_check_privileged_peer(link);
+ if (r < 0)
+ return r;
+
+ if (!isempty(root)) {
+ if (!path_is_valid(root))
+ return sd_varlink_error_invalid_parameter_name(link, "root");
+ if (!path_is_absolute(root))
+ return sd_varlink_error_invalid_parameter_name(link, "root");
+
+ r = path_simplify_alloc(root, &rt);
+ if (r < 0)
+ return r;
+ }
+
+ /* We need at least the pidref, otherwise there's nothing to log about. */
+ r = varlink_get_peer_pidref(link, &pidref);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get peer pidref, ignoring: %m");
+ else
+ manager_log_caller(m, &pidref, manager_objective_to_string(objective));
+
+ if (can_do_root)
+ free_and_replace(m->switch_root, rt);
+ m->objective = objective;
+
+ return sd_varlink_reply(link, NULL);
+}
+
+int vl_method_poweroff_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ return manager_do_set_objective(link, parameters, MANAGER_POWEROFF, "halt", /* can_do_root= */ false);
+}
+
+int vl_method_reboot_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ return manager_do_set_objective(link, parameters, MANAGER_REBOOT, "reboot", /* can_do_root= */ false);
+}
+
+int vl_method_halt_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ return manager_do_set_objective(link, parameters, MANAGER_HALT, "halt", /* can_do_root= */ false);
+}
+
+int vl_method_kexec_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ return manager_do_set_objective(link, parameters, MANAGER_KEXEC, "reboot", /* can_do_root= */ false);
+}
+
+int vl_method_soft_reboot_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
+ return manager_do_set_objective(link, parameters, MANAGER_SOFT_REBOOT, "reboot", /* can_do_root= */ true);
+}
int vl_method_reexecute_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_reload_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
int vl_method_enqueue_marked_jobs_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_poweroff_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_reboot_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_halt_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_kexec_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
+int vl_method_soft_reboot_manager(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata);
"io.systemd.Manager.Reexecute", vl_method_reexecute_manager,
"io.systemd.Manager.Reload", vl_method_reload_manager,
"io.systemd.Manager.EnqueueMarkedJobs", vl_method_enqueue_marked_jobs_manager,
+ "io.systemd.Manager.PowerOff", vl_method_poweroff_manager,
+ "io.systemd.Manager.Reboot", vl_method_reboot_manager,
+ "io.systemd.Manager.Halt", vl_method_halt_manager,
+ "io.systemd.Manager.KExec", vl_method_kexec_manager,
+ "io.systemd.Manager.SoftReboot", vl_method_soft_reboot_manager,
"io.systemd.Unit.List", vl_method_list_units,
"io.systemd.Unit.SetProperties", vl_method_set_unit_properties,
"io.systemd.service.Ping", varlink_method_ping,
SD_VARLINK_FIELD_COMMENT("Job enqueue error message (on failure)"),
SD_VARLINK_DEFINE_OUTPUT(errorMessage, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
+static SD_VARLINK_DEFINE_METHOD(PowerOff);
+static SD_VARLINK_DEFINE_METHOD(Reboot);
+static SD_VARLINK_DEFINE_METHOD(Halt);
+static SD_VARLINK_DEFINE_METHOD(KExec);
+static SD_VARLINK_DEFINE_METHOD(
+ SoftReboot,
+ SD_VARLINK_FIELD_COMMENT("New root directory for the soft reboot"),
+ SD_VARLINK_DEFINE_INPUT(root, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
+
static SD_VARLINK_DEFINE_ERROR(RateLimitReached);
SD_VARLINK_DEFINE_INTERFACE(
&vl_method_Reload,
SD_VARLINK_SYMBOL_COMMENT("Enqueue all marked jobs"),
&vl_method_EnqueueMarkedJobs,
+ SD_VARLINK_SYMBOL_COMMENT("Power off the system"),
+ &vl_method_PowerOff,
+ SD_VARLINK_SYMBOL_COMMENT("Reboot the system"),
+ &vl_method_Reboot,
+ SD_VARLINK_SYMBOL_COMMENT("Halt the system"),
+ &vl_method_Halt,
+ SD_VARLINK_SYMBOL_COMMENT("Reboot the system via kexec"),
+ &vl_method_KExec,
+ SD_VARLINK_SYMBOL_COMMENT("Soft-reboot the userspace"),
+ &vl_method_SoftReboot,
&vl_error_RateLimitReached,
&vl_type_ManagerContext,
&vl_type_ManagerRuntime,