Separate display from sampling in SysArch and Hostname Meters

Several of our newer meters have merged coding concerns in terms
of extracting values and displaying those values.  This commit
rectifies that for the SysArch and Hostname meters, allowing use
of this code with alternative front/back ends.  The SysArch code
is also refined to detect whether the platform has an os-release
file at all and/or the sys/utsname.h header via configure.ac.
This commit is contained in:
Nathan Scott 2021-03-02 15:58:11 +11:00
parent 2328e52403
commit 5b50ae3aa3
14 changed files with 210 additions and 77 deletions

102
Generic.c Normal file
View File

@ -0,0 +1,102 @@
/*
htop - Generic.c
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Generic.h"
#include <stdio.h>
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
#include <unistd.h>
#include "XUtils.h"
void Generic_Hostname(char* buffer, size_t size) {
gethostname(buffer, size - 1);
}
#ifdef HAVE_SYS_UTSNAME_H
#ifndef OSRELEASEFILE
#define OSRELEASEFILE "/etc/os-release"
#endif
static void parseOSRelease(char* buffer, size_t bufferLen) {
FILE* stream = fopen(OSRELEASEFILE, "r");
if (!stream) {
xSnprintf(buffer, bufferLen, "No OS Release");
return;
}
char name[64] = {'\0'};
char version[64] = {'\0'};
char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), stream)) {
if (String_startsWith(lineBuffer, "PRETTY_NAME=\"")) {
const char* start = lineBuffer + strlen("PRETTY_NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(buffer, start, MINIMUM(bufferLen, (size_t)(stop - start + 1)));
fclose(stream);
return;
}
if (String_startsWith(lineBuffer, "NAME=\"")) {
const char* start = lineBuffer + strlen("NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(name, start, MINIMUM(sizeof(name), (size_t)(stop - start + 1)));
continue;
}
if (String_startsWith(lineBuffer, "VERSION=\"")) {
const char* start = lineBuffer + strlen("VERSION=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(version, start, MINIMUM(sizeof(version), (size_t)(stop - start + 1)));
continue;
}
}
fclose(stream);
snprintf(buffer, bufferLen, "%s%s%s", name[0] ? name : "", name[0] && version[0] ? " " : "", version);
}
char* Generic_OSRelease(void) {
static struct utsname uname_info;
static char savedString[
/* uname structure fields - manpages recommend sizeof */
sizeof(uname_info.sysname) +
sizeof(uname_info.release) +
sizeof(uname_info.machine) +
16/*markup*/ +
128/*distro*/] = {'\0'};
static bool loaded_data = false;
if (!loaded_data) {
int uname_result = uname(&uname_info);
char distro[128];
parseOSRelease(distro, sizeof(distro));
if (uname_result == 0) {
size_t written = xSnprintf(savedString, sizeof(savedString), "%s %s [%s]", uname_info.sysname, uname_info.release, uname_info.machine);
if (!String_contains_i(savedString, distro) && sizeof(savedString) > written)
snprintf(savedString + written, sizeof(savedString) - written, " @ %s", distro);
} else {
snprintf(savedString, sizeof(savedString), "%s", distro);
}
loaded_data = true;
}
return savedString;
}
#endif

16
Generic.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef HEADER_Generic
#define HEADER_Generic
/*
htop - Generic.h
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include <stddef.h>
void Generic_Hostname(char* buffer, size_t size);
char* Generic_OSRelease(void);
#endif

View File

@ -8,6 +8,7 @@ in the source distribution for its full text.
#include "config.h" // IWYU pragma: keep
#include "HostnameMeter.h"
#include "Platform.h"
#include <unistd.h>
@ -19,9 +20,8 @@ static const int HostnameMeter_attributes[] = {
HOSTNAME
};
static void HostnameMeter_updateValues(Meter* this, char* buffer, size_t size) {
(void) this;
gethostname(buffer, size - 1);
static void HostnameMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, size_t size) {
Platform_getHostname(buffer, size);
}
const MeterClass HostnameMeter_class = {

View File

@ -42,6 +42,7 @@ myhtopsources = \
DisplayOptionsPanel.c \
EnvScreen.c \
FunctionBar.c \
Generic.c \
Hashtable.c \
Header.c \
HostnameMeter.c \
@ -96,6 +97,7 @@ myhtopheaders = \
DisplayOptionsPanel.h \
EnvScreen.h \
FunctionBar.h \
Generic.h \
Hashtable.h \
Header.h \
HostnameMeter.h \

View File

@ -6,90 +6,21 @@ in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
#include "Platform.h"
#include "SysArchMeter.h"
#include <stdio.h>
#include <sys/utsname.h>
#include "XUtils.h"
static const int SysArchMeter_attributes[] = {HOSTNAME};
static void parseOSRelease(char* buffer, size_t bufferLen) {
FILE* stream = fopen("/etc/os-release", "r");
if (!stream) {
stream = fopen("/usr/lib/os-release", "r");
if (!stream) {
xSnprintf(buffer, bufferLen, "Unknown Distro");
return;
}
}
char name[64] = {'\0'};
char version[64] = {'\0'};
char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), stream)) {
if (String_startsWith(lineBuffer, "PRETTY_NAME=\"")) {
const char* start = lineBuffer + strlen("PRETTY_NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(buffer, start, MINIMUM(bufferLen, (size_t)(stop - start + 1)));
fclose(stream);
return;
}
if (String_startsWith(lineBuffer, "NAME=\"")) {
const char* start = lineBuffer + strlen("NAME=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(name, start, MINIMUM(sizeof(name), (size_t)(stop - start + 1)));
continue;
}
if (String_startsWith(lineBuffer, "VERSION=\"")) {
const char* start = lineBuffer + strlen("VERSION=\"");
const char* stop = strrchr(lineBuffer, '"');
if (!stop || stop <= start)
continue;
String_safeStrncpy(version, start, MINIMUM(sizeof(version), (size_t)(stop - start + 1)));
continue;
}
}
fclose(stream);
snprintf(buffer, bufferLen, "%s%s%s", name[0] ? name : "", name[0] && version[0] ? " " : "", version);
}
static void SysArchMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, size_t size) {
static char savedString[
/* uname structure fields - manpages recommend sizeof */
sizeof(((struct utsname*)0)->sysname) +
sizeof(((struct utsname*)0)->release) +
sizeof(((struct utsname*)0)->machine) +
16/*markup*/ +
128/*distro*/] = {'\0'};
static bool loaded_data = false;
static char* string;
if (!loaded_data) {
struct utsname uname_info;
int uname_result = uname(&uname_info);
if (string == NULL)
Platform_getRelease(&string);
char distro[128];
parseOSRelease(distro, sizeof(distro));
if (uname_result == 0) {
size_t written = xSnprintf(savedString, sizeof(savedString), "%s %s [%s]", uname_info.sysname, uname_info.release, uname_info.machine);
if (!String_contains_i(savedString, distro) && sizeof(savedString) > written)
snprintf(savedString + written, sizeof(savedString) - written, " @ %s", distro);
} else {
snprintf(savedString, sizeof(savedString), "%s", distro);
}
loaded_data = true;
}
String_safeStrncpy(buffer, savedString, size);
String_safeStrncpy(buffer, string, size);
}
const MeterClass SysArchMeter_class = {

View File

@ -108,6 +108,7 @@ AC_CHECK_HEADERS([ \
strings.h \
sys/param.h \
sys/time.h \
sys/utsname.h \
unistd.h
], [], [AC_MSG_ERROR([can not find required generic header files])])
@ -316,6 +317,18 @@ case "$enable_hwloc" in
;;
esac
AC_ARG_WITH([os-release],
[AS_HELP_STRING([--with-os-release=FILE],
[location of an os-release file @<:@default=/etc/os-release@:>@])],
[],
[with_os_release=/etc/os-release])
if test -n "$with_os_release" -a ! -f "$with_os_release"; then
if test -f "/usr/lib/os-release"; then
with_os_release="/usr/lib/os-release"
fi
fi
AC_DEFINE_UNQUOTED([OSRELEASEFILE], ["$with_os_release"], [File with OS release details.])
# ----------------------------------------------------------------------
@ -608,6 +621,7 @@ AC_MSG_RESULT([
${PACKAGE_NAME} ${VERSION}
platform: $my_htop_platform
os-release file: $with_os_release
(Linux) proc directory: $with_proc
(Linux) openvz: $enable_openvz
(Linux) vserver: $enable_vserver

View File

@ -16,6 +16,7 @@ in the source distribution for its full text.
#include "CPUMeter.h"
#include "DarwinProcess.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "NetworkIOMeter.h"
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
@ -67,4 +68,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double *percent, ACPresence *isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -14,6 +14,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "NetworkIOMeter.h"
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
@ -57,4 +58,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double* percent, ACPresence* isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -13,6 +13,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
#include "Process.h"
@ -62,4 +63,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double* percent, ACPresence* isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -14,6 +14,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
#include "Process.h"
@ -72,4 +73,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double *percent, ACPresence *isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -14,6 +14,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "Meter.h"
#include "NetworkIOMeter.h"
#include "Process.h"
@ -60,4 +61,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double* percent, ACPresence* isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -19,6 +19,7 @@ in the source distribution for its full text.
#include "Action.h"
#include "BatteryMeter.h"
#include "DiskIOMeter.h"
#include "Generic.h"
#include "NetworkIOMeter.h"
#include "ProcessLocksScreen.h"
#include "SignalsPanel.h"
@ -79,4 +80,12 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double* percent, ACPresence* isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) {
Generic_Hostname(buffer, size);
}
static inline void Platform_getRelease(char** string) {
*string = Generic_OSRelease();
}
#endif

View File

@ -64,6 +64,8 @@ const MeterClass* const Platform_meterTypes[] = {
NULL
};
static const char Platform_unsupported[] = "unsupported";
void Platform_init(void) {
/* no platform-specific setup needed */
}
@ -146,3 +148,11 @@ void Platform_getBattery(double* percent, ACPresence* isOnAC) {
*percent = NAN;
*isOnAC = AC_ERROR;
}
void Platform_getHostname(char* buffer, size_t size) {
String_safeStrncpy(buffer, Platform_unsupported, size);
}
void Platform_getRelease(char** string) {
*string = xStrdup(Platform_unsupported);
}

View File

@ -57,4 +57,8 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double *percent, ACPresence *isOnAC);
void Platform_getHostname(char* buffer, size_t size);
void Platform_getRelease(char** string);
#endif