1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <sys/reboot.h>
7 #include "emergency-action.h"
8 #include "raw-reboot.h"
9 #include "reboot-util.h"
11 #include "string-table.h"
12 #include "terminal-util.h"
15 static void log_and_status(Manager
*m
, bool warn
, const char *message
, const char *reason
) {
16 log_full(warn
? LOG_WARNING
: LOG_DEBUG
, "%s: %s", message
, reason
);
18 manager_status_printf(m
, STATUS_TYPE_EMERGENCY
,
19 ANSI_HIGHLIGHT_RED
" !! " ANSI_NORMAL
,
20 "%s: %s", message
, reason
);
23 void emergency_action(
25 EmergencyAction action
,
26 EmergencyActionFlags options
,
27 const char *reboot_arg
,
33 assert(action
< _EMERGENCY_ACTION_MAX
);
35 if (action
== EMERGENCY_ACTION_NONE
)
38 if (FLAGS_SET(options
, EMERGENCY_ACTION_IS_WATCHDOG
) && !m
->service_watchdogs
) {
39 log_warning("Watchdog disabled! Not acting on: %s", reason
);
43 bool warn
= FLAGS_SET(options
, EMERGENCY_ACTION_WARN
);
47 case EMERGENCY_ACTION_REBOOT
:
48 log_and_status(m
, warn
, "Rebooting", reason
);
50 (void) update_reboot_parameter_and_warn(reboot_arg
, true);
51 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_REBOOT_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
54 case EMERGENCY_ACTION_REBOOT_FORCE
:
55 log_and_status(m
, warn
, "Forcibly rebooting", reason
);
57 (void) update_reboot_parameter_and_warn(reboot_arg
, true);
58 m
->objective
= MANAGER_REBOOT
;
62 case EMERGENCY_ACTION_REBOOT_IMMEDIATE
:
63 log_and_status(m
, warn
, "Rebooting immediately", reason
);
67 if (!isempty(reboot_arg
)) {
68 log_info("Rebooting with argument '%s'.", reboot_arg
);
69 (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2
, reboot_arg
);
70 log_warning_errno(errno
, "Failed to reboot with parameter, retrying without: %m");
73 log_info("Rebooting.");
74 (void) reboot(RB_AUTOBOOT
);
77 case EMERGENCY_ACTION_EXIT
:
80 m
->return_value
= exit_status
;
82 if (MANAGER_IS_USER(m
) || detect_container() > 0) {
83 log_and_status(m
, warn
, "Exiting", reason
);
84 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_EXIT_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
88 log_notice("Doing \"poweroff\" action instead of an \"exit\" emergency action.");
91 case EMERGENCY_ACTION_POWEROFF
:
92 log_and_status(m
, warn
, "Powering off", reason
);
93 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_POWEROFF_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
96 case EMERGENCY_ACTION_EXIT_FORCE
:
99 m
->return_value
= exit_status
;
101 if (MANAGER_IS_USER(m
) || detect_container() > 0) {
102 log_and_status(m
, warn
, "Exiting immediately", reason
);
103 m
->objective
= MANAGER_EXIT
;
107 log_notice("Doing \"poweroff-force\" action instead of an \"exit-force\" emergency action.");
110 case EMERGENCY_ACTION_POWEROFF_FORCE
:
111 log_and_status(m
, warn
, "Forcibly powering off", reason
);
112 m
->objective
= MANAGER_POWEROFF
;
115 case EMERGENCY_ACTION_POWEROFF_IMMEDIATE
:
116 log_and_status(m
, warn
, "Powering off immediately", reason
);
120 log_info("Powering off.");
121 (void) reboot(RB_POWER_OFF
);
125 assert_not_reached("Unknown emergency action");
129 static const char* const emergency_action_table
[_EMERGENCY_ACTION_MAX
] = {
130 [EMERGENCY_ACTION_NONE
] = "none",
131 [EMERGENCY_ACTION_REBOOT
] = "reboot",
132 [EMERGENCY_ACTION_REBOOT_FORCE
] = "reboot-force",
133 [EMERGENCY_ACTION_REBOOT_IMMEDIATE
] = "reboot-immediate",
134 [EMERGENCY_ACTION_POWEROFF
] = "poweroff",
135 [EMERGENCY_ACTION_POWEROFF_FORCE
] = "poweroff-force",
136 [EMERGENCY_ACTION_POWEROFF_IMMEDIATE
] = "poweroff-immediate",
137 [EMERGENCY_ACTION_EXIT
] = "exit",
138 [EMERGENCY_ACTION_EXIT_FORCE
] = "exit-force",
140 DEFINE_STRING_TABLE_LOOKUP(emergency_action
, EmergencyAction
);
142 int parse_emergency_action(
145 EmergencyAction
*ret
) {
149 x
= emergency_action_from_string(value
);
153 if (!system
&& x
!= EMERGENCY_ACTION_NONE
&& x
< _EMERGENCY_ACTION_FIRST_USER_ACTION
)