Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux: add meter showing the current active user sessions #1364

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 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 All @@ -380,9 +400,11 @@ endif
# -------

solaris_platform_headers = \
UserSessionsMeter.h \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
generic/utmpx.h \
solaris/ProcessField.h \
solaris/Platform.h \
solaris/SolarisMachine.h \
Expand All @@ -393,9 +415,11 @@ solaris_platform_headers = \
zfs/ZfsCompressedArcMeter.h

solaris_platform_sources = \
UserSessionsMeter.c \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
generic/utmpx.c \
solaris/Platform.c \
solaris/SolarisMachine.c \
solaris/SolarisProcess.c \
Expand Down
157 changes: 157 additions & 0 deletions UserSessionsMeter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
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
Comment on lines +26 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should not be a platform-specific reference in the platform-independent code section.



static int users = 0;

#ifdef BUILD_STATIC
#define sym_sd_get_sessions sd_get_sessions
#else

# ifdef HTOP_LINUX
static int (*sym_sd_get_sessions)(char***);
static void* dlopenHandle;
static size_t activeHandles;
# endif /* HTOP_LINUX */

#endif /* BUILD_STATIC */


static void UserSessionsMeter_init(ATTR_UNUSED Meter* this) {
#if !defined(BUILD_STATIC) && defined(HTOP_LINUX)
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 && HTOP_LINUX */
}

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

#if (!defined(BUILD_STATIC) && defined(HTOP_LINUX)) || 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 && HTOP_LINUX) || HAVE_LIBSYSTEMD */

static void UserSessionsMeter_updateValues(Meter* this) {
int ret;
#if (!defined(BUILD_STATIC) && defined(HTOP_LINUX)) || 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 && HTOP_LINUX) || HAVE_LIBSYSTEMD */

users = ret;
Comment on lines +107 to +116
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this code into a platform-specific function. For everything aside from Linux this can be a direct forward to Generic_utmpx_get_users; on Linux that's mostly the above block of code.


if (users >= 0) {
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%d", ret);
Comment on lines +118 to +119
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why distinguish here between ret and users?

} 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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe shadow the value if not available?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For meter text, I don't think shadowing is a good idea. IMHO.

}
}

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
Loading
Loading