1/*******************************************************************
2* systeminformation.cpp
3* Copyright 2009 Dario Andres Rodriguez <andresbajotierra@gmail.com>
4* Copyright 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>
5*
6* This program is free software; you can redistribute it and/or
7* modify it under the terms of the GNU General Public License as
8* published by the Free Software Foundation; either version 2 of
9* the License, or (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program. If not, see <http://www.gnu.org/licenses/>.
18*
19******************************************************************/
20
21#include <config-drkonqi.h>
22
23#include "systeminformation.h"
24
25#ifdef HAVE_UNAME
26# include <sys/utsname.h>
27#endif
28
29#include <QtCore/QFile>
30
31#include <KStandardDirs>
32#include <KProcess>
33#include <KDebug>
34#include <KConfig>
35#include <KConfigGroup>
36#include <kdeversion.h>
37
38static const QString OS_UNSPECIFIED = "unspecified";
39static const QString PLATFORM_UNSPECIFIED = "unspecified";
40
41SystemInformation::SystemInformation(QObject * parent)
42 : QObject(parent)
43 , m_bugzillaOperatingSystem(OS_UNSPECIFIED)
44 , m_bugzillaPlatform(PLATFORM_UNSPECIFIED)
45{
46 // NOTE: the relative order is important here
47 m_bugzillaOperatingSystem = fetchOSBasicInformation();
48 m_operatingSystem = fetchOSDetailInformation();
49
50 tryToSetBugzillaPlatform();
51
52 KConfigGroup config(KGlobal::config(), "SystemInformation");
53 m_compiledSources = config.readEntry("CompiledSources", false);
54}
55
56SystemInformation::~SystemInformation()
57{
58 KConfigGroup config(KGlobal::config(), "SystemInformation");
59 config.writeEntry("CompiledSources", m_compiledSources);
60 config.sync();
61}
62
63void SystemInformation::tryToSetBugzillaPlatform()
64{
65 QString platform = PLATFORM_UNSPECIFIED;
66 // first, try to guess bugzilla platfrom from the internal OS information
67 // this should work for BSDs, solaris and windows.
68 platform = guessBugzillaPlatform(m_bugzillaOperatingSystem);
69
70 // if the internal information is not enough, refer to external information
71 if (platform == PLATFORM_UNSPECIFIED) {
72 tryToSetBugzillaPlatformFromExternalInfo();
73 } else {
74 setBugzillaPlatform(platform);
75 }
76}
77
78void SystemInformation::tryToSetBugzillaPlatformFromExternalInfo()
79{
80 //Run lsb_release async
81 QString lsb_release = KStandardDirs::findExe(QLatin1String("lsb_release"));
82 if ( !lsb_release.isEmpty() ) {
83 kDebug() << "found lsb_release";
84 KProcess *process = new KProcess();
85 process->setOutputChannelMode(KProcess::OnlyStdoutChannel);
86 process->setEnv("LC_ALL", "C");
87 *process << lsb_release << "-sd";
88 connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(lsbReleaseFinished()));
89 process->start();
90 } else {
91 // when lsb_release is unavailable, turn to /etc/os-release
92 const QString& osReleaseInfo = fetchOSReleaseInformation();
93 const QString& platform = guessBugzillaPlatform(osReleaseInfo);
94 setBugzillaPlatform(platform);
95 }
96}
97
98void SystemInformation::lsbReleaseFinished()
99{
100 KProcess *process = qobject_cast<KProcess*>(sender());
101 Q_ASSERT(process);
102 m_lsbRelease = QString::fromLocal8Bit(process->readAllStandardOutput().trimmed());
103 process->deleteLater();
104
105 //Guess distro string
106 QString platform = guessBugzillaPlatform(m_lsbRelease);
107
108 // if lsb_release doesn't work well, turn to the /etc/os-release file
109 if (platform == PLATFORM_UNSPECIFIED) {
110 const QString& osReleaseInfo = fetchOSReleaseInformation();
111 platform = guessBugzillaPlatform(osReleaseInfo);
112 }
113
114 setBugzillaPlatform(platform);
115}
116
117//this function maps the distribution information to an "Hardware Platform" .
118//value that is accepted by bugs.kde.org. If the values change on the server .
119//side, they need to be updated here as well .
120QString SystemInformation::guessBugzillaPlatform(const QString& distroInfo) const
121{
122 if ( distroInfo.contains("suse",Qt::CaseInsensitive) ) {
123 return (QLatin1String("openSUSE RPMs"));
124 } else if ( distroInfo.contains("mint",Qt::CaseInsensitive) ) {
125 return (QLatin1String("Mint (Ubuntu Based)"));
126 } else if ( distroInfo.contains("lmde",Qt::CaseInsensitive) ) {
127 return (QLatin1String("Mint (Debian Based)"));
128 } else if ( distroInfo.contains("ubuntu",Qt::CaseInsensitive) ) {
129 return (QLatin1String("Ubuntu Packages"));
130 } else if ( distroInfo.contains("fedora",Qt::CaseInsensitive) ) {
131 return (QLatin1String("Fedora RPMs"));
132 } else if ( distroInfo.contains("redhat",Qt::CaseInsensitive) ) {
133 return (QLatin1String("RedHat RPMs"));
134 } else if ( distroInfo.contains("gentoo",Qt::CaseInsensitive) ) {
135 return (QLatin1String("Gentoo Packages"));
136 } else if ( distroInfo.contains("mandriva",Qt::CaseInsensitive) ) {
137 return (QLatin1String("Mandriva RPMs"));
138 } else if ( distroInfo.contains("mageia",Qt::CaseInsensitive) ) {
139 return (QLatin1String("Mageia RPMs"));
140 } else if ( distroInfo.contains("slack",Qt::CaseInsensitive) ) {
141 return (QLatin1String("Slackware Packages"));
142 } else if ( distroInfo.contains("pclinuxos",Qt::CaseInsensitive) ) {
143 return (QLatin1String("PCLinuxOS"));
144 } else if ( distroInfo.contains("pardus",Qt::CaseInsensitive) ) {
145 return (QLatin1String("Pardus Packages"));
146 } else if ( distroInfo.contains("freebsd",Qt::CaseInsensitive) ) {
147 return (QLatin1String("FreeBSD Ports"));
148 } else if ( distroInfo.contains("netbsd",Qt::CaseInsensitive) ) {
149 return (QLatin1String("NetBSD pkgsrc"));
150 } else if ( distroInfo.contains("openbsd",Qt::CaseInsensitive) ) {
151 return (QLatin1String("OpenBSD Packages"));
152 } else if ( distroInfo.contains("solaris",Qt::CaseInsensitive) ) {
153 return (QLatin1String("Solaris Packages"));
154 } else if ( distroInfo.contains("chakra",Qt::CaseInsensitive) ) {
155 return (QLatin1String("Chakra"));
156 } else if ( distroInfo.contains("ms windows",Qt::CaseInsensitive) ) {
157 return (QLatin1String("MS Windows"));
158 } else if ( distroInfo.contains("arch",Qt::CaseInsensitive) ) {
159 return (QLatin1String("Archlinux Packages"));
160 } else if ( distroInfo.contains("debian",Qt::CaseInsensitive) ) {
161 if ( distroInfo.contains("unstable",Qt::CaseInsensitive) ) {
162 return (QLatin1String("Debian unstable"));
163 } else if ( distroInfo.contains("testing",Qt::CaseInsensitive) ) {
164 return (QLatin1String("Debian testing"));
165 } else {
166 return (QLatin1String("Debian stable"));
167 }
168 } else {
169 return PLATFORM_UNSPECIFIED;
170 }
171}
172
173//this function maps the operating system to an OS value that is accepted by bugs.kde.org.
174//if the values change on the server side, they need to be updated here as well.
175QString SystemInformation::fetchOSBasicInformation() const
176{
177 //krazy:excludeall=cpp
178 //Get the base OS string (bugzillaOS)
179#if defined(Q_OS_LINUX)
180 return QLatin1String("Linux");
181#elif defined(Q_OS_FREEBSD)
182 return QLatin1String("FreeBSD");
183#elif defined(Q_OS_NETBSD)
184 return QLatin1String("NetBSD");
185#elif defined(Q_OS_OPENBSD)
186 return QLatin1String("OpenBSD");
187#elif defined(Q_OS_AIX)
188 return QLatin1String("AIX");
189#elif defined(Q_OS_HPUX)
190 return QLatin1String("HP-UX");
191#elif defined(Q_OS_IRIX)
192 return QLatin1String("IRIX");
193#elif defined(Q_OS_OSF)
194 return QLatin1String("Tru64");
195#elif defined(Q_OS_SOLARIS)
196 return QLatin1String("Solaris");
197#elif defined(Q_OS_CYGWIN)
198 return QLatin1String("Cygwin");
199#elif defined(Q_OS_DARWIN)
200 return QLatin1String("OS X");
201#elif defined(Q_OS_WIN32)
202 return QLatin1String("MS Windows");
203#else
204 return OS_UNSPECIFIED;
205#endif
206
207}
208
209QString SystemInformation::fetchOSDetailInformation() const
210{
211 //Get complete OS string (and fallback to base string)
212 QString operatingSystem = m_bugzillaOperatingSystem;
213
214#ifdef HAVE_UNAME
215 struct utsname buf;
216 if (uname(&buf) == -1) {
217 kDebug() << "call to uname failed" << perror;
218 } else {
219 operatingSystem = QString::fromLocal8Bit(buf.sysname) + ' '
220 + QString::fromLocal8Bit(buf.release) + ' '
221 + QString::fromLocal8Bit(buf.machine);
222 }
223#endif
224
225 return operatingSystem;
226}
227
228QString SystemInformation::fetchOSReleaseInformation() const
229{
230 QFile data("/etc/os-release");
231 if (!data.open(QIODevice::ReadOnly | QIODevice::Text)) {
232 return QString();
233 }
234
235 QMap<QString,QString> distroInfos;
236
237 QTextStream in(&data);
238 while (!in.atEnd()) {
239 const QString line = in.readLine();
240
241 // its format is one simple NAME=VALUE per line
242 // don't use QString.split() here since its value might contain '=''
243 const int index = line.indexOf('=');
244 if ( index != -1 ) {
245 const QString key = line.left(index);
246 const QString value = line.mid(index+1);
247 distroInfos.insert(key, value);
248 }
249 }
250
251 // the PRETTY_NAME entry should be the most appropriate one,
252 // but I could be wrong.
253 const QString prettyName = distroInfos.value("PRETTY_NAME", "Linux");
254 return prettyName;
255}
256
257QString SystemInformation::operatingSystem() const
258{
259 return m_operatingSystem;
260}
261
262QString SystemInformation::bugzillaOperatingSystem() const
263{
264 return m_bugzillaOperatingSystem;
265}
266
267QString SystemInformation::bugzillaPlatform() const
268{
269 return m_bugzillaPlatform;
270}
271
272void SystemInformation::setBugzillaPlatform(const QString & platform)
273{
274 m_bugzillaPlatform = platform;
275}
276
277QString SystemInformation::lsbRelease() const
278{
279 return m_lsbRelease;
280}
281
282bool SystemInformation::compiledSources() const
283{
284 return m_compiledSources;
285}
286
287void SystemInformation::setCompiledSources(bool compiled)
288{
289 m_compiledSources = compiled;
290}
291
292QString SystemInformation::kdeVersion() const
293{
294 return KDE::versionString();
295}
296
297QString SystemInformation::qtVersion() const
298{
299 return qVersion();
300}
301