From: Bruno Haible Date: Sat, 26 Jan 2019 10:56:31 +0000 (+0100) Subject: ttyname_r: Work around bug on Android 4.3. X-Git-Tag: v1.0~5124 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=0c4342cb67e62f981c654c5fa830bd76cc3bd68f;p=gnulib.git 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 --git a/ChangeLog b/ChangeLog index 812b423895..44c15eb151 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 --git a/doc/posix-functions/ttyname.texi b/doc/posix-functions/ttyname.texi index df5c387ac4..5b9ff5aee2 100644 --- a/doc/posix-functions/ttyname.texi +++ b/doc/posix-functions/ttyname.texi @@ -15,4 +15,8 @@ Portability problems not fixed by Gnulib: @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 --git a/doc/posix-functions/ttyname_r.texi b/doc/posix-functions/ttyname_r.texi index ea842423e1..ad108a65b3 100644 --- a/doc/posix-functions/ttyname_r.texi +++ b/doc/posix-functions/ttyname_r.texi @@ -26,6 +26,10 @@ OSF/1 5.1. 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 --git a/lib/ttyname_r.c b/lib/ttyname_r.c index 67f559d2e6..5d921ab19b 100644 --- a/lib/ttyname_r.c +++ b/lib/ttyname_r.c @@ -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 --git a/m4/ttyname_r.m4 b/m4/ttyname_r.m4 index b17dcfbe23..051de0caa8 100644 --- a/m4/ttyname_r.m4 +++ b/m4/ttyname_r.m4 @@ -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 @@ AC_DEFUN([gl_FUNC_TTYNAME_R], 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. -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" ;; + 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 changequote([,])dnl - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ #include #include int @@ -81,16 +112,17 @@ main (void) 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 ])