13#include <QDBusConnection>
14#include <QDBusArgument>
16#include <sys/utsname.h>
34SsuDeviceInfo::~SsuDeviceInfo()
45 if (boardMappings->contains(model +
"/adaptation-repos"))
46 result = boardMappings->value(model +
"/adaptation-repos").toStringList();
53 SsuLog *ssuLog = SsuLog::instance();
63 QRegExp regex(
"adaptation\\d*", Qt::CaseSensitive, QRegExp::RegExp2);
64 if (regex.exactMatch(adaptationName)) {
65 regex.setPattern(
"\\d*");
66 regex.lastIndexIn(adaptationName);
67 int n = regex.cap().toInt();
69 if (!adaptationRepoList.isEmpty()) {
70 if (adaptationRepoList.size() <= n) {
71 ssuLog->
print(LOG_INFO,
"Note: repo index out of bounds, substituting 0" + adaptationName);
75 QString adaptationRepo = adaptationRepoList.at(n);
76 storageHash->insert(
"adaptation", adaptationRepo);
77 ssuLog->
print(LOG_DEBUG,
"Found first adaptation " + adaptationName);
79 QHash<QString, QString> h;
82 if (boardMappings->contains(model +
"/variables")) {
83 QStringList sections = boardMappings->value(model +
"/variables").toStringList();
84 foreach (
const QString §ion, sections)
91 QHash<QString, QString>::const_iterator i = h.constBegin();
92 while (i != h.constEnd()) {
93 storageHash->insert(i.key(), i.value());
97 ssuLog->
print(LOG_INFO,
"Note: adaptation repo for invalid repo requested " + adaptationName);
104 else if (boardMappings->contains(model +
"/repository-specific-variables")) {
105 QStringList sections = boardMappings->value(model +
"/repository-specific-variables").toStringList();
106 if (sections.contains(model +
"-" + adaptationName)) {
107 QHash<QString, QString> h;
111 QHash<QString, QString>::const_iterator i = h.constBegin();
112 while (i != h.constEnd()) {
113 storageHash->insert(i.key(), i.value());
118 return adaptationName;
121void SsuDeviceInfo::clearCache()
123 cachedFamily.clear();
125 cachedVariant.clear();
133 if (!model.isEmpty()) {
140 if (boardMappings->childGroups().contains(
deviceModel()))
143 if (!model.isEmpty()) {
152 if (!cachedFamily.isEmpty())
157 if (boardMappings->contains(model +
"/family")) {
158 cachedFamily = boardMappings->value(model +
"/family").toString();
164 cachedFamily = model;
172 if (!cachedVariant.isEmpty())
173 return cachedVariant;
175 if (boardMappings->contains(
"variants/" +
deviceModel())) {
176 cachedVariant = boardMappings->value(
"variants/" +
deviceModel()).toString();
179 if (cachedVariant.isEmpty() && fallback)
182 return cachedVariant;
187 if (!cachedModel.isEmpty())
190 boardMappings->beginGroup(
"file.exists");
191 QStringList keys = boardMappings->allKeys();
194 foreach (
const QString &key, keys) {
195 QString
value = boardMappings->value(key).toString();
197 if (dir.exists(Sandbox::map(
value))) {
202 boardMappings->endGroup();
203 if (!cachedModel.isEmpty())
return cachedModel;
207 procCpuinfo.setFileName(Sandbox::map(
"/proc/cpuinfo"));
208 procCpuinfo.open(QIODevice::ReadOnly | QIODevice::Text);
209 if (procCpuinfo.isOpen()) {
210 QTextStream in(&procCpuinfo);
211 QString cpuinfo = in.readAll();
212 boardMappings->beginGroup(
"cpuinfo.contains");
213 keys = boardMappings->allKeys();
215 foreach (
const QString &key, keys) {
216 QString
value = boardMappings->value(key).toString();
217 if (cpuinfo.contains(
value)) {
222 boardMappings->endGroup();
224 if (!cachedModel.isEmpty())
return cachedModel;
227 QString hwReleaseDevice = hwRelease()[
"MER_HA_DEVICE"];
228 if (!hwReleaseDevice.isEmpty()) {
229 boardMappings->beginGroup(
"hwrelease.device");
230 keys = boardMappings->allKeys();
232 foreach (
const QString &key, keys) {
233 QString
value = boardMappings->value(key).toString();
234 if (hwReleaseDevice ==
value) {
239 boardMappings->endGroup();
241 if (!cachedModel.isEmpty())
return cachedModel;
246 QString utsRelease(buf.release);
247 boardMappings->beginGroup(
"uname-release.contains");
248 keys = boardMappings->allKeys();
250 foreach (
const QString &key, keys) {
251 QString
value = boardMappings->value(key).toString();
252 if (utsRelease.contains(
value)) {
257 boardMappings->endGroup();
259 if (!cachedModel.isEmpty())
return cachedModel;
263 boardMappings->beginGroup(
"arch.equals");
264 keys = boardMappings->allKeys();
267 foreach (
const QString &key, keys) {
268 QString
value = boardMappings->value(key).toString();
269 if (settings->value(
"arch").toString() ==
value) {
274 boardMappings->endGroup();
275 if (cachedModel.isEmpty()) cachedModel =
"UNKNOWN";
285 QDBusReply<QStringList> reply = QDBusConnection::systemBus().call(
286 QDBusMessage::createMethodCall(
"org.ofono",
"/",
287 "org.nemomobile.ofono.ModemManager",
"GetIMEI"));
289 if (reply.isValid()) {
290 result = reply.value();
302 QStringList dirs = QDir(QLatin1String(
"/sys/class/net/"))
303 .entryList(QStringList() << QLatin1String(
"wlan*"));
304 foreach (
const QString &dir, dirs) {
305 QFile carrier(QString(
"/sys/class/net/%1/address").arg(dir));
306 if (carrier.open(QIODevice::ReadOnly)) {
307 result.append(QString::fromLatin1(carrier.readAll().simplified().data()));
314normalizeUid(
const QString &uid)
317 return uid.trimmed().replace(
":",
"").replace(
"-",
"").toLower();
322 SsuLog *ssuLog = SsuLog::instance();
323 QStringList imeis = ofonoGetImeis();
324 if (imeis.size() > 0) {
328 QStringList wlanMacs = getWlanMacs();
329 if (wlanMacs.size() > 0) {
330 return normalizeUid(wlanMacs[0]);
333 ssuLog->
print(LOG_WARNING,
"Could not get IMEI(s) from ofono, nor WLAN mac, trying fallback");
336 QStringList fallbackFiles;
337 fallbackFiles <<
"/sys/devices/virtual/dmi/id/product_uuid";
338 fallbackFiles <<
"/etc/machine-id";
339 fallbackFiles <<
"/etc/unique-id";
340 fallbackFiles <<
"/var/lib/dbus/machine-id";
342 foreach (
const QString &filename, fallbackFiles) {
343 QFile machineId(filename);
344 if (machineId.open(QFile::ReadOnly | QFile::Text) && machineId.size() > 0) {
345 QTextStream in(&machineId);
346 return normalizeUid(in.readAll());
350 ssuLog->
print(LOG_CRIT,
"Could not read fallback UID - returning empty string");
360 if (boardMappings->contains(model +
"/disabled-repos"))
361 result = boardMappings->value(model +
"/disabled-repos").toStringList();
374 key =
"/deviceManufacturer";
377 key =
"/prettyModel";
380 key =
"/deviceDesignation";
394 if (boardMappings->contains(model + key))
395 value = boardMappings->value(model + key).toString();
396 else if (!variant.isEmpty() && boardMappings->contains(variant + key))
397 value = boardMappings->value(variant + key).toString();
398 else if (boardMappings->contains(key))
399 value = boardMappings->value(key).toString();
420 for (
int i = 0; i < adaptationCount; i++)
421 result.append(QString(
"adaptation%1").arg(i));
425 QString group = (rnd ?
"rnd" :
"release");
426 repoSettings.beginGroup(group);
427 result.append(repoSettings.allKeys());
428 repoSettings.endGroup();
431 repoKey = (rnd ?
"default-repos/rnd" :
"default-repos/release");
432 if (repoSettings.contains(repoKey))
433 result.append(repoSettings.value(repoKey).toStringList());
440 result.append(boardMappings->value(
deviceVariant(
true) +
"/repos").toStringList());
443 repoKey = (rnd ?
"/repos-rnd" :
"/repos-release");
445 result.append(boardMappings->value(
deviceVariant(
true) + repoKey).toStringList());
451 result.removeAll(key);
455 result.removeDuplicates();
463 QString varSection(section);
464 if (!varSection.startsWith(
"var-"))
465 varSection =
"var-" + varSection;
472 QString varSection(section);
473 if (!varSection.startsWith(
"var-"))
474 varSection =
"var-" + varSection;
486 cachedFamily.clear();
487 cachedVariant.clear();
492 if (boardMappings->contains(
deviceModel() +
"/" + key)) {
493 return boardMappings->value(
deviceModel() +
"/" + key);
494 }
else if (boardMappings->contains(
deviceVariant() +
"/" + key)) {
501QMap<QString, QString> SsuDeviceInfo::hwRelease()
503 QMap<QString, QString> result;
508 QFile hwRelease(
"/etc/hw-release");
509 if (hwRelease.open(QIODevice::ReadOnly | QIODevice::Text)) {
510 QTextStream in(&hwRelease);
514 in.setCodec(
"UTF-8");
516 while (!in.atEnd()) {
517 QString line = in.readLine();
520 if (line.startsWith(
'#')) {
524 QString key = line.section(
'=', 0, 0);
525 QString
value = line.section(
'=', 1);
538 if (!QRegExp(
"[a-zA-Z_]+[a-zA-Z0-9_]*").exactMatch(key)) {
539 qWarning(
"Invalid key in input line: '%s'", qPrintable(line));
546 if (((
value.at(0) ==
'\'') || (
value.at(0) ==
'"'))) {
548 qWarning(
"Quoting error in input line: '%s'", qPrintable(line));
Q_INVOKABLE QString deviceUid()
Q_INVOKABLE QString deviceFamily()
QString adaptationVariables(const QString &adaptationName, QHash< QString, QString > *storageHash)
void variableSection(const QString §ion, QHash< QString, QString > *storageHash)
QVariant value(const QString &key, const QVariant &value=QVariant())
SsuDeviceInfo(const QString &model=QString())
QStringList disabledRepos()
QStringList repos(bool rnd=false, int filter=Ssu::NoFilter)
QVariant variable(const QString §ion, const QString &key)
Q_INVOKABLE void setDeviceModel(const QString &model=QString())
QStringList adaptationRepos()
bool contains(const QString &model=QString())
Q_INVOKABLE QString deviceVariant(bool fallback=false)
Q_INVOKABLE QString displayName(int type)
Q_INVOKABLE QString deviceModel()
void print(int priority, const QString &message)
QVariant variable(const QString §ion, const QString &key)
void variableSection(const QString §ion, QHash< QString, QString > *storageHash)
@ DeviceModel
Marketed device name, like Pogoblaster 3000. Board mappings key "prettyModel".
@ DeviceDesignation
Type designation, like NCC-1701. Beard mappings key "deviceDesignation".
@ DeviceManufacturer
Manufacturer, like ACME Corp. Board mappings key "deviceManufacturer".
@ BoardFilter
Only global repositories.
@ Available
Include all defined repos, including disabled.
#define SSU_REPO_CONFIGURATION_DIR
Path to config.d for ssu domain configurations.
#define SSU_BOARD_MAPPING_CONFIGURATION
Path to board / device family mappings file.
#define SSU_BOARD_MAPPING_CONFIGURATION_DIR
Path to config.d for board mappings.
#define SSU_REPO_CONFIGURATION
Path to the ssu domain configuration file.