* 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-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.
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;
}
${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
# 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,
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
])
# 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,
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])
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])
$(GETLOGIN_LIB)
License:
-LGPLv2+
+GPL
Maintainer:
all
-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' \
#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;
}