blob: 3040ebf43f58e2892bf638d2b0c41dea8fb102f8 [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>
Patrick Williams9a286db2024-01-17 06:29:47 -06009#include <xyz/openbmc_project/Logging/Create/client.hpp>
10#include <xyz/openbmc_project/Logging/Entry/client.hpp>
11#include <xyz/openbmc_project/State/Boot/Progress/client.hpp>
Andrew Geisslerba0163a2021-08-11 15:09:50 -040012
13#include <cstdlib>
Patrick Williams78c066f2024-02-13 12:25:58 -060014#include <format>
Andrew Geissler5259f972021-08-30 15:46:55 -050015#include <fstream>
Andrew Geisslerba0163a2021-08-11 15:09:50 -040016#include <string>
17
Andrew Geissler8ffdb262021-09-20 15:25:19 -050018namespace phosphor
19{
20namespace state
21{
22namespace manager
23{
24
25PHOSPHOR_LOG2_USING;
26
Patrick Williams9a286db2024-01-17 06:29:47 -060027using BootProgress =
28 sdbusplus::client::xyz::openbmc_project::state::boot::Progress<>;
29using LoggingCreate =
30 sdbusplus::client::xyz::openbmc_project::logging::Create<>;
31using LoggingEntry = sdbusplus::client::xyz::openbmc_project::logging::Entry<>;
32
Andrew Geisslerba0163a2021-08-11 15:09:50 -040033constexpr auto HOST_STATE_SVC = "xyz.openbmc_project.State.Host";
34constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
35constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
Andrew Geisslerba0163a2021-08-11 15:09:50 -040036constexpr auto BOOT_PROGRESS_PROP = "BootProgress";
37
Andrew Geissler7b01b0b2021-08-11 16:14:49 -040038constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
39constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
40constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
41constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
42
Patrick Williamsf053e6f2022-07-22 19:26:54 -050043bool wasHostBooting(sdbusplus::bus_t& bus)
Andrew Geisslerba0163a2021-08-11 15:09:50 -040044{
45 try
46 {
Patrick Williams9a286db2024-01-17 06:29:47 -060047 using ProgressStages = BootProgress::ProgressStages;
NodeMan9780db4752022-05-04 09:06:40 -050048
Andrew Geisslerba0163a2021-08-11 15:09:50 -040049 auto method = bus.new_method_call(HOST_STATE_SVC, HOST_STATE_PATH,
50 PROPERTY_INTERFACE, "Get");
Patrick Williams9a286db2024-01-17 06:29:47 -060051 method.append(BootProgress::interface, BOOT_PROGRESS_PROP);
Andrew Geisslerba0163a2021-08-11 15:09:50 -040052
53 auto response = bus.call(method);
54
NodeMan9780db4752022-05-04 09:06:40 -050055 std::variant<ProgressStages> bootProgressV;
56 response.read(bootProgressV);
57 auto bootProgress = std::get<ProgressStages>(bootProgressV);
Andrew Geisslerba0163a2021-08-11 15:09:50 -040058
NodeMan9780db4752022-05-04 09:06:40 -050059 if (bootProgress == ProgressStages::Unspecified)
Andrew Geisslerba0163a2021-08-11 15:09:50 -040060 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050061 info("Host was not booting before BMC reboot");
Andrew Geisslerba0163a2021-08-11 15:09:50 -040062 return false;
63 }
64
Andrew Geissler8ffdb262021-09-20 15:25:19 -050065 info("Host was booting before BMC reboot: {BOOTPROGRESS}",
NodeMan9780db4752022-05-04 09:06:40 -050066 "BOOTPROGRESS", bootProgress);
Andrew Geisslerba0163a2021-08-11 15:09:50 -040067 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -050068 catch (const sdbusplus::exception_t& e)
Andrew Geisslerba0163a2021-08-11 15:09:50 -040069 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050070 error("Error reading BootProgress, error {ERROR}, service {SERVICE}, "
71 "path {PATH}",
72 "ERROR", e, "SERVICE", HOST_STATE_SVC, "PATH", HOST_STATE_PATH);
Andrew Geisslerba0163a2021-08-11 15:09:50 -040073
74 throw;
75 }
76
77 return true;
78}
79
Patrick Williamsf053e6f2022-07-22 19:26:54 -050080void createErrorLog(sdbusplus::bus_t& bus)
Andrew Geissler556153a2021-08-11 15:29:58 -040081{
82 try
83 {
84 // Create interface requires something for additionalData
85 std::map<std::string, std::string> additionalData;
86 additionalData.emplace("_PID", std::to_string(getpid()));
87
88 static constexpr auto errorMessage =
89 "xyz.openbmc_project.State.Error.HostNotRunning";
Patrick Williams9a286db2024-01-17 06:29:47 -060090 auto method = bus.new_method_call(LoggingCreate::default_service,
91 LoggingCreate::instance_path,
92 LoggingCreate::interface, "Create");
93 method.append(errorMessage, LoggingEntry::Level::Error, additionalData);
Andrew Geissler556153a2021-08-11 15:29:58 -040094 auto resp = bus.call(method);
95 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -050096 catch (const sdbusplus::exception_t& e)
Andrew Geissler556153a2021-08-11 15:29:58 -040097 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050098 error(
99 "sdbusplus D-Bus call exception, error {ERROR}, objpath {OBJPATH}, "
100 "interface {INTERFACE}",
Patrick Williams9a286db2024-01-17 06:29:47 -0600101 "ERROR", e, "OBJPATH", LoggingCreate::instance_path, "INTERFACE",
102 LoggingCreate::interface);
Andrew Geissler556153a2021-08-11 15:29:58 -0400103
104 throw std::runtime_error(
105 "Error in invoking D-Bus logging create interface");
106 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500107 catch (const std::exception& e)
Andrew Geissler556153a2021-08-11 15:29:58 -0400108 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500109 error("D-bus call exception: {ERROR}", "ERROR", e);
Andrew Geissler556153a2021-08-11 15:29:58 -0400110 throw e;
111 }
112}
113
Andrew Geissler5259f972021-08-30 15:46:55 -0500114// Once CHASSIS_ON_FILE is removed, the obmc-chassis-poweron@.target has
115// completed and the phosphor-chassis-state-manager code has processed it.
116bool isChassisTargetComplete()
117{
Patrick Williams78c066f2024-02-13 12:25:58 -0600118 auto chassisFile = std::format(CHASSIS_ON_FILE, 0);
Andrew Geissler5259f972021-08-30 15:46:55 -0500119
Patrick Williams78c066f2024-02-13 12:25:58 -0600120 std::ifstream f(chassisFile);
Andrew Geissler5259f972021-08-30 15:46:55 -0500121 return !f.good();
122}
123
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500124void moveToHostQuiesce(sdbusplus::bus_t& bus)
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400125{
126 try
127 {
128 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
129 SYSTEMD_INTERFACE, "StartUnit");
130
131 method.append(HOST_STATE_QUIESCE_TGT);
132 method.append("replace");
133
134 bus.call_noreply(method);
135 }
Patrick Williamsf053e6f2022-07-22 19:26:54 -0500136 catch (const sdbusplus::exception_t& e)
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400137 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500138 error("sdbusplus call exception starting quiesce target: {ERROR}",
139 "ERROR", e);
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400140
141 throw std::runtime_error(
142 "Error in invoking D-Bus systemd StartUnit method");
143 }
144}
145
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500146} // namespace manager
147} // namespace state
148} // namespace phosphor
149
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400150int main()
151{
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500152 using namespace phosphor::state::manager;
153 PHOSPHOR_LOG2_USING;
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400154
155 auto bus = sdbusplus::bus::new_default();
156
Andrew Geissler5259f972021-08-30 15:46:55 -0500157 // Chassis power is on if this service starts but need to wait for the
158 // obmc-chassis-poweron@.target to complete before potentially initiating
159 // another systemd target transition (i.e. Quiesce->Reboot)
160 while (!isChassisTargetComplete())
161 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500162 debug("Waiting for chassis on target to complete");
Andrew Geissler5259f972021-08-30 15:46:55 -0500163 std::this_thread::sleep_for(std::chrono::seconds(1));
164
165 // There is no timeout here, wait until it happens or until system
166 // is powered off and this service is stopped
167 }
168
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500169 info("Chassis power on has completed, checking if host is "
170 "still running after the BMC reboot");
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400171
172 // Check the last BootProgeress to see if the host was booting before
173 // the BMC reboot occurred
174 if (!wasHostBooting(bus))
175 {
176 return 0;
177 }
178
179 // Host was booting before the BMC reboot so log an error and go to host
180 // quiesce target
Andrew Geissler556153a2021-08-11 15:29:58 -0400181 createErrorLog(bus);
Andrew Geissler7b01b0b2021-08-11 16:14:49 -0400182 moveToHostQuiesce(bus);
Andrew Geisslerba0163a2021-08-11 15:09:50 -0400183
184 return 0;
185}