From fab606b00a44ea2114a4029ad09b70c66c3049f7 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 2 Aug 2012 23:58:02 +0200 Subject: [PATCH] Add an option to enable support for pseudo terminals. Pseudo terminals are very convenient for testing purposes, but they are not fully compatible with real serial (or even usb-serial) hardware. With the new option, some workarounds can be enabled to hide the differences and increase compatibility. Although these workarounds shouldn't cause any problems in production builds, the advise is to disable this feature. A few ioctl's are not supported for pseudo terminals. They fail with EINVAL (Linux) or ENOTTY (Mac OS X). Since these specific error codes should not occur under normal conditions, they are simply ignored when pseudo terminal support is enabled. The TIOCEXCL ioctl (exclusive access) is also problematic. The TIOCEXCL setting is shared between the master and slave side of the pty. When the setting is applied on the slave side, it persists for as long as the master side remains open. The result is that re-opening the slave side will fail with EBUSY, unless the process has root priviliges. Since this is very inconvenient, the TIOCEXCL setting is not used when pseudo terminal support is enabled. --- configure.ac | 9 +++++++++ src/serial_posix.c | 20 ++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 2b54da2..9b39a8d 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,15 @@ AS_IF([test "x$enable_logging" = "xyes"], [ AC_DEFINE(ENABLE_LOGGING, [1], [Enable logging.]) ]) +# Pseudo terminal support. +AC_ARG_ENABLE([pty], + [AS_HELP_STRING([--enable-pty=@<:@yes/no@:>@], + [Enable pseudo terminal support @<:@default=no@:>@])], + [], [enable_pty=no]) +AS_IF([test "x$enable_pty" = "xyes"], [ + AC_DEFINE(ENABLE_PTY, [1], [Enable pseudo terminal support.]) +]) + # Checks for programs. AC_PROG_CC AC_PROG_CC_C99 diff --git a/src/serial_posix.c b/src/serial_posix.c index d9ad4e7..45dd406 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -43,6 +43,12 @@ #define TIOCINQ FIONREAD #endif +#ifdef ENABLE_PTY +#define NOPTY (errno != EINVAL && errno != ENOTTY) +#else +#define NOPTY 1 +#endif + #include "serial.h" #include "context-private.h" @@ -103,6 +109,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) return -1; // Error during open call. } +#ifndef ENABLE_PTY // Enable exclusive access mode. if (ioctl (device->fd, TIOCEXCL, NULL) != 0) { SYSERROR (context, errno); @@ -110,6 +117,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) free (device); return -1; } +#endif // Retrieve the current terminal attributes, to // be able to restore them when closing the device. @@ -373,7 +381,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int #if defined(TIOCGSERIAL) && defined(TIOCSSERIAL) // Get the current settings. struct serial_struct ss; - if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0) { + if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; } @@ -384,13 +392,13 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int ss.flags |= ASYNC_SPD_CUST; // Apply the new settings. - if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0) { + if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; } #elif defined(IOSSIOSPEED) speed_t speed = baudrate; - if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0) { + if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; } @@ -655,7 +663,7 @@ serial_set_break (serial_t *device, int level) unsigned long action = (level ? TIOCSBRK : TIOCCBRK); - if (ioctl (device->fd, action, NULL) != 0) { + if (ioctl (device->fd, action, NULL) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; } @@ -673,7 +681,7 @@ serial_set_dtr (serial_t *device, int level) unsigned long action = (level ? TIOCMBIS : TIOCMBIC); int value = TIOCM_DTR; - if (ioctl (device->fd, action, &value) != 0) { + if (ioctl (device->fd, action, &value) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; } @@ -691,7 +699,7 @@ serial_set_rts (serial_t *device, int level) unsigned long action = (level ? TIOCMBIS : TIOCMBIC); int value = TIOCM_RTS; - if (ioctl (device->fd, action, &value) != 0) { + if (ioctl (device->fd, action, &value) != 0 && NOPTY) { SYSERROR (device->context, errno); return -1; }