1 /**
2  * Copyright © 2017 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 "../utils/flight_recorder.hpp"
20 #include "argument.hpp"
21 #include "manager.hpp"
22 #else
23 #include "json/manager.hpp"
24 #endif
25 #include "sdbusplus.hpp"
26 #include "sdeventplus.hpp"
27 
28 #include <phosphor-logging/log.hpp>
29 #include <sdbusplus/bus.hpp>
30 #include <sdeventplus/event.hpp>
31 #include <sdeventplus/source/signal.hpp>
32 #include <stdplus/signal.hpp>
33 
34 #include <fstream>
35 
36 using namespace phosphor::fan::control;
37 using namespace phosphor::logging;
38 
39 #ifdef CONTROL_USE_JSON
40 void dumpFlightRecorder()
41 {
42     nlohmann::json data;
43     phosphor::fan::control::json::FlightRecorder::instance().dump(data);
44     std::ofstream file{json::Manager::dumpFile};
45     file << std::setw(4) << data;
46 }
47 #endif
48 
49 int main(int argc, char* argv[])
50 {
51     auto event = phosphor::fan::util::SDEventPlus::getEvent();
52 
53 #ifndef CONTROL_USE_JSON
54     phosphor::fan::util::ArgumentParser args(argc, argv);
55     if (argc != 2)
56     {
57         args.usage(argv);
58         return 1;
59     }
60 
61     Mode mode;
62 
63     if (args["init"] == "true")
64     {
65         mode = Mode::init;
66     }
67     else if (args["control"] == "true")
68     {
69         mode = Mode::control;
70     }
71     else
72     {
73         args.usage(argv);
74         return 1;
75     }
76 #endif
77 
78     // Attach the event object to the bus object so we can
79     // handle both sd_events (for the timers) and dbus signals.
80     phosphor::fan::util::SDBusPlus::getBus().attach_event(
81         event.get(), SD_EVENT_PRIORITY_NORMAL);
82 
83     try
84     {
85 #ifdef CONTROL_USE_JSON
86         phosphor::fan::control::json::FlightRecorder::instance().log("main",
87                                                                      "Startup");
88         json::Manager manager(event);
89 
90         // Handle loading fan control's config file(s)
91         phosphor::fan::JsonConfig config(
92             std::bind(&json::Manager::load, &manager));
93 
94         // Enable SIGHUP handling to reload JSON configs
95         stdplus::signal::block(SIGHUP);
96         sdeventplus::source::Signal signal(
97             event, SIGHUP,
98             std::bind(&json::Manager::sighupHandler, &manager,
99                       std::placeholders::_1, std::placeholders::_2));
100 
101         // Enable SIGUSR1 handling to dump the flight recorder
102         stdplus::signal::block(SIGUSR1);
103         sdeventplus::source::Signal sigUsr1(
104             event, SIGUSR1,
105             std::bind(&json::Manager::sigUsr1Handler, &manager,
106                       std::placeholders::_1, std::placeholders::_2));
107 
108         phosphor::fan::util::SDBusPlus::getBus().request_name(CONTROL_BUSNAME);
109 #else
110         Manager manager(phosphor::fan::util::SDBusPlus::getBus(), event, mode);
111 
112         // Init mode will just set fans to max and delay
113         if (mode == Mode::init)
114         {
115             manager.doInit(event);
116             return 0;
117         }
118 #endif
119         return event.loop();
120     }
121     // Log the useful metadata on these exceptions and let the app
122     // return 1 so it is restarted without a core dump.
123     catch (const phosphor::fan::util::DBusServiceError& e)
124     {
125         log<level::ERR>("Uncaught DBus service lookup failure exception",
126                         entry("PATH=%s", e.path.c_str()),
127                         entry("INTERFACE=%s", e.interface.c_str()));
128     }
129     catch (const phosphor::fan::util::DBusMethodError& e)
130     {
131         log<level::ERR>("Uncaught DBus method failure exception",
132                         entry("BUSNAME=%s", e.busName.c_str()),
133                         entry("PATH=%s", e.path.c_str()),
134                         entry("INTERFACE=%s", e.interface.c_str()),
135                         entry("METHOD=%s", e.method.c_str()));
136     }
137     catch (const phosphor::fan::util::DBusPropertyError& e)
138     {
139         log<level::ERR>("Uncaught DBus property access failure exception",
140                         entry("BUSNAME=%s", e.busName.c_str()),
141                         entry("PATH=%s", e.path.c_str()),
142                         entry("INTERFACE=%s", e.interface.c_str()),
143                         entry("PROPERTY=%s", e.property.c_str()));
144     }
145     catch (std::exception& e)
146     {
147 #ifdef CONTROL_USE_JSON
148         phosphor::fan::control::json::FlightRecorder::instance().log(
149             "main", "Unexpected exception exit");
150         dumpFlightRecorder();
151 #endif
152         throw;
153     }
154 
155 #ifdef CONTROL_USE_JSON
156     phosphor::fan::control::json::FlightRecorder::instance().log(
157         "main", "Abnormal exit");
158     dumpFlightRecorder();
159 #endif
160 
161     return 1;
162 }
163