]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/emergency-action.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / core / emergency-action.c
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 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);
17 if (warn)
18 manager_status_printf(m, STATUS_TYPE_EMERGENCY,
19 ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL,
20 "%s: %s", message, reason);
21 }
22
23 int 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 assert(m);
32 assert(action >= 0);
33 assert(action < _EMERGENCY_ACTION_MAX);
34
35 if (action == EMERGENCY_ACTION_NONE)
36 return -ECANCELED;
37
38 if (FLAGS_SET(options, EMERGENCY_ACTION_IS_WATCHDOG) && !m->service_watchdogs) {
39 log_warning("Watchdog disabled! Not acting on: %s", reason);
40 return -ECANCELED;
41 }
42
43 bool warn = FLAGS_SET(options, EMERGENCY_ACTION_WARN);
44
45 switch (action) {
46
47 case EMERGENCY_ACTION_REBOOT:
48 log_and_status(m, warn, "Rebooting", reason);
49
50 (void) update_reboot_parameter_and_warn(reboot_arg);
51 (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
52
53 break;
54
55 case EMERGENCY_ACTION_REBOOT_FORCE:
56 log_and_status(m, warn, "Forcibly rebooting", reason);
57
58 (void) update_reboot_parameter_and_warn(reboot_arg);
59 m->objective = MANAGER_REBOOT;
60
61 break;
62
63 case EMERGENCY_ACTION_REBOOT_IMMEDIATE:
64 log_and_status(m, warn, "Rebooting immediately", reason);
65
66 sync();
67
68 if (!isempty(reboot_arg)) {
69 log_info("Rebooting with argument '%s'.", reboot_arg);
70 (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, reboot_arg);
71 log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
72 }
73
74 log_info("Rebooting.");
75 (void) reboot(RB_AUTOBOOT);
76 break;
77
78 case EMERGENCY_ACTION_EXIT:
79
80 if (exit_status >= 0)
81 m->return_value = exit_status;
82
83 if (MANAGER_IS_USER(m) || detect_container() > 0) {
84 log_and_status(m, warn, "Exiting", reason);
85 (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
86 break;
87 }
88
89 log_notice("Doing \"poweroff\" action instead of an \"exit\" emergency action.");
90 _fallthrough_;
91
92 case EMERGENCY_ACTION_POWEROFF:
93 log_and_status(m, warn, "Powering off", reason);
94 (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
95 break;
96
97 case EMERGENCY_ACTION_EXIT_FORCE:
98
99 if (exit_status >= 0)
100 m->return_value = exit_status;
101
102 if (MANAGER_IS_USER(m) || detect_container() > 0) {
103 log_and_status(m, warn, "Exiting immediately", reason);
104 m->objective = MANAGER_EXIT;
105 break;
106 }
107
108 log_notice("Doing \"poweroff-force\" action instead of an \"exit-force\" emergency action.");
109 _fallthrough_;
110
111 case EMERGENCY_ACTION_POWEROFF_FORCE:
112 log_and_status(m, warn, "Forcibly powering off", reason);
113 m->objective = MANAGER_POWEROFF;
114 break;
115
116 case EMERGENCY_ACTION_POWEROFF_IMMEDIATE:
117 log_and_status(m, warn, "Powering off immediately", reason);
118
119 sync();
120
121 log_info("Powering off.");
122 (void) reboot(RB_POWER_OFF);
123 break;
124
125 default:
126 assert_not_reached("Unknown emergency action");
127 }
128
129 return -ECANCELED;
130 }
131
132 static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
133 [EMERGENCY_ACTION_NONE] = "none",
134 [EMERGENCY_ACTION_REBOOT] = "reboot",
135 [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
136 [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
137 [EMERGENCY_ACTION_POWEROFF] = "poweroff",
138 [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
139 [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
140 [EMERGENCY_ACTION_EXIT] = "exit",
141 [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
142 };
143 DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
144
145 int parse_emergency_action(
146 const char *value,
147 bool system,
148 EmergencyAction *ret) {
149
150 EmergencyAction x;
151
152 x = emergency_action_from_string(value);
153 if (x < 0)
154 return -EINVAL;
155
156 if (!system && x != EMERGENCY_ACTION_NONE && x < _EMERGENCY_ACTION_FIRST_USER_ACTION)
157 return -EOPNOTSUPP;
158
159 *ret = x;
160 return 0;
161 }