summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Lange <DLange@git.local>2020-11-15 14:52:25 +0100
committerDaniel Lange <DLange@git.local>2020-11-15 14:52:25 +0100
commitf2b2735e07afc6b05aa933bdf3a112059991b131 (patch)
treefa7b14fb181f2d74f357b8028f44eafcdafc882a
parentbb908f3dc4ac5847592e9698dec150658067e84e (diff)
parent2a9e8ca07475e61e74d7b6f0afd0a5fd272cb07f (diff)
Resolve merge conflicts, merge #229 "Add SystemdMeter" from @cgzones
-rw-r--r--CRT.c3
-rw-r--r--CRT.h3
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac2
-rw-r--r--linux/Platform.c2
-rw-r--r--linux/SystemdMeter.c329
-rw-r--r--linux/SystemdMeter.h15
7 files changed, 354 insertions, 2 deletions
diff --git a/CRT.c b/CRT.c
index 08f1cef3..2406e602 100644
--- a/CRT.c
+++ b/CRT.c
@@ -173,9 +173,10 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[METER_TEXT] = A_NORMAL,
[METER_VALUE] = A_BOLD,
[METER_VALUE_ERROR] = A_BOLD,
- [METER_VALUE_NOTICE] = A_BOLD,
[METER_VALUE_IOREAD] = A_NORMAL,
[METER_VALUE_IOWRITE] = A_NORMAL,
+ [METER_VALUE_NOTICE] = A_BOLD,
+ [METER_VALUE_OK] = A_NORMAL,
[LED_COLOR] = A_NORMAL,
[TASKS_RUNNING] = A_BOLD,
[PROCESS] = A_NORMAL,
diff --git a/CRT.h b/CRT.h
index fccf65c1..ed9cbf42 100644
--- a/CRT.h
+++ b/CRT.h
@@ -53,9 +53,10 @@ typedef enum ColorElements_ {
METER_TEXT,
METER_VALUE,
METER_VALUE_ERROR,
- METER_VALUE_NOTICE,
METER_VALUE_IOREAD,
METER_VALUE_IOWRITE,
+ METER_VALUE_NOTICE,
+ METER_VALUE_OK,
LED_COLOR,
UPTIME,
BATTERY,
diff --git a/Makefile.am b/Makefile.am
index 9a3067ff..41d8c9fb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -132,6 +132,7 @@ linux_platform_headers = \
linux/Platform.h \
linux/PressureStallMeter.h \
linux/SELinuxMeter.h \
+ linux/SystemdMeter.h \
linux/ZramMeter.h \
linux/ZramStats.h \
zfs/ZfsArcMeter.h \
@@ -148,6 +149,7 @@ myhtopplatsources = \
linux/Platform.c \
linux/PressureStallMeter.c \
linux/SELinuxMeter.c \
+ linux/SystemdMeter.c \
linux/ZramMeter.c \
zfs/ZfsArcMeter.c \
zfs/ZfsArcStats.c \
diff --git a/configure.ac b/configure.ac
index 95a8f909..6e76240d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -90,6 +90,8 @@ AC_FUNC_CLOSEDIR_VOID
AC_FUNC_STAT
AC_CHECK_FUNCS([fstatat memmove readlinkat strdup strncasecmp strstr])
+AC_SEARCH_LIBS([dlopen], [dl dld])
+
save_cflags="${CFLAGS}"
CFLAGS="${CFLAGS} -std=c99"
AC_MSG_CHECKING([whether cc -std=c99 option works])
diff --git a/linux/Platform.c b/linux/Platform.c
index bc52f512..28eb9f3c 100644
--- a/linux/Platform.c
+++ b/linux/Platform.c
@@ -44,6 +44,7 @@ in the source distribution for its full text.
#include "SELinuxMeter.h"
#include "Settings.h"
#include "SwapMeter.h"
+#include "SystemdMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "XUtils.h"
@@ -161,6 +162,7 @@ const MeterClass* const Platform_meterTypes[] = {
&DiskIOMeter_class,
&NetworkIOMeter_class,
&SELinuxMeter_class,
+ &SystemdMeter_class,
NULL
};
diff --git a/linux/SystemdMeter.c b/linux/SystemdMeter.c
new file mode 100644
index 00000000..368d5cca
--- /dev/null
+++ b/linux/SystemdMeter.c
@@ -0,0 +1,329 @@
+/*
+htop - SystemdMeter.c
+(C) 2020 Christian Göttsche
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "SystemdMeter.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "CRT.h"
+#include "XUtils.h"
+
+
+#define INVALID_VALUE ((unsigned int)-1)
+
+typedef void sd_bus;
+typedef void sd_bus_error;
+static int (*sym_sd_bus_open_system)(sd_bus**);
+static int (*sym_sd_bus_get_property_string)(sd_bus*, const char*, const char*, const char*, const char*, sd_bus_error*, char**);
+static int (*sym_sd_bus_get_property_trivial)(sd_bus*, const char*, const char*, const char*, const char*, sd_bus_error*, char, void*);
+static sd_bus* (*sym_sd_bus_unref)(sd_bus*);
+
+static char* systemState = NULL;
+static unsigned int nFailedUnits = INVALID_VALUE;
+static unsigned int nInstalledJobs = INVALID_VALUE;
+static unsigned int nNames = INVALID_VALUE;
+static unsigned int nJobs = INVALID_VALUE;
+static void* dlopenHandle = NULL;
+static sd_bus* bus = NULL;
+
+static void SystemdMeter_done(ATTR_UNUSED Meter* this) {
+ free(systemState);
+ systemState = NULL;
+
+ if (bus && dlopenHandle) {
+ sym_sd_bus_unref(bus);
+ }
+ bus = NULL;
+
+ if (dlopenHandle) {
+ dlclose(dlopenHandle);
+ dlopenHandle = NULL;
+ }
+}
+
+static int updateViaLib(void) {
+ if (!dlopenHandle) {
+ dlopenHandle = dlopen("libsystemd.so.0", RTLD_LAZY);
+ if (!dlopenHandle)
+ goto dlfailure;
+
+ /* Clear any errors */
+ dlerror();
+
+ #define resolve(symbolname) do { \
+ *(void **)(&sym_##symbolname) = dlsym(dlopenHandle, #symbolname); \
+ if (!sym_##symbolname || dlerror() != NULL) \
+ goto dlfailure; \
+ } while(0)
+
+ resolve(sd_bus_open_system);
+ resolve(sd_bus_get_property_string);
+ resolve(sd_bus_get_property_trivial);
+ resolve(sd_bus_unref);
+
+ #undef resolve
+ }
+
+ int r;
+
+ /* Connect to the system bus */
+ if (!bus) {
+ r = sym_sd_bus_open_system(&bus);
+ if (r < 0)
+ goto busfailure;
+ }
+
+ static const char* const busServiceName = "org.freedesktop.systemd1";
+ static const char* const busObjectPath = "/org/freedesktop/systemd1";
+ static const char* const busInterfaceName = "org.freedesktop.systemd1.Manager";
+
+ r = sym_sd_bus_get_property_string(bus,
+ busServiceName, /* service to contact */
+ busObjectPath, /* object path */
+ busInterfaceName, /* interface name */
+ "SystemState", /* property name */
+ NULL, /* object to return error in */
+ &systemState);
+ if (r < 0)
+ goto busfailure;
+
+ r = sym_sd_bus_get_property_trivial(bus,
+ busServiceName, /* service to contact */
+ busObjectPath, /* object path */
+ busInterfaceName, /* interface name */
+ "NFailedUnits", /* property name */
+ NULL, /* object to return error in */
+ 'u', /* property type */
+ &nFailedUnits);
+ if (r < 0)
+ goto busfailure;
+
+ r = sym_sd_bus_get_property_trivial(bus,
+ busServiceName, /* service to contact */
+ busObjectPath, /* object path */
+ busInterfaceName, /* interface name */
+ "NInstalledJobs", /* property name */
+ NULL, /* object to return error in */
+ 'u', /* property type */
+ &nInstalledJobs);
+ if (r < 0)
+ goto busfailure;
+
+ r = sym_sd_bus_get_property_trivial(bus,
+ busServiceName, /* service to contact */
+ busObjectPath, /* object path */
+ busInterfaceName, /* interface name */
+ "NNames", /* property name */
+ NULL, /* object to return error in */
+ 'u', /* property type */
+ &nNames);
+ if (r < 0)
+ goto busfailure;
+
+ r = sym_sd_bus_get_property_trivial(bus,
+ busServiceName, /* service to contact */
+ busObjectPath, /* object path */
+ busInterfaceName, /* interface name */
+ "NJobs", /* property name */
+ NULL, /* object to return error in */
+ 'u', /* property type */
+ &nJobs);
+ if (r < 0)
+ goto busfailure;
+
+ /* success */
+ return 0;
+
+busfailure:
+ sym_sd_bus_unref(bus);
+ bus = NULL;
+ return -2;
+
+dlfailure:
+ if (dlopenHandle) {
+ dlclose(dlopenHandle);
+ dlopenHandle = NULL;
+ }
+ return -1;
+}
+
+static void updateViaExec(void) {
+ int fdpair[2];
+ if (pipe(fdpair) < 0)
+ return;
+
+ pid_t child = fork();
+ if (child < 0) {
+ close(fdpair[1]);
+ close(fdpair[0]);
+ return;
+ }
+
+ if (child == 0) {
+ close(fdpair[0]);
+ dup2(fdpair[1], STDOUT_FILENO);
+ close(fdpair[1]);
+ int fdnull = open("/dev/null", O_WRONLY);
+ if (fdnull < 0)
+ exit(1);
+ dup2(fdnull, STDERR_FILENO);
+ close(fdnull);
+ execl("/bin/systemctl",
+ "/bin/systemctl",
+ "show",
+ "--property=SystemState",
+ "--property=NFailedUnits",
+ "--property=NNames",
+ "--property=NJobs",
+ "--property=NInstalledJobs",
+ NULL);
+ exit(127);
+ }
+ close(fdpair[1]);
+
+ int wstatus;
+ if (waitpid(child, &wstatus, 0) < 0 || !WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
+ close(fdpair[0]);
+ return;
+ }
+
+ FILE* commandOutput = fdopen(fdpair[0], "r");
+ if (!commandOutput) {
+ close(fdpair[0]);
+ return;
+ }
+
+ char lineBuffer[128];
+ while (fgets(lineBuffer, sizeof(lineBuffer), commandOutput)) {
+ if (String_startsWith(lineBuffer, "SystemState=")) {
+ char* newline = strchr(lineBuffer + strlen("SystemState="), '\n');
+ if (newline)
+ *newline = '\0';
+ systemState = xStrdup(lineBuffer + strlen("SystemState="));
+ } else if (String_startsWith(lineBuffer, "NFailedUnits=")) {
+ nFailedUnits = strtoul(lineBuffer + strlen("NFailedUnits="), NULL, 10);
+ } else if (String_startsWith(lineBuffer, "NNames=")) {
+ nNames = strtoul(lineBuffer + strlen("NNames="), NULL, 10);
+ } else if (String_startsWith(lineBuffer, "NJobs=")) {
+ nJobs = strtoul(lineBuffer + strlen("NJobs="), NULL, 10);
+ } else if (String_startsWith(lineBuffer, "NInstalledJobs=")) {
+ nInstalledJobs = strtoul(lineBuffer + strlen("NInstalledJobs="), NULL, 10);
+ }
+ }
+
+ fclose(commandOutput);
+}
+
+static void SystemdMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, int size) {
+ free(systemState);
+ systemState = NULL;
+ nFailedUnits = nInstalledJobs = nNames = nJobs = INVALID_VALUE;
+
+ if (updateViaLib() < 0)
+ updateViaExec();
+
+ xSnprintf(buffer, size, "%s", systemState ? systemState : "???");
+}
+
+static int zeroDigitColor(unsigned int value) {
+ switch (value) {
+ case 0:
+ return CRT_colors[METER_VALUE];
+ case INVALID_VALUE:
+ return CRT_colors[METER_VALUE_ERROR];
+ default:
+ return CRT_colors[METER_VALUE_NOTICE];
+ }
+}
+
+static int valueDigitColor(unsigned int value) {
+ switch (value) {
+ case 0:
+ return CRT_colors[METER_VALUE_NOTICE];
+ case INVALID_VALUE:
+ return CRT_colors[METER_VALUE_ERROR];
+ default:
+ return CRT_colors[METER_VALUE];
+ }
+}
+
+
+static void SystemdMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
+ char buffer[16];
+
+ int color = (systemState && 0 == strcmp(systemState, "running")) ? METER_VALUE_OK : METER_VALUE_ERROR;
+ RichString_write(out, CRT_colors[color], systemState ? systemState : "???");
+
+ RichString_append(out, CRT_colors[METER_TEXT], " (");
+
+ if (nFailedUnits == INVALID_VALUE) {
+ buffer[0] = '?';
+ buffer[1] = '\0';
+ } else {
+ xSnprintf(buffer, sizeof(buffer), "%u", nFailedUnits);
+ }
+ RichString_append(out, zeroDigitColor(nFailedUnits), buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], "/");
+
+ if (nNames == INVALID_VALUE) {
+ buffer[0] = '?';
+ buffer[1] = '\0';
+ } else {
+ xSnprintf(buffer, sizeof(buffer), "%u", nNames);
+ }
+ RichString_append(out, valueDigitColor(nNames), buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], " failed) (");
+
+ if (nJobs == INVALID_VALUE) {
+ buffer[0] = '?';
+ buffer[1] = '\0';
+ } else {
+ xSnprintf(buffer, sizeof(buffer), "%u", nJobs);
+ }
+ RichString_append(out, zeroDigitColor(nJobs), buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], "/");
+
+ if (nInstalledJobs == INVALID_VALUE) {
+ buffer[0] = '?';
+ buffer[1] = '\0';
+ } else {
+ xSnprintf(buffer, sizeof(buffer), "%u", nInstalledJobs);
+ }
+ RichString_append(out, valueDigitColor(nInstalledJobs), buffer);
+
+ RichString_append(out, CRT_colors[METER_TEXT], " jobs)");
+}
+
+static const int SystemdMeter_attributes[] = {
+ METER_VALUE
+};
+
+const MeterClass SystemdMeter_class = {
+ .super = {
+ .extends = Class(Meter),
+ .delete = Meter_delete,
+ .display = SystemdMeter_display
+ },
+ .updateValues = SystemdMeter_updateValues,
+ .done = SystemdMeter_done,
+ .defaultMode = TEXT_METERMODE,
+ .maxItems = 0,
+ .total = 100.0,
+ .attributes = SystemdMeter_attributes,
+ .name = "Systemd",
+ .uiName = "Systemd state",
+ .description = "Systemd system state and unit overview",
+ .caption = "Systemd: ",
+};
diff --git a/linux/SystemdMeter.h b/linux/SystemdMeter.h
new file mode 100644
index 00000000..6ab4834d
--- /dev/null
+++ b/linux/SystemdMeter.h
@@ -0,0 +1,15 @@
+#ifndef HEADER_SystemdMeter
+#define HEADER_SystemdMeter
+
+/*
+htop - SystemdMeter.h
+(C) 2020 Christian Göttsche
+Released under the GNU GPLv2, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Meter.h"
+
+extern const MeterClass SystemdMeter_class;
+
+#endif /* HEADER_SystemdMeter */

© 2014-2024 Faster IT GmbH | imprint | privacy policy