123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- /*
- * Copyright (C) 2015 Malte Veerman <maldela@halloarsch.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
- #include "loader.h"
- #include "hwmon.h"
- #include "fancontrolaction.h"
- #include <QtCore/QFile>
- #include <QtCore/QDir>
- #include <QtCore/QTextStream>
- #include <QtCore/QTimer>
- #include <QtCore/QDebug>
- #include <KAuth/KAuthExecuteJob>
- #include <KI18n/KLocalizedString>
- #define HWMON_PATH "/sys/class/hwmon"
- #ifndef STANDARD_CONFIG_FILE
- #define STANDARD_CONFIG_FILE "/etc/fancontrol"
- #endif
- namespace Fancontrol
- {
- Loader::Loader(QObject *parent) : QObject(parent),
- m_interval(10),
- m_configUrl(QUrl::fromLocalFile(QStringLiteral(STANDARD_CONFIG_FILE))),
- m_timer(new QTimer(this))
- {
- parseHwmons();
- m_timer->setSingleShot(false);
- m_timer->start(1);
- connect(m_timer, SIGNAL(timeout()), this, SLOT(updateSensors()));
- }
- void Loader::parseHwmons()
- {
- QDir hwmonDir(QStringLiteral(HWMON_PATH));
- QStringList list;
- if (hwmonDir.isReadable())
- list = hwmonDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
- else if (hwmonDir.exists())
- {
- setError(i18n("%1 is not readable!", QStringLiteral(HWMON_PATH)), true);
- return;
- }
- else
- {
- setError(i18n("%1 does not exist!", QStringLiteral(HWMON_PATH)), true);
- return;
- }
- QStringList dereferencedList;
- while (!list.isEmpty())
- dereferencedList << QFile::symLinkTarget(hwmonDir.absoluteFilePath(list.takeFirst()));
- foreach (Hwmon *hwmon, m_hwmons)
- {
- if (!dereferencedList.contains(hwmon->path()))
- {
- m_hwmons.removeOne(hwmon);
- emit hwmonsChanged();
- hwmon->deleteLater();
- }
- else
- hwmon->initialize();
- }
- foreach (const QString &hwmonPath, dereferencedList)
- {
- bool hwmonExists = false;
- foreach (const Hwmon *hwmon, m_hwmons)
- {
- if (hwmon->path() == hwmonPath)
- {
- hwmonExists = true;
- break;
- }
- }
- if (!hwmonExists)
- {
- Hwmon *newHwmon = new Hwmon(hwmonPath, this);
- if (newHwmon->isValid())
- {
- connect(this, SIGNAL(sensorsUpdateNeeded()), newHwmon, SLOT(updateSensors()));
- m_hwmons << newHwmon;
- emit hwmonsChanged();
- }
- else
- delete newHwmon;
- }
- }
- }
- PwmFan * Loader::getPwmFan(const QPair<int, int> &indexPair) const
- {
- Hwmon *hwmon = m_hwmons.value(indexPair.first, Q_NULLPTR);
- if (!hwmon)
- return Q_NULLPTR;
- return hwmon->pwmFan(indexPair.second);
- }
- Temp * Loader::getTemp(const QPair<int, int> &indexPair) const
- {
- Hwmon *hwmon = m_hwmons.value(indexPair.first, Q_NULLPTR);
- if (!hwmon)
- return Q_NULLPTR;
- return hwmon->temp(indexPair.second);
- }
- QPair<int, int> Loader::getEntryNumbers(const QString &entry)
- {
- if (entry.isEmpty())
- {
- qWarning() << "Loader::getHwmonNumber(): given empty string.";
- return QPair<int, int>(-1, -1);
- }
- QStringList list = entry.split('/', QString::SkipEmptyParts);
- if (list.size() != 2)
- {
- qWarning() << "Invalid entry to parse:" << entry << "Should contain exactly one \'/\'";
- return QPair<int, int>(-1, -1);
- }
- QString hwmon = list.at(0);
- QString sensor = list.at(1);
- if (!hwmon.startsWith(QStringLiteral("hwmon")))
- {
- qWarning() << "Invalid entry to parse:" << entry << "Should begin with \"hwmon\"";
- return QPair<int, int>(-1, -1);
- }
- if (!sensor.contains(QRegExp("^(pwm|fan|temp)\\d+")))
- {
- qWarning() << "Invalid entry to parse:" << entry << "\n Sensor should begin with pwm|fan|temp followed by a number";
- return QPair<int, int>(-1, -1);
- }
- bool success;
- hwmon.remove(QStringLiteral("hwmon"));
- sensor.remove(QRegExp("^(pwm|fan|temp)"));
- sensor.remove(QStringLiteral("_input"));
- int hwmonResult = hwmon.toInt(&success);
- if (!success)
- {
- qWarning() << "Invalid entry to parse:" << entry << "Could not convert" << hwmon << "to int";
- return QPair<int, int>(-1, -1);
- }
- int sensorResult = sensor.toInt(&success);
- if (!success)
- {
- qWarning() << "Invalid entry to parse:" << entry << "Could not convert" << sensor << "to int";
- return QPair<int, int>(-1, -1);
- }
- return QPair<int, int>(hwmonResult, sensorResult - 1);
- }
- void Loader::parseConfigLine(const QString &line, void (PwmFan::*memberSetFunction)(int)) const
- {
- if (!memberSetFunction)
- {
- qWarning() << "Loader::parseConfigLine(): Null for member function pointer";
- return;
- }
- QStringList entries = line.split(' ');
- foreach (const QString &entry, entries)
- {
- QStringList fanValuePair = entry.split('=');
- if (fanValuePair.size() == 2)
- {
- QString fanString = fanValuePair.at(0);
- QString valueString = fanValuePair.at(1);
- bool success;
- int value = valueString.toInt(&success);
- if (success)
- {
- PwmFan *fan = getPwmFan(getEntryNumbers(fanString));
- if (fan)
- (fan->*memberSetFunction)(value);
- }
- else
- qWarning() << valueString << "is not an int";
- }
- else
- qWarning() << "Invalid Entry:" << entry;
- }
- }
- bool Loader::load(const QUrl &url)
- {
- QString fileName;
- if (url.isEmpty())
- {
- qDebug() << "Given empty url. Fallback to " << m_configUrl;
- fileName = m_configUrl.toLocalFile();
- }
- else if (url.isValid())
- {
- if (url.isLocalFile())
- fileName = url.toLocalFile();
- else
- {
- setError(i18n("%1 is not a local file!", url.toDisplayString()));
- return false;
- }
- }
- else
- {
- setError(i18n("%1 is not a valid url!", url.toDisplayString()));
- return false;
- }
- QTextStream stream;
- QFile file(fileName);
- QString fileContent;
- if (file.open(QFile::ReadOnly | QFile::Text))
- {
- if (!url.isEmpty())
- {
- m_configUrl = url;
- emit configUrlChanged();
- }
- stream.setDevice(&file);
- fileContent = stream.readAll();
- }
- else if (file.exists())
- {
- KAuth::Action action = newFancontrolAction();
- QVariantMap map;
- map[QStringLiteral("action")] = QVariant("read");
- map[QStringLiteral("filename")] = fileName;
- action.setArguments(map);
- KAuth::ExecuteJob *reply = action.execute();
- if (!reply->exec())
- {
- qDebug() << reply->error();
- setError(reply->errorString() + reply->errorText(), true);
- return false;
- }
- else
- {
- if (!url.isEmpty())
- {
- m_configUrl = url;
- emit configUrlChanged();
- }
- fileContent = reply->data().value(QStringLiteral("content")).toString();
- }
- }
- else
- {
- if (!url.isEmpty())
- {
- emit invalidConfigUrl();
- setError(i18n("%1 does not exist!", file.fileName()));
- }
- return false;
- }
- //Disconnect hwmons for performance reasons
- //They get reconnected later
- foreach (Hwmon *hwmon, m_hwmons)
- {
- disconnect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- foreach (QObject *pwmFan, hwmon->pwmFans())
- {
- qobject_cast<PwmFan *>(pwmFan)->reset();
- }
- }
- stream.setString(&fileContent);
- QStringList lines;
- do
- {
- QString line(stream.readLine());
- if (line.startsWith('#') || line.trimmed().isEmpty())
- continue;
- int offset = line.indexOf('#');
- if (offset != -1)
- line.truncate(offset-1);
- line = line.simplified();
- lines << line;
- }
- while(!stream.atEnd());
- foreach (QString line, lines)
- {
- if (line.startsWith(QStringLiteral("INTERVAL=")))
- {
- line.remove(QStringLiteral("INTERVAL="));
- bool success;
- int interval = line.toInt(&success);
- if (success)
- {
- setInterval(interval, false);
- }
- else
- {
- //Connect hwmons again
- foreach (Hwmon *hwmon, m_hwmons)
- connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- setError(i18n("Unable to parse interval line: \n %1", line), true);
- return false;
- }
- }
- else if (line.startsWith(QStringLiteral("FCTEMPS=")))
- {
- line.remove(QStringLiteral("FCTEMPS="));
- QStringList fctemps = line.split(' ');
- foreach (const QString &fctemp, fctemps)
- {
- QStringList nameValuePair = fctemp.split('=');
- if (nameValuePair.size() == 2)
- {
- QString pwm = nameValuePair.at(0);
- QString temp = nameValuePair.at(1);
- PwmFan *pwmPointer = getPwmFan(getEntryNumbers(pwm));
- Temp *tempPointer = getTemp(getEntryNumbers(temp));
- if (pwmPointer && tempPointer)
- {
- pwmPointer->setTemp(tempPointer);
- pwmPointer->setHasTemp(true);
- pwmPointer->setMinPwm(0);
- }
- }
- else
- qWarning() << "Invalid entry:" << fctemp;
- }
- }
- else if (line.startsWith(QStringLiteral("DEVNAME=")))
- {
- line.remove(QStringLiteral("DEVNAME="));
- QStringList devnames = line.split(' ');
- foreach (const QString &devname, devnames)
- {
- QStringList indexNamePair = devname.split('=');
- if (indexNamePair.size() == 2)
- {
- QString hwmon = indexNamePair.at(0);
- QString name = indexNamePair.at(1);
- bool success;
- Hwmon *hwmonPointer = m_hwmons.value(hwmon.remove(QStringLiteral("hwmon")).toInt(&success), Q_NULLPTR);
- if (!success)
- {
- //Connect hwmons again
- foreach (Hwmon *hwmon, m_hwmons)
- connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- setError(i18n("Can not parse %1", devname), true);
- return false;
- }
- if (!hwmonPointer || hwmonPointer->name().split('.').first() != name)
- {
- //Connect hwmons again
- foreach (Hwmon *hwmon, m_hwmons)
- connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- setError(i18n("Invalid config file!"), true);
- return false;
- }
- }
- }
- }
- else if (line.startsWith(QStringLiteral("MINTEMP=")))
- {
- line.remove(QStringLiteral("MINTEMP="));
- parseConfigLine(line, &PwmFan::setMinTemp);
- }
- else if (line.startsWith(QStringLiteral("MAXTEMP=")))
- {
- line.remove(QStringLiteral("MAXTEMP="));
- parseConfigLine(line, &PwmFan::setMaxTemp);
- }
- else if (line.startsWith(QStringLiteral("MINSTART=")))
- {
- line.remove(QStringLiteral("MINSTART="));
- parseConfigLine(line, &PwmFan::setMinStart);
- }
- else if (line.startsWith(QStringLiteral("MINSTOP=")))
- {
- line.remove(QStringLiteral("MINSTOP="));
- parseConfigLine(line, &PwmFan::setMinStop);
- }
- else if (line.startsWith(QStringLiteral("MINPWM=")))
- {
- line.remove(QStringLiteral("MINPWM="));
- parseConfigLine(line, &PwmFan::setMinPwm);
- }
- else if (line.startsWith(QStringLiteral("MAXPWM=")))
- {
- line.remove(QStringLiteral("MAXPWM="));
- parseConfigLine(line, &PwmFan::setMaxPwm);
- }
- else if (!line.startsWith(QStringLiteral("DEVPATH=")) &&
- !line.startsWith(QStringLiteral("FCFANS=")))
- {
- //Connect hwmons again
- foreach (Hwmon *hwmon, m_hwmons)
- connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- setError(i18n("Unrecognized line in config:\n%1", line), true);
- return false;
- }
- }
- createConfigFile();
- //Connect hwmons again
- foreach (Hwmon *hwmon, m_hwmons)
- connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
- emit configUrlChanged();
- return true;
- }
- bool Loader::save(const QUrl &url)
- {
- QString fileName;
- if (url.isEmpty())
- {
- qDebug() << "Given empty url. Fallback to " << m_configUrl;
- fileName = m_configUrl.toLocalFile();
- }
- else if (url.isLocalFile())
- fileName = url.toLocalFile();
- else
- {
- setError(i18n("%1 is not a local file!", url.toDisplayString()), true);
- return false;
- }
- QFile file(fileName);
- if (file.open(QFile::WriteOnly | QFile::Text))
- {
- QTextStream stream(&file);
- stream << m_configFile;
- }
- else
- {
- KAuth::Action action = newFancontrolAction();
- QVariantMap map;
- map[QStringLiteral("action")] = QVariant("write");
- map[QStringLiteral("filename")] = fileName;
- map[QStringLiteral("content")] = m_configFile;
- action.setArguments(map);
- KAuth::ExecuteJob *reply = action.execute();
- if (!reply->exec())
- {
- qDebug() << reply->error();
- setError(reply->errorString() + reply->errorText(), true);
- return false;
- }
- }
- return true;
- }
- void Loader::createConfigFile()
- {
- QList<Hwmon *> usedHwmons;
- QList<PwmFan *> usedFans;
- foreach (Hwmon *hwmon, m_hwmons)
- {
- if (hwmon->pwmFans().size() > 0)
- usedHwmons << hwmon;
- foreach (QObject *fan, hwmon->pwmFans())
- {
- PwmFan *pwmFan = qobject_cast<PwmFan *>(fan);
- if (pwmFan->hasTemp() && pwmFan->temp() && !pwmFan->testing())
- {
- usedFans << pwmFan;
- if (!usedHwmons.contains(pwmFan->temp()->parent()))
- usedHwmons << pwmFan->temp()->parent();
- }
- }
- }
- QString configFile = QStringLiteral("# This file was created by Fancontrol-GUI") + QChar(QChar::LineFeed);
- if (m_interval != 0)
- configFile += QStringLiteral("INTERVAL=") + QString::number(m_interval) + QChar(QChar::LineFeed);
- if (!usedHwmons.isEmpty())
- {
- configFile += QStringLiteral("DEVPATH=");
- foreach (Hwmon *hwmon, usedHwmons)
- {
- QString sanitizedPath = hwmon->path();
- sanitizedPath.remove(QRegExp("^/sys/"));
- sanitizedPath.remove(QRegExp("/hwmon/hwmon\\d\\s*$"));
- configFile += QStringLiteral("hwmon") + QString::number(hwmon->index()) + "=" + sanitizedPath + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("DEVNAME=");
- foreach (Hwmon *hwmon, usedHwmons)
- {
- configFile += QStringLiteral("hwmon") + QString::number(hwmon->index()) + "=" + hwmon->name().split('.').first() + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
-
- if (!usedFans.isEmpty())
- {
- configFile += QStringLiteral("FCTEMPS=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->temp()->parent()->index()) + "/";
- configFile += QStringLiteral("temp") + QString::number(pwmFan->temp()->index()) + QStringLiteral("_input ");
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("FCFANS=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("fan") + QString::number(pwmFan->index()) + QStringLiteral("_input ");
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("MINTEMP=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->minTemp()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("MAXTEMP=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->maxTemp()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("MINSTART=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->minStart()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
-
- configFile += QStringLiteral("MINSTOP=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->minStop()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
- configFile += QStringLiteral("MINPWM=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->minPwm()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
- configFile += QStringLiteral("MAXPWM=");
- foreach (PwmFan *pwmFan, usedFans)
- {
- configFile += QStringLiteral("hwmon") + QString::number(pwmFan->parent()->index()) + "/";
- configFile += QStringLiteral("pwm") + QString::number(pwmFan->index()) + "=";
- configFile += QString::number(pwmFan->maxPwm()) + QChar(QChar::Space);
- }
- configFile += QChar(QChar::LineFeed);
- }
- }
- if (configFile != m_configFile)
- {
- m_configFile = configFile;
- emit configFileChanged();
- }
- }
- void Loader::setInterval(int interval, bool writeNewConfig)
- {
- if (interval != m_interval)
- {
- m_interval = interval;
- emit intervalChanged();
- if (writeNewConfig)
- createConfigFile();
- }
- }
- void Loader::testFans()
- {
- for (int i=0; i<m_hwmons.size(); i++)
- {
- m_hwmons.at(i)->testFans();
- }
- }
- void Loader::abortTestingFans()
- {
- for (int i=0; i<m_hwmons.size(); i++)
- {
- m_hwmons.at(i)->abortTestingFans();
- }
- }
- void Loader::detectSensors()
- {
- KAuth::Action action = newFancontrolAction();
- QVariantMap map;
- map[QStringLiteral("action")] = QVariant("detectSensors");
- action.setArguments(map);
- KAuth::ExecuteJob *job = action.execute();
- connect(job, SIGNAL(result(KJob*)), this, SLOT(handleDetectSensorsResult(KJob*)));
- job->start();
- }
- void Loader::handleDetectSensorsResult(KJob *job)
- {
- if (job->error())
- {
- qDebug() << job->error();
- setError(job->errorString() + job->errorText(), true);
- }
- else
- parseHwmons();
- }
- QList<QObject *> Loader::hwmonsAsObjects() const
- {
- QList<QObject *> list;
- foreach (Hwmon *hwmon, m_hwmons)
- {
- list << qobject_cast<QObject *>(hwmon);
- }
- return list;
- }
- QList<QObject *> Loader::allTemps() const
- {
- QList<QObject *> list;
- foreach (const Hwmon *hwmon, m_hwmons)
- {
- list += hwmon->tempsAsObjects();
- }
- return list;
- }
- void Loader::setError (const QString &error, bool critical)
- {
- m_error = error;
- emit errorChanged();
- if (critical)
- {
- qCritical() << error;
- emit criticalError();
- }
- else
- qWarning() << error;
- }
- }
|