1 /**
2  * Copyright © 2020 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 #include "manager.hpp"
19 
20 #include "../utils/flight_recorder.hpp"
21 #include "action.hpp"
22 #include "event.hpp"
23 #include "fan.hpp"
24 #include "group.hpp"
25 #include "json_config.hpp"
26 #include "power_state.hpp"
27 #include "profile.hpp"
28 #include "sdbusplus.hpp"
29 #include "zone.hpp"
30 
31 #include <nlohmann/json.hpp>
32 #include <sdbusplus/bus.hpp>
33 #include <sdbusplus/server/manager.hpp>
34 #include <sdeventplus/event.hpp>
35 #include <sdeventplus/utility/timer.hpp>
36 
37 #include <algorithm>
38 #include <chrono>
39 #include <filesystem>
40 #include <functional>
41 #include <map>
42 #include <memory>
43 #include <tuple>
44 #include <utility>
45 #include <vector>
46 
47 namespace phosphor::fan::control::json
48 {
49 
50 using json = nlohmann::json;
51 
52 std::vector<std::string> Manager::_activeProfiles;
53 std::map<std::string,
54          std::map<std::string, std::pair<bool, std::vector<std::string>>>>
55     Manager::_servTree;
56 std::map<std::string,
57          std::map<std::string, std::map<std::string, PropertyVariantType>>>
58     Manager::_objects;
59 std::unordered_map<std::string, PropertyVariantType> Manager::_parameters;
60 
61 Manager::Manager(const sdeventplus::Event& event) :
62     _bus(util::SDBusPlus::getBus()), _event(event),
63     _mgr(util::SDBusPlus::getBus(), CONTROL_OBJPATH), _loadAllowed(true),
64     _powerState(std::make_unique<PGoodState>(
65         util::SDBusPlus::getBus(),
66         std::bind(std::mem_fn(&Manager::powerStateChanged), this,
67                   std::placeholders::_1)))
68 {}
69 
70 void Manager::sighupHandler(sdeventplus::source::Signal&,
71                             const struct signalfd_siginfo*)
72 {
73     // Save current set of available and active profiles
74     std::map<configKey, std::unique_ptr<Profile>> profiles;
75     profiles.swap(_profiles);
76     std::vector<std::string> activeProfiles;
77     activeProfiles.swap(_activeProfiles);
78 
79     try
80     {
81         _loadAllowed = true;
82         load();
83     }
84     catch (const std::runtime_error& re)
85     {
86         // Restore saved available and active profiles
87         _loadAllowed = false;
88         _profiles.swap(profiles);
89         _activeProfiles.swap(activeProfiles);
90         log<level::ERR>("Error reloading configs, no changes made",
91                         entry("LOAD_ERROR=%s", re.what()));
92     }
93 }
94 
95 void Manager::sigUsr1Handler(sdeventplus::source::Signal&,
96                              const struct signalfd_siginfo*)
97 {
98     _flightRecEventSource = std::make_unique<sdeventplus::source::Defer>(
99         _event, std::bind(std::mem_fn(&Manager::dumpFlightRecorder), this,
100                           std::placeholders::_1));
101 }
102 
103 void Manager::dumpFlightRecorder(sdeventplus::source::EventBase& /*source*/)
104 {
105     FlightRecorder::instance().dump();
106     _flightRecEventSource.reset();
107 }
108 
109 void Manager::load()
110 {
111     if (_loadAllowed)
112     {
113         // Load the available profiles and which are active
114         setProfiles();
115 
116         // Load the zone configurations
117         auto zones = getConfig<Zone>(false, _event, this);
118         // Load the fan configurations and move each fan into its zone
119         auto fans = getConfig<Fan>(false);
120         for (auto& fan : fans)
121         {
122             configKey fanProfile =
123                 std::make_pair(fan.second->getZone(), fan.first.second);
124             auto itZone = std::find_if(
125                 zones.begin(), zones.end(), [&fanProfile](const auto& zone) {
126                     return Manager::inConfig(fanProfile, zone.first);
127                 });
128             if (itZone != zones.end())
129             {
130                 if (itZone->second->getTarget() != fan.second->getTarget() &&
131                     fan.second->getTarget() != 0)
132                 {
133                     // Update zone target to current target of the fan in the
134                     // zone
135                     itZone->second->setTarget(fan.second->getTarget());
136                 }
137                 itZone->second->addFan(std::move(fan.second));
138             }
139         }
140 
141         // Save all currently available groups, if any, then clear for reloading
142         auto groups = std::move(Event::getAllGroups(false));
143         Event::clearAllGroups();
144 
145         std::map<configKey, std::unique_ptr<Event>> events;
146         try
147         {
148             // Load any events configured, including all the groups
149             events = getConfig<Event>(true, this, zones);
150         }
151         catch (const std::runtime_error& re)
152         {
153             // Restore saved set of all available groups for current events
154             Event::setAllGroups(std::move(groups));
155             throw re;
156         }
157 
158         // Enable zones
159         _zones = std::move(zones);
160         std::for_each(_zones.begin(), _zones.end(),
161                       [](const auto& entry) { entry.second->enable(); });
162 
163         // Clear current timers and signal subscriptions before enabling events
164         // To save reloading services and/or objects into cache, do not clear
165         // cache
166         _timers.clear();
167         _signals.clear();
168 
169         // Enable events
170         _events = std::move(events);
171         std::for_each(_events.begin(), _events.end(),
172                       [](const auto& entry) { entry.second->enable(); });
173 
174         _loadAllowed = false;
175     }
176 }
177 
178 void Manager::powerStateChanged(bool powerStateOn)
179 {
180     if (powerStateOn)
181     {
182         if (_zones.empty())
183         {
184             throw std::runtime_error("No configured zones found at poweron");
185         }
186         std::for_each(_zones.begin(), _zones.end(), [](const auto& entry) {
187             entry.second->setTarget(entry.second->getPoweronTarget());
188         });
189     }
190 }
191 
192 const std::vector<std::string>& Manager::getActiveProfiles()
193 {
194     return _activeProfiles;
195 }
196 
197 bool Manager::inConfig(const configKey& input, const configKey& comp)
198 {
199     // Config names dont match, do not include in config
200     if (input.first != comp.first)
201     {
202         return false;
203     }
204     // No profiles specified by input config, can be used in any config
205     if (input.second.empty())
206     {
207         return true;
208     }
209     else
210     {
211         // Profiles must have one match in the other's profiles(and they must be
212         // an active profile) to be used in the config
213         return std::any_of(
214             input.second.begin(), input.second.end(),
215             [&comp](const auto& lProfile) {
216                 return std::any_of(
217                     comp.second.begin(), comp.second.end(),
218                     [&lProfile](const auto& rProfile) {
219                         if (lProfile != rProfile)
220                         {
221                             return false;
222                         }
223                         auto activeProfs = getActiveProfiles();
224                         return std::find(activeProfs.begin(), activeProfs.end(),
225                                          lProfile) != activeProfs.end();
226                     });
227             });
228     }
229 }
230 
231 bool Manager::hasOwner(const std::string& path, const std::string& intf)
232 {
233     auto itServ = _servTree.find(path);
234     if (itServ == _servTree.end())
235     {
236         // Path not found in cache, therefore owner missing
237         return false;
238     }
239     for (const auto& service : itServ->second)
240     {
241         auto itIntf = std::find_if(
242             service.second.second.begin(), service.second.second.end(),
243             [&intf](const auto& interface) { return intf == interface; });
244         if (itIntf != std::end(service.second.second))
245         {
246             // Service found, return owner state
247             return service.second.first;
248         }
249     }
250     // Interface not found in cache, therefore owner missing
251     return false;
252 }
253 
254 void Manager::setOwner(const std::string& path, const std::string& serv,
255                        const std::string& intf, bool isOwned)
256 {
257     // Set owner state for specific object given
258     auto& ownIntf = _servTree[path][serv];
259     ownIntf.first = isOwned;
260     auto itIntf = std::find_if(
261         ownIntf.second.begin(), ownIntf.second.end(),
262         [&intf](const auto& interface) { return intf == interface; });
263     if (itIntf == std::end(ownIntf.second))
264     {
265         ownIntf.second.emplace_back(intf);
266     }
267 
268     // Update owner state on all entries of the same `serv` & `intf`
269     for (auto& itPath : _servTree)
270     {
271         if (itPath.first == path)
272         {
273             // Already set/updated owner on this path for `serv` & `intf`
274             continue;
275         }
276         for (auto& itServ : itPath.second)
277         {
278             if (itServ.first != serv)
279             {
280                 continue;
281             }
282             auto itIntf = std::find_if(
283                 itServ.second.second.begin(), itServ.second.second.end(),
284                 [&intf](const auto& interface) { return intf == interface; });
285             if (itIntf != std::end(itServ.second.second))
286             {
287                 itServ.second.first = isOwned;
288             }
289         }
290     }
291 }
292 
293 const std::string& Manager::findService(const std::string& path,
294                                         const std::string& intf)
295 {
296     static const std::string empty = "";
297 
298     auto itServ = _servTree.find(path);
299     if (itServ != _servTree.end())
300     {
301         for (const auto& service : itServ->second)
302         {
303             auto itIntf = std::find_if(
304                 service.second.second.begin(), service.second.second.end(),
305                 [&intf](const auto& interface) { return intf == interface; });
306             if (itIntf != std::end(service.second.second))
307             {
308                 // Service found, return service name
309                 return service.first;
310             }
311         }
312     }
313 
314     return empty;
315 }
316 
317 void Manager::addServices(const std::string& intf, int32_t depth)
318 {
319     // Get all subtree objects for the given interface
320     auto objects = util::SDBusPlus::getSubTreeRaw(util::SDBusPlus::getBus(),
321                                                   "/", intf, depth);
322     // Add what's returned to the cache of path->services
323     for (auto& itPath : objects)
324     {
325         auto pathIter = _servTree.find(itPath.first);
326         if (pathIter != _servTree.end())
327         {
328             // Path found in cache
329             for (auto& itServ : itPath.second)
330             {
331                 auto servIter = pathIter->second.find(itServ.first);
332                 if (servIter != pathIter->second.end())
333                 {
334                     // Service found in cache
335                     for (auto& itIntf : itServ.second)
336                     {
337                         if (std::find(servIter->second.second.begin(),
338                                       servIter->second.second.end(),
339                                       itIntf) == servIter->second.second.end())
340                         {
341                             // Add interface to cache
342                             servIter->second.second.emplace_back(itIntf);
343                         }
344                     }
345                 }
346                 else
347                 {
348                     // Service not found in cache
349                     auto intfs = {intf};
350                     pathIter->second[itServ.first] =
351                         std::make_pair(true, intfs);
352                 }
353             }
354         }
355         else
356         {
357             // Path not found in cache
358             auto intfs = {intf};
359             _servTree[itPath.first] = {
360                 {itPath.second.begin()->first, std::make_pair(true, intfs)}};
361         }
362     }
363 }
364 
365 const std::string& Manager::getService(const std::string& path,
366                                        const std::string& intf)
367 {
368     // Retrieve service from cache
369     const auto& serviceName = findService(path, intf);
370     if (serviceName.empty())
371     {
372         addServices(intf, 0);
373         return findService(path, intf);
374     }
375 
376     return serviceName;
377 }
378 
379 std::vector<std::string> Manager::findPaths(const std::string& serv,
380                                             const std::string& intf)
381 {
382     std::vector<std::string> paths;
383 
384     for (const auto& path : _servTree)
385     {
386         auto itServ = path.second.find(serv);
387         if (itServ != path.second.end())
388         {
389             if (std::find(itServ->second.second.begin(),
390                           itServ->second.second.end(),
391                           intf) != itServ->second.second.end())
392             {
393                 if (std::find(paths.begin(), paths.end(), path.first) ==
394                     paths.end())
395                 {
396                     paths.push_back(path.first);
397                 }
398             }
399         }
400     }
401 
402     return paths;
403 }
404 
405 std::vector<std::string> Manager::getPaths(const std::string& serv,
406                                            const std::string& intf)
407 {
408     auto paths = findPaths(serv, intf);
409     if (paths.empty())
410     {
411         addServices(intf, 0);
412         return findPaths(serv, intf);
413     }
414 
415     return paths;
416 }
417 
418 void Manager::addObjects(const std::string& path, const std::string& intf,
419                          const std::string& prop)
420 {
421     auto service = getService(path, intf);
422     if (service.empty())
423     {
424         // Log service not found for object
425         log<level::DEBUG>(
426             fmt::format("Unable to get service name for path {}, interface {}",
427                         path, intf)
428                 .c_str());
429         return;
430     }
431 
432     auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager");
433     if (objMgrPaths.empty())
434     {
435         // No object manager interface provided by service?
436         // Attempt to retrieve property directly
437         auto variant = util::SDBusPlus::getPropertyVariant<PropertyVariantType>(
438             _bus, service, path, intf, prop);
439         _objects[path][intf][prop] = variant;
440         return;
441     }
442 
443     for (const auto& objMgrPath : objMgrPaths)
444     {
445         // Get all managed objects of service
446         auto objects = util::SDBusPlus::getManagedObjects<PropertyVariantType>(
447             _bus, service, objMgrPath);
448 
449         // Add what's returned to the cache of objects
450         for (auto& object : objects)
451         {
452             auto itPath = _objects.find(object.first);
453             if (itPath != _objects.end())
454             {
455                 // Path found in cache
456                 for (auto& interface : itPath->second)
457                 {
458                     auto itIntf = itPath->second.find(interface.first);
459                     if (itIntf != itPath->second.end())
460                     {
461                         // Interface found in cache
462                         for (auto& property : itIntf->second)
463                         {
464                             auto itProp = itIntf->second.find(property.first);
465                             if (itProp != itIntf->second.end())
466                             {
467                                 // Property found, update value
468                                 itProp->second = property.second;
469                             }
470                             else
471                             {
472                                 itIntf->second.insert(property);
473                             }
474                         }
475                     }
476                     else
477                     {
478                         // Interface not found in cache
479                         itPath->second.insert(interface);
480                     }
481                 }
482             }
483             else
484             {
485                 // Path not found in cache
486                 _objects.insert(object);
487             }
488         }
489     }
490 }
491 
492 const std::optional<PropertyVariantType>
493     Manager::getProperty(const std::string& path, const std::string& intf,
494                          const std::string& prop)
495 {
496     // TODO Objects hosted by fan control (i.e. ThermalMode) are required to
497     // update the cache upon being set/updated
498     auto itPath = _objects.find(path);
499     if (itPath != _objects.end())
500     {
501         auto itIntf = itPath->second.find(intf);
502         if (itIntf != itPath->second.end())
503         {
504             auto itProp = itIntf->second.find(prop);
505             if (itProp != itIntf->second.end())
506             {
507                 return itProp->second;
508             }
509         }
510     }
511 
512     return std::nullopt;
513 }
514 
515 void Manager::addTimer(const TimerType type,
516                        const std::chrono::microseconds interval,
517                        std::unique_ptr<TimerPkg> pkg)
518 {
519     auto dataPtr =
520         std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
521     Timer timer(_event,
522                 std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
523     if (type == TimerType::repeating)
524     {
525         timer.restart(interval);
526     }
527     else if (type == TimerType::oneshot)
528     {
529         timer.restartOnce(interval);
530     }
531     else
532     {
533         throw std::invalid_argument("Invalid Timer Type");
534     }
535     _timers.emplace_back(std::move(dataPtr), std::move(timer));
536 }
537 
538 void Manager::timerExpired(TimerData& data)
539 {
540     auto& actions =
541         std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
542     // Perform the actions in the timer data
543     std::for_each(actions.begin(), actions.end(),
544                   [](auto& action) { action->run(); });
545 
546     // Remove oneshot timers after they expired
547     if (data.first == TimerType::oneshot)
548     {
549         auto itTimer = std::find_if(
550             _timers.begin(), _timers.end(), [&data](const auto& timer) {
551                 return (data.first == timer.first->first &&
552                         (std::get<std::string>(data.second) ==
553                          std::get<std::string>(timer.first->second)));
554             });
555         if (itTimer != std::end(_timers))
556         {
557             _timers.erase(itTimer);
558         }
559     }
560 }
561 
562 void Manager::handleSignal(sdbusplus::message::message& msg,
563                            const std::vector<SignalPkg>& pkgs)
564 {
565     for (auto& pkg : pkgs)
566     {
567         // Handle the signal callback and only run the actions if the handler
568         // updated the cache for the given SignalObject
569         if (std::get<SignalHandler>(pkg)(msg, std::get<SignalObject>(pkg),
570                                          *this))
571         {
572             // Perform the actions in the handler package
573             auto& actions = std::get<SignalActions>(pkg);
574             std::for_each(actions.begin(), actions.end(),
575                           [](auto& action) { action.get()->run(); });
576         }
577     }
578 }
579 
580 void Manager::setProfiles()
581 {
582     // Profiles JSON config file is optional
583     auto confFile = fan::JsonConfig::getConfFile(_bus, confAppName,
584                                                  Profile::confFileName, true);
585 
586     _profiles.clear();
587     if (!confFile.empty())
588     {
589         for (const auto& entry : fan::JsonConfig::load(confFile))
590         {
591             auto obj = std::make_unique<Profile>(entry);
592             _profiles.emplace(
593                 std::make_pair(obj->getName(), obj->getProfiles()),
594                 std::move(obj));
595         }
596     }
597 
598     // Ensure all configurations use the same set of active profiles
599     // (In case a profile's active state changes during configuration)
600     _activeProfiles.clear();
601     for (const auto& profile : _profiles)
602     {
603         if (profile.second->isActive())
604         {
605             _activeProfiles.emplace_back(profile.first.first);
606         }
607     }
608 }
609 
610 } // namespace phosphor::fan::control::json
611