blob: f138c3cb84615dd51516c34ce5ea009d03a9b96b [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 Geisslerba0163a2021-08-11 15:09:50 -04006#include <phosphor-logging/log.hpp>
7#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
16constexpr auto HOST_STATE_SVC = "xyz.openbmc_project.State.Host";
17constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
18constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
19constexpr auto BOOT_STATE_INTF = "xyz.openbmc_project.State.Boot.Progress";
20constexpr auto BOOT_PROGRESS_PROP = "BootProgress";
21
Andrew Geissler556153a2021-08-11 15:29:58 -040022constexpr auto LOGGING_SVC = "xyz.openbmc_project.Logging";
23constexpr auto LOGGING_PATH = "/xyz/openbmc_project/logging";
24constexpr auto LOGGING_CREATE_INTF = "xyz.openbmc_project.Logging.Create";
25
Andrew Geissler7b01b0b2021-08-11 16:14:49 -040026constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
27constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
28constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
29constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
30
Andrew Geisslerba0163a2021-08-11 15:09:50 -040031using namespace phosphor::logging;
32
33bool wasHostBooting(sdbusplus::bus::bus& bus)
34{
35 try
36 {
37 auto method = bus.new_method_call(HOST_STATE_SVC, HOST_STATE_PATH,
38 PROPERTY_INTERFACE, "Get");
39 method.append(BOOT_STATE_INTF, BOOT_PROGRESS_PROP);
40
41 auto response = bus.call(method);
42
43 std::variant<std::string> bootProgress;
44 response.read(bootProgress);
45
46 if (std::get<std::string>(bootProgress) ==
47 "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
48 "Unspecified")
49 {
50 log<level::INFO>("Host was not booting before BMC reboot");
51 return false;
52 }
53
54 log<level::INFO>("Host was booting before BMC reboot",
55 entry("BOOTPROGRESS=%s",
56 std::get<std::string>(bootProgress).c_str()));
57 }
58 catch (const sdbusplus::exception::exception& e)
59 {
60 log<level::ERR>("Error reading BootProgress",
61 entry("ERROR=%s", e.what()),
62 entry("SERVICE=%s", HOST_STATE_SVC),
63 entry("PATH=%s", HOST_STATE_PATH));
64
65 throw;
66 }
67
68 return true;
69}
70
Andrew Geissler556153a2021-08-11 15:29:58 -040071void createErrorLog(sdbusplus::bus::bus& bus)
72{
73 try
74 {
75 // Create interface requires something for additionalData
76 std::map<std::string, std::string> additionalData;
77 additionalData.emplace("_PID", std::to_string(getpid()));
78
79 static constexpr auto errorMessage =
80 "xyz.openbmc_project.State.Error.HostNotRunning";
81 auto method = bus.new_method_call(LOGGING_SVC, LOGGING_PATH,
82 LOGGING_CREATE_INTF, "Create");
83 auto level =
84 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
85 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
86 Error);
87 method.append(errorMessage, level, additionalData);
88 auto resp = bus.call(method);
89 }
90 catch (const sdbusplus::exception::exception& e)
91 {
92 log<level::ERR>("sdbusplus D-Bus call exception",
93 entry("OBJPATH=%s", LOGGING_PATH),
94 entry("INTERFACE=%s", LOGGING_CREATE_INTF),
95 entry("EXCEPTION=%s", e.what()));
96
97 throw std::runtime_error(
98 "Error in invoking D-Bus logging create interface");
99 }
100 catch (std::exception& e)
101 {
102 log<level::ERR>("D-bus call exception",
103 entry("EXCEPTION=%s", e.what()));
104 throw e;
105 }
106}
107
Andrew Geissler5259f972021-08-30 15:46:55 -0500108// Once CHASSIS_ON_FILE is removed, the obmc-chassis-poweron@.target has
109// completed and the phosphor-chassis-state-manager code has processed it.
110bool isChassisTargetComplete()
111{
112 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
113 size++; // null
114 std::unique_ptr<char[]> buf(new char[size]);
115 std::snprintf(buf.get(), size, CHASSIS_ON_FILE, 0);
116
117 std::ifstream f(buf.get());
118 return !f.good();
119}
120
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400121void moveToHostQuiesce(sdbusplus::bus::bus& bus)
122{
123 try
124 {
125 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
126 SYSTEMD_INTERFACE, "StartUnit");
127
128 method.append(HOST_STATE_QUIESCE_TGT);
129 method.append("replace");
130
131 bus.call_noreply(method);
132 }
133 catch (const sdbusplus::exception::exception& e)
134 {
135 log<level::ERR>("sdbusplus call exception starting quiesce target",
136 entry("EXCEPTION=%s", e.what()));
137
138 throw std::runtime_error(
139 "Error in invoking D-Bus systemd StartUnit method");
140 }
141}
142
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400143int main()
144{
145
146 auto bus = sdbusplus::bus::new_default();
147
Andrew Geissler5259f972021-08-30 15:46:55 -0500148 // Chassis power is on if this service starts but need to wait for the
149 // obmc-chassis-poweron@.target to complete before potentially initiating
150 // another systemd target transition (i.e. Quiesce->Reboot)
151 while (!isChassisTargetComplete())
152 {
153 log<level::DEBUG>("Waiting for chassis on target to complete");
154 std::this_thread::sleep_for(std::chrono::seconds(1));
155
156 // There is no timeout here, wait until it happens or until system
157 // is powered off and this service is stopped
158 }
159
160 log<level::INFO>("Chassis power on has completed, checking if host is "
161 "still running after the BMC reboot");
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400162
163 // Check the last BootProgeress to see if the host was booting before
164 // the BMC reboot occurred
165 if (!wasHostBooting(bus))
166 {
167 return 0;
168 }
169
170 // Host was booting before the BMC reboot so log an error and go to host
171 // quiesce target
Andrew Geissler556153a2021-08-11 15:29:58 -0400172 createErrorLog(bus);
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400173 moveToHostQuiesce(bus);
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400174
175 return 0;
176}