blob: 4ba1c605338bc6ce0facfc4a094e8bc5767f6d0c [file] [log] [blame]
Andrew Geissler5259f972021-08-30 15:46:55 -05001#include "config.h"
2
Andrew Geissler556153a2021-08-11 15:29:58 -04003#include <unistd.h>
4
5#include <phosphor-logging/elog.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -05006#include <phosphor-logging/lg2.hpp>
Andrew Geisslerba0163a2021-08-11 15:09:50 -04007#include <sdbusplus/bus.hpp>
8#include <sdbusplus/exception.hpp>
Andrew Geissler556153a2021-08-11 15:29:58 -04009#include <xyz/openbmc_project/Logging/Create/server.hpp>
10#include <xyz/openbmc_project/Logging/Entry/server.hpp>
Andrew Geisslerba0163a2021-08-11 15:09:50 -040011
12#include <cstdlib>
Andrew Geissler5259f972021-08-30 15:46:55 -050013#include <fstream>
Andrew Geisslerba0163a2021-08-11 15:09:50 -040014#include <string>
15
Andrew Geissler8ffdb262021-09-20 15:25:19 -050016namespace phosphor
17{
18namespace state
19{
20namespace manager
21{
22
23PHOSPHOR_LOG2_USING;
24
Andrew Geisslerba0163a2021-08-11 15:09:50 -040025constexpr auto HOST_STATE_SVC = "xyz.openbmc_project.State.Host";
26constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
27constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
28constexpr auto BOOT_STATE_INTF = "xyz.openbmc_project.State.Boot.Progress";
29constexpr auto BOOT_PROGRESS_PROP = "BootProgress";
30
Andrew Geissler556153a2021-08-11 15:29:58 -040031constexpr auto LOGGING_SVC = "xyz.openbmc_project.Logging";
32constexpr auto LOGGING_PATH = "/xyz/openbmc_project/logging";
33constexpr auto LOGGING_CREATE_INTF = "xyz.openbmc_project.Logging.Create";
34
Andrew Geissler7b01b0b2021-08-11 16:14:49 -040035constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
36constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
37constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
38constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
39
Andrew Geisslerba0163a2021-08-11 15:09:50 -040040bool wasHostBooting(sdbusplus::bus::bus& bus)
41{
42 try
43 {
44 auto method = bus.new_method_call(HOST_STATE_SVC, HOST_STATE_PATH,
45 PROPERTY_INTERFACE, "Get");
46 method.append(BOOT_STATE_INTF, BOOT_PROGRESS_PROP);
47
48 auto response = bus.call(method);
49
50 std::variant<std::string> bootProgress;
51 response.read(bootProgress);
52
53 if (std::get<std::string>(bootProgress) ==
54 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
55 "Unspecified")
56 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050057 info("Host was not booting before BMC reboot");
Andrew Geisslerba0163a2021-08-11 15:09:50 -040058 return false;
59 }
60
Andrew Geissler8ffdb262021-09-20 15:25:19 -050061 info("Host was booting before BMC reboot: {BOOTPROGRESS}",
62 "BOOTPROGRESS", std::get<std::string>(bootProgress));
Andrew Geisslerba0163a2021-08-11 15:09:50 -040063 }
64 catch (const sdbusplus::exception::exception& e)
65 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050066 error("Error reading BootProgress, error {ERROR}, service {SERVICE}, "
67 "path {PATH}",
68 "ERROR", e, "SERVICE", HOST_STATE_SVC, "PATH", HOST_STATE_PATH);
Andrew Geisslerba0163a2021-08-11 15:09:50 -040069
70 throw;
71 }
72
73 return true;
74}
75
Andrew Geissler556153a2021-08-11 15:29:58 -040076void createErrorLog(sdbusplus::bus::bus& bus)
77{
78 try
79 {
80 // Create interface requires something for additionalData
81 std::map<std::string, std::string> additionalData;
82 additionalData.emplace("_PID", std::to_string(getpid()));
83
84 static constexpr auto errorMessage =
85 "xyz.openbmc_project.State.Error.HostNotRunning";
86 auto method = bus.new_method_call(LOGGING_SVC, LOGGING_PATH,
87 LOGGING_CREATE_INTF, "Create");
88 auto level =
89 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
90 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
91 Error);
92 method.append(errorMessage, level, additionalData);
93 auto resp = bus.call(method);
94 }
95 catch (const sdbusplus::exception::exception& e)
96 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050097 error(
98 "sdbusplus D-Bus call exception, error {ERROR}, objpath {OBJPATH}, "
99 "interface {INTERFACE}",
100 "ERROR", e, "OBJPATH", LOGGING_PATH, "INTERFACE",
101 LOGGING_CREATE_INTF);
Andrew Geissler556153a2021-08-11 15:29:58 -0400102
103 throw std::runtime_error(
104 "Error in invoking D-Bus logging create interface");
105 }
106 catch (std::exception& e)
107 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500108 error("D-bus call exception: {ERROR}", "ERROR", e);
Andrew Geissler556153a2021-08-11 15:29:58 -0400109 throw e;
110 }
111}
112
Andrew Geissler5259f972021-08-30 15:46:55 -0500113// Once CHASSIS_ON_FILE is removed, the obmc-chassis-poweron@.target has
114// completed and the phosphor-chassis-state-manager code has processed it.
115bool isChassisTargetComplete()
116{
117 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
118 size++; // null
119 std::unique_ptr<char[]> buf(new char[size]);
120 std::snprintf(buf.get(), size, CHASSIS_ON_FILE, 0);
121
122 std::ifstream f(buf.get());
123 return !f.good();
124}
125
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400126void moveToHostQuiesce(sdbusplus::bus::bus& bus)
127{
128 try
129 {
130 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
131 SYSTEMD_INTERFACE, "StartUnit");
132
133 method.append(HOST_STATE_QUIESCE_TGT);
134 method.append("replace");
135
136 bus.call_noreply(method);
137 }
138 catch (const sdbusplus::exception::exception& e)
139 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500140 error("sdbusplus call exception starting quiesce target: {ERROR}",
141 "ERROR", e);
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400142
143 throw std::runtime_error(
144 "Error in invoking D-Bus systemd StartUnit method");
145 }
146}
147
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500148} // namespace manager
149} // namespace state
150} // namespace phosphor
151
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400152int main()
153{
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500154 using namespace phosphor::state::manager;
155 PHOSPHOR_LOG2_USING;
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400156
157 auto bus = sdbusplus::bus::new_default();
158
Andrew Geissler5259f972021-08-30 15:46:55 -0500159 // Chassis power is on if this service starts but need to wait for the
160 // obmc-chassis-poweron@.target to complete before potentially initiating
161 // another systemd target transition (i.e. Quiesce->Reboot)
162 while (!isChassisTargetComplete())
163 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500164 debug("Waiting for chassis on target to complete");
Andrew Geissler5259f972021-08-30 15:46:55 -0500165 std::this_thread::sleep_for(std::chrono::seconds(1));
166
167 // There is no timeout here, wait until it happens or until system
168 // is powered off and this service is stopped
169 }
170
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500171 info("Chassis power on has completed, checking if host is "
172 "still running after the BMC reboot");
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400173
174 // Check the last BootProgeress to see if the host was booting before
175 // the BMC reboot occurred
176 if (!wasHostBooting(bus))
177 {
178 return 0;
179 }
180
181 // Host was booting before the BMC reboot so log an error and go to host
182 // quiesce target
Andrew Geissler556153a2021-08-11 15:29:58 -0400183 createErrorLog(bus);
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400184 moveToHostQuiesce(bus);
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400185
186 return 0;
187}