xref: /openbmc/phosphor-fan-presence/control/main.cpp (revision 64b5ac203518568ec8b7569d0e785352278f2472)
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