1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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 const char* const emergency_action_table
[_EMERGENCY_ACTION_MAX
] = {
16 [EMERGENCY_ACTION_NONE
] = "none",
17 [EMERGENCY_ACTION_REBOOT
] = "reboot",
18 [EMERGENCY_ACTION_REBOOT_FORCE
] = "reboot-force",
19 [EMERGENCY_ACTION_REBOOT_IMMEDIATE
] = "reboot-immediate",
20 [EMERGENCY_ACTION_POWEROFF
] = "poweroff",
21 [EMERGENCY_ACTION_POWEROFF_FORCE
] = "poweroff-force",
22 [EMERGENCY_ACTION_POWEROFF_IMMEDIATE
] = "poweroff-immediate",
23 [EMERGENCY_ACTION_EXIT
] = "exit",
24 [EMERGENCY_ACTION_EXIT_FORCE
] = "exit-force",
27 static void log_and_status(Manager
*m
, bool warn
, const char *message
, const char *reason
) {
28 log_full(warn
? LOG_WARNING
: LOG_DEBUG
, "%s: %s", message
, reason
);
30 manager_status_printf(m
, STATUS_TYPE_EMERGENCY
,
31 ANSI_HIGHLIGHT_RED
" !! " ANSI_NORMAL
,
32 "%s: %s", message
, reason
);
35 void emergency_action(
37 EmergencyAction action
,
38 EmergencyActionFlags options
,
39 const char *reboot_arg
,
47 assert(action
< _EMERGENCY_ACTION_MAX
);
49 /* Is the special shutdown target active or queued? If so, we are in shutdown state */
50 if (IN_SET(action
, EMERGENCY_ACTION_REBOOT
, EMERGENCY_ACTION_POWEROFF
, EMERGENCY_ACTION_EXIT
)) {
51 u
= manager_get_unit(m
, SPECIAL_SHUTDOWN_TARGET
);
52 if (u
&& unit_active_or_pending(u
)) {
53 log_notice("Shutdown is already active. Skipping emergency action request %s.",
54 emergency_action_table
[action
]);
59 if (action
== EMERGENCY_ACTION_NONE
)
62 if (FLAGS_SET(options
, EMERGENCY_ACTION_IS_WATCHDOG
) && !m
->service_watchdogs
) {
63 log_warning("Watchdog disabled! Not acting on: %s", reason
);
67 bool warn
= FLAGS_SET(options
, EMERGENCY_ACTION_WARN
);
71 case EMERGENCY_ACTION_REBOOT
:
72 log_and_status(m
, warn
, "Rebooting", reason
);
74 (void) update_reboot_parameter_and_warn(reboot_arg
, true);
75 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_REBOOT_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
78 case EMERGENCY_ACTION_REBOOT_FORCE
:
79 log_and_status(m
, warn
, "Forcibly rebooting", reason
);
81 (void) update_reboot_parameter_and_warn(reboot_arg
, true);
82 m
->objective
= MANAGER_REBOOT
;
86 case EMERGENCY_ACTION_REBOOT_IMMEDIATE
:
87 log_and_status(m
, warn
, "Rebooting immediately", reason
);
91 if (!isempty(reboot_arg
)) {
92 log_info("Rebooting with argument '%s'.", reboot_arg
);
93 (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2
, reboot_arg
);
94 log_warning_errno(errno
, "Failed to reboot with parameter, retrying without: %m");
97 log_info("Rebooting.");
98 (void) reboot(RB_AUTOBOOT
);
101 case EMERGENCY_ACTION_EXIT
:
103 if (exit_status
>= 0)
104 m
->return_value
= exit_status
;
106 if (MANAGER_IS_USER(m
) || detect_container() > 0) {
107 log_and_status(m
, warn
, "Exiting", reason
);
108 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_EXIT_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
112 log_notice("Doing \"poweroff\" action instead of an \"exit\" emergency action.");
115 case EMERGENCY_ACTION_POWEROFF
:
116 log_and_status(m
, warn
, "Powering off", reason
);
117 (void) manager_add_job_by_name_and_warn(m
, JOB_START
, SPECIAL_POWEROFF_TARGET
, JOB_REPLACE_IRREVERSIBLY
, NULL
, NULL
);
120 case EMERGENCY_ACTION_EXIT_FORCE
:
122 if (exit_status
>= 0)
123 m
->return_value
= exit_status
;
125 if (MANAGER_IS_USER(m
) || detect_container() > 0) {
126 log_and_status(m
, warn
, "Exiting immediately", reason
);
127 m
->objective
= MANAGER_EXIT
;
131 log_notice("Doing \"poweroff-force\" action instead of an \"exit-force\" emergency action.");
134 case EMERGENCY_ACTION_POWEROFF_FORCE
:
135 log_and_status(m
, warn
, "Forcibly powering off", reason
);
136 m
->objective
= MANAGER_POWEROFF
;
139 case EMERGENCY_ACTION_POWEROFF_IMMEDIATE
:
140 log_and_status(m
, warn
, "Powering off immediately", reason
);
144 log_info("Powering off.");
145 (void) reboot(RB_POWER_OFF
);
149 assert_not_reached("Unknown emergency action");
153 DEFINE_STRING_TABLE_LOOKUP(emergency_action
, EmergencyAction
);
155 int parse_emergency_action(
158 EmergencyAction
*ret
) {
162 x
= emergency_action_from_string(value
);
166 if (!system
&& x
!= EMERGENCY_ACTION_NONE
&& x
< _EMERGENCY_ACTION_FIRST_USER_ACTION
)