1 /**
2  * Copyright 2017 Google Inc.
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 
17 #include <iostream>
18 #include <map>
19 #include <string>
20 
21 /* Configuration. */
22 #include "conf.hpp"
23 #include "dbus/dbuspassive.hpp"
24 #include "dbus/dbuswrite.hpp"
25 #include "errors/exception.hpp"
26 #include "interfaces.hpp"
27 #include "notimpl/readonly.hpp"
28 #include "notimpl/writeonly.hpp"
29 #include "sensors/builder.hpp"
30 #include "sensors/host.hpp"
31 #include "sensors/manager.hpp"
32 #include "sensors/pluggable.hpp"
33 #include "sysfs/sysfsread.hpp"
34 #include "sysfs/sysfswrite.hpp"
35 #include "util.hpp"
36 
37 static constexpr bool deferSignals = true;
38 static DbusHelper helper;
39 
40 SensorManager
41     buildSensors(const std::map<std::string, struct conf::SensorConfig>& config,
42                  sdbusplus::bus::bus& passive, sdbusplus::bus::bus& host)
43 {
44     SensorManager mgmr(passive, host);
45     auto& hostSensorBus = mgmr.getHostBus();
46     auto& passiveListeningBus = mgmr.getPassiveBus();
47 
48     for (const auto& it : config)
49     {
50         std::unique_ptr<ReadInterface> ri;
51         std::unique_ptr<WriteInterface> wi;
52 
53         std::string name = it.first;
54         const struct conf::SensorConfig* info = &it.second;
55 
56         std::cerr << "Sensor: " << name << " " << info->type << " ";
57         std::cerr << info->readPath << " " << info->writePath << "\n";
58 
59         IOInterfaceType rtype = getReadInterfaceType(info->readPath);
60         IOInterfaceType wtype = getWriteInterfaceType(info->writePath);
61 
62         // fan sensors can be ready any way and written others.
63         // fan sensors are the only sensors this is designed to write.
64         // Nothing here should be write-only, although, in theory a fan could
65         // be. I'm just not sure how that would fit together.
66         // TODO(venture): It should check with the ObjectMapper to check if
67         // that sensor exists on the Dbus.
68         switch (rtype)
69         {
70             case IOInterfaceType::DBUSPASSIVE:
71                 // we only need to make one match based on the dbus object
72                 static std::shared_ptr<DbusPassiveRedundancy> redundancy =
73                     std::make_shared<DbusPassiveRedundancy>(
74                         passiveListeningBus);
75 
76                 if (info->type == "fan")
77                 {
78                     ri = DbusPassive::createDbusPassive(
79                         passiveListeningBus, info->type, name, &helper, info,
80                         redundancy);
81                 }
82                 else
83                 {
84                     ri = DbusPassive::createDbusPassive(passiveListeningBus,
85                                                         info->type, name,
86                                                         &helper, info, nullptr);
87                 }
88                 if (ri == nullptr)
89                 {
90                     throw SensorBuildException(
91                         "Failed to create dbus passive sensor: " + name +
92                         " of type: " + info->type);
93                 }
94                 break;
95             case IOInterfaceType::EXTERNAL:
96                 // These are a special case for read-only.
97                 break;
98             case IOInterfaceType::SYSFS:
99                 ri = std::make_unique<SysFsRead>(info->readPath);
100                 break;
101             default:
102                 ri = std::make_unique<WriteOnly>();
103                 break;
104         }
105 
106         if (info->type == "fan")
107         {
108             switch (wtype)
109             {
110                 case IOInterfaceType::SYSFS:
111                     if (info->max > 0)
112                     {
113                         wi = std::make_unique<SysFsWritePercent>(
114                             info->writePath, info->min, info->max);
115                     }
116                     else
117                     {
118                         wi = std::make_unique<SysFsWrite>(info->writePath,
119                                                           info->min, info->max);
120                     }
121 
122                     break;
123                 case IOInterfaceType::DBUSACTIVE:
124                     if (info->max > 0)
125                     {
126                         wi = DbusWritePercent::createDbusWrite(
127                             info->writePath, info->min, info->max, helper);
128                     }
129                     else
130                     {
131                         wi = DbusWrite::createDbusWrite(
132                             info->writePath, info->min, info->max, helper);
133                     }
134 
135                     if (wi == nullptr)
136                     {
137                         throw SensorBuildException(
138                             "Unable to create write dbus interface for path: " +
139                             info->writePath);
140                     }
141 
142                     break;
143                 default:
144                     wi = std::make_unique<ReadOnlyNoExcept>();
145                     break;
146             }
147 
148             auto sensor = std::make_unique<PluggableSensor>(
149                 name, info->timeout, std::move(ri), std::move(wi));
150             mgmr.addSensor(info->type, name, std::move(sensor));
151         }
152         else if (info->type == "temp" || info->type == "margin")
153         {
154             // These sensors are read-only, but only for this application
155             // which only writes to fan sensors.
156             std::cerr << info->type << " readPath: " << info->readPath << "\n";
157 
158             if (IOInterfaceType::EXTERNAL == rtype)
159             {
160                 std::cerr << "Creating HostSensor: " << name
161                           << " path: " << info->readPath << "\n";
162 
163                 /*
164                  * The reason we handle this as a HostSensor is because it's
165                  * not quite pluggable; but maybe it could be.
166                  */
167                 auto sensor = HostSensor::createTemp(
168                     name, info->timeout, hostSensorBus, info->readPath.c_str(),
169                     deferSignals);
170                 mgmr.addSensor(info->type, name, std::move(sensor));
171             }
172             else
173             {
174                 wi = std::make_unique<ReadOnlyNoExcept>();
175                 auto sensor = std::make_unique<PluggableSensor>(
176                     name, info->timeout, std::move(ri), std::move(wi));
177                 mgmr.addSensor(info->type, name, std::move(sensor));
178             }
179         }
180     }
181 
182     return mgmr;
183 }
184