KCoreAddons

kosrelease.cpp
1 /*
2  SPDX-FileCopyrightText: 2014-2019 Harald Sitter <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "kosrelease.h"
8 
9 #include <QFile>
10 
11 #include "kcoreaddons_debug.h"
12 #include "kshell.h"
13 
14 // Sets a QString var
15 static void setVar(QString *var, const QString &value)
16 {
17  // Values may contain quotation marks, strip them as we have no use for them.
19  QStringList args = KShell::splitArgs(value, KShell::NoOptions, &error);
20  if (error != KShell::NoError) { // Failed to parse.
21  return;
22  }
23  *var = args.join(QLatin1Char(' '));
24 }
25 
26 // Sets a QStringList var (i.e. splits a string value)
27 static void setVar(QStringList *var, const QString &value)
28 {
29  // Instead of passing the verbatim value we manually strip any initial quotes
30  // and then run it through KShell. At this point KShell will actually split
31  // by spaces giving us the final QStringList.
32  // NOTE: Splitting like this does not actually allow escaped substrings to
33  // be handled correctly, so "kitteh \"french fries\"" would result in
34  // three list entries. I'd argue that if someone makes an id like that
35  // they are at fault for the bogus parsing here though as id explicitly
36  // is required to not contain spaces even if more advanced shell escaping
37  // is also allowed...
38  QString value_ = value;
39  if (value_.at(0) == QLatin1Char('"') && value_.at(value_.size()-1) == QLatin1Char('"')) {
40  value_.remove(0, 1);
41  value_.remove(-1, 1);
42  }
43  KShell::Errors error;
44  QStringList args = KShell::splitArgs(value_, KShell::NoOptions, &error);
45  if (error != KShell::NoError) { // Failed to parse.
46  return;
47  }
48  *var = args;
49 }
50 
51 static QStringList splitEntry(const QString &line)
52 {
54  const int separatorIndex = line.indexOf(QLatin1Char('='));
55  list << line.mid(0, separatorIndex);
56  if (separatorIndex != -1) {
57  list << line.mid(separatorIndex + 1, -1);
58  }
59  return list;
60 }
61 
62 static QString defaultFilePath()
63 {
64  if (QFile::exists(QStringLiteral("/etc/os-release"))) {
65  return QStringLiteral("/etc/os-release");
66  } else if (QFile::exists(QStringLiteral("/usr/lib/os-release"))) {
67  return QStringLiteral("/usr/lib/os-release");
68  } else {
69  return QString();
70  }
71 }
72 
73 class Q_DECL_HIDDEN KOSRelease::Private
74 {
75 public:
76  Private(QString filePath)
77  : name(QStringLiteral("Linux"))
78  , id(QStringLiteral("linux"))
79  , prettyName(QStringLiteral("Linux"))
80  {
81  // Default values for non-optional fields set above ^.
82 
83  QHash<QString, QString *> stringHash = {
84  { QStringLiteral("NAME"), &name },
85  { QStringLiteral("VERSION"), &version },
86  { QStringLiteral("ID"), &id },
87  // idLike is not a QString, special handling below!
88  { QStringLiteral("VERSION_CODENAME"), &versionCodename },
89  { QStringLiteral("VERSION_ID"), &versionId },
90  { QStringLiteral("PRETTY_NAME"), &prettyName },
91  { QStringLiteral("ANSI_COLOR"), &ansiColor },
92  { QStringLiteral("CPE_NAME"), &cpeName },
93  { QStringLiteral("HOME_URL"), &homeUrl },
94  { QStringLiteral("DOCUMENTATION_URL"), &documentationUrl },
95  { QStringLiteral("SUPPORT_URL"), &supportUrl },
96  { QStringLiteral("BUG_REPORT_URL"), &bugReportUrl },
97  { QStringLiteral("PRIVACY_POLICY_URL"), &privacyPolicyUrl },
98  { QStringLiteral("BUILD_ID"), &buildId },
99  { QStringLiteral("VARIANT"), &variant },
100  { QStringLiteral("VARIANT_ID"), &variantId },
101  { QStringLiteral("LOGO"), &logo }
102  };
103 
104  if (filePath.isEmpty()) {
105  filePath = defaultFilePath();
106  }
107  if (filePath.isEmpty()) {
108  qCWarning(KCOREADDONS_DEBUG) << "Failed to find os-release file!";
109  return;
110  }
111 
112  QFile file(filePath);
113  // NOTE: The os-release specification defines default values for specific
114  // fields which means that even if we can not read the os-release file
115  // we have sort of expected default values to use.
116  // TODO: it might still be handy to indicate to the outside whether
117  // fallback values are being used or not.
119  QString line;
120  QStringList parts;
121  while (!file.atEnd()) {
122  // Trimmed to handle indented comment lines properly
123  line = QString::fromLatin1(file.readLine()).trimmed();
124 
125  if (line.startsWith(QLatin1Char('#'))) {
126  // Comment line
127  // Lines beginning with "#" shall be ignored as comments.
128  continue;
129  }
130 
131  parts = splitEntry(line);
132 
133  if (parts.size() != 2) {
134  // Line has no =, must be invalid.
135  qCDebug(KCOREADDONS_DEBUG) << "Unexpected/invalid os-release line:" << line;
136  continue;
137  }
138 
139  QString key = parts.at(0);
140  QString value = parts.at(1).trimmed();
141 
142  if (QString *var = stringHash.value(key, nullptr)) {
143  setVar(var, value);
144  continue;
145  }
146 
147  // ID_LIKE is a list and parsed as such (rather than a QString).
148  if (key == QLatin1String("ID_LIKE")) {
149  setVar(&idLike, value);
150  continue;
151  }
152 
153  // os-release explicitly allows for vendor specific additions, we'll
154  // collect them as strings and exposes them as "extras".
155  QString parsedValue;
156  setVar(&parsedValue, value);
157  extras.insert(key, parsedValue);
158  }
159  }
160 
161  QString name;
163  QString id;
164  QStringList idLike;
165  QString versionCodename;
166  QString versionId;
167  QString prettyName;
168  QString ansiColor;
169  QString cpeName;
170  QString homeUrl;
171  QString documentationUrl;
172  QString supportUrl;
173  QString bugReportUrl;
174  QString privacyPolicyUrl;
175  QString buildId;
176  QString variant;
177  QString variantId;
178  QString logo;
179 
181 };
182 
184  : d(new Private(filePath))
185 {
186 }
187 
188 KOSRelease::~KOSRelease()
189 {
190  delete d;
191 }
192 
194 {
195  return d->name;
196 }
197 
199 {
200  return d->version;
201 }
202 
204 {
205  return d->id;
206 }
207 
209 {
210  return d->idLike;
211 }
212 
214 {
215  return d->versionCodename;
216 }
217 
219 {
220  return d->versionId;
221 }
222 
224 {
225  return d->prettyName;
226 }
227 
229 {
230  return d->ansiColor;
231 }
232 
234 {
235  return d->cpeName;
236 }
237 
239 {
240  return d->homeUrl;
241 }
242 
244 {
245  return d->documentationUrl;
246 }
247 
249 {
250  return d->supportUrl;
251 }
252 
254 {
255  return d->bugReportUrl;
256 }
257 
259 {
260  return d->privacyPolicyUrl;
261 }
262 
264 {
265  return d->buildId;
266 }
267 
269 {
270  return d->variant;
271 }
272 
274 {
275  return d->variantId;
276 }
277 
279 {
280  return d->logo;
281 }
282 
284 {
285  return d->extras.keys();
286 }
287 
289 {
290  return d->extras.value(key);
291 }
QString cpeName() const
Definition: kosrelease.cpp:233
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString versionCodename() const
Definition: kosrelease.cpp:213
QString name(const QVariant &location)
QString prettyName() const
Definition: kosrelease.cpp:223
const T & at(int i) const const
int size() const const
QString variantId() const
Definition: kosrelease.cpp:273
KOSRelease(const QString &filePath=QString())
Constructs a new OSRelease instance.
Definition: kosrelease.cpp:183
QString join(const QString &separator) const const
bool exists() const const
QString & remove(int position, int n)
int size() const const
QString buildId() const
Definition: kosrelease.cpp:263
QString id() const
Definition: kosrelease.cpp:203
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
Errors
Status codes from splitArgs()
Definition: kshell.h:78
QString variant() const
Definition: kosrelease.cpp:268
The OSRelease class parses /etc/os-release files.
Definition: kosrelease.h:25
QStringList idLike() const
Definition: kosrelease.cpp:208
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
Splits cmd according to system shell word splitting and quoting rules.
Definition: kshell_unix.cpp:58
QString privacyPolicyUrl() const
Definition: kosrelease.cpp:258
const T value(const Key &key) const const
QString versionId() const
Definition: kosrelease.cpp:218
QString extraValue(const QString &key) const
Extra values are values assoicated with keys that are unknown.
Definition: kosrelease.cpp:288
QString mid(int position, int n) const const
QString ansiColor() const
Definition: kosrelease.cpp:228
const QChar at(int position) const const
QString logo() const
Definition: kosrelease.cpp:278
QString homeUrl() const
Definition: kosrelease.cpp:238
Success.
Definition: kshell.h:82
QStringList extraKeys() const
Extra keys are keys that are unknown or specified by a vendor.
Definition: kosrelease.cpp:283
QString name() const
Definition: kosrelease.cpp:193
QString fromLatin1(const char *str, int size)
QString bugReportUrl() const
Definition: kosrelease.cpp:253
QString documentationUrl() const
Definition: kosrelease.cpp:243
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
KDB_EXPORT KDbVersionInfo version()
Returns a numerical version number of KCoreAddons at run-time in the form 0xMMNNPP (MM = major...
Definition: kcoreaddons.cpp:20
QString supportUrl() const
Definition: kosrelease.cpp:248
QString version() const
Definition: kosrelease.cpp:198
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Aug 10 2020 23:06:07 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.