build: fix build on platforms without ptsname_r

MacOS lacks ptsname_r, and gnulib doesn't (yet) provide it.
But we can avoid it altogether, by using gnulib openpty()
instead.  Note that we do _not_ want the pt_chown module;
gnulib uses it only to implement a replacement openpty() if
the system lacks both openpty() and granpt(), but all
systems that we currently port to either have at least one of
openpty() and/or grantpt(), or lack ptys altogether.  That is,
we aren't porting to any system that requires us to deal with
the hassle of installing a setuid pt_chown helper just to use
gnulib's ability to provide openpty() on obscure platforms.

* .gnulib: Update to latest, for openpty fixes
* bootstrap.conf (gnulib_modules): Add openpty, ttyname_r.
(gnulib_tool_option_extras): Exclude pt_chown module.
* src/util/util.c (virFileOpenTty): Rewrite in terms of openpty
and ttyname_r.
* src/util/util.h (virFileOpenTtyAt): Delete dead prototype.
This commit is contained in:
Eric Blake 2011-11-03 14:56:13 -06:00
parent 07bf96ee3f
commit f7bd00c12c
4 changed files with 59 additions and 26 deletions

@ -1 +1 @@
Subproject commit 2394a603e7586e671226478e5b15d924c3841f42 Subproject commit 0031e4f6353cc7077a9d0dad0c793bd6e3dc7aaa

View File

@ -68,6 +68,7 @@ mkstemps
mktempd mktempd
netdb netdb
nonblocking nonblocking
openpty
passfd passfd
perror perror
physmem physmem
@ -101,6 +102,7 @@ sys_wait
termios termios
time_r time_r
timegm timegm
ttyname_r
uname uname
useless-if-before-free useless-if-before-free
usleep usleep
@ -168,6 +170,7 @@ tests_base=gnulib/tests
gnulib_tool_option_extras="\ gnulib_tool_option_extras="\
--lgpl=2\ --lgpl=2\
--with-tests\ --with-tests\
--avoid=pt_chown\
" "
# Convince bootstrap to use multiple m4 directories. # Convince bootstrap to use multiple m4 directories.

View File

@ -45,10 +45,11 @@
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <termios.h> #include <termios.h>
#include <pty.h>
#if HAVE_LIBDEVMAPPER_H #if HAVE_LIBDEVMAPPER_H
# include <libdevmapper.h> # include <libdevmapper.h>
#endif #endif
#include "c-ctype.h"
#ifdef HAVE_PATHS_H #ifdef HAVE_PATHS_H
# include <paths.h> # include <paths.h>
@ -65,6 +66,7 @@
# include <mntent.h> # include <mntent.h>
#endif #endif
#include "c-ctype.h"
#include "dirname.h" #include "dirname.h"
#include "virterror_internal.h" #include "virterror_internal.h"
#include "logging.h" #include "logging.h"
@ -1172,52 +1174,85 @@ virFileBuildPath(const char *dir, const char *name, const char *ext)
return path; return path;
} }
/* Open a non-blocking master side of a pty. If ttyName is not NULL,
* then populate it with the name of the slave. If rawmode is set,
* also put the master side into raw mode before returning. */
#ifndef WIN32 #ifndef WIN32
int virFileOpenTty(int *ttymaster, int virFileOpenTty(int *ttymaster,
char **ttyName, char **ttyName,
int rawmode) int rawmode)
{ {
int rc = -1; /* XXX A word of caution - on some platforms (Solaris and HP-UX),
* additional ioctl() calls are needs after opening the slave
* before it will cause isatty() to return true. Should we make
* virFileOpenTty also return the opened slave fd, so the caller
* doesn't have to worry about that mess? */
int ret = -1;
int slave = -1;
char *name = NULL;
if ((*ttymaster = posix_openpt(O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0) /* Unfortunately, we can't use the name argument of openpty, since
goto cleanup; * there is no guarantee on how large the buffer has to be.
* Likewise, we can't use the termios argument: we have to use
if (unlockpt(*ttymaster) < 0) * read-modify-write since there is no portable way to initialize
goto cleanup; * a struct termios without use of tcgetattr. */
if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0)
if (grantpt(*ttymaster) < 0) return -1;
/* What a shame that openpty cannot atomically set FD_CLOEXEC, but
* that using posix_openpt/grantpt/unlockpt/ptsname is not
* thread-safe, and that ptsname_r is not portable. */
if (virSetNonBlock(*ttymaster) < 0 ||
virSetCloseExec(*ttymaster) < 0)
goto cleanup; goto cleanup;
/* While Linux supports tcgetattr on either the master or the
* slave, Solaris requires it to be on the slave. */
if (rawmode) { if (rawmode) {
struct termios ttyAttr; struct termios ttyAttr;
if (tcgetattr(*ttymaster, &ttyAttr) < 0) if (tcgetattr(slave, &ttyAttr) < 0)
goto cleanup; goto cleanup;
cfmakeraw(&ttyAttr); cfmakeraw(&ttyAttr);
if (tcsetattr(*ttymaster, TCSADRAIN, &ttyAttr) < 0) if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0)
goto cleanup; goto cleanup;
} }
/* ttyname_r on the slave is required by POSIX, while ptsname_r on
* the master is a glibc extension, and the POSIX ptsname is not
* thread-safe. Since openpty gave us both descriptors, guess
* which way we will determine the name? :) */
if (ttyName) { if (ttyName) {
if (VIR_ALLOC_N(*ttyName, PATH_MAX) < 0) { /* Initial guess of 64 is generally sufficient; rely on ERANGE
errno = ENOMEM; * to tell us if we need to grow. */
size_t len = 64;
int rc;
if (VIR_ALLOC_N(name, len) < 0)
goto cleanup;
while ((rc = ttyname_r(slave, name, len)) == ERANGE) {
if (VIR_RESIZE_N(name, len, len, len) < 0)
goto cleanup; goto cleanup;
} }
if (rc != 0) {
if (ptsname_r(*ttymaster, *ttyName, PATH_MAX) != 0) { errno = rc;
VIR_FREE(*ttyName);
goto cleanup; goto cleanup;
} }
*ttyName = name;
name = NULL;
} }
rc = 0; ret = 0;
cleanup: cleanup:
if (rc != 0) if (ret != 0)
VIR_FORCE_CLOSE(*ttymaster); VIR_FORCE_CLOSE(*ttymaster);
VIR_FORCE_CLOSE(slave);
VIR_FREE(name);
return rc; return ret;
} }
#else /* WIN32 */ #else /* WIN32 */
int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED,

View File

@ -121,11 +121,6 @@ int virFileAbsPath(const char *path,
int virFileOpenTty(int *ttymaster, int virFileOpenTty(int *ttymaster,
char **ttyName, char **ttyName,
int rawmode); int rawmode);
int virFileOpenTtyAt(const char *ptmx,
int *ttymaster,
char **ttyName,
int rawmode);
char *virArgvToString(const char *const *argv); char *virArgvToString(const char *const *argv);