summaryrefslogtreecommitdiffstats
path: root/linux
diff options
context:
space:
mode:
authorChristian Göttsche <cgzones@googlemail.com>2024-03-30 13:47:14 +0100
committercgzones <cgzones@googlemail.com>2024-04-05 19:27:07 +0200
commit24b1513296fd61722166625ad46be1c56a5efc44 (patch)
treea0137954bfd9252bef84f18c57d90c95696d9dfc /linux
parenta782ef357067962f60580478067f4023facab6a0 (diff)
linux: use dlopen for libnl3 instead of dynamic linking
Instead of the current behavior of dynamic linking against libnl3 and libnl-genl-3 when configured with --enable-delayacct, load the shared libraries on request, if any delay accounting related process field is active, via dlopen(3), similar to libsensors and libsystemd. Distribution, who currently build htop with --enable-delayacct, need to explicitly add libnl3 and libnl-genl-3 as runtime dependencies to continue supporting delay accounting out-of-the-box.
Diffstat (limited to 'linux')
-rw-r--r--linux/LibNl.c159
1 files changed, 136 insertions, 23 deletions
diff --git a/linux/LibNl.c b/linux/LibNl.c
index e61b14f6..72465f22 100644
--- a/linux/LibNl.c
+++ b/linux/LibNl.c
@@ -13,36 +13,149 @@ in the source distribution for its full text.
#include "linux/LibNl.h"
+#include <dlfcn.h>
+
#include <linux/netlink.h>
#include <linux/taskstats.h>
#include <netlink/attr.h>
#include <netlink/handlers.h>
#include <netlink/msg.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/ctrl.h>
+static void* libnlHandle;
+static void* libnlGenlHandle;
+
+static void (*sym_nl_close)(struct nl_sock*);
+static int (*sym_nl_connect)(struct nl_sock*, int);
+static int (*sym_nl_recvmsgs_default)(struct nl_sock*);
+static int (*sym_nl_send_sync)(struct nl_sock*, struct nl_msg*);
+static struct nl_sock* (*sym_nl_socket_alloc)(void);
+static void (*sym_nl_socket_free)(struct nl_sock*);
+static int (*sym_nl_socket_modify_cb)(struct nl_sock*, enum nl_cb_type, enum nl_cb_kind, nl_recvmsg_msg_cb_t, void*);
+static void* (*sym_nla_data)(const struct nlattr*);
+static struct nlattr* (*sym_nla_next)(const struct nlattr*, int*);
+static int (*sym_nla_put_u32)(struct nl_msg*, int, uint32_t);
+static struct nl_msg* (*sym_nlmsg_alloc)(void);
+static struct nlmsghdr* (*sym_nlmsg_hdr)(struct nl_msg*);
+static void (*sym_nlmsg_free)(struct nl_msg*);
+
+static int (*sym_genl_ctrl_resolve)(struct nl_sock*, const char*);
+static int (*sym_genlmsg_parse)(struct nlmsghdr*, int, struct nlattr**, int, const struct nla_policy*);
+static void* (*sym_genlmsg_put)(struct nl_msg*, uint32_t, uint32_t, int, int, int, uint8_t, uint8_t);
+
+
+static void unload_libnl(void) {
+ sym_nl_close = NULL;
+ sym_nl_connect = NULL;
+ sym_nl_recvmsgs_default = NULL;
+ sym_nl_send_sync = NULL;
+ sym_nl_socket_alloc = NULL;
+ sym_nl_socket_free = NULL;
+ sym_nl_socket_modify_cb = NULL;
+ sym_nla_data = NULL;
+ sym_nla_next = NULL;
+ sym_nla_put_u32 = NULL;
+ sym_nlmsg_alloc = NULL;
+ sym_nlmsg_free = NULL;
+ sym_nlmsg_hdr = NULL;
+
+ sym_genl_ctrl_resolve = NULL;
+ sym_genlmsg_parse = NULL;
+ sym_genlmsg_put = NULL;
+
+ if (libnlGenlHandle) {
+ dlclose(libnlGenlHandle);
+ libnlGenlHandle = NULL;
+ }
+ if (libnlHandle) {
+ dlclose(libnlHandle);
+ libnlHandle = NULL;
+ }
+}
+
+static int load_libnl(void) {
+ if (libnlHandle && libnlGenlHandle)
+ return 0;
+
+ libnlHandle = dlopen("libnl-3.so", RTLD_LAZY);
+ if (!libnlHandle) {
+ libnlHandle = dlopen("libnl-3.so.200", RTLD_LAZY);
+ if (!libnlHandle) {
+ goto dlfailure;
+ }
+ }
+
+ libnlGenlHandle = dlopen("libnl-genl-3.so", RTLD_LAZY);
+ if (!libnlGenlHandle) {
+ libnlGenlHandle = dlopen("libnl-genl-3.so.200", RTLD_LAZY);
+ if (!libnlGenlHandle) {
+ goto dlfailure;
+ }
+ }
+
+ /* Clear any errors */
+ dlerror();
+
+ #define resolve(handle, symbolname) do { \
+ *(void **)(&sym_##symbolname) = dlsym(handle, #symbolname); \
+ if (!sym_##symbolname || dlerror() != NULL) { \
+ goto dlfailure; \
+ } \
+ } while(0)
+
+ resolve(libnlHandle, nl_close);
+ resolve(libnlHandle, nl_connect);
+ resolve(libnlHandle, nl_recvmsgs_default);
+ resolve(libnlHandle, nl_send_sync);
+ resolve(libnlHandle, nl_socket_alloc);
+ resolve(libnlHandle, nl_socket_free);
+ resolve(libnlHandle, nl_socket_modify_cb);
+ resolve(libnlHandle, nla_data);
+ resolve(libnlHandle, nla_next);
+ resolve(libnlHandle, nla_put_u32);
+ resolve(libnlHandle, nlmsg_alloc);
+ resolve(libnlHandle, nlmsg_free);
+ resolve(libnlHandle, nlmsg_hdr);
+
+ resolve(libnlGenlHandle, genl_ctrl_resolve);
+ resolve(libnlGenlHandle, genlmsg_parse);
+ resolve(libnlGenlHandle, genlmsg_put);
+
+ #undef resolve
+
+ return 0;
+
+dlfailure:
+ unload_libnl();
+ return -1;
+}
+
static void initNetlinkSocket(LinuxProcessTable* this) {
- this->netlink_socket = nl_socket_alloc();
+ if (load_libnl() < 0) {
+ return;
+ }
+
+ this->netlink_socket = sym_nl_socket_alloc();
if (this->netlink_socket == NULL) {
return;
}
- if (nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) {
+ if (sym_nl_connect(this->netlink_socket, NETLINK_GENERIC) < 0) {
return;
}
- this->netlink_family = genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME);
+ this->netlink_family = sym_genl_ctrl_resolve(this->netlink_socket, TASKSTATS_GENL_NAME);
}
void LibNl_destroyNetlinkSocket(LinuxProcessTable* this) {
- if (!this->netlink_socket)
- return;
+ if (this->netlink_socket) {
+ assert(libnlHandle);
+
+ sym_nl_close(this->netlink_socket);
+ sym_nl_socket_free(this->netlink_socket);
+ this->netlink_socket = NULL;
+ }
- nl_close(this->netlink_socket);
- nl_socket_free(this->netlink_socket);
- this->netlink_socket = NULL;
+ unload_libnl();
}
static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
@@ -53,14 +166,14 @@ static int handleNetlinkMsg(struct nl_msg* nlmsg, void* linuxProcess) {
int rem;
LinuxProcess* lp = (LinuxProcess*) linuxProcess;
- nlhdr = nlmsg_hdr(nlmsg);
+ nlhdr = sym_nlmsg_hdr(nlmsg);
- if (genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
+ if (sym_genlmsg_parse(nlhdr, 0, nlattrs, TASKSTATS_TYPE_MAX, NULL) < 0) {
return NL_SKIP;
}
if ((nlattr = nlattrs[TASKSTATS_TYPE_AGGR_PID]) || (nlattr = nlattrs[TASKSTATS_TYPE_NULL])) {
- memcpy(&stats, nla_data(nla_next(nla_data(nlattr), &rem)), sizeof(stats));
+ memcpy(&stats, sym_nla_data(sym_nla_next(sym_nla_data(nlattr), &rem)), sizeof(stats));
assert(Process_getPid(&lp->super) == (pid_t)stats.ac_pid);
// The xxx_delay_total values wrap around on overflow.
@@ -90,27 +203,27 @@ void LibNl_readDelayAcctData(LinuxProcessTable* this, LinuxProcess* process) {
}
}
- if (nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
+ if (sym_nl_socket_modify_cb(this->netlink_socket, NL_CB_VALID, NL_CB_CUSTOM, handleNetlinkMsg, process) < 0) {
goto delayacct_failure;
}
- if (! (msg = nlmsg_alloc())) {
+ if (! (msg = sym_nlmsg_alloc())) {
goto delayacct_failure;
}
- if (! genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
- nlmsg_free(msg);
+ if (! sym_genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, this->netlink_family, 0, NLM_F_REQUEST, TASKSTATS_CMD_GET, TASKSTATS_VERSION)) {
+ sym_nlmsg_free(msg);
}
- if (nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) {
- nlmsg_free(msg);
+ if (sym_nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, Process_getPid(&process->super)) < 0) {
+ sym_nlmsg_free(msg);
}
- if (nl_send_sync(this->netlink_socket, msg) < 0) {
+ if (sym_nl_send_sync(this->netlink_socket, msg) < 0) {
goto delayacct_failure;
}
- if (nl_recvmsgs_default(this->netlink_socket) < 0) {
+ if (sym_nl_recvmsgs_default(this->netlink_socket) < 0) {
goto delayacct_failure;
}

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