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