File logind_y2038.patch of Package saltbundlepy-psutil

From 89b2d1896ffa8e5c9a8d9b89c3af0bb9027ce23b Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Tue, 22 Aug 2023 15:54:09 +0200
Subject: [PATCH] Use logind instead of utmp because of Y2038

Bi-arch systems line x86-64 present the Y2038 problem, where an overflow
can be produced because some glibc compatibility decissions (see
https://github.com/thkukuk/utmpx/blob/main/Y2038.md for more
information)

This patch uses logind from systemd instead of utmp on Linux systems, if
the systemd version is support the new API (>= 254).

Signed-off-by: Alberto Planas <aplanas@suse.com>
---
 INSTALL.rst            |  4 +--
 psutil/_psutil_linux.c | 81 ++++++++++++++++++++++++++++++++++++++++--
 setup.py               | 22 ++++++++++++
 3 files changed, 102 insertions(+), 5 deletions(-)

Index: psutil-5.9.5/INSTALL.rst
===================================================================
--- psutil-5.9.5.orig/INSTALL.rst
+++ psutil-5.9.5/INSTALL.rst
@@ -17,12 +17,12 @@ Linux (build)
 
 Ubuntu / Debian::
 
-    sudo apt-get install gcc python3-dev
+    sudo apt-get install gcc python3-dev libsystemd-dev
     pip install --no-binary :all: psutil
 
 RedHat / CentOS::
 
-    sudo yum install gcc python3-devel
+    sudo yum install gcc python3-devel systemd-devel
     pip install --no-binary :all: psutil
 
 Alpine::
Index: psutil-5.9.5/psutil/_psutil_linux.c
===================================================================
--- psutil-5.9.5.orig/psutil/_psutil_linux.c
+++ psutil-5.9.5/psutil/_psutil_linux.c
@@ -14,7 +14,11 @@
 #include <stdlib.h>
 #include <mntent.h>
 #include <features.h>
-#include <utmp.h>
+#ifdef SYSTEMD_LINUX
+    #include <systemd/sd-login.h>
+#else
+    #include <utmp.h>
+#endif
 #include <sched.h>
 #include <linux/version.h>
 #include <sys/syscall.h>
@@ -363,42 +367,102 @@ psutil_proc_cpu_affinity_set(PyObject *s
  */
 static PyObject *
 psutil_users(PyObject *self, PyObject *args) {
+#ifdef SYSTEMD_LINUX
+    char **sessions_list = NULL;
+#else
     struct utmp *ut;
+#endif
     PyObject *py_retlist = PyList_New(0);
     PyObject *py_tuple = NULL;
     PyObject *py_username = NULL;
     PyObject *py_tty = NULL;
     PyObject *py_hostname = NULL;
     PyObject *py_user_proc = NULL;
+    double tstamp = 0.0;
+    pid_t pid = 0;
 
     if (py_retlist == NULL)
         return NULL;
+#ifdef SYSTEMD_LINUX
+    int sessions = sd_get_sessions(&sessions_list);
+    for (int i = 0; i < sessions; i++) {
+        const char *session_id = sessions_list[i];
+#else
     setutent();
     while (NULL != (ut = getutent())) {
+#endif
         py_tuple = NULL;
         py_user_proc = NULL;
+    #ifdef SYSTEMD_LINUX
+        py_user_proc = Py_True;
+    #else
         if (ut->ut_type == USER_PROCESS)
             py_user_proc = Py_True;
         else
             py_user_proc = Py_False;
+    #endif
+
+    #ifdef SYSTEMD_LINUX
+        char *username = NULL;
+        if (sd_session_get_username(session_id, &username) < 0)
+            goto error;
+        py_username = PyUnicode_DecodeFSDefault(username);
+        free(username);
+    #else
         py_username = PyUnicode_DecodeFSDefault(ut->ut_user);
+    #endif
         if (! py_username)
             goto error;
+
+    #ifdef SYSTEMD_LINUX
+        char *tty = NULL;
+        if (sd_session_get_tty(session_id, &tty) < 0) {
+            py_tty = PyUnicode_DecodeFSDefault("n/a");
+        } else {
+            py_tty = PyUnicode_DecodeFSDefault(tty);
+            free(tty);
+        }
+    #else
         py_tty = PyUnicode_DecodeFSDefault(ut->ut_line);
+    #endif
         if (! py_tty)
             goto error;
+    #ifdef SYSTEMD_LINUX
+        char *hostname = NULL;
+        if (sd_session_get_remote_host(session_id, &hostname) < 0)
+            goto error;
+        py_hostname = PyUnicode_DecodeFSDefault(hostname);
+        free(hostname);
+    #else
         py_hostname = PyUnicode_DecodeFSDefault(ut->ut_host);
+    #endif
         if (! py_hostname)
             goto error;
 
+    #ifdef SYSTEMD_LINUX
+        uint64_t usec = 0;
+        if (sd_session_get_start_time(session_id, &usec) < 0)
+           goto error;
+        tstamp = (double)usec / 1000000.0;
+    #else
+        tstamp = (double)ut->ut_tv.tv_sec;
+    #endif
+
+    #ifdef SYSTEMD_LINUX
+        if (sd_session_get_leader(session_id, &pid) < 0)
+           goto error;
+    #else
+        pid = ut->ut_pid;
+    #endif
+
         py_tuple = Py_BuildValue(
             "OOOdO" _Py_PARSE_PID,
             py_username,              // username
             py_tty,                   // tty
             py_hostname,              // hostname
-            (double)ut->ut_tv.tv_sec,  // tstamp
+            tstamp,                   // tstamp
             py_user_proc,             // (bool) user process
-            ut->ut_pid                // process id
+            pid                       // process id
         );
         if (! py_tuple)
             goto error;
@@ -408,8 +472,15 @@ psutil_users(PyObject *self, PyObject *a
         Py_CLEAR(py_tty);
         Py_CLEAR(py_hostname);
         Py_CLEAR(py_tuple);
+    #ifdef SYSTEMD_LINUX
+        free (sessions_list[i]);
+    #endif
     }
+#ifdef SYSTEMD_LINUX
+    free(sessions_list);
+#else
     endutent();
+#endif
     return py_retlist;
 
 error:
@@ -418,7 +489,11 @@ error:
     Py_XDECREF(py_hostname);
     Py_XDECREF(py_tuple);
     Py_DECREF(py_retlist);
+#ifdef SYSTEMD_LINUX
+    free(sessions_list);
+#else
     endutent();
+#endif
     return NULL;
 }
 
Index: psutil-5.9.5/setup.py
===================================================================
--- psutil-5.9.5.orig/setup.py
+++ psutil-5.9.5/setup.py
@@ -184,6 +184,20 @@ def unix_can_compile(c_code):
         shutil.rmtree(tempdir)
 
 
+def get_systemd_version():
+    r = subprocess.run(["systemctl", "--version"], capture_output=True)
+    if r.returncode != 0:
+        return 0
+    out = r.stdout.split()
+    if len(out) < 2:
+        return 0
+    version = out[1]
+    try:
+        return int(version)
+    except ValueError:
+        return 0
+
+
 if WINDOWS:
     def get_winver():
         maj, min = sys.getwindowsversion()[0:2]
@@ -302,10 +316,18 @@ elif LINUX:
     if not unix_can_compile("#include <linux/ethtool.h>"):
         macros.append(("PSUTIL_ETHTOOL_MISSING_TYPES", 1))
 
+    libraries = []
+    # Systemd >= 254 can replace utmp. See:
+    # https://github.com/thkukuk/utmpx/blob/main/utmp-to-logind.md
+    if get_systemd_version() >= 254:
+        macros.append(("SYSTEMD_LINUX", 1))
+        libraries.append("systemd")
+
     macros.append(("PSUTIL_LINUX", 1))
     ext = Extension(
         'psutil._psutil_linux',
         sources=sources + ['psutil/_psutil_linux.c'],
+        libraries=libraries,
         define_macros=macros,
         **py_limited_api)
 
openSUSE Build Service is sponsored by