[procps] [RFC] w using logind instead of utmp

  • From: "Thorsten Kukuk" <dmarc-noreply@xxxxxxxxxxxxx> ("kukuk")
  • To: procps@xxxxxxxxxxxxx
  • Date: Fri, 9 Jun 2023 13:26:55 +0000


Hi,

with w there is one binary left which only uses utmp, here is a patch to
add logind support, too.

systemd-logind v245 (or current git) will be necessary for this, as only
this version has all the APIs to access the data.

Would it be Ok this way? Or what to change?

 Thorsten
-- 
Thorsten Kukuk, Distinguished Engineer, Senior Architect, Future Technologies
SUSE Software Solutions Germany GmbH, Frankenstraße 146, 90461 Nuernberg, 
Germany
Managing Director: Ivo Totev, Andrew Myers, Andrew McDonald, Martje Boudien 
Moerman
(HRB 36809, AG Nürnberg)
diff --git a/configure.ac b/configure.ac
index e20a2c55..04e92757 100644
--- a/configure.ac
+++ b/configure.ac
@@ -280,6 +280,13 @@ AS_IF([test "x$with_systemd" != "xno"], [
     [PKG_CHECK_MODULES([SYSTEMD], [libsystemd-login])]
   )
   AC_DEFINE(WITH_SYSTEMD, 1, [enable systemd support])
+
+  # The functions needed to replace utmp with logind are only available
+  # with systemd v254 or later.
+  old_LIBS="$LIBS"
+  LIBS="$LIBS $SYSTEMD_LIBS"
+  AC_CHECK_FUNCS([sd_session_get_leader])
+  LIBS="$old_LIBS"
 ])
 AM_CONDITIONAL([WITH_SYSTEMD], [test x$with_systemd != xno])
 
diff --git a/src/w.c b/src/w.c
index 093cfbc7..b0784a93 100644
--- a/src/w.c
+++ b/src/w.c
@@ -53,6 +53,14 @@
 #      include <utmp.h>
 #endif
 #include <arpa/inet.h>
+#ifdef WITH_SYSTEMD
+#      include <systemd/sd-login.h>
+#      include <systemd/sd-daemon.h>
+#endif
+#ifdef WITH_ELOGIND
+#      include <elogind/sd-login.h>
+#      include <elogind/sd-daemon.h>
+#endif
 
 #include "c.h"
 #include "fileutils.h"
@@ -196,7 +204,25 @@ static void print_display_or_interface(const char 
*restrict host, int len, int r
 
 
 /* This routine prints either the hostname or the IP address of the remote */
-static void print_from(const utmp_t *restrict const u, const int ip_addresses, 
const int fromlen) {
+static void print_from(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+                      const char *session,
+#endif
+                      const utmp_t *restrict const u, const int ip_addresses, 
const int fromlen) {
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        if (session) {
+           char *host = NULL;
+           int r;
+
+           r = sd_session_get_remote_host(session, &host);
+           if (r < 0 || host == NULL)
+               print_host("", 0, fromlen);
+           else {
+               print_host(host, strlen(host), fromlen);
+               free(host);
+           }
+       } else {
+#endif
        char buf[fromlen + 1];
        char buf_ipv6[INET6_ADDRSTRLEN];
        int len;
@@ -241,6 +267,9 @@ static void print_from(const utmp_t *restrict const u, 
const int ip_addresses, c
 #else
        print_host(u->ut_host, UT_HOSTSIZE, fromlen);
 #endif
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+       }
+#endif
 }
 
 
@@ -343,7 +372,7 @@ static int get_tty_device(const char *restrict const name)
 
     for (i=0; dev_paths[i] != NULL; i++) {
         snprintf(buf, 32, dev_paths[i], name);
-        if (stat(buf, &st) == 0)
+        if (stat(buf, &st) == 0 && (st.st_mode & S_IFMT) == S_IFCHR)
             return st.st_rdev;
     }
     return -1;
@@ -357,6 +386,9 @@ static int get_tty_device(const char *restrict const name)
  * essential core of 'w'.
  */
 static int find_best_proc(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        const char *session,
+#endif
         const utmp_t * restrict const u,
         const char *restrict const tty,
         unsigned long long *restrict const jcpu,
@@ -394,6 +426,12 @@ static int find_best_proc(
     *jcpu = 0;
     *pcpu = 0;
     if (!ignoreuser) {
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        if (session) {
+            if (sd_session_get_uid(session, &uid) < 0)
+                return 0;
+        } else {
+#endif
         char buf[UT_NAMESIZE + 1];
         struct passwd *passwd_data;
         strncpy(buf, u->ut_user, UT_NAMESIZE);
@@ -402,6 +440,9 @@ static int find_best_proc(
             return 0;
         uid = passwd_data->pw_uid;
         /* OK to have passwd_data go out of scope here */
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+       }
+#endif
     }
 
     line = get_tty_device(tty);
@@ -415,8 +456,15 @@ static int find_best_proc(
     total_procs = reap->counts->total;
 
     for (i=0; i < total_procs; i++) {
+        pid_t ut_pid = -1;
+        if (u)
+            ut_pid = u->ut_pid;
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        else
+          sd_session_get_leader(session, &ut_pid);
+#endif
         /* is this the login process? */
-        if (PIDS_GETINT(TGID) == u->ut_pid) {
+        if (PIDS_GETINT(TGID) == ut_pid) {
             found_utpid = 1;
             if (!best_time) {
                 best_time = PIDS_GETULL(START);
@@ -458,6 +506,9 @@ static int find_best_proc(
 }
 
 static void showinfo(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+            const char *session, const char *name,
+#endif
             utmp_t * u, int formtype, int maxcmd, int from,
             const int userlen, const int fromlen, const int ip_addresses,
             const int pids)
@@ -473,14 +524,37 @@ static void showinfo(
     strcpy(cmdline, "-");
 
     hertz = procps_hertz_get();
+
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+    if (session) {
+        char *sd_tty;
+
+        if (sd_session_get_tty(session, &sd_tty) >= 0) {
+            for (i = 0; i < strlen (sd_tty); i++)
+                /* clean up tty if garbled */
+               if (isalnum(sd_tty[i]) || (sd_tty[i] == '/'))
+                   tty[i + 5] = sd_tty[i];
+               else
+                   tty[i + 5] = '\0';
+           free(sd_tty);
+       }
+    } else {
+#endif
     for (i = 0; i < UT_LINESIZE; i++)
         /* clean up tty if garbled */
         if (isalnum(u->ut_line[i]) || (u->ut_line[i] == '/'))
             tty[i + 5] = u->ut_line[i];
         else
             tty[i + 5] = '\0';
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+    }
+#endif
 
-    if (find_best_proc(u, tty + 5, &jcpu, &pcpu, cmdline, &best_pid) == 0)
+    if (find_best_proc(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+                      session,
+#endif
+                      u, tty + 5, &jcpu, &pcpu, cmdline, &best_pid) == 0)
     /*
      * just skip if stale utmp entry (i.e. login proc doesn't
      * exist). If there is a desire a cmdline flag could be
@@ -489,20 +563,42 @@ static void showinfo(
      */
         return;
 
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+    if (name)
+      strncpy(uname, name, UT_NAMESIZE);
+    else
+#endif
+      strncpy(uname, u->ut_user, UT_NAMESIZE);
     /* force NUL term for printf */
-    strncpy(uname, u->ut_user, UT_NAMESIZE);
     uname[UT_NAMESIZE] = '\0';
 
     if (formtype) {
         printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, tty + 5);
-        if (from)
-            print_from(u, ip_addresses, fromlen);
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        if (session) {
+            uint64_t ltime;
+            uid_t uid;
+
+            if (from)
+              print_from(session, NULL, ip_addresses, fromlen);
+
+            sd_session_get_uid(session, &uid);
+            sd_uid_get_login_time(uid, &ltime);
+            print_logintime(ltime/((uint64_t) 1000000ULL), stdout);
+        } else {
+#endif
+            if (from)
+                print_from(NULL, u, ip_addresses, fromlen);
+
 #ifdef HAVE_UTMPX_H
-        print_logintime(u->ut_tv.tv_sec, stdout);
+            print_logintime(u->ut_tv.tv_sec, stdout);
 #else
-        print_logintime(u->ut_time, stdout);
+            print_logintime(u->ut_time, stdout);
+#endif
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+        }
 #endif
-        if (*u->ut_line == ':')
+        if (u && *u->ut_line == ':')
             /* idle unknown for xdm logins */
             printf(" ?xdm? ");
         else
@@ -518,15 +614,22 @@ static void showinfo(
     } else {
         printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, tty + 5);
         if (from)
-            print_from(u, ip_addresses, fromlen);
-        if (*u->ut_line == ':')
+           print_from(NULL, u, ip_addresses, fromlen);
+        if (u && *u->ut_line == ':')
             /* idle unknown for xdm logins */
             printf(" ?xdm? ");
         else
             print_time_ival7(idletime(tty), 0, stdout);
     }
     if (pids) {
-        pids_length = printf(" %d/%d", u->ut_pid, best_pid);
+        pid_t ut_pid = -1;
+        if (u)
+           ut_pid = u->ut_pid;
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+       else
+           sd_session_get_leader(session, &ut_pid);
+#endif
+        pids_length = printf(" %d/%d", ut_pid, best_pid);
         if (pids_length > maxcmd) {
             maxcmd = 0;
         } else if (pids_length > 0) {
@@ -692,7 +795,40 @@ int main(int argc, char **argv)
                else
                        printf(_("   IDLE WHAT\n"));
        }
-
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+       if (sd_booted() > 0) {
+               char **sessions_list;
+               int sessions;
+               int i;
+
+               sessions = sd_get_sessions (&sessions_list);
+               if (sessions < 0 && sessions != -ENOENT)
+                       error(EXIT_FAILURE, -sessions, _("error getting 
sessions"));
+
+               if (sessions >= 0) {
+                       for (int i = 0; i < sessions; i++) {
+                               char *name;
+                               int r;
+
+                               if ((r = 
sd_session_get_username(sessions_list[i], &name)) < 0)
+                                       error(EXIT_FAILURE, -r, _("get user 
name failed"));
+
+                               if (user) {
+                                       if (!strcmp(name, user))
+                                               showinfo(sessions_list[i], 
name, NULL, longform,
+                                                        maxcmd, from, userlen, 
fromlen,
+                                                        ip_addresses, pids);
+                               } else {
+                                       showinfo(sessions_list[i], name, NULL, 
longform, maxcmd,
+                                                from, userlen, fromlen, 
ip_addresses, pids);
+                               }
+                               free(name);
+                               free(sessions_list[i]);
+                       }
+                       free(sessions_list);
+               }
+       } else {
+#endif
 #ifdef HAVE_UTMPX_H
        setutxent();
 #else
@@ -711,7 +847,11 @@ int main(int argc, char **argv)
                        if (u->ut_type != USER_PROCESS)
                                continue;
                        if (!strncmp(u->ut_user, user, UT_NAMESIZE))
-                               showinfo(u, longform, maxcmd, from, userlen,
+                               showinfo(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+                                        NULL, NULL,
+#endif
+                                        u, longform, maxcmd, from, userlen,
                                         fromlen, ip_addresses, pids);
                }
        } else {
@@ -726,7 +866,11 @@ int main(int argc, char **argv)
                        if (u->ut_type != USER_PROCESS)
                                continue;
                        if (*u->ut_user)
-                               showinfo(u, longform, maxcmd, from, userlen,
+                               showinfo(
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+                                        NULL, NULL,
+#endif
+                                        u, longform, maxcmd, from, userlen,
                                         fromlen, ip_addresses, pids);
                }
        }
@@ -735,6 +879,9 @@ int main(int argc, char **argv)
 #else
        endutent();
 #endif
+#if (defined(WITH_SYSTEMD) || defined(WITH_ELOGIND)) && 
defined(HAVE_SD_SESSION_GET_LEADER)
+       }
+#endif
 
        return EXIT_SUCCESS;
 }

Other related posts: