Skip to content

Commit

Permalink
Linux: add meter showing the current active user sessions
Browse files Browse the repository at this point in the history
Display the active user sessions either via systemd-logind or utmp.

On Linux try to query systemd-login first, and otherwise count only the
number of distinct sessions.  On other platforms the number of unique
sessions can not be determined and the number of all user entries are
returned.

Suggested in #1363.
  • Loading branch information
cgzones committed Jan 10, 2024
1 parent 2a58f5d commit 9499ecb
Show file tree
Hide file tree
Showing 13 changed files with 389 additions and 45 deletions.
24 changes: 22 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,11 @@ myhtopheaders = \
# -----

linux_platform_headers = \
UserSessionsMeter.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
generic/utmpx.h \
linux/CGroupUtils.h \
linux/HugePageMeter.h \
linux/IOPriority.h \
Expand All @@ -192,9 +194,11 @@ linux_platform_headers = \
zfs/ZfsCompressedArcMeter.h

linux_platform_sources = \
UserSessionsMeter.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
generic/utmpx.c \
linux/CGroupUtils.c \
linux/HugePageMeter.c \
linux/IOPriorityPanel.c \
Expand All @@ -220,6 +224,7 @@ endif
# -------

freebsd_platform_headers = \
UserSessionsMeter.h \
freebsd/FreeBSDMachine.h \
freebsd/FreeBSDProcessTable.h \
freebsd/FreeBSDProcess.h \
Expand All @@ -230,11 +235,13 @@ freebsd_platform_headers = \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
generic/utmpx.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h

freebsd_platform_sources = \
UserSessionsMeter.c \
freebsd/Platform.c \
freebsd/FreeBSDMachine.c \
freebsd/FreeBSDProcessTable.c \
Expand All @@ -244,6 +251,7 @@ freebsd_platform_sources = \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
generic/utmpx.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c

Expand All @@ -256,6 +264,7 @@ endif
# ------------

dragonflybsd_platform_headers = \
UserSessionsMeter.h \
dragonflybsd/DragonFlyBSDMachine.h \
dragonflybsd/DragonFlyBSDProcessTable.h \
dragonflybsd/DragonFlyBSDProcess.h \
Expand All @@ -264,17 +273,20 @@ dragonflybsd_platform_headers = \
generic/fdstat_sysctl.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h
generic/uname.h \
generic/utmpx.h

dragonflybsd_platform_sources = \
UserSessionsMeter.c \
dragonflybsd/DragonFlyBSDMachine.c \
dragonflybsd/DragonFlyBSDProcessTable.c \
dragonflybsd/DragonFlyBSDProcess.c \
dragonflybsd/Platform.c \
generic/fdstat_sysctl.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c
generic/uname.c \
generic/utmpx.c

if HTOP_DRAGONFLYBSD
myhtopplatheaders = $(dragonflybsd_platform_headers)
Expand All @@ -285,21 +297,25 @@ endif
# -------

netbsd_platform_headers = \
UserSessionsMeter.h \
generic/fdstat_sysctl.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
generic/utmpx.h \
netbsd/Platform.h \
netbsd/ProcessField.h \
netbsd/NetBSDMachine.h \
netbsd/NetBSDProcess.h \
netbsd/NetBSDProcessTable.h

netbsd_platform_sources = \
UserSessionsMeter.c \
generic/fdstat_sysctl.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
generic/utmpx.c \
netbsd/Platform.c \
netbsd/NetBSDMachine.c \
netbsd/NetBSDProcess.c \
Expand Down Expand Up @@ -341,6 +357,7 @@ endif
# ------

darwin_platform_headers = \
UserSessionsMeter.h \
darwin/DarwinMachine.h \
darwin/DarwinProcess.h \
darwin/DarwinProcessTable.h \
Expand All @@ -352,11 +369,13 @@ darwin_platform_headers = \
generic/hostname.h \
generic/openzfs_sysctl.h \
generic/uname.h \
generic/utmpx.h \
zfs/ZfsArcMeter.h \
zfs/ZfsArcStats.h \
zfs/ZfsCompressedArcMeter.h

darwin_platform_sources = \
UserSessionsMeter.c \
darwin/Platform.c \
darwin/PlatformHelpers.c \
darwin/DarwinMachine.c \
Expand All @@ -367,6 +386,7 @@ darwin_platform_sources = \
generic/hostname.c \
generic/openzfs_sysctl.c \
generic/uname.c \
generic/utmpx.c \
zfs/ZfsArcMeter.c \
zfs/ZfsCompressedArcMeter.c

Expand Down
155 changes: 155 additions & 0 deletions UserSessionsMeter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
htop - UserSessionsMeter.c
(C) 2024 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 "UserSessionsMeter.h"

#include <dlfcn.h>


#include "CRT.h"
#include "Macros.h"
#include "Object.h"
#include "RichString.h"
#include "XUtils.h"
#include "generic/utmpx.h"

#if defined(BUILD_STATIC) && defined(HAVE_LIBSYSTEMD)
#include <systemd/sd-login.h>
#endif

#ifndef BUILD_STATIC
#include <dlfcn.h>
#include "linux/Platform.h"
#endif


static int users = 0;

#ifdef BUILD_STATIC
#define sym_sd_get_sessions sd_get_sessions
#else

static int (*sym_sd_get_sessions)(char***);
static void* dlopenHandle;
static size_t activeHandles;

#endif /* BUILD_STATIC */


static void UserSessionsMeter_init(ATTR_UNUSED Meter* this) {
#ifndef BUILD_STATIC
assert(activeHandles != SIZE_MAX);
assert((dlopenHandle != NULL) == (activeHandles > 0));

if (activeHandles > 0) {
activeHandles++;
return;
}

dlopenHandle = Platform_load_libsystemd();
if (!dlopenHandle)
return;

/* 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_get_sessions);

#undef resolve

activeHandles++;
return;

dlfailure:
Platform_close_libsystemd();
dlopenHandle = NULL;
#endif /* !BUILD_STATIC */
}

static void UserSessionsMeter_done(ATTR_UNUSED Meter* this) {
#ifndef BUILD_STATIC
if (activeHandles > 0) {
activeHandles--;
if (activeHandles == 0) {
Platform_close_libsystemd();
dlopenHandle = NULL;
}
}
#endif /* !BUILD_STATIC */
}

#if !defined(BUILD_STATIC) || defined(HAVE_LIBSYSTEMD)
static int update_via_sd_login(void) {
#ifndef BUILD_STATIC
if (!dlopenHandle)
return -1;
#endif /* !BUILD_STATIC */

return sym_sd_get_sessions(NULL);
}
#endif /* !BUILD_STATIC || HAVE_LIBSYSTEMD */

static void UserSessionsMeter_updateValues(Meter* this) {
int ret;
#if !defined(BUILD_STATIC) || defined(HAVE_LIBSYSTEMD)
ret = update_via_sd_login();
if (ret < 0)
ret = Generic_utmpx_get_users();
#else
ret = Generic_utmpx_get_users();
#endif /* !BUILD_STATIC || HAVE_LIBSYSTEMD */

users = ret;

if (users >= 0) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%d", ret);
} else {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "N/A");
}
}

static void UserSessionsMeter_display(ATTR_UNUSED const Object* cast, RichString* out) {
char buffer[16];

if (users >= 0) {
int len = xSnprintf(buffer, sizeof(buffer), "%d", users);
RichString_appendnAscii(out, CRT_colors[METER_VALUE], buffer, len);
} else {
RichString_appendAscii(out, CRT_colors[METER_VALUE], "N/A");
}
}

static const int UserSessionsMeter_attributes[] = {
METER_VALUE
};

const MeterClass UserSessionsMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete,
.display = UserSessionsMeter_display
},
.updateValues = UserSessionsMeter_updateValues,
.init = UserSessionsMeter_init,
.done = UserSessionsMeter_done,
.defaultMode = TEXT_METERMODE,
.maxItems = 0,
.total = 100.0,
.attributes = UserSessionsMeter_attributes,
.name = "Users",
.uiName = "User Sessions",
.description = "Number of currently active user sessions",
.caption = "User sessions: ",
};
16 changes: 16 additions & 0 deletions UserSessionsMeter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef HEADER_UserSessionsMeter
#define HEADER_UserSessionsMeter

/*
htop - UserSessionsMeter.h
(C) 2024 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/

#include "Meter.h"


extern const MeterClass UserSessionsMeter_class;

#endif /* HEADER_UserSessionsMeter */
6 changes: 4 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fi])

# Optional Section

AC_CHECK_HEADERS([execinfo.h])
AC_CHECK_HEADERS([execinfo.h utmpx.h])

if test "$my_htop_platform" = darwin; then
AC_CHECK_HEADERS([mach/mach_time.h])
Expand All @@ -183,6 +183,8 @@ AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_UINT64_T

AC_CHECK_MEMBERS([struct utmpx.ut_session], [], [], [[#include <utmpx.h>]])

AC_MSG_CHECKING(for alloc_size)
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wno-error -Werror=attributes"
Expand Down Expand Up @@ -336,7 +338,7 @@ if test "$my_htop_platform" = pcp; then
fi

if test "$my_htop_platform" = linux && test "x$enable_static" = xyes; then
AC_CHECK_LIB([systemd], [sd_bus_open_system])
AC_CHECK_LIB([systemd], [sd_bus_open_system], [], [], [-lcap])
fi

# ----------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions darwin/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ in the source distribution for its full text.
#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "UserSessionsMeter.h"
#include "darwin/DarwinMachine.h"
#include "darwin/PlatformHelpers.h"
#include "generic/fdstat_sysctl.h"
Expand Down Expand Up @@ -144,6 +145,7 @@ const MeterClass* const Platform_meterTypes[] = {
&DiskIOMeter_class,
&NetworkIOMeter_class,
&FileDescriptorMeter_class,
&UserSessionsMeter_class,
&BlankMeter_class,
NULL
};
Expand Down
2 changes: 2 additions & 0 deletions dragonflybsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ in the source distribution for its full text.
#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "UserSessionsMeter.h"
#include "XUtils.h"
#include "dragonflybsd/DragonFlyBSDProcess.h"
#include "dragonflybsd/DragonFlyBSDProcessTable.h"
Expand Down Expand Up @@ -116,6 +117,7 @@ const MeterClass* const Platform_meterTypes[] = {
&LeftCPUs8Meter_class,
&RightCPUs8Meter_class,
&FileDescriptorMeter_class,
&UserSessionsMeter_class,
&BlankMeter_class,
NULL
};
Expand Down
2 changes: 2 additions & 0 deletions freebsd/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ in the source distribution for its full text.
#include "SysArchMeter.h"
#include "TasksMeter.h"
#include "UptimeMeter.h"
#include "UserSessionsMeter.h"
#include "XUtils.h"
#include "freebsd/FreeBSDMachine.h"
#include "generic/fdstat_sysctl.h"
Expand Down Expand Up @@ -133,6 +134,7 @@ const MeterClass* const Platform_meterTypes[] = {
&DiskIOMeter_class,
&FileDescriptorMeter_class,
&NetworkIOMeter_class,
&UserSessionsMeter_class,
NULL
};

Expand Down
Loading

0 comments on commit 9499ecb

Please sign in to comment.