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  }
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 KOSReleasePrivate
74 {
75 public:
76  explicit KOSReleasePrivate(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 = {{QStringLiteral("NAME"), &name},
84  {QStringLiteral("VERSION"), &version},
85  {QStringLiteral("ID"), &id},
86  // idLike is not a QString, special handling below!
87  {QStringLiteral("VERSION_CODENAME"), &versionCodename},
88  {QStringLiteral("VERSION_ID"), &versionId},
89  {QStringLiteral("PRETTY_NAME"), &prettyName},
90  {QStringLiteral("ANSI_COLOR"), &ansiColor},
91  {QStringLiteral("CPE_NAME"), &cpeName},
92  {QStringLiteral("HOME_URL"), &homeUrl},
93  {QStringLiteral("DOCUMENTATION_URL"), &documentationUrl},
94  {QStringLiteral("SUPPORT_URL"), &supportUrl},
95  {QStringLiteral("BUG_REPORT_URL"), &bugReportUrl},
96  {QStringLiteral("PRIVACY_POLICY_URL"), &privacyPolicyUrl},
97  {QStringLiteral("BUILD_ID"), &buildId},
98  {QStringLiteral("VARIANT"), &variant},
99  {QStringLiteral("VARIANT_ID"), &variantId},
100  {QStringLiteral("LOGO"), &logo}};
101 
102  if (filePath.isEmpty()) {
103  filePath = defaultFilePath();
104  }
105  if (filePath.isEmpty()) {
106  qCWarning(KCOREADDONS_DEBUG) << "Failed to find os-release file!";
107  return;
108  }
109 
110  QFile file(filePath);
111  // NOTE: The os-release specification defines default values for specific
112  // fields which means that even if we can not read the os-release file
113  // we have sort of expected default values to use.
114  // TODO: it might still be handy to indicate to the outside whether
115  // fallback values are being used or not.
117  QString line;
118  QStringList parts;
119  while (!file.atEnd()) {
120  // Trimmed to handle indented comment lines properly
121  line = QString::fromLatin1(file.readLine()).trimmed();
122 
123  if (line.startsWith(QLatin1Char('#'))) {
124  // Comment line
125  // Lines beginning with "#" shall be ignored as comments.
126  continue;
127  }
128 
129  parts = splitEntry(line);
130 
131  if (parts.size() != 2) {
132  // Line has no =, must be invalid.
133  qCDebug(KCOREADDONS_DEBUG) << "Unexpected/invalid os-release line:" << line;
134  continue;
135  }
136 
137  QString key = parts.at(0);
138  QString value = parts.at(1).trimmed();
139 
140  if (QString *var = stringHash.value(key, nullptr)) {
141  setVar(var, value);
142  continue;
143  }
144 
145  // ID_LIKE is a list and parsed as such (rather than a QString).
146  if (key == QLatin1String("ID_LIKE")) {
147  setVar(&idLike, value);
148  continue;
149  }
150 
151  // os-release explicitly allows for vendor specific additions, we'll
152  // collect them as strings and exposes them as "extras".
153  QString parsedValue;
154  setVar(&parsedValue, value);
155  extras.insert(key, parsedValue);
156  }
157  }
158 
159  QString name;
161  QString id;
162  QStringList idLike;
163  QString versionCodename;
164  QString versionId;
165  QString prettyName;
166  QString ansiColor;
167  QString cpeName;
168  QString homeUrl;
169  QString documentationUrl;
170  QString supportUrl;
171  QString bugReportUrl;
172  QString privacyPolicyUrl;
173  QString buildId;
174  QString variant;
175  QString variantId;
176  QString logo;
177 
179 };
180 
182  : d(new KOSReleasePrivate(filePath))
183 {
184 }
185 
186 KOSRelease::~KOSRelease() = default;
187 
189 {
190  return d->name;
191 }
192 
194 {
195  return d->version;
196 }
197 
199 {
200  return d->id;
201 }
202 
204 {
205  return d->idLike;
206 }
207 
209 {
210  return d->versionCodename;
211 }
212 
214 {
215  return d->versionId;
216 }
217 
219 {
220  return d->prettyName;
221 }
222 
224 {
225  return d->ansiColor;
226 }
227 
229 {
230  return d->cpeName;
231 }
232 
234 {
235  return d->homeUrl;
236 }
237 
239 {
240  return d->documentationUrl;
241 }
242 
244 {
245  return d->supportUrl;
246 }
247 
249 {
250  return d->bugReportUrl;
251 }
252 
254 {
255  return d->privacyPolicyUrl;
256 }
257 
259 {
260  return d->buildId;
261 }
262 
264 {
265  return d->variant;
266 }
267 
269 {
270  return d->variantId;
271 }
272 
274 {
275  return d->logo;
276 }
277 
279 {
280  return d->extras.keys();
281 }
282 
284 {
285  return d->extras.value(key);
286 }
QString logo() const
Definition: kosrelease.cpp:273
const T value(const Key &key) const const
int size() const const
QStringList extraKeys() const
Extra keys are keys that are unknown or specified by a vendor.
Definition: kosrelease.cpp:278
Errors
Status codes from splitArgs()
Definition: kshell.h:78
QString id() const
Definition: kosrelease.cpp:198
QString trimmed() const const
QString variantId() const
Definition: kosrelease.cpp:268
QString extraValue(const QString &key) const
Extra values are values assoicated with keys that are unknown.
Definition: kosrelease.cpp:283
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
bool exists() const const
int size() const const
QString homeUrl() const
Definition: kosrelease.cpp:233
QString cpeName() const
Definition: kosrelease.cpp:228
QString documentationUrl() const
Definition: kosrelease.cpp:238
QString version() const
Definition: kosrelease.cpp:193
bool isEmpty() const const
QString buildId() const
Definition: kosrelease.cpp:258
QString supportUrl() const
Definition: kosrelease.cpp:243
QString versionId() const
Definition: kosrelease.cpp:213
const T & at(int i) const const
QStringList idLike() const
Definition: kosrelease.cpp:203
QString prettyName() const
Definition: kosrelease.cpp:218
QString variant() const
Definition: kosrelease.cpp:263
QString join(const QString &separator) const const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString versionCodename() const
Definition: kosrelease.cpp:208
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString & remove(int position, int n)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString name() const
Definition: kosrelease.cpp:188
QString bugReportUrl() const
Definition: kosrelease.cpp:248
unsigned int version()
Returns a numerical version number of KCoreAddons at run-time in the form 0xMMNNPP (MM = major,...
Definition: kcoreaddons.cpp:18
QString fromLatin1(const char *str, int size)
QString name(StandardShortcut id)
const QChar at(int position) const const
QString privacyPolicyUrl() const
Definition: kosrelease.cpp:253
QString ansiColor() const
Definition: kosrelease.cpp:223
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:46
QString mid(int position, int n) const const
@ NoError
Success.
Definition: kshell.h:82
KOSRelease(const QString &filePath=QString())
Constructs a new OSRelease instance.
Definition: kosrelease.cpp:181
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 04:04:52 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.