loader.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. * Copyright (C) 2015 Malte Veerman <maldela@halloarsch.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. */
  19. #include "loader.h"
  20. #include <QFile>
  21. #include <QDir>
  22. #include <QTextStream>
  23. #include <QDebug>
  24. #include <KF5/KAuth/kauthexecutejob.h>
  25. #define HWMON_PATH "/sys/class/hwmon"
  26. Loader::Loader(QObject *parent) : QObject(parent),
  27. m_interval(10),
  28. m_configUrl(QUrl::fromLocalFile("/etc/fancontrol")),
  29. m_error("Success")
  30. {
  31. parseHwmons();
  32. m_timer.setSingleShot(false);
  33. m_timer.start(1);
  34. connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateSensors()));
  35. }
  36. void Loader::parseHwmons()
  37. {
  38. foreach (Hwmon *hwmon, m_hwmons)
  39. {
  40. hwmon->deleteLater();
  41. }
  42. m_hwmons.clear();
  43. QDir hwmonDir(HWMON_PATH);
  44. QStringList list;
  45. if (hwmonDir.isReadable())
  46. {
  47. list = hwmonDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
  48. }
  49. else
  50. {
  51. qDebug() << HWMON_PATH << " is not readable!";
  52. return;
  53. }
  54. foreach (QString hwmonPath, list)
  55. {
  56. Hwmon *hwmon = new Hwmon(QFile::symLinkTarget(hwmonDir.absoluteFilePath(hwmonPath)), this);
  57. connect(hwmon, SIGNAL(configUpdateNeeded()), this, SLOT(createConfigFile()));
  58. connect(hwmon, SIGNAL(pwmFansChanged()), this, SLOT(emitAllPwmFansChanged()));
  59. connect(this, SIGNAL(sensorsUpdateNeeded()), hwmon, SLOT(updateSensors()));
  60. m_hwmons << hwmon;
  61. }
  62. emit hwmonsChanged();
  63. emit allPwmFansChanged();
  64. }
  65. bool Loader::load(const QUrl &url)
  66. {
  67. QString fileName;
  68. if (url.isEmpty())
  69. {
  70. qDebug() << "Given empty url. Fallback to " << m_configUrl;
  71. fileName = m_configUrl.toLocalFile();
  72. }
  73. else if (url.isLocalFile())
  74. fileName = url.toLocalFile();
  75. else
  76. {
  77. setError("Url is not a local file");
  78. return false;
  79. }
  80. QTextStream stream;
  81. QFile file(fileName);
  82. if (file.open(QFile::ReadOnly | QFile::Text))
  83. {
  84. stream.setDevice(&file);
  85. m_configFile = stream.readAll();
  86. emit configFileChanged();
  87. }
  88. else if (file.exists())
  89. {
  90. KAuth::Action action("fancontrol.gui.helper.action");
  91. action.setHelperId("fancontrol.gui.helper");
  92. QVariantMap map;
  93. map["action"] = "read";
  94. map["filename"] = fileName;
  95. action.setArguments(map);
  96. KAuth::ExecuteJob *reply = action.execute();
  97. if (!reply->exec())
  98. {
  99. setError(reply->errorString());
  100. return false;
  101. }
  102. else
  103. {
  104. m_configFile = reply->data()["content"].toString();
  105. emit configFileChanged();
  106. }
  107. }
  108. else
  109. {
  110. setError("File does not exist");
  111. return false;
  112. }
  113. m_configUrl = url;
  114. emit configUrlChanged();
  115. foreach (Hwmon *hwmon, m_hwmons)
  116. {
  117. foreach (QObject *pwmFan, hwmon->pwmFans())
  118. {
  119. qobject_cast<PwmFan *>(pwmFan)->reset();
  120. }
  121. }
  122. stream.setString(&m_configFile);
  123. QStringList lines;
  124. do
  125. {
  126. QString line(stream.readLine());
  127. if (line.startsWith('#')) continue;
  128. int offset = line.indexOf('#');
  129. if (offset != -1) line.truncate(offset-1);
  130. line = line.simplified();
  131. lines << line;
  132. }
  133. while(!stream.atEnd());
  134. foreach (QString line, lines)
  135. {
  136. if (line.startsWith("INTERVAL="))
  137. {
  138. line.remove("INTERVAL=");
  139. bool success;
  140. int interval = line.toInt(&success);
  141. if (success)
  142. setInterval(interval, false);
  143. else
  144. {
  145. setError("Unable to parse interval line");
  146. return false;
  147. }
  148. }
  149. else if (line.startsWith("FCTEMPS="))
  150. {
  151. line.remove("FCTEMPS=");
  152. QStringList fctemps = line.split(' ');
  153. foreach (QString fctemp, fctemps)
  154. {
  155. QStringList nameValuePair = fctemp.split('=');
  156. if (nameValuePair.size() == 2)
  157. {
  158. QString pwm = nameValuePair.at(0);
  159. QString temp = nameValuePair.at(1);
  160. int pwmSensorIndex = getSensorNumber(pwm);
  161. int tempSensorIndex = getSensorNumber(temp);
  162. Hwmon *pwmHwmon = m_hwmons.value(getHwmonNumber(pwm), Q_NULLPTR);
  163. if (pwmHwmon)
  164. {
  165. Hwmon *tempHwmon = m_hwmons.value(getHwmonNumber(temp), Q_NULLPTR);
  166. PwmFan *pwmPointer = pwmHwmon->pwmFan(pwmSensorIndex);
  167. if (tempHwmon)
  168. {
  169. Temp *tempPointer = tempHwmon->temp(tempSensorIndex);
  170. if (pwmPointer)
  171. {
  172. pwmPointer->setTemp(tempPointer);
  173. pwmPointer->setMinPwm(0);
  174. }
  175. }
  176. else if (pwmPointer)
  177. pwmPointer->setTemp(Q_NULLPTR);
  178. }
  179. }
  180. }
  181. }
  182. else if (line.startsWith("MINTEMP="))
  183. {
  184. line.remove("MINTEMP=");
  185. QStringList mintemps = line.split(' ');
  186. foreach (QString mintemp, mintemps)
  187. {
  188. QStringList nameValuePair = mintemp.split('=');
  189. if (nameValuePair.size() == 2)
  190. {
  191. QString pwm = nameValuePair.at(0);
  192. int value = nameValuePair.at(1).toInt();
  193. int pwmHwmon = getHwmonNumber(pwm);
  194. int pwmSensor = getSensorNumber(pwm);
  195. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  196. if (pwmPointer)
  197. pwmPointer->setMinTemp(value);
  198. }
  199. }
  200. }
  201. else if (line.startsWith("MAXTEMP="))
  202. {
  203. line.remove("MAXTEMP=");
  204. QStringList maxtemps = line.split(' ');
  205. foreach (QString maxtemp, maxtemps)
  206. {
  207. QStringList nameValuePair = maxtemp.split('=');
  208. if (nameValuePair.size() == 2)
  209. {
  210. QString pwm = nameValuePair.at(0);
  211. int value = nameValuePair.at(1).toInt();
  212. int pwmHwmon = getHwmonNumber(pwm);
  213. int pwmSensor = getSensorNumber(pwm);
  214. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  215. if (pwmPointer)
  216. pwmPointer->setMaxTemp(value);
  217. }
  218. }
  219. }
  220. else if (line.startsWith("MINSTART="))
  221. {
  222. line.remove("MINSTART=");
  223. QStringList minstarts = line.split(' ');
  224. foreach (QString minstart, minstarts)
  225. {
  226. QStringList nameValuePair = minstart.split('=');
  227. if (nameValuePair.size() == 2)
  228. {
  229. QString pwm = nameValuePair.at(0);
  230. int value = nameValuePair.at(1).toInt();
  231. int pwmHwmon = getHwmonNumber(pwm);
  232. int pwmSensor = getSensorNumber(pwm);
  233. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  234. if (pwmPointer)
  235. pwmPointer->setMinStart(value);
  236. }
  237. }
  238. }
  239. else if (line.startsWith("MINSTOP="))
  240. {
  241. line.remove("MINSTOP=");
  242. QStringList minstops = line.split(' ');
  243. foreach (QString minstop, minstops)
  244. {
  245. QStringList nameValuePair = minstop.split('=');
  246. if (nameValuePair.size() == 2)
  247. {
  248. QString pwm = nameValuePair.at(0);
  249. int value = nameValuePair.at(1).toInt();
  250. int pwmHwmon = getHwmonNumber(pwm);
  251. int pwmSensor = getSensorNumber(pwm);
  252. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  253. if (pwmPointer)
  254. pwmPointer->setMinStop(value);
  255. }
  256. }
  257. }
  258. else if (line.startsWith("MINPWM="))
  259. {
  260. line.remove("MINPWM=");
  261. QStringList minpwms = line.split(' ');
  262. foreach (QString minpwm, minpwms)
  263. {
  264. QStringList nameValuePair = minpwm.split('=');
  265. if (nameValuePair.size() == 2)
  266. {
  267. QString pwm = nameValuePair.at(0);
  268. int value = nameValuePair.at(1).toInt();
  269. int pwmHwmon = getHwmonNumber(pwm);
  270. int pwmSensor = getSensorNumber(pwm);
  271. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  272. if (pwmPointer)
  273. pwmPointer->setMinPwm(value);
  274. }
  275. }
  276. }
  277. else if (line.startsWith("MAXPWM="))
  278. {
  279. line.remove("MAXPWM=");
  280. QStringList maxpwms = line.split(' ');
  281. foreach (QString maxpwm, maxpwms)
  282. {
  283. QStringList nameValuePair = maxpwm.split('=');
  284. if (nameValuePair.size() == 2)
  285. {
  286. QString pwm = nameValuePair.at(0);
  287. int value = nameValuePair.at(1).toInt();
  288. int pwmHwmon = getHwmonNumber(pwm);
  289. int pwmSensor = getSensorNumber(pwm);
  290. PwmFan *pwmPointer = m_hwmons.value(pwmHwmon, Q_NULLPTR)->pwmFan(pwmSensor);
  291. if (pwmPointer)
  292. pwmPointer->setMaxPwm(value);
  293. }
  294. }
  295. }
  296. }
  297. success();
  298. return true;
  299. }
  300. bool Loader::save(const QUrl &url)
  301. {
  302. QString fileName;
  303. if (url.isEmpty())
  304. {
  305. qDebug() << "Given empty url. Fallback to " << m_configUrl;
  306. fileName = m_configUrl.toLocalFile();
  307. }
  308. else if (url.isLocalFile())
  309. fileName = url.toLocalFile();
  310. else
  311. {
  312. setError("Url is not a local file");
  313. return false;
  314. }
  315. QFile file(fileName);
  316. if (file.open(QFile::WriteOnly | QFile::Text))
  317. {
  318. QTextStream stream(&file);
  319. stream << m_configFile;
  320. }
  321. else
  322. {
  323. KAuth::Action action("fancontrol.gui.helper.action");
  324. action.setHelperId("fancontrol.gui.helper");
  325. QVariantMap map;
  326. map["action"] = "write";
  327. map["filename"] = fileName;
  328. map["content"] = m_configFile;
  329. action.setArguments(map);
  330. KAuth::ExecuteJob *reply = action.execute();
  331. if (!reply->exec())
  332. {
  333. setError(reply->errorString());
  334. return false;
  335. }
  336. }
  337. success();
  338. return true;
  339. }
  340. void Loader::createConfigFile()
  341. {
  342. QList<Hwmon *> usedHwmons;
  343. QList<PwmFan *> usedFans;
  344. foreach (Hwmon *hwmon, m_hwmons)
  345. {
  346. if (hwmon->pwmFans().size() > 0)
  347. usedHwmons << hwmon;
  348. foreach (QObject *fan, hwmon->pwmFans())
  349. {
  350. PwmFan *pwmFan = qobject_cast<PwmFan *>(fan);
  351. if (pwmFan->hasTemp() && pwmFan->temp())
  352. {
  353. usedFans << pwmFan;
  354. if (!usedHwmons.contains(pwmFan->temp()->parent()))
  355. usedHwmons << pwmFan->temp()->parent();
  356. }
  357. }
  358. }
  359. QString configFile = "# This file was created by Fancontrol-GUI \n";
  360. if (m_interval != 0)
  361. configFile += "INTERVAL=" + QString::number(m_interval) + "\n";
  362. if (!usedHwmons.isEmpty())
  363. {
  364. configFile += "DEVPATH=";
  365. foreach (Hwmon *hwmon, usedHwmons)
  366. {
  367. QString sanitizedPath = hwmon->path();
  368. sanitizedPath.remove(QRegExp("^/sys/"));
  369. sanitizedPath.remove(QRegExp("/hwmon/hwmon\\d\\s*$"));
  370. configFile += "hwmon" + QString::number(hwmon->index()) + "=" + sanitizedPath + " ";
  371. }
  372. configFile += "\n";
  373. configFile += "DEVNAME=";
  374. foreach (Hwmon *hwmon, usedHwmons)
  375. {
  376. configFile += "hwmon" + QString::number(hwmon->index()) + "=" + hwmon->name().split('.').first() + " ";
  377. }
  378. configFile += "\n";
  379. if (!usedFans.isEmpty())
  380. {
  381. configFile += "FCTEMPS=";
  382. foreach (PwmFan *pwmFan, usedFans)
  383. {
  384. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  385. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  386. configFile += "hwmon" + QString::number(pwmFan->temp()->parent()->index()) + "/";
  387. configFile += "temp" + QString::number(pwmFan->temp()->index()) + "_input ";
  388. }
  389. configFile += "\n";
  390. configFile += "FCFANS=";
  391. foreach (PwmFan *pwmFan, usedFans)
  392. {
  393. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  394. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  395. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  396. configFile += "fan" + QString::number(pwmFan->index()) + "_input ";
  397. }
  398. configFile += "\n";
  399. configFile += "MINTEMP=";
  400. foreach (PwmFan *pwmFan, usedFans)
  401. {
  402. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  403. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  404. configFile += QString::number(pwmFan->minTemp()) + " ";
  405. }
  406. configFile += "\n";
  407. configFile += "MAXTEMP=";
  408. foreach (PwmFan *pwmFan, usedFans)
  409. {
  410. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  411. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  412. configFile += QString::number(pwmFan->maxTemp()) + " ";
  413. }
  414. configFile += "\n";
  415. configFile += "MINSTART=";
  416. foreach (PwmFan *pwmFan, usedFans)
  417. {
  418. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  419. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  420. configFile += QString::number(pwmFan->minStart()) + " ";
  421. }
  422. configFile += "\n";
  423. configFile += "MINSTOP=";
  424. foreach (PwmFan *pwmFan, usedFans)
  425. {
  426. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  427. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  428. configFile += QString::number(pwmFan->minStop()) + " ";
  429. }
  430. configFile += "\n";
  431. configFile += "MINPWM=";
  432. foreach (PwmFan *pwmFan, usedFans)
  433. {
  434. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  435. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  436. configFile += QString::number(pwmFan->minPwm()) + " ";
  437. }
  438. configFile += "\n";
  439. configFile += "MAXPWM=";
  440. foreach (PwmFan *pwmFan, usedFans)
  441. {
  442. configFile += "hwmon" + QString::number(pwmFan->parent()->index()) + "/";
  443. configFile += "pwm" + QString::number(pwmFan->index()) + "=";
  444. configFile += QString::number(pwmFan->maxPwm()) + " ";
  445. }
  446. configFile += "\n";
  447. }
  448. }
  449. if (configFile != m_configFile)
  450. {
  451. m_configFile = configFile;
  452. emit configFileChanged();
  453. }
  454. }
  455. void Loader::setInterval(int interval, bool writeNewConfig)
  456. {
  457. if (interval != m_interval)
  458. {
  459. m_interval = interval;
  460. emit intervalChanged();
  461. qDebug() << "Changed interval to" << interval;
  462. if (writeNewConfig)
  463. createConfigFile();
  464. }
  465. }
  466. void Loader::testFans()
  467. {
  468. for (int i=0; i<m_hwmons.size(); i++)
  469. {
  470. m_hwmons.at(i)->testFans();
  471. }
  472. }
  473. QList<QObject *> Loader::hwmons() const
  474. {
  475. QList<QObject *> list;
  476. foreach (Hwmon *hwmon, m_hwmons)
  477. {
  478. list << qobject_cast<QObject *>(hwmon);
  479. }
  480. return list;
  481. }
  482. QList< QObject* > Loader::allPwmFans() const
  483. {
  484. QList<QObject *> list;
  485. foreach (const Hwmon *hwmon, m_hwmons)
  486. {
  487. list += hwmon->pwmFans();
  488. }
  489. return list;
  490. }