Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <sys/reboot.h>
4 : :
5 : : #include "bus-error.h"
6 : : #include "bus-util.h"
7 : : #include "emergency-action.h"
8 : : #include "raw-reboot.h"
9 : : #include "reboot-util.h"
10 : : #include "special.h"
11 : : #include "string-table.h"
12 : : #include "terminal-util.h"
13 : : #include "virt.h"
14 : :
15 : 0 : static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
16 [ # # # # ]: 0 : log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
17 [ # # ]: 0 : if (warn)
18 : 0 : manager_status_printf(m, STATUS_TYPE_EMERGENCY,
19 : : ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL,
20 : : "%s: %s", message, reason);
21 : 0 : }
22 : :
23 : 28 : void emergency_action(
24 : : Manager *m,
25 : : EmergencyAction action,
26 : : EmergencyActionFlags options,
27 : : const char *reboot_arg,
28 : : int exit_status,
29 : : const char *reason) {
30 : :
31 [ - + ]: 28 : assert(m);
32 [ - + ]: 28 : assert(action >= 0);
33 [ - + ]: 28 : assert(action < _EMERGENCY_ACTION_MAX);
34 : :
35 [ + - ]: 28 : if (action == EMERGENCY_ACTION_NONE)
36 : 28 : return;
37 : :
38 [ # # # # ]: 0 : if (FLAGS_SET(options, EMERGENCY_ACTION_IS_WATCHDOG) && !m->service_watchdogs) {
39 [ # # ]: 0 : log_warning("Watchdog disabled! Not acting on: %s", reason);
40 : 0 : return;
41 : : }
42 : :
43 : 0 : bool warn = FLAGS_SET(options, EMERGENCY_ACTION_WARN);
44 : :
45 [ # # # # : 0 : switch (action) {
# # # #
# ]
46 : :
47 : 0 : case EMERGENCY_ACTION_REBOOT:
48 : 0 : log_and_status(m, warn, "Rebooting", reason);
49 : :
50 : 0 : (void) update_reboot_parameter_and_warn(reboot_arg, true);
51 : 0 : (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
52 : 0 : break;
53 : :
54 : 0 : case EMERGENCY_ACTION_REBOOT_FORCE:
55 : 0 : log_and_status(m, warn, "Forcibly rebooting", reason);
56 : :
57 : 0 : (void) update_reboot_parameter_and_warn(reboot_arg, true);
58 : 0 : m->objective = MANAGER_REBOOT;
59 : :
60 : 0 : break;
61 : :
62 : 0 : case EMERGENCY_ACTION_REBOOT_IMMEDIATE:
63 : 0 : log_and_status(m, warn, "Rebooting immediately", reason);
64 : :
65 : 0 : sync();
66 : :
67 [ # # ]: 0 : if (!isempty(reboot_arg)) {
68 [ # # ]: 0 : log_info("Rebooting with argument '%s'.", reboot_arg);
69 : 0 : (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, reboot_arg);
70 [ # # ]: 0 : log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
71 : : }
72 : :
73 [ # # ]: 0 : log_info("Rebooting.");
74 : 0 : (void) reboot(RB_AUTOBOOT);
75 : 0 : break;
76 : :
77 : 0 : case EMERGENCY_ACTION_EXIT:
78 : :
79 [ # # ]: 0 : if (exit_status >= 0)
80 : 0 : m->return_value = exit_status;
81 : :
82 [ # # # # ]: 0 : if (MANAGER_IS_USER(m) || detect_container() > 0) {
83 : 0 : log_and_status(m, warn, "Exiting", reason);
84 : 0 : (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
85 : 0 : break;
86 : : }
87 : :
88 [ # # ]: 0 : log_notice("Doing \"poweroff\" action instead of an \"exit\" emergency action.");
89 : : _fallthrough_;
90 : :
91 : 0 : case EMERGENCY_ACTION_POWEROFF:
92 : 0 : log_and_status(m, warn, "Powering off", reason);
93 : 0 : (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
94 : 0 : break;
95 : :
96 : 0 : case EMERGENCY_ACTION_EXIT_FORCE:
97 : :
98 [ # # ]: 0 : if (exit_status >= 0)
99 : 0 : m->return_value = exit_status;
100 : :
101 [ # # # # ]: 0 : if (MANAGER_IS_USER(m) || detect_container() > 0) {
102 : 0 : log_and_status(m, warn, "Exiting immediately", reason);
103 : 0 : m->objective = MANAGER_EXIT;
104 : 0 : break;
105 : : }
106 : :
107 [ # # ]: 0 : log_notice("Doing \"poweroff-force\" action instead of an \"exit-force\" emergency action.");
108 : : _fallthrough_;
109 : :
110 : 0 : case EMERGENCY_ACTION_POWEROFF_FORCE:
111 : 0 : log_and_status(m, warn, "Forcibly powering off", reason);
112 : 0 : m->objective = MANAGER_POWEROFF;
113 : 0 : break;
114 : :
115 : 0 : case EMERGENCY_ACTION_POWEROFF_IMMEDIATE:
116 : 0 : log_and_status(m, warn, "Powering off immediately", reason);
117 : :
118 : 0 : sync();
119 : :
120 [ # # ]: 0 : log_info("Powering off.");
121 : 0 : (void) reboot(RB_POWER_OFF);
122 : 0 : break;
123 : :
124 : 0 : default:
125 : 0 : assert_not_reached("Unknown emergency action");
126 : : }
127 : : }
128 : :
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",
139 : : };
140 [ + + + + ]: 168 : DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
141 : :
142 : 80 : int parse_emergency_action(
143 : : const char *value,
144 : : bool system,
145 : : EmergencyAction *ret) {
146 : :
147 : : EmergencyAction x;
148 : :
149 : 80 : x = emergency_action_from_string(value);
150 [ + + ]: 80 : if (x < 0)
151 : 8 : return -EINVAL;
152 : :
153 [ + + + + : 72 : if (!system && x != EMERGENCY_ACTION_NONE && x < _EMERGENCY_ACTION_FIRST_USER_ACTION)
+ + ]
154 : 24 : return -EOPNOTSUPP;
155 : :
156 : 48 : *ret = x;
157 : 48 : return 0;
158 : : }
|