* modules/posix_openpt: New module. * m4/posix_openpt.m4: New file. * lib/posix_openpt.c: Likewise. * m4/stdlib_h.m4 (gl_STDLIB_H): Check for decl. (gl_STDLIB_H_DEFAULTS): Set defaults. * modules/stdlib (Makefile.am): Substitute macros. * lib/stdlib.in.h (posix_openpt): Declare. * MODULES.html.sh (systems lacking POSIX:2008): Document it. * doc/posix-functions/posix_openpt.texi (posix_openpt): Likewise. * modules/posix_openpt-tests: New test module. * tests/test-posix_openpt.c: New test. ---
openpty() is certainly easier to use than posix_openpt()/grantpt()/unlockpt(), especially given Solaris where isatty() fails on the slave unless you also use ioctl() to enable the tty STREAMS interface on the slave. But we might as well provide the POSIX interface. Tested so far on Linux, Cygwin 1.7, Solaris 10, HP-UX 11.31. ChangeLog | 15 ++++++ MODULES.html.sh | 1 + doc/posix-functions/posix_openpt.texi | 11 +++-- lib/posix_openpt.c | 50 +++++++++++++++++++++ lib/stdlib.in.h | 16 +++++++ m4/posix_openpt.m4 | 21 +++++++++ m4/stdlib_h.m4 | 10 +++-- modules/posix_openpt | 28 ++++++++++++ modules/posix_openpt-tests | 15 ++++++ modules/stdlib | 2 + tests/test-posix_openpt.c | 76 +++++++++++++++++++++++++++++++++ 11 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 lib/posix_openpt.c create mode 100644 m4/posix_openpt.m4 create mode 100644 modules/posix_openpt create mode 100644 modules/posix_openpt-tests create mode 100644 tests/test-posix_openpt.c diff --git a/ChangeLog b/ChangeLog index 28133a6..c04c1e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2011-10-17 Eric Blake <ebl...@redhat.com> + + posix_openpt: new module + * modules/posix_openpt: New module. + * m4/posix_openpt.m4: New file. + * lib/posix_openpt.c: Likewise. + * m4/stdlib_h.m4 (gl_STDLIB_H): Check for decl. + (gl_STDLIB_H_DEFAULTS): Set defaults. + * modules/stdlib (Makefile.am): Substitute macros. + * lib/stdlib.in.h (posix_openpt): Declare. + * MODULES.html.sh (systems lacking POSIX:2008): Document it. + * doc/posix-functions/posix_openpt.texi (posix_openpt): Likewise. + * modules/posix_openpt-tests: New test module. + * tests/test-posix_openpt.c: New test. + 2011-10-15 Bruno Haible <br...@clisp.org> xstrtoll: Fix compilation failure. diff --git a/MODULES.html.sh b/MODULES.html.sh index f84d3b1..b51e283 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2411,6 +2411,7 @@ func_all_modules () func_module perror func_module poll func_module popen + func_module posix_openpt func_module posix_spawn func_module posix_spawnattr_destroy func_module posix_spawnattr_getflags diff --git a/doc/posix-functions/posix_openpt.texi b/doc/posix-functions/posix_openpt.texi index bd848e6..86653c1 100644 --- a/doc/posix-functions/posix_openpt.texi +++ b/doc/posix-functions/posix_openpt.texi @@ -4,16 +4,17 @@ posix_openpt POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html} -Gnulib module: --- +Gnulib module: posix_openpt Portability problems fixed by Gnulib: @itemize -@end itemize - -Portability problems not fixed by Gnulib: -@itemize @item This function is missing on some platforms: MacOS X 10.3, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11.23, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 1.5.x, mingw, MSVC 9, Interix 3.5, BeOS. +However, the replacement may fail with ENOSYS on some platforms. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize @end itemize diff --git a/lib/posix_openpt.c b/lib/posix_openpt.c new file mode 100644 index 0000000..b2e4999 --- /dev/null +++ b/lib/posix_openpt.c @@ -0,0 +1,50 @@ +/* Open the master side of a pseudo-terminal. + Copyright (C) 2010-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + 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 program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <stdlib.h> + +#include <fcntl.h> +#include <errno.h> + +int +posix_openpty (int flags) +{ + int master; + +#ifdef _AIX /* AIX */ + + master = open ("/dev/ptc", flags); + +#elif (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__ /* mingw */ + + /* Mingw lacks pseudo-terminals altogether. */ + master = -1; + errno = ENOSYS; + +#else /* MacOS, OpenBSD, HP-UX, IRIX, Solaris 9, Cygwin 1.5 */ + + /* Most systems that lack posix_openpt() have /dev/ptmx. */ + master = open ("/dev/ptmx", flags); + +#endif + + return master; +} + +#endif diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 047fac1..19d0d67 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -423,6 +423,22 @@ _GL_WARN_ON_USE (mkstemps, "mkstemps is unportable - " # endif #endif +#if @GNULIB_POSIX_OPENPT@ +/* Return an FD open to the master side of a pseudo-terminal. Flags should + include O_RDWR, and may also include O_NOCTTY. */ +# if !@HAVE_POSIX_OPENPT@ +_GL_FUNCDECL_SYS (posix_openpt, int, (int flags)); +# endif +_GL_CXXALIAS_SYS (posix_openpt, int, (int flags)); +_GL_CXXALIASWARN (posix_openpt); +#elif defined GNULIB_POSIXCHECK +# undef posix_openpt +# if HAVE_RAW_DECL_POSIX_OPENPT +_GL_WARN_ON_USE (posix_openpt, "posix_openpt is not portable - " + "use gnulib module posix_openpt for portability"); +# endif +#endif + #if @GNULIB_PTSNAME@ /* Return the pathname of the pseudo-terminal slave associated with the master FD is open on, or NULL on errors. */ diff --git a/m4/posix_openpt.m4 b/m4/posix_openpt.m4 new file mode 100644 index 0000000..8d90f9b --- /dev/null +++ b/m4/posix_openpt.m4 @@ -0,0 +1,21 @@ +# posix_openpt.m4 serial 1 +dnl Copyright (C) 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, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_POSIX_OPENPT], +[ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + + dnl Persuade Solaris <stdlib.h> to declare posix_openpt(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([posix_openpt]) + if test $ac_cv_have_posix_openpt != yes; then + dnl The system does not have posix_openpt. + HAVE_POSIX_OPENPT=0 + dnl Prerequisites of lib/posix_openpt.c in this case. + AC_CHECK_FUNCS([_getpty]) + fi +]) diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index 25fdada..fbdba98 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -19,10 +19,10 @@ AC_DEFUN([gl_STDLIB_H], #if HAVE_RANDOM_H # include <random.h> #endif - ]], [_Exit atoll canonicalize_file_name getloadavg getsubopt grantpt mkdtemp - mkostemp mkostemps mkstemp mkstemps ptsname random_r initstat_r srandom_r - setstate_r realpath rpmatch setenv strtod strtoll strtoull unlockpt - unsetenv]) + ]], [_Exit atoll canonicalize_file_name getloadavg getsubopt grantpt + initstate_r mkdtemp mkostemp mkostemps mkstemp mkstemps posix_openpt + ptsname random_r realpath rpmatch setenv setstate_r srandom_r strtod + strtoll strtoull unlockpt unsetenv]) ]) AC_DEFUN([gl_STDLIB_MODULE_INDICATOR], @@ -50,6 +50,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], GNULIB_MKOSTEMPS=0; AC_SUBST([GNULIB_MKOSTEMPS]) GNULIB_MKSTEMP=0; AC_SUBST([GNULIB_MKSTEMP]) GNULIB_MKSTEMPS=0; AC_SUBST([GNULIB_MKSTEMPS]) + GNULIB_POSIX_OPENPT=0; AC_SUBST([GNULIB_POSIX_OPENPT]) GNULIB_PTSNAME=0; AC_SUBST([GNULIB_PTSNAME]) GNULIB_PUTENV=0; AC_SUBST([GNULIB_PUTENV]) GNULIB_RANDOM_R=0; AC_SUBST([GNULIB_RANDOM_R]) @@ -76,6 +77,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], HAVE_MKOSTEMPS=1; AC_SUBST([HAVE_MKOSTEMPS]) HAVE_MKSTEMP=1; AC_SUBST([HAVE_MKSTEMP]) HAVE_MKSTEMPS=1; AC_SUBST([HAVE_MKSTEMPS]) + HAVE_POSIX_OPENPT=1; AC_SUBST([HAVE_POSIX_OPENPT]) HAVE_PTSNAME=1; AC_SUBST([HAVE_PTSNAME]) HAVE_RANDOM_H=1; AC_SUBST([HAVE_RANDOM_H]) HAVE_RANDOM_R=1; AC_SUBST([HAVE_RANDOM_R]) diff --git a/modules/posix_openpt b/modules/posix_openpt new file mode 100644 index 0000000..5bef9e2 --- /dev/null +++ b/modules/posix_openpt @@ -0,0 +1,28 @@ +Description: +posix_openpt() function: Open the master side of a pseudo-terminal. + +Files: +lib/posix_openpt.c +m4/posix_openpt.m4 + +Depends-on: +extensions +stdlib + +configure.ac: +gl_FUNC_POSIX_OPENPT +if test $HAVE_POSIX_OPENPT = 0; then + AC_LIBOBJ([posix_openpt]) +fi +gl_STDLIB_MODULE_INDICATOR([posix_openpt]) + +Makefile.am: + +Include: +<stdlib.h> + +License: +LGPLv2+ + +Maintainer: +Eric Blake diff --git a/modules/posix_openpt-tests b/modules/posix_openpt-tests new file mode 100644 index 0000000..9ebf805 --- /dev/null +++ b/modules/posix_openpt-tests @@ -0,0 +1,15 @@ +Files: +tests/test-posix_openpt.c +tests/signature.h +tests/macros.h + +Depends-on: +grantpt +ptsname +unlockpt + +configure.ac: + +Makefile.am: +TESTS += test-posix_openpt +check_PROGRAMS += test-posix_openpt diff --git a/modules/stdlib b/modules/stdlib index 9ab19ee..707d5e5 100644 --- a/modules/stdlib +++ b/modules/stdlib @@ -45,6 +45,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's/@''GNULIB_MKOSTEMPS''@/$(GNULIB_MKOSTEMPS)/g' \ -e 's/@''GNULIB_MKSTEMP''@/$(GNULIB_MKSTEMP)/g' \ -e 's/@''GNULIB_MKSTEMPS''@/$(GNULIB_MKSTEMPS)/g' \ + -e 's/@''GNULIB_POSIX_OPENPT''@/$(GNULIB_POSIX_OPENPT)/g' \ -e 's/@''GNULIB_PTSNAME''@/$(GNULIB_PTSNAME)/g' \ -e 's/@''GNULIB_PUTENV''@/$(GNULIB_PUTENV)/g' \ -e 's/@''GNULIB_RANDOM_R''@/$(GNULIB_RANDOM_R)/g' \ @@ -71,6 +72,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''HAVE_MKOSTEMPS''@|$(HAVE_MKOSTEMPS)|g' \ -e 's|@''HAVE_MKSTEMP''@|$(HAVE_MKSTEMP)|g' \ -e 's|@''HAVE_MKSTEMPS''@|$(HAVE_MKSTEMPS)|g' \ + -e 's|@''HAVE_POSIX_OPENPT''@|$(HAVE_POSIX_OPENPT)|g' \ -e 's|@''HAVE_PTSNAME''@|$(HAVE_PTSNAME)|g' \ -e 's|@''HAVE_RANDOM_H''@|$(HAVE_RANDOM_H)|g' \ -e 's|@''HAVE_RANDOM_R''@|$(HAVE_RANDOM_R)|g' \ diff --git a/tests/test-posix_openpt.c b/tests/test-posix_openpt.c new file mode 100644 index 0000000..3ea701e --- /dev/null +++ b/tests/test-posix_openpt.c @@ -0,0 +1,76 @@ +/* Test of posix_openpt function. + Copyright (C) 2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + 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 program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebl...@redhat.com>, 2011. */ + +#include <config.h> + +#include <stdlib.h> + +#include "signature.h" +SIGNATURE_CHECK (posix_openpt, int, (int)); + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#if defined __sun || defined __hpux /* Solaris, HP-UX */ +# include <stropts.h> +#endif + +#include "macros.h" + +int +main (void) +{ + int master; + int slave; + char *name; + + /* Open the master of a pseudo-terminal pair. */ + master = posix_openpt(O_RDWR | O_NOCTTY); + if (master < 0 && errno == ENOSYS) + { + fputs ("skipping: platform lacks pty support\n", stderr); + return 77; + } + + ASSERT (0 <= master); + name = ptsname (master); + ASSERT (name); + ASSERT (grantpt (master) == 0); + ASSERT (unlockpt (master) == 0); + slave = open (name, O_RDWR); + ASSERT (0 <= slave); + +#if defined __sun || defined __hpux /* Solaris, HP-UX */ + ASSERT (ioctl (slave, I_PUSH, "ptem") == 0); + ASSERT (ioctl (slave, I_PUSH, "ldterm") == 0); +# if defined __sun + ASSERT (ioctl (slave, I_PUSH, "ttcompat") == 0); +# endif +#endif + + ASSERT (isatty (slave)); + + /* Close the master side before the slave side gets closed. + This is necessary on MacOS X 10.4.11. */ + ASSERT (close (master) == 0); + ASSERT (close (slave) == 0); + + return 0; +} -- 1.7.4.4