]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2928b0a8 LP |
2 | |
3 | #include <sys/reboot.h> | |
2928b0a8 | 4 | |
2928b0a8 | 5 | #include "bus-error.h" |
8b43440b | 6 | #include "bus-util.h" |
87a47f99 | 7 | #include "emergency-action.h" |
c52a937b | 8 | #include "raw-reboot.h" |
e3631d1c | 9 | #include "reboot-util.h" |
8b43440b LP |
10 | #include "special.h" |
11 | #include "string-table.h" | |
288a74cc | 12 | #include "terminal-util.h" |
a400bd8c | 13 | #include "virt.h" |
2928b0a8 | 14 | |
a1ba8c5b JB |
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", | |
25 | }; | |
26 | ||
c7adcb1a ZJS |
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); | |
29 | if (warn) | |
30 | manager_status_printf(m, STATUS_TYPE_EMERGENCY, | |
31 | ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL, | |
32 | "%s: %s", message, reason); | |
ebc5788e ZJS |
33 | } |
34 | ||
36c4dc08 | 35 | void emergency_action( |
2928b0a8 | 36 | Manager *m, |
87a47f99 | 37 | EmergencyAction action, |
1710d4be | 38 | EmergencyActionFlags options, |
87a47f99 | 39 | const char *reboot_arg, |
7af67e9a | 40 | int exit_status, |
87a47f99 | 41 | const char *reason) { |
2928b0a8 | 42 | |
a1ba8c5b JB |
43 | Unit *u; |
44 | ||
2928b0a8 LP |
45 | assert(m); |
46 | assert(action >= 0); | |
87a47f99 | 47 | assert(action < _EMERGENCY_ACTION_MAX); |
2928b0a8 | 48 | |
a1ba8c5b JB |
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]); | |
55 | return; | |
56 | } | |
57 | } | |
58 | ||
87a47f99 | 59 | if (action == EMERGENCY_ACTION_NONE) |
36c4dc08 | 60 | return; |
2928b0a8 | 61 | |
1710d4be | 62 | if (FLAGS_SET(options, EMERGENCY_ACTION_IS_WATCHDOG) && !m->service_watchdogs) { |
2a12e32e | 63 | log_warning("Watchdog disabled! Not acting on: %s", reason); |
36c4dc08 | 64 | return; |
2a12e32e JK |
65 | } |
66 | ||
c7adcb1a ZJS |
67 | bool warn = FLAGS_SET(options, EMERGENCY_ACTION_WARN); |
68 | ||
f07756bf | 69 | switch (action) { |
2928b0a8 | 70 | |
87a47f99 | 71 | case EMERGENCY_ACTION_REBOOT: |
c7adcb1a | 72 | log_and_status(m, warn, "Rebooting", reason); |
2928b0a8 | 73 | |
77defcf5 | 74 | (void) update_reboot_parameter_and_warn(reboot_arg, true); |
50cbaba4 | 75 | (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL); |
2928b0a8 | 76 | break; |
2928b0a8 | 77 | |
87a47f99 | 78 | case EMERGENCY_ACTION_REBOOT_FORCE: |
c7adcb1a | 79 | log_and_status(m, warn, "Forcibly rebooting", reason); |
ebc5788e | 80 | |
77defcf5 | 81 | (void) update_reboot_parameter_and_warn(reboot_arg, true); |
af41e508 | 82 | m->objective = MANAGER_REBOOT; |
27c06cb5 | 83 | |
2928b0a8 LP |
84 | break; |
85 | ||
87a47f99 | 86 | case EMERGENCY_ACTION_REBOOT_IMMEDIATE: |
c7adcb1a | 87 | log_and_status(m, warn, "Rebooting immediately", reason); |
2928b0a8 LP |
88 | |
89 | sync(); | |
90 | ||
27c06cb5 | 91 | if (!isempty(reboot_arg)) { |
2928b0a8 | 92 | log_info("Rebooting with argument '%s'.", reboot_arg); |
c52a937b | 93 | (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, reboot_arg); |
27c06cb5 | 94 | log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); |
2928b0a8 LP |
95 | } |
96 | ||
97 | log_info("Rebooting."); | |
118cf952 | 98 | (void) reboot(RB_AUTOBOOT); |
2928b0a8 LP |
99 | break; |
100 | ||
54fcb619 | 101 | case EMERGENCY_ACTION_EXIT: |
7af67e9a LP |
102 | |
103 | if (exit_status >= 0) | |
104 | m->return_value = exit_status; | |
105 | ||
a400bd8c | 106 | if (MANAGER_IS_USER(m) || detect_container() > 0) { |
c7adcb1a | 107 | log_and_status(m, warn, "Exiting", reason); |
50cbaba4 | 108 | (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL); |
a400bd8c ZJS |
109 | break; |
110 | } | |
54fcb619 | 111 | |
a400bd8c ZJS |
112 | log_notice("Doing \"poweroff\" action instead of an \"exit\" emergency action."); |
113 | _fallthrough_; | |
54fcb619 | 114 | |
87a47f99 | 115 | case EMERGENCY_ACTION_POWEROFF: |
c7adcb1a | 116 | log_and_status(m, warn, "Powering off", reason); |
50cbaba4 | 117 | (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL); |
f07756bf | 118 | break; |
f07756bf | 119 | |
54fcb619 | 120 | case EMERGENCY_ACTION_EXIT_FORCE: |
7af67e9a LP |
121 | |
122 | if (exit_status >= 0) | |
123 | m->return_value = exit_status; | |
124 | ||
a400bd8c | 125 | if (MANAGER_IS_USER(m) || detect_container() > 0) { |
c7adcb1a | 126 | log_and_status(m, warn, "Exiting immediately", reason); |
a400bd8c ZJS |
127 | m->objective = MANAGER_EXIT; |
128 | break; | |
129 | } | |
54fcb619 | 130 | |
a400bd8c ZJS |
131 | log_notice("Doing \"poweroff-force\" action instead of an \"exit-force\" emergency action."); |
132 | _fallthrough_; | |
54fcb619 | 133 | |
87a47f99 | 134 | case EMERGENCY_ACTION_POWEROFF_FORCE: |
c7adcb1a | 135 | log_and_status(m, warn, "Forcibly powering off", reason); |
af41e508 | 136 | m->objective = MANAGER_POWEROFF; |
f07756bf LP |
137 | break; |
138 | ||
87a47f99 | 139 | case EMERGENCY_ACTION_POWEROFF_IMMEDIATE: |
c7adcb1a | 140 | log_and_status(m, warn, "Powering off immediately", reason); |
f07756bf LP |
141 | |
142 | sync(); | |
143 | ||
144 | log_info("Powering off."); | |
118cf952 | 145 | (void) reboot(RB_POWER_OFF); |
f07756bf LP |
146 | break; |
147 | ||
2928b0a8 | 148 | default: |
87a47f99 | 149 | assert_not_reached("Unknown emergency action"); |
2928b0a8 | 150 | } |
2928b0a8 LP |
151 | } |
152 | ||
87a47f99 | 153 | DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction); |
54fcb619 ZJS |
154 | |
155 | int parse_emergency_action( | |
156 | const char *value, | |
157 | bool system, | |
158 | EmergencyAction *ret) { | |
159 | ||
160 | EmergencyAction x; | |
161 | ||
162 | x = emergency_action_from_string(value); | |
163 | if (x < 0) | |
164 | return -EINVAL; | |
165 | ||
a400bd8c | 166 | if (!system && x != EMERGENCY_ACTION_NONE && x < _EMERGENCY_ACTION_FIRST_USER_ACTION) |
54fcb619 ZJS |
167 | return -EOPNOTSUPP; |
168 | ||
169 | *ret = x; | |
170 | return 0; | |
171 | } |