]> Savannah Git Hosting - gnulib.git/commitdiff
getlogin: Work around musl bug.
authorBruno Haible <bruno@clisp.org>
Sun, 9 Mar 2025 09:16:58 +0000 (10:16 +0100)
committerBruno Haible <bruno@clisp.org>
Tue, 1 Apr 2025 14:27:33 +0000 (16:27 +0200)
* lib/unistd.in.h (getlogin): Consider REPLACE_GETLOGIN.
* lib/getlogin.c: Change license header to GPL.
(getlogin): Add implementation for Linux.
* m4/getlogin.m4 (gl_FUNC_GETLOGIN): Test whether getlogin works.
* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize REPLACE_GETLOGIN.
* modules/unistd-h (Makefile.am): Substitute REPLACE_GETLOGIN.
* modules/getlogin (Depends-on): Add readutmp.
(configure.ac): Consider REPLACE_GETLOGIN.
(License): Change to GPL.
* tests/test-getlogin.c (main): Add another test.

ChangeLog
lib/getlogin.c
lib/unistd.in.h
m4/getlogin.m4
m4/unistd_h.m4
modules/getlogin
modules/unistd-h
tests/test-getlogin.c

index 62e5213e037f2fbae97ca930a314d403a39ea1e3..6bb1ab55542180b5826b768c62234ba72fac6877 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2025-03-09  Bruno Haible  <bruno@clisp.org>
+
+       getlogin: Work around musl bug.
+       * lib/unistd.in.h (getlogin): Consider REPLACE_GETLOGIN.
+       * lib/getlogin.c: Change license header to GPL.
+       (getlogin): Add implementation for Linux.
+       * m4/getlogin.m4 (gl_FUNC_GETLOGIN): Test whether getlogin works.
+       * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize REPLACE_GETLOGIN.
+       * modules/unistd-h (Makefile.am): Substitute REPLACE_GETLOGIN.
+       * modules/getlogin (Depends-on): Add readutmp.
+       (configure.ac): Consider REPLACE_GETLOGIN.
+       (License): Change to GPL.
+       * tests/test-getlogin.c (main): Add another test.
+
 2025-03-03  Bruno Haible  <bruno@clisp.org>
 
        vasprintf-posix, vasprintf-gnu: Fix module description.
index 72c25acbc70827dfd2f14713aeff6e85f96e9457..47721115676b2b5f259bfef511f001906a89292f 100644 (file)
@@ -3,19 +3,19 @@
    Copyright (C) 2010-2025 Free Software Foundation, Inc.
 
    This file is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
 
    This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
+   GNU General Public License for more details.
 
-   You should have received a copy of the GNU Lesser General Public License
+   You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-/* Written by Bruno Haible, 2010.  */
+/* Written by Bruno Haible, 2010, 2025.  */
 
 #include <config.h>
 
 # define GetUserName GetUserNameA
 #endif
 
+#if defined __linux__ || defined __ANDROID__
+# include <fcntl.h>
+# include <pwd.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+# include "readutmp.h"
+#endif
+
 char *
 getlogin (void)
 {
 #if defined _WIN32 && ! defined __CYGWIN__
+  /* Native Windows platform.  */
   static char login_name[1024];
   DWORD sz = sizeof (login_name);
 
   if (GetUserName (login_name, &sz))
     return login_name;
+#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 *p = getpwuid (uid);
+                if (p != NULL && strlen (p->pw_name) < 64)
+                  {
+                    static char resultbuf[64];
+                    strcpy (resultbuf, p->pw_name);
+                    close (fd);
+                    return resultbuf;
+                  }
+              }
+          }
+        close (fd);
+      }
+  }
+  {
+    /* Find the tty connected to the current process.  */
+    char *tty = ttyname (STDIN_FILENO);
+    if (tty != NULL)
+      {
+        /* Try to see to which user it is allocated, via utmp.  */
+        if (strncmp (tty, "/dev/tty", 8) == 0)
+          {
+            idx_t n;
+            STRUCT_UTMP *entries;
+            if (read_utmp (UTMP_FILE, &n, &entries, READ_UTMP_USER_PROCESS)
+                == 0)
+              {
+                idx_t i;
+                for (i = 0; i < n; i++)
+                  if (strcmp (entries[i].ut_line, tty + 5) == 0)
+                    {
+                      if (strlen (entries[i].ut_user) < 64)
+                        {
+                          static char resultbuf[64];
+                          strcpy (resultbuf, entries[i].ut_user);
+                          free (entries);
+                          return resultbuf;
+                        }
+                      break;
+                    }
+                free (entries);
+              }
+          }
+        /* 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 *p = getpwuid (uid);
+            if (p != NULL && strlen (p->pw_name) < 64)
+              {
+                static char resultbuf[64];
+                strcpy (resultbuf, p->pw_name);
+                return resultbuf;
+              }
+          }
+      }
+  }
 #endif
   return NULL;
 }
index 3f96e10d7e77bbdd0c7738314aa07b93c95b58ee..23d2d53c959a8bb23686df9748b32e10a762aa4d 100644 (file)
@@ -1362,11 +1362,21 @@ _GL_WARN_ON_USE (gethostname, "gethostname is unportable - "
      ${LOGNAME-$USER}        on Unix platforms,
      $USERNAME               on native Windows platforms.
  */
-# if !@HAVE_DECL_GETLOGIN@
+# if @REPLACE_GETLOGIN@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define getlogin rpl_getlogin
+#  endif
+_GL_FUNCDECL_RPL (getlogin, char *, (void), );
+_GL_CXXALIAS_RPL (getlogin, char *, (void));
+# else
+#  if !@HAVE_DECL_GETLOGIN@
 _GL_FUNCDECL_SYS (getlogin, char *, (void), );
-# endif
+#  endif
 _GL_CXXALIAS_SYS (getlogin, char *, (void));
+# endif
+# if __GLIBC__ >= 2
 _GL_CXXALIASWARN (getlogin);
+# endif
 #elif defined GNULIB_POSIXCHECK
 # undef getlogin
 # if HAVE_RAW_DECL_GETLOGIN
index e876fad5eadfc6b03185a47618919a1d54e9029e..7f1f07319d95af5ee17fcd27a64b7de916ce7beb 100644 (file)
@@ -1,5 +1,5 @@
 # getlogin.m4
-# serial 7
+# serial 8
 dnl Copyright (C) 2010-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,
@@ -16,6 +16,53 @@ AC_DEFUN([gl_FUNC_GETLOGIN],
   AC_CHECK_FUNCS_ONCE([getlogin])
   if test $ac_cv_func_getlogin = no; then
     HAVE_GETLOGIN=0
+  else
+    dnl On musl libc, getlogin returns getenv ("LOGNAME").
+    AC_REQUIRE([AC_CANONICAL_HOST])
+    AC_CACHE_CHECK([whether getlogin works],
+      [gl_cv_func_getlogin_works],
+      [
+        dnl Initial guess, used when cross-compiling.
+changequote(,)dnl
+        case "$host_os" in
+                              # Guess no on musl libc.
+          *-musl* | midipix*) gl_cv_func_getlogin_works="guessing no" ;;
+                              # Guess yes otherwise.
+          *)                  gl_cv_func_getlogin_works="guessing yes" ;;
+        esac
+changequote([,])dnl
+        AC_RUN_IFELSE(
+          [AC_LANG_SOURCE([[
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if !HAVE_DECL_GETLOGIN
+extern
+# ifdef __cplusplus
+"C"
+# endif
+char *getlogin (void);
+#endif
+int
+main (void)
+{
+  int result = 0;
+  char *buf;
+
+  putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke");
+  buf = getlogin ();
+  if (buf != NULL && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0)
+    result |= 1;
+  return result;
+}]])],
+          [gl_cv_func_getlogin_works=yes],
+          [gl_cv_func_getlogin_works=no],
+          [:])
+      ])
+    case "$gl_cv_func_getlogin_works" in
+      *yes) ;;
+      *) REPLACE_GETLOGIN=1 ;;
+    esac
   fi
 ])
 
index 2c08d65e0d84391395b9609ea5161e71e41494b5..6ec16286ef8d548226982cbc6571745d78783866 100644 (file)
@@ -1,5 +1,5 @@
 # unistd_h.m4
-# serial 96
+# serial 97
 dnl Copyright (C) 2006-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,
@@ -244,6 +244,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   REPLACE_GETDOMAINNAME=0;           AC_SUBST([REPLACE_GETDOMAINNAME])
   REPLACE_GETDTABLESIZE=0;           AC_SUBST([REPLACE_GETDTABLESIZE])
   REPLACE_GETENTROPY=0;              AC_SUBST([REPLACE_GETENTROPY])
+  REPLACE_GETLOGIN=0;                AC_SUBST([REPLACE_GETLOGIN])
   REPLACE_GETLOGIN_R=0;              AC_SUBST([REPLACE_GETLOGIN_R])
   REPLACE_GETGROUPS=0;               AC_SUBST([REPLACE_GETGROUPS])
   REPLACE_GETPAGESIZE=0;             AC_SUBST([REPLACE_GETPAGESIZE])
index 8725a7031efce41f437083b469c5252c13da07bc..7acee58a81aed89dbf310b91594b09a6ea363557 100644 (file)
@@ -7,10 +7,12 @@ m4/getlogin.m4
 
 Depends-on:
 unistd-h
+readutmp        [test $HAVE_GETLOGIN = 0 || test $REPLACE_GETLOGIN = 1]
 
 configure.ac:
 gl_FUNC_GETLOGIN
-gl_CONDITIONAL([GL_COND_OBJ_GETLOGIN], [test $HAVE_GETLOGIN = 0])
+gl_CONDITIONAL([GL_COND_OBJ_GETLOGIN],
+               [test $HAVE_GETLOGIN = 0 || test $REPLACE_GETLOGIN = 1])
 gl_UNISTD_MODULE_INDICATOR([getlogin])
 AC_REQUIRE([gl_LIB_GETLOGIN])
 
@@ -26,7 +28,7 @@ Link:
 $(GETLOGIN_LIB)
 
 License:
-LGPLv2+
+GPL
 
 Maintainer:
 all
index af7fda5944c7a2bb268f6223c02685bf6c8785a8..d2bafb789ec9212fbd9ef1adc1d1005762f73a2a 100644 (file)
@@ -200,6 +200,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''REPLACE_GETDOMAINNAME''@|$(REPLACE_GETDOMAINNAME)|g' \
              -e 's|@''REPLACE_GETDTABLESIZE''@|$(REPLACE_GETDTABLESIZE)|g' \
              -e 's|@''REPLACE_GETENTROPY''@|$(REPLACE_GETENTROPY)|g' \
+             -e 's|@''REPLACE_GETLOGIN''@|$(REPLACE_GETLOGIN)|g' \
              -e 's|@''REPLACE_GETLOGIN_R''@|$(REPLACE_GETLOGIN_R)|g' \
              -e 's|@''REPLACE_GETGROUPS''@|$(REPLACE_GETGROUPS)|g' \
              -e 's|@''REPLACE_GETPAGESIZE''@|$(REPLACE_GETPAGESIZE)|g' \
index 1b980a152dd283a9f4b1d2f06d7ffc1525afc542..431844bd715a6cdce90b09f68126657a01f5e446 100644 (file)
@@ -41,5 +41,11 @@ main (void)
 #endif
   test_getlogin_result (buf, err);
 
+  /* Check that getlogin() does not merely return getenv ("LOGNAME").  */
+  putenv ("LOGNAME=ygvfibmslhkmvoetbrcegzwydorcke");
+  buf = getlogin ();
+  ASSERT (!(buf != NULL
+            && strcmp (buf, "ygvfibmslhkmvoetbrcegzwydorcke") == 0));
+
   return test_exit_status;
 }