/** * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include /* Configuration. */ #include "conf.hpp" #include "interfaces.hpp" #include "manager.hpp" #include "util.hpp" #include "dbus/dbuspassive.hpp" #include "notimpl/readonly.hpp" #include "notimpl/writeonly.hpp" #include "sysfs/sysfsread.hpp" #include "sensors/manager.hpp" #include "sensors/host.hpp" #include "sensors/pluggable.hpp" #include "sysfs/sysfswrite.hpp" static constexpr bool deferSignals = true; std::shared_ptr BuildSensors( std::map& Config) { auto mgmr = std::make_shared(); auto& HostSensorBus = mgmr->getHostBus(); auto& PassiveListeningBus = mgmr->getPassiveBus(); for (auto& it : Config) { std::unique_ptr ri; std::unique_ptr wi; std::string name = it.first; struct sensor* info = &it.second; std::cerr << "Sensor: " << name << " " << info->type << " "; std::cerr << info->readpath << " " << info->writepath << "\n"; IOInterfaceType rtype = GetReadInterfaceType(info->readpath); IOInterfaceType wtype = GetWriteInterfaceType(info->writepath); // fan sensors can be ready any way and written others. // fan sensors are the only sensors this is designed to write. // Nothing here should be write-only, although, in theory a fan could be. // I'm just not sure how that would fit together. // TODO(venture): It should check with the ObjectMapper to check if // that sensor exists on the Dbus. switch (rtype) { case IOInterfaceType::DBUSPASSIVE: ri = std::make_unique( PassiveListeningBus, info->type, name); break; case IOInterfaceType::EXTERNAL: // These are a special case for read-only. break; case IOInterfaceType::SYSFS: ri = std::make_unique(info->readpath); break; default: ri = std::make_unique(); break; } if (info->type == "fan") { switch (wtype) { case IOInterfaceType::SYSFS: if (info->max > 0) { wi = std::make_unique( info->writepath, info->min, info->max); } else { wi = std::make_unique( info->writepath, info->min, info->max); } break; default: wi = std::make_unique(); break; } auto sensor = std::make_unique( name, info->timeout, std::move(ri), std::move(wi)); mgmr->addSensor(info->type, name, std::move(sensor)); } else if (info->type == "temp" || info->type == "margin") { // These sensors are read-only, but only for this application // which only writes to fan sensors. std::cerr << info->type << " readpath: " << info->readpath << "\n"; if (IOInterfaceType::EXTERNAL == rtype) { std::cerr << "Creating HostSensor: " << name << " path: " << info->readpath << "\n"; /* * The reason we handle this as a HostSensor is because it's * not quite pluggable; but maybe it could be. */ auto sensor = HostSensor::CreateTemp( name, info->timeout, HostSensorBus, info->readpath.c_str(), deferSignals); mgmr->addSensor(info->type, name, std::move(sensor)); } else { wi = std::make_unique(); auto sensor = std::make_unique( name, info->timeout, std::move(ri), std::move(wi)); mgmr->addSensor(info->type, name, std::move(sensor)); } } } return mgmr; } /* * If there's a configuration file, we build from that, and it requires special * parsing. I should just ditch the compile-time version to reduce the * probability of sync bugs. */ std::shared_ptr BuildSensorsFromConfig(std::string& path) { using namespace libconfig; std::map config; Config cfg; std::cerr << "entered BuildSensorsFromConfig\n"; /* The load was modeled after the example source provided. */ try { cfg.readFile(path.c_str()); } catch (const FileIOException& fioex) { std::cerr << "I/O error while reading file: " << fioex.what() << std::endl; throw; } catch (const ParseException& pex) { std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine() << " - " << pex.getError() << std::endl; throw; } try { const Setting& root = cfg.getRoot(); /* Grab the list of sensors and create them all */ const Setting& sensors = root["sensors"]; int count = sensors.getLength(); for (int i = 0; i < count; ++i) { const Setting& sensor = sensors[i]; std::string name; struct sensor thisOne; /* Not a super fan of using this library for run-time configuration. */ name = sensor.lookup("name").c_str(); thisOne.type = sensor.lookup("type").c_str(); thisOne.readpath = sensor.lookup("readpath").c_str(); thisOne.writepath = sensor.lookup("writepath").c_str(); /* TODO: Document why this is wonky. The library probably doesn't * like int64_t */ int min = sensor.lookup("min"); thisOne.min = static_cast(min); int max = sensor.lookup("max"); thisOne.max = static_cast(max); int timeout = sensor.lookup("timeout"); thisOne.timeout = static_cast(timeout); // leaving for verification for now. and yea the above is // necessary. std::cerr << "min: " << min << " max: " << max << " savedmin: " << thisOne.min << " savedmax: " << thisOne.max << " timeout: " << thisOne.timeout << std::endl; config[name] = thisOne; } } catch (const SettingTypeException &setex) { std::cerr << "Setting '" << setex.getPath() << "' type exception!" << std::endl; throw; } catch (const SettingNotFoundException& snex) { std::cerr << "Setting not found!" << std::endl; throw; } return BuildSensors(config); }