Blindly implementing ptsname_r from scratch using the glibc algorithm fails on Solaris 10, where isatty() doesn't set errno when returning 0. While not thread-safe, wrapping ptsname() instead of implementing things ourselves has better results.
* m4/ptsname_r.m4 (gl_FUNC_PTSNAME_R): Also check for ptsname. * m4/ptsname.m4 (gl_FUNC_PTSNAME): Optimize check. * lib/ptsname_r.c (ptsname_r): Provide wrapper around ptsname, when it is available, since Solaris isatty doesn't set errno. Signed-off-by: Eric Blake <ebl...@redhat.com> --- ChangeLog | 6 +++++ lib/ptsname_r.c | 62 +++++++++++++++++++++++++++++++++++++++---------------- m4/ptsname.m4 | 4 +- m4/ptsname_r.m4 | 4 +- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 379dd63..70172b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2011-11-07 Eric Blake <ebl...@redhat.com> + ptsname_r: port to Solaris + * m4/ptsname_r.m4 (gl_FUNC_PTSNAME_R): Also check for ptsname. + * m4/ptsname.m4 (gl_FUNC_PTSNAME): Optimize check. + * lib/ptsname_r.c (ptsname_r): Provide wrapper around ptsname, + when it is available, since Solaris isatty doesn't set errno. + ptsname_r-tests: new test module * modules/ptsname_r-tests: New module. * tests/test-ptsname_r.c: New file. diff --git a/lib/ptsname_r.c b/lib/ptsname_r.c index e7f2d5b..e200f34 100644 --- a/lib/ptsname_r.c +++ b/lib/ptsname_r.c @@ -20,26 +20,51 @@ #include <errno.h> #include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#ifdef _LIBC -# include <paths.h> -#else -# ifndef _PATH_TTY -# define _PATH_TTY "/dev/tty" -# endif -# ifndef _PATH_DEV -# define _PATH_DEV "/dev/" -# endif -# define __set_errno(e) errno = (e) -# define __isatty isatty -# define __stat stat -# define __ttyname_r ttyname_r -# define __ptsname_r ptsname_r +#if HAVE_PTSNAME -#endif +/* Store at most BUFLEN characters of the pathname of the slave pseudo + terminal associated with the master FD is open on in BUF. + Return 0 on success, otherwise an error number. */ +int +ptsname_r (int fd, char *buf, size_t buflen) +{ + /* This assumes nothing else directly calls ptsname(). */ + char *name; + + if (!buf) + return errno = EINVAL; + name = ptsname (fd); + if (!name) + return errno; + if (buflen <= strlen (name)) + return errno = ERANGE; + strcpy (buf, name); + return 0; +} + +#else /* !HAVE_PTSNAME */ + +# include <sys/stat.h> +# include <unistd.h> + +# ifdef _LIBC +# include <paths.h> +# else +# ifndef _PATH_TTY +# define _PATH_TTY "/dev/tty" +# endif +# ifndef _PATH_DEV +# define _PATH_DEV "/dev/" +# endif + +# define __set_errno(e) errno = (e) +# define __isatty isatty +# define __stat stat +# define __ttyname_r ttyname_r +# define __ptsname_r ptsname_r + +# endif /* Store at most BUFLEN characters of the pathname of the slave pseudo @@ -83,3 +108,4 @@ __ptsname_r (int fd, char *buf, size_t buflen) __set_errno (save_errno); return 0; } +#endif /* !HAVE_PTSNAME */ diff --git a/m4/ptsname.m4 b/m4/ptsname.m4 index 4dba5f3..2403cd1 100644 --- a/m4/ptsname.m4 +++ b/m4/ptsname.m4 @@ -1,4 +1,4 @@ -# ptsname.m4 serial 2 +# ptsname.m4 serial 3 dnl Copyright (C) 2010-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,7 +11,7 @@ AC_DEFUN([gl_FUNC_PTSNAME], dnl Persuade glibc <stdlib.h> to declare ptsname(). AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) - AC_CHECK_FUNCS([ptsname]) + AC_CHECK_FUNCS_ONCE([ptsname]) if test $ac_cv_func_ptsname = no; then HAVE_PTSNAME=0 fi diff --git a/m4/ptsname_r.m4 b/m4/ptsname_r.m4 index fb07099..cbc3029 100644 --- a/m4/ptsname_r.m4 +++ b/m4/ptsname_r.m4 @@ -1,4 +1,4 @@ -# ptsname_r.m4 serial 1 +# ptsname_r.m4 serial 2 dnl Copyright (C) 2010-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,7 +11,7 @@ AC_DEFUN([gl_FUNC_PTSNAME_R], dnl Persuade glibc <stdlib.h> to declare ptsname_r(). AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) - AC_CHECK_FUNCS_ONCE([ptsname_r]) + AC_CHECK_FUNCS_ONCE([ptsname ptsname_r]) if test $ac_cv_func_ptsname_r = no; then HAVE_PTSNAME_R=0 fi -- 1.7.4.4