mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	
							
								
								
									
										55
									
								
								include/utils/SysInfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								include/utils/SysInfo.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QString> | ||||
| #include <QByteArray> | ||||
|  | ||||
| class SysInfo : public QObject | ||||
| { | ||||
| //	Q_OBJECT | ||||
| 	 | ||||
| public: | ||||
| 	struct HyperionSysInfo | ||||
| 	{ | ||||
| 		QString kernelType; | ||||
| 		QString kernelVersion; | ||||
| 		QString architecture; | ||||
| 		QString wordSize; | ||||
| 		QString productType;    // $ID                          $DISTRIB_ID                    // single line file containing:       // Debian | ||||
| 		QString productVersion; // $VERSION_ID                  $DISTRIB_RELEASE               // <Vendor_ID release Version_ID>     // single line file <Release_ID/sid> | ||||
| 		QString prettyName;     // $PRETTY_NAME                 $DISTRIB_DESCRIPTION | ||||
| 	}; | ||||
|  | ||||
| 	static HyperionSysInfo get(); | ||||
|  | ||||
| private: | ||||
| 	SysInfo(); | ||||
| 	~SysInfo(); | ||||
| 	static SysInfo* _instance; | ||||
|  | ||||
| 	HyperionSysInfo _sysinfo; | ||||
|  | ||||
| 	struct QUnixOSVersion | ||||
| 	{ | ||||
| 	                        // from /etc/os-release         older /etc/lsb-release         // redhat /etc/redhat-release         // debian /etc/debian_version | ||||
| 	QString productType;    // $ID                          $DISTRIB_ID                    // single line file containing:       // Debian | ||||
| 	QString productVersion; // $VERSION_ID                  $DISTRIB_RELEASE               // <Vendor_ID release Version_ID>     // single line file <Release_ID/sid> | ||||
| 	QString prettyName;     // $PRETTY_NAME                 $DISTRIB_DESCRIPTION | ||||
| 	}; | ||||
|  | ||||
| 	QString machineHostName(); | ||||
| 	QString currentCpuArchitecture(); | ||||
| 	QString kernelType(); | ||||
| 	QString kernelVersion(); | ||||
| 	bool findUnixOsVersion(QUnixOSVersion &v); | ||||
|  | ||||
| 	QByteArray getEtcFileFirstLine(const char *fileName); | ||||
| 	bool readEtcRedHatRelease(QUnixOSVersion &v); | ||||
| 	bool readEtcDebianVersion(QUnixOSVersion &v); | ||||
|  | ||||
| 	bool readEtcOsRelease(SysInfo::QUnixOSVersion &v); | ||||
| 	bool readEtcFile(SysInfo::QUnixOSVersion &v, const char *filename, const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey); | ||||
| 	QByteArray getEtcFileContent(const char *filename); | ||||
| 	QString unquote(const char *begin, const char *end); | ||||
| 	bool readEtcLsbRelease(SysInfo::QUnixOSVersion &v); | ||||
| }; | ||||
| @@ -26,6 +26,7 @@ SET(Utils_HEADERS | ||||
| 	${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h | ||||
| 	${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h | ||||
| 	${CURRENT_HEADER_DIR}/global_defines.h | ||||
| 	${CURRENT_HEADER_DIR}/SysInfo.h | ||||
| ) | ||||
|  | ||||
| SET(Utils_SOURCES | ||||
| @@ -42,6 +43,7 @@ SET(Utils_SOURCES | ||||
| 	${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp | ||||
| 	${CURRENT_SOURCE_DIR}/RgbTransform.cpp | ||||
| 	${CURRENT_SOURCE_DIR}/RgbToRgbw.cpp | ||||
| 	${CURRENT_SOURCE_DIR}/SysInfo.cpp | ||||
| 	${CURRENT_SOURCE_DIR}/jsonschema/QJsonSchemaChecker.cpp | ||||
| ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										305
									
								
								libsrc/utils/SysInfo.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								libsrc/utils/SysInfo.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | ||||
| #include "utils/SysInfo.h" | ||||
|  | ||||
| #include <QSysInfo> | ||||
| #include <iostream> | ||||
| #include <sys/utsname.h> | ||||
| #include "HyperionConfig.h" | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <limits.h> | ||||
| #include <stdarg.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| SysInfo* SysInfo::_instance = nullptr; | ||||
|  | ||||
| SysInfo::SysInfo() | ||||
| 	: QObject() | ||||
| { | ||||
| 	SysInfo::QUnixOSVersion v; | ||||
| 	findUnixOsVersion(v); | ||||
| 	 | ||||
| 	std::cout | ||||
| 		<< currentCpuArchitecture().toStdString() << " " | ||||
| 		<< kernelType().toStdString() << " " | ||||
| 		<< kernelVersion().toStdString() << " " | ||||
| 		<< v.productType.toStdString() << " " | ||||
| 		<< v.productVersion.toStdString() << " " | ||||
| 		<< v.prettyName.toStdString() << " " | ||||
| 		<< std::endl; | ||||
| 	 | ||||
| 	_sysinfo.kernelType     = kernelType(); | ||||
| 	_sysinfo.kernelVersion  = kernelVersion(); | ||||
| 	_sysinfo.architecture   = currentCpuArchitecture(); | ||||
| 	_sysinfo.wordSize       = QSysInfo::WordSize; | ||||
| 	_sysinfo.productType    = v.productType; | ||||
| 	_sysinfo.productVersion = v.productVersion; | ||||
| 	_sysinfo.prettyName     = v.prettyName; | ||||
| } | ||||
|  | ||||
| SysInfo::~SysInfo() | ||||
| { | ||||
| } | ||||
|  | ||||
| SysInfo::HyperionSysInfo SysInfo::get() | ||||
| { | ||||
| 	if ( SysInfo::_instance == nullptr ) | ||||
| 		SysInfo::_instance = new SysInfo(); | ||||
| 	 | ||||
| 	return SysInfo::_instance->_sysinfo; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| QString SysInfo::kernelType() | ||||
| { | ||||
| #if defined(Q_OS_WIN) | ||||
| 	return QStringLiteral("winnt"); | ||||
| #elif defined(Q_OS_UNIX) | ||||
| 	struct utsname u; | ||||
| 	if (uname(&u) == 0) | ||||
| 		return QString::fromLatin1(u.sysname).toLower(); | ||||
| #endif | ||||
| 	return QString(); | ||||
| } | ||||
|  | ||||
| QString SysInfo::kernelVersion() | ||||
| { | ||||
| 	struct utsname u; | ||||
| 	if (uname(&u) == 0) | ||||
| 		return QString::fromLocal8Bit(u.release).toLower(); | ||||
|  | ||||
| 	return QString(); | ||||
| } | ||||
|  | ||||
| QString SysInfo::machineHostName() | ||||
| { | ||||
| #if defined(Q_OS_LINUX) | ||||
| 	// gethostname(3) on Linux just calls uname(2), so do it ourselves and avoid a memcpy | ||||
| 	struct utsname u; | ||||
| 	if (uname(&u) == 0) | ||||
| 		return QString::fromLocal8Bit(u.nodename); | ||||
| #else | ||||
| 	char hostName[512]; | ||||
| 	if (gethostname(hostName, sizeof(hostName)) == -1) | ||||
| 		return QString(); | ||||
| 	hostName[sizeof(hostName) - 1] = '\0'; | ||||
| 	return QString::fromLocal8Bit(hostName); | ||||
| #endif | ||||
| 	return QString(); | ||||
| } | ||||
|  | ||||
|  | ||||
| QString SysInfo::currentCpuArchitecture() | ||||
| { | ||||
| #if defined(Q_OS_UNIX) | ||||
| 	long ret = -1; | ||||
| 	struct utsname u; | ||||
|  | ||||
| 	if (ret == -1) | ||||
| 		ret = uname(&u); | ||||
|  | ||||
| 	// we could use detectUnixVersion() above, but we only need a field no other function does | ||||
| 	if (ret != -1) | ||||
| 	{ | ||||
| 		// the use of QT_BUILD_INTERNAL here is simply to ensure all branches build | ||||
| 		// as we don't often build on some of the less common platforms | ||||
| #  if defined(Q_PROCESSOR_ARM) | ||||
| 		if (strcmp(u.machine, "aarch64") == 0) | ||||
| 			return QStringLiteral("arm64"); | ||||
| 		if (strncmp(u.machine, "armv", 4) == 0) | ||||
| 			return QStringLiteral("arm"); | ||||
| #  endif | ||||
| #  if defined(Q_PROCESSOR_POWER) | ||||
| 		// harmonize "powerpc" and "ppc" to "power" | ||||
| 		if (strncmp(u.machine, "ppc", 3) == 0) | ||||
| 			return QLatin1String("power") + QLatin1String(u.machine + 3); | ||||
| 		if (strncmp(u.machine, "powerpc", 7) == 0) | ||||
| 			return QLatin1String("power") + QLatin1String(u.machine + 7); | ||||
| 		if (strcmp(u.machine, "Power Macintosh") == 0) | ||||
| 			return QLatin1String("power"); | ||||
| #  endif | ||||
| #  if defined(Q_PROCESSOR_X86) | ||||
| 		// harmonize all "i?86" to "i386" | ||||
| 		if (strlen(u.machine) == 4 && u.machine[0] == 'i' && u.machine[2] == '8' && u.machine[3] == '6') | ||||
| 			return QStringLiteral("i386"); | ||||
| 		if (strcmp(u.machine, "amd64") == 0) // Solaris | ||||
| 			return QStringLiteral("x86_64"); | ||||
| #  endif | ||||
| 		return QString::fromLatin1(u.machine); | ||||
| 	} | ||||
| #endif | ||||
| 	return QString(); | ||||
| } | ||||
|  | ||||
| bool SysInfo::findUnixOsVersion(SysInfo::QUnixOSVersion &v) | ||||
| { | ||||
| 	if (readEtcOsRelease(v)) | ||||
| 		return true; | ||||
| 	if (readEtcLsbRelease(v)) | ||||
| 		return true; | ||||
| #if defined(Q_OS_LINUX) | ||||
| 	if (readEtcRedHatRelease(v)) | ||||
| 		return true; | ||||
| 	if (readEtcDebianVersion(v)) | ||||
| 		return true; | ||||
| #endif | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| QByteArray SysInfo::getEtcFileFirstLine(const char *fileName) | ||||
| { | ||||
| 	QByteArray buffer = getEtcFileContent(fileName); | ||||
| 	if (buffer.isEmpty()) | ||||
| 		return QByteArray(); | ||||
|  | ||||
| 	const char *ptr = buffer.constData(); | ||||
| 	int eol = buffer.indexOf("\n"); | ||||
| 	return QByteArray(ptr, eol).trimmed(); | ||||
| } | ||||
|  | ||||
| bool SysInfo::readEtcRedHatRelease(SysInfo::QUnixOSVersion &v) | ||||
| { | ||||
| 	// /etc/redhat-release analysed should be a one line file | ||||
| 	// the format of its content is <Vendor_ID release Version> | ||||
| 	// i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)" | ||||
| 	QByteArray line = getEtcFileFirstLine("/etc/redhat-release"); | ||||
| 	if (line.isEmpty()) | ||||
| 		return false; | ||||
|  | ||||
| 	v.prettyName = QString::fromLatin1(line); | ||||
|  | ||||
| 	const char keyword[] = "release "; | ||||
| 	int releaseIndex = line.indexOf(keyword); | ||||
| 	v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(QLatin1Char(' ')); | ||||
| 	int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword)); | ||||
| 	v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword), | ||||
| 													spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1)); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool SysInfo::readEtcDebianVersion(SysInfo::QUnixOSVersion &v) | ||||
| { | ||||
| 	// /etc/debian_version analysed should be a one line file | ||||
| 	// the format of its content is <Release_ID/sid> | ||||
| 	// i.e. "jessie/sid" | ||||
| 	QByteArray line = getEtcFileFirstLine("/etc/debian_version"); | ||||
| 	if (line.isEmpty()) | ||||
| 		return false; | ||||
|  | ||||
| 	v.productType = QStringLiteral("Debian"); | ||||
| 	v.productVersion = QString::fromLatin1(line); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| QString SysInfo::unquote(const char *begin, const char *end) | ||||
| { | ||||
| 	if (*begin == '"') { | ||||
| 		Q_ASSERT(end[-1] == '"'); | ||||
| 		return QString::fromLatin1(begin + 1, end - begin - 2); | ||||
| 	} | ||||
| 	return QString::fromLatin1(begin, end - begin); | ||||
| } | ||||
|  | ||||
| QByteArray SysInfo::getEtcFileContent(const char *filename) | ||||
| { | ||||
| 	// we're avoiding QFile here | ||||
| 	int fd = open(filename, O_RDONLY); | ||||
| 	if (fd == -1) | ||||
| 		return QByteArray(); | ||||
|  | ||||
| 	struct stat sbuf; | ||||
| 	if (::fstat(fd, &sbuf) == -1) { | ||||
| 		close(fd); | ||||
| 		return QByteArray(); | ||||
| 	} | ||||
|  | ||||
| 	QByteArray buffer(sbuf.st_size, Qt::Uninitialized); | ||||
| 	buffer.resize(read(fd, buffer.data(), sbuf.st_size)); | ||||
| 	close(fd); | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| bool SysInfo::readEtcFile(SysInfo::QUnixOSVersion &v, const char *filename, | ||||
| 						const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey) | ||||
| { | ||||
|  | ||||
| 	QByteArray buffer = getEtcFileContent(filename); | ||||
| 	if (buffer.isEmpty()) | ||||
| 		return false; | ||||
|  | ||||
| 	const char *ptr = buffer.constData(); | ||||
| 	const char *end = buffer.constEnd(); | ||||
| 	const char *eol; | ||||
| 	QByteArray line; | ||||
| 	for ( ; ptr != end; ptr = eol + 1) { | ||||
| 		// find the end of the line after ptr | ||||
| 		eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr)); | ||||
| 		if (!eol) | ||||
| 			eol = end - 1; | ||||
| 		line.setRawData(ptr, eol - ptr); | ||||
|  | ||||
| 		if (line.startsWith(idKey)) { | ||||
| 			ptr += idKey.length(); | ||||
| 			v.productType = unquote(ptr, eol); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (line.startsWith(prettyNameKey)) { | ||||
| 			ptr += prettyNameKey.length(); | ||||
| 			v.prettyName = unquote(ptr, eol); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (line.startsWith(versionKey)) { | ||||
| 			ptr += versionKey.length(); | ||||
| 			v.productVersion = unquote(ptr, eol); | ||||
| 			continue; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool SysInfo::readEtcOsRelease(SysInfo::QUnixOSVersion &v) | ||||
| { | ||||
| 	return readEtcFile(v, "/etc/os-release", QByteArrayLiteral("ID="), | ||||
| 					   QByteArrayLiteral("VERSION_ID="), QByteArrayLiteral("PRETTY_NAME=")); | ||||
| } | ||||
|  | ||||
| bool SysInfo::readEtcLsbRelease(SysInfo::QUnixOSVersion &v) | ||||
| { | ||||
| 	bool ok = readEtcFile(v, "/etc/lsb-release", QByteArrayLiteral("DISTRIB_ID="), | ||||
| 						  QByteArrayLiteral("DISTRIB_RELEASE="), QByteArrayLiteral("DISTRIB_DESCRIPTION=")); | ||||
| 	if (ok && (v.prettyName.isEmpty() || v.prettyName == v.productType)) { | ||||
| 		// some distributions have redundant information for the pretty name, | ||||
| 		// so try /etc/<lowercasename>-release | ||||
|  | ||||
| 		// we're still avoiding QFile here | ||||
| 		QByteArray distrorelease = "/etc/" + v.productType.toLatin1().toLower() + "-release"; | ||||
| 		int fd = open(distrorelease, O_RDONLY); | ||||
| 		if (fd != -1) { | ||||
| 			struct stat sbuf; | ||||
| 			if (::fstat(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.length()) { | ||||
| 				// file apparently contains interesting information | ||||
| 				QByteArray buffer(sbuf.st_size, Qt::Uninitialized); | ||||
| 				buffer.resize(read(fd, buffer.data(), sbuf.st_size)); | ||||
| 				v.prettyName = QString::fromLatin1(buffer.trimmed()); | ||||
| 			} | ||||
| 			close(fd); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// some distributions have a /etc/lsb-release file that does not provide the values | ||||
| 	// we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION. | ||||
| 	// Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values, | ||||
| 	// returning false for readEtcLsbRelease will allow further /etc/<lowercasename>-release parsing. | ||||
| 	return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty()); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user