1 /**
2 * Copyright © 2022 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "config.h"
17
18 #ifndef CONTROL_USE_JSON
19 #include "manager.hpp"
20
21 #include <CLI/CLI.hpp>
22 #else
23 #include "../utils/flight_recorder.hpp"
24 #include "json/manager.hpp"
25 #endif
26
27 #include "dbus_paths.hpp"
28 #include "sdbusplus.hpp"
29 #include "sdeventplus.hpp"
30
31 #include <phosphor-logging/lg2.hpp>
32 #include <sdbusplus/bus.hpp>
33 #include <sdeventplus/event.hpp>
34 #include <sdeventplus/source/signal.hpp>
35 #include <stdplus/signal.hpp>
36
37 #include <fstream>
38
39 using namespace phosphor::fan::control;
40
41 #ifdef CONTROL_USE_JSON
dumpFlightRecorder()42 void dumpFlightRecorder()
43 {
44 nlohmann::json data;
45 phosphor::fan::control::json::FlightRecorder::instance().dump(data);
46 std::ofstream file{json::Manager::dumpFile};
47 file << std::setw(4) << data;
48 }
49 #endif
50
main(int argc,char * argv[])51 int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
52 {
53 auto event = phosphor::fan::util::SDEventPlus::getEvent();
54
55 #ifndef CONTROL_USE_JSON
56 CLI::App app{"Phosphor Fan Control"};
57
58 bool init = false;
59 bool control = false;
60 app.add_flag("-i,--init", init, "Sets fans to full speed, delays, exits");
61 app.add_flag("-c,--control", control, "Start fan control algorithm");
62 app.require_option();
63
64 try
65 {
66 app.parse(argc, argv);
67 }
68 catch (const CLI::Error& e)
69 {
70 return app.exit(e);
71 }
72
73 Mode mode;
74 if (init)
75 {
76 mode = Mode::init;
77 }
78 else if (control)
79 {
80 mode = Mode::control;
81 }
82 #endif
83
84 // Attach the event object to the bus object so we can
85 // handle both sd_events (for the timers) and dbus signals.
86 phosphor::fan::util::SDBusPlus::getBus().attach_event(
87 event.get(), SD_EVENT_PRIORITY_NORMAL);
88
89 try
90 {
91 #ifdef CONTROL_USE_JSON
92 phosphor::fan::control::json::FlightRecorder::instance().log(
93 "main", "Startup");
94 json::Manager manager(event);
95
96 // Handle loading fan control's config file(s)
97 phosphor::fan::JsonConfig config(
98 std::bind(&json::Manager::load, &manager));
99
100 // Enable SIGHUP handling to reload JSON configs
101 stdplus::signal::block(SIGHUP);
102 sdeventplus::source::Signal signal(
103 event, SIGHUP,
104 std::bind(&json::Manager::sighupHandler, &manager,
105 std::placeholders::_1, std::placeholders::_2));
106
107 // Enable SIGUSR1 handling to dump the flight recorder
108 stdplus::signal::block(SIGUSR1);
109 sdeventplus::source::Signal sigUsr1(
110 event, SIGUSR1,
111 std::bind(&json::Manager::dumpDebugData, &manager,
112 std::placeholders::_1, std::placeholders::_2));
113
114 phosphor::fan::util::SDBusPlus::getBus().request_name(CONTROL_BUSNAME);
115 #else
116 Manager manager(phosphor::fan::util::SDBusPlus::getBus(), event, mode);
117
118 // Init mode will just set fans to max and delay
119 if (mode == Mode::init)
120 {
121 manager.doInit(event);
122 return 0;
123 }
124 #endif
125 return event.loop();
126 }
127 // Log the useful metadata on these exceptions and let the app
128 // return 1 so it is restarted without a core dump.
129 catch (const phosphor::fan::util::DBusServiceError& e)
130 {
131 lg2::error(
132 "Uncaught DBus service lookup failure exception, Path={PATH}, Interface={INTERFACE}",
133 "PATH", e.path, "INTERFACE", e.interface);
134 }
135 catch (const phosphor::fan::util::DBusMethodError& e)
136 {
137 lg2::error(
138 "Uncaught DBus method failure exception, Busname={BUSNAME}, Path={PATH}, Interface={INTERFACE}, Method={METHOD}",
139 "BUSNAME", e.busName, "PATH", e.path, "INTERFACE", e.interface,
140 "METHOD", e.method);
141 }
142 catch (const phosphor::fan::util::DBusPropertyError& e)
143 {
144 lg2::error(
145 "Uncaught DBus property access failure exception, Busname={BUSNAME}, Path={PATH}, Interface={INTERFACE}, Property={PROPERTY}",
146 "BUSNAME", e.busName, "PATH", e.path, "INTERFACE", e.interface,
147 "PROPERTY", e.property);
148 }
149 catch (std::exception& e)
150 {
151 #ifdef CONTROL_USE_JSON
152 phosphor::fan::control::json::FlightRecorder::instance().log(
153 "main", "Unexpected exception exit");
154 dumpFlightRecorder();
155 #endif
156 throw;
157 }
158
159 #ifdef CONTROL_USE_JSON
160 phosphor::fan::control::json::FlightRecorder::instance().log(
161 "main", "Abnormal exit");
162 dumpFlightRecorder();
163 #endif
164
165 return 1;
166 }
167