]> Savannah Git Hosting - gnulib.git/commitdiff
getlogin_r: Work around musl bug.
authorBruno Haible <bruno@clisp.org>
Sun, 9 Mar 2025 09:19:20 +0000 (10:19 +0100)
committerBruno Haible <bruno@clisp.org>
Tue, 1 Apr 2025 14:28:43 +0000 (16:28 +0200)
* lib/getlogin_r.c (getlogin_r): Add implementation for Linux.
* m4/getlogin_r.m4 (gl_FUNC_GETLOGIN_R): Test whether getlogin_r has the
musl bug.
* tests/test-getlogin_r.c (main): Add another test.

ChangeLog
lib/getlogin_r.c
m4/getlogin_r.m4
tests/test-getlogin_r.c

index 6bb1ab55542180b5826b768c62234ba72fac6877..3f80b9a2b470552b6daadc4235b3348d4005239f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-03-09  Bruno Haible  <bruno@clisp.org>
+
+       getlogin_r: Work around musl bug.
+       * lib/getlogin_r.c (getlogin_r): Add implementation for Linux.
+       * m4/getlogin_r.m4 (gl_FUNC_GETLOGIN_R): Test whether getlogin_r has the
+       musl bug.
+       * tests/test-getlogin_r.c (main): Add another test.
+
 2025-03-09  Bruno Haible  <bruno@clisp.org>
 
        getlogin: Work around musl bug.
index 6a13e8e405e700f19a98d690ab35fdd944c001f5..ade819940ee208cf1af80b5b758a9f2c52231e5d 100644 (file)
@@ -39,6 +39,14 @@ extern char *getlogin (void);
 # endif
 #endif
 
+#if defined __linux__ || defined __ANDROID__
+# include <fcntl.h>
+# include <pwd.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+#endif
+
 /* See unistd.in.h for documentation.  */
 int
 getlogin_r (char *name, size_t size)
@@ -64,6 +72,72 @@ getlogin_r (char *name, size_t size)
         return ENOENT;
     }
   return 0;
+#elif defined __linux__ || defined __ANDROID__
+  /* Linux.  */
+  {
+    /* Read the login uid from the /proc file system.  */
+    int fd = open ("/proc/self/loginuid", O_RDONLY);
+    if (fd >= 0)
+      {
+        char buf[20 + 1];
+        int n = read (fd, buf, sizeof (buf) - 1);
+        if (n > 0)
+          {
+            buf[n] = '\0';
+            char *endptr;
+            unsigned long uid = strtoul (buf, &endptr, 10);
+            if (endptr == buf + n && uid != (uid_t) -1)
+              {
+                /* Convert the uid to a user name.  */
+                struct passwd pbuf1;
+                char pbuf2[1024];
+                struct passwd *p;
+                if (getpwuid_r (uid, &pbuf1, pbuf2, sizeof (pbuf2), &p) == 0)
+                  {
+                    if (strlen (p->pw_name) < size)
+                      {
+                        strcpy (name, p->pw_name);
+                        close (fd);
+                        return 0;
+                      }
+                    return ERANGE;
+                  }
+              }
+          }
+        close (fd);
+      }
+  }
+  {
+    /* Find the tty connected to the current process.  */
+    char tty[1024];
+    if (ttyname_r (STDIN_FILENO, tty, sizeof (tty)) == 0)
+      {
+        /* We cannot use read_utmp here, since it is not multithread-safe.  */
+        /* Fallback for systems which don't maintain an utmp database
+           or for ttys that are not recorded in that the utmp database:
+           Look at the owner of that tty.  */
+        struct stat statbuf;
+        if (stat (tty, &statbuf) >= 0)
+          {
+            uid_t uid = statbuf.st_uid;
+            /* Convert the uid to a user name.  */
+            struct passwd pbuf1;
+            char pbuf2[1024];
+            struct passwd *p;
+            if (getpwuid_r (uid, &pbuf1, pbuf2, sizeof (pbuf2), &p) == 0)
+              {
+                if (strlen (p->pw_name) < size)
+                  {
+                    strcpy (name, p->pw_name);
+                    return 0;
+                  }
+                return ERANGE;
+              }
+          }
+      }
+  }
+  /* ENOENT is a reasonable errno value if getlogin returns NULL.  */
+  return ENOENT;
 #elif HAVE_GETLOGIN_R
   /* Platform with a getlogin_r() function.  */
   int ret = getlogin_r (name, size);
index 26664e1fda82ed9cd9a2895b8b1039f9661761d0..5ac8a89ff87fcd0376030a6a3e0c222022ac7fa7 100644 (file)
@@ -1,5 +1,5 @@
 # getlogin_r.m4
-# serial 15
+# serial 16
 dnl Copyright (C) 2005-2007, 2009-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -35,22 +35,26 @@ AC_DEFUN([gl_FUNC_GETLOGIN_R],
     HAVE_GETLOGIN_R=1
     dnl On Mac OS X 10.13 and OSF/1 5.1, getlogin_r returns a truncated result
     dnl if the buffer is not large enough.
+    dnl On musl libc, getlogin_r returns getenv ("LOGNAME").
     AC_REQUIRE([AC_CANONICAL_HOST])
-    AC_CACHE_CHECK([whether getlogin_r works with small buffers],
+    AC_CACHE_CHECK([whether getlogin_r works],
       [gl_cv_func_getlogin_r_works],
       [
         dnl Initial guess, used when cross-compiling.
 changequote(,)dnl
         case "$host_os" in
-                          # Guess no on Mac OS X, OSF/1.
-          darwin* | osf*) gl_cv_func_getlogin_r_works="guessing no" ;;
-                          # Guess yes otherwise.
-          *)              gl_cv_func_getlogin_r_works="guessing yes" ;;
+                              # Guess no on Mac OS X, OSF/1.
+          darwin* | osf*)     gl_cv_func_getlogin_r_works="guessing no" ;;
+                              # Guess no on musl libc.
+          *-musl* | midipix*) gl_cv_func_getlogin_r_works="guessing no" ;;
+                              # Guess yes otherwise.
+          *)                  gl_cv_func_getlogin_r_works="guessing yes" ;;
         esac
 changequote([,])dnl
         AC_RUN_IFELSE(
           [AC_LANG_SOURCE([[
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #if !HAVE_DECL_GETLOGIN_R
@@ -76,6 +80,10 @@ main (void)
       if (getlogin_r (buf, n) == 0)
         result |= 4;
     }
+  putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke");
+  if (getlogin_r (buf, 100) == 0
+      && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0)
+    result |= 8;
   return result;
 }]])],
           [gl_cv_func_getlogin_r_works=yes],
index 4deddfbb01c7a7323c8fa7ac4cb694031615131b..3674195e55fe443cd8d133ffdf4a1b4a05617c51 100644 (file)
@@ -68,5 +68,10 @@ main (void)
     ASSERT (strcmp (hugebuf, buf) == 0);
   }
 
+  /* Check that getlogin_r() does not merely return getenv ("LOGNAME").  */
+  putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke");
+  err = getlogin_r (buf, sizeof buf);
+  ASSERT (!(err == 0 && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0));
+
   return test_exit_status;
 }