KCoreAddons

kosrelease.cpp
1/*
2 SPDX-FileCopyrightText: 2014-2019 Harald Sitter <sitter@kde.org>
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
15static 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)
27static 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
51static 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
62static 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
73class KOSReleasePrivate
74{
75public:
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;
160 QString version;
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
186KOSRelease::~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 documentationUrl() const
QString buildId() const
QString version() const
QString extraValue(const QString &key) const
Extra values are values assoicated with keys that are unknown.
QString supportUrl() const
QString bugReportUrl() const
QString versionCodename() const
QString privacyPolicyUrl() const
QString versionId() const
QString cpeName() const
QString ansiColor() const
QString id() const
QStringList idLike() const
QString homeUrl() const
QString prettyName() const
QString logo() const
QString name() const
QStringList extraKeys() const
Extra keys are keys that are unknown or specified by a vendor.
KOSRelease(const QString &filePath=QString())
Constructs a new OSRelease instance.
QString variantId() const
QString variant() const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
Splits cmd according to system shell word splitting and quoting rules.
Errors
Status codes from splitArgs()
Definition kshell.h:78
@ NoError
Success.
Definition kshell.h:82
bool exists() const const
iterator insert(const Key &key, const T &value)
T value(const Key &key) const const
const_reference at(qsizetype i) const const
qsizetype size() const const
const QChar at(qsizetype position) const const
QString fromLatin1(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString trimmed() const const
QString join(QChar separator) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 3 2024 11:44:15 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.