# HG changeset patch # User Bruno Haible # Date 1548500191 -3600 # Node ID 3bacbf659cc9e39b137ce7c7b38c5cb232e99d5e # Parent bec39651dc8d67d941f37c1f604db23f964b1d1b ttyname_r: Work around bug on Android 4.3. * m4/ttyname_r.m4 (gl_FUNC_TTYNAME_R): Test whether ttyname_r is a stub. * lib/ttyname_r.c (ttyname_r): Implement for Android. * doc/posix-functions/ttyname_r.texi: Mention the Android bug. * doc/posix-functions/ttyname.texi: Likewise. diff -r bec39651dc8d -r 3bacbf659cc9 ChangeLog --- a/ChangeLog Sat Jan 26 00:03:51 2019 +0100 +++ b/ChangeLog Sat Jan 26 11:56:31 2019 +0100 @@ -1,3 +1,11 @@ +2019-01-26 Bruno Haible + + ttyname_r: Work around bug on Android 4.3. + * m4/ttyname_r.m4 (gl_FUNC_TTYNAME_R): Test whether ttyname_r is a stub. + * lib/ttyname_r.c (ttyname_r): Implement for Android. + * doc/posix-functions/ttyname_r.texi: Mention the Android bug. + * doc/posix-functions/ttyname.texi: Likewise. + 2019-01-25 Bruno Haible getprogname: Port to Android 4.3. diff -r bec39651dc8d -r 3bacbf659cc9 doc/posix-functions/ttyname.texi --- a/doc/posix-functions/ttyname.texi Sat Jan 26 00:03:51 2019 +0100 +++ b/doc/posix-functions/ttyname.texi Sat Jan 26 11:56:31 2019 +0100 @@ -15,4 +15,8 @@ @item This function is missing on some platforms: mingw, MSVC 14. +@item +This function is just a stub that produces an error message on standard error +on some platforms: +Android 4.3. @end itemize diff -r bec39651dc8d -r 3bacbf659cc9 doc/posix-functions/ttyname_r.texi --- a/doc/posix-functions/ttyname_r.texi Sat Jan 26 00:03:51 2019 +0100 +++ b/doc/posix-functions/ttyname_r.texi Sat Jan 26 11:56:31 2019 +0100 @@ -26,6 +26,10 @@ This function refuses to do anything when the output buffer is less than 128 bytes large, on some platforms: Solaris 11 2010-11. +@item +This function is just a stub that produces an error message on standard error +on some platforms: +Android 4.3. @end itemize Portability problems not fixed by Gnulib: diff -r bec39651dc8d -r 3bacbf659cc9 lib/ttyname_r.c --- a/lib/ttyname_r.c Sat Jan 26 00:03:51 2019 +0100 +++ b/lib/ttyname_r.c Sat Jan 26 11:56:31 2019 +0100 @@ -24,13 +24,41 @@ #include #include #include +#if defined __ANDROID__ +# include +#endif int ttyname_r (int fd, char *buf, size_t buflen) #undef ttyname_r { +#if defined __ANDROID__ + /* On Android, read the result from the /proc file system. */ + if (!isatty (fd)) + /* We rely on isatty to set errno properly (i.e. EBADF or ENOTTY). */ + return errno; + else if (buflen == 0) + return ERANGE; + else + { + char procfile[14+11+1]; + char largerbuf[512]; + ssize_t ret; + sprintf (procfile, "/proc/self/fd/%d", fd); + ret = (buflen < sizeof (largerbuf) + ? readlink (procfile, largerbuf, sizeof (largerbuf)) + : readlink (procfile, buf, buflen <= INT_MAX ? buflen : INT_MAX)); + if (ret < 0) + return errno; + if ((size_t) ret >= buflen) + return ERANGE; + if (buflen < sizeof (largerbuf)) + memcpy (buf, largerbuf, (size_t) ret); + buf[(size_t) ret] = '\0'; + return 0; + } +#elif HAVE_TTYNAME_R /* When ttyname_r exists, use it. */ -#if HAVE_TTYNAME_R /* This code is multithread-safe. */ /* On Solaris, ttyname_r always fails if buflen < 128. On OSF/1 5.1, ttyname_r ignores the buffer size and assumes the buffer is large enough. diff -r bec39651dc8d -r 3bacbf659cc9 m4/ttyname_r.m4 --- a/m4/ttyname_r.m4 Sat Jan 26 00:03:51 2019 +0100 +++ b/m4/ttyname_r.m4 Sat Jan 26 11:56:31 2019 +0100 @@ -1,4 +1,4 @@ -# ttyname_r.m4 serial 9 +# ttyname_r.m4 serial 10 dnl Copyright (C) 2010-2019 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -45,24 +45,55 @@ dnl anything when the output buffer is less than 128 bytes large. dnl On OSF/1 5.1, ttyname_r ignores the buffer size and assumes the dnl buffer is large enough. + dnl On Android 4.3, ttyname_r is a stub that prints + dnl "int ttyname_r(int, char*, size_t)(3) is not implemented on Android" + dnl on stderr and returns -ERANGE. AC_REQUIRE([AC_CANONICAL_HOST]) - AC_CACHE_CHECK([whether ttyname_r works with small buffers], - [gl_cv_func_ttyname_r_works], - [ - dnl Initial guess, used when cross-compiling or when /dev/tty cannot - dnl be opened. + case "$host_os" in + linux*-android*) + AC_CACHE_CHECK([whether ttyname_r works at least minimally], + [gl_cv_func_ttyname_r_not_stub], + [AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +int +main (void) +{ + char buf[80]; + close(2); + return ttyname_r (-1, buf, sizeof (buf)) == -ERANGE; +}]])], + [gl_cv_func_ttyname_r_not_stub=yes], + [gl_cv_func_ttyname_r_not_stub=no], + [# Guess no on Android. + gl_cv_func_ttyname_r_not_stub="guessing no" + ]) + ]) + case "$gl_cv_func_ttyname_r_not_stub" in + *yes) ;; + *) REPLACE_TTYNAME_R=1 ;; + esac + ;; + esac + if test $REPLACE_TTYNAME_R = 0; then + AC_CACHE_CHECK([whether ttyname_r works with small buffers], + [gl_cv_func_ttyname_r_works], + [ + dnl Initial guess, used when cross-compiling or when /dev/tty cannot + dnl be opened. changequote(,)dnl - case "$host_os" in - # Guess no on Solaris. - solaris*) gl_cv_func_ttyname_r_works="guessing no" ;; - # Guess no on OSF/1. - osf*) gl_cv_func_ttyname_r_works="guessing no" ;; - # Guess yes otherwise. - *) gl_cv_func_ttyname_r_works="guessing yes" ;; - esac + case "$host_os" in + # Guess no on Solaris. + solaris*) gl_cv_func_ttyname_r_works="guessing no" ;; + # Guess no on OSF/1. + osf*) gl_cv_func_ttyname_r_works="guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_ttyname_r_works="guessing yes" ;; + esac changequote([,])dnl - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ #include #include int @@ -81,16 +112,17 @@ result |= 18; return result; }]])], - [gl_cv_func_ttyname_r_works=yes], - [case $? in - 17 | 18) gl_cv_func_ttyname_r_works=no ;; - esac], - [:]) - ]) - case "$gl_cv_func_ttyname_r_works" in - *yes) ;; - *) REPLACE_TTYNAME_R=1 ;; - esac + [gl_cv_func_ttyname_r_works=yes], + [case $? in + 17 | 18) gl_cv_func_ttyname_r_works=no ;; + esac], + [:]) + ]) + case "$gl_cv_func_ttyname_r_works" in + *yes) ;; + *) REPLACE_TTYNAME_R=1 ;; + esac + fi fi fi ])