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 <cstring>
18 #include <iostream>
19 #include <libconfig.h++>
20 #include <map>
21 #include <memory>
22 
23 /* Configuration. */
24 #include "conf.hpp"
25 
26 #include "interfaces.hpp"
27 #include "manager.hpp"
28 #include "util.hpp"
29 
30 #include "dbus/dbuspassive.hpp"
31 #include "notimpl/readonly.hpp"
32 #include "notimpl/writeonly.hpp"
33 #include "sysfs/sysfsread.hpp"
34 #include "sensors/manager.hpp"
35 #include "sensors/host.hpp"
36 #include "sensors/pluggable.hpp"
37 #include "sysfs/sysfswrite.hpp"
38 
39 
40 static constexpr bool deferSignals = true;
41 
42 std::shared_ptr<SensorManager> BuildSensors(
43     std::map<std::string, struct sensor>& Config)
44 {
45     auto mgmr = std::make_shared<SensorManager>();
46     auto& HostSensorBus = mgmr->getHostBus();
47     auto& PassiveListeningBus = mgmr->getPassiveBus();
48 
49     for (auto& it : Config)
50     {
51         std::unique_ptr<ReadInterface> ri;
52         std::unique_ptr<WriteInterface> wi;
53 
54         std::string name = it.first;
55         struct sensor* info = &it.second;
56 
57         std::cerr << "Sensor: " << name << " " << info->type << " ";
58         std::cerr << info->readpath << " " << info->writepath << "\n";
59 
60         IOInterfaceType rtype = GetReadInterfaceType(info->readpath);
61         IOInterfaceType wtype = GetWriteInterfaceType(info->writepath);
62 
63         // fan sensors can be ready any way and written others.
64         // fan sensors are the only sensors this is designed to write.
65         // Nothing here should be write-only, although, in theory a fan could be.
66         // I'm just not sure how that would fit together.
67         // TODO(venture): It should check with the ObjectMapper to check if
68         // that sensor exists on the Dbus.
69         switch (rtype)
70         {
71             case IOInterfaceType::DBUSPASSIVE:
72                 ri = std::make_unique<DbusPassive>(
73                          PassiveListeningBus,
74                          info->type,
75                          name);
76                 break;
77             case IOInterfaceType::EXTERNAL:
78                 // These are a special case for read-only.
79                 break;
80             case IOInterfaceType::SYSFS:
81                 ri = std::make_unique<SysFsRead>(info->readpath);
82                 break;
83             default:
84                 ri = std::make_unique<WriteOnly>();
85                 break;
86         }
87 
88         if (info->type == "fan")
89         {
90             switch (wtype)
91             {
92                 case IOInterfaceType::SYSFS:
93                     if (info->max > 0)
94                     {
95                         wi = std::make_unique<SysFsWritePercent>(
96                                  info->writepath,
97                                  info->min,
98                                  info->max);
99                     }
100                     else
101                     {
102                         wi = std::make_unique<SysFsWrite>(
103                                  info->writepath,
104                                  info->min,
105                                  info->max);
106                     }
107 
108                     break;
109                 default:
110                     wi = std::make_unique<ReadOnlyNoExcept>();
111                     break;
112             }
113 
114             auto sensor = std::make_unique<PluggableSensor>(
115                               name,
116                               info->timeout,
117                               std::move(ri),
118                               std::move(wi));
119             mgmr->addSensor(info->type, name, std::move(sensor));
120         }
121         else if (info->type == "temp" || info->type == "margin")
122         {
123             // These sensors are read-only, but only for this application
124             // which only writes to fan sensors.
125             std::cerr << info->type << " readpath: " << info->readpath << "\n";
126 
127             if (IOInterfaceType::EXTERNAL == rtype)
128             {
129                 std::cerr << "Creating HostSensor: " << name
130                           << " path: " << info->readpath << "\n";
131 
132                 /*
133                  * The reason we handle this as a HostSensor is because it's
134                  * not quite pluggable; but maybe it could be.
135                  */
136                 auto sensor = HostSensor::CreateTemp(
137                                   name,
138                                   info->timeout,
139                                   HostSensorBus,
140                                   info->readpath.c_str(),
141                                   deferSignals);
142                 mgmr->addSensor(info->type, name, std::move(sensor));
143             }
144             else
145             {
146                 wi = std::make_unique<ReadOnlyNoExcept>();
147                 auto sensor = std::make_unique<PluggableSensor>(
148                                   name,
149                                   info->timeout,
150                                   std::move(ri),
151                                   std::move(wi));
152                 mgmr->addSensor(info->type, name, std::move(sensor));
153             }
154         }
155     }
156 
157     return mgmr;
158 }
159 
160 /*
161  * If there's a configuration file, we build from that, and it requires special
162  * parsing.  I should just ditch the compile-time version to reduce the
163  * probability of sync bugs.
164  */
165 std::shared_ptr<SensorManager> BuildSensorsFromConfig(std::string& path)
166 {
167     using namespace libconfig;
168 
169     std::map<std::string, struct sensor> config;
170     Config cfg;
171 
172     std::cerr << "entered BuildSensorsFromConfig\n";
173 
174     /* The load was modeled after the example source provided. */
175     try
176     {
177         cfg.readFile(path.c_str());
178     }
179     catch (const FileIOException& fioex)
180     {
181         std::cerr << "I/O error while reading file: " << fioex.what() << std::endl;
182         throw;
183     }
184     catch (const ParseException& pex)
185     {
186         std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
187                   << " - " << pex.getError() << std::endl;
188         throw;
189     }
190 
191     try
192     {
193         const Setting& root = cfg.getRoot();
194 
195         /* Grab the list of sensors and create them all */
196         const Setting& sensors = root["sensors"];
197         int count = sensors.getLength();
198 
199         for (int i = 0; i < count; ++i)
200         {
201             const Setting& sensor = sensors[i];
202 
203             std::string name;
204             struct sensor thisOne;
205 
206             /* Not a super fan of using this library for run-time configuration. */
207             name = sensor.lookup("name").c_str();
208             thisOne.type = sensor.lookup("type").c_str();
209             thisOne.readpath = sensor.lookup("readpath").c_str();
210             thisOne.writepath = sensor.lookup("writepath").c_str();
211 
212             /* TODO: Document why this is wonky.  The library probably doesn't
213              * like int64_t
214              */
215             int min = sensor.lookup("min");
216             thisOne.min = static_cast<int64_t>(min);
217             int max = sensor.lookup("max");
218             thisOne.max = static_cast<int64_t>(max);
219             int timeout = sensor.lookup("timeout");
220             thisOne.timeout = static_cast<int64_t>(timeout);
221 
222             // leaving for verification for now.  and yea the above is
223             // necessary.
224             std::cerr << "min: " << min
225                     << " max: " << max
226                     << " savedmin: " << thisOne.min
227                     << " savedmax: " << thisOne.max
228                     << " timeout: " << thisOne.timeout
229                     << std::endl;
230 
231             config[name] = thisOne;
232         }
233     }
234     catch (const SettingTypeException &setex)
235     {
236         std::cerr << "Setting '" << setex.getPath()
237                   << "' type exception!" << std::endl;
238         throw;
239     }
240     catch (const SettingNotFoundException& snex)
241     {
242         std::cerr << "Setting not found!" << std::endl;
243         throw;
244     }
245 
246     return BuildSensors(config);
247 }
248 
249