summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2013-08-23 18:06:42 +0000
committeremaste <emaste@FreeBSD.org>2013-08-23 18:06:42 +0000
commit424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch)
tree05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp
parentcde487f27a84e02a560384f75178fddca68740f6 (diff)
parentdcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff)
downloadFreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip
FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp')
-rw-r--r--contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp339
1 files changed, 339 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp b/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp
new file mode 100644
index 0000000..e4b444c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Utility/PseudoTerminal.cpp
@@ -0,0 +1,339 @@
+//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#if defined(TIOCSCTTY)
+#include <sys/ioctl.h>
+#endif
+
+using namespace lldb_utility;
+
+//----------------------------------------------------------------------
+// PseudoTerminal constructor
+//----------------------------------------------------------------------
+PseudoTerminal::PseudoTerminal () :
+ m_master_fd(invalid_fd),
+ m_slave_fd(invalid_fd)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// The destructor will close the master and slave file descriptors
+// if they are valid and ownwership has not been released using the
+// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor()
+// member functions.
+//----------------------------------------------------------------------
+PseudoTerminal::~PseudoTerminal ()
+{
+ CloseMasterFileDescriptor();
+ CloseSlaveFileDescriptor();
+}
+
+//----------------------------------------------------------------------
+// Close the master file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseMasterFileDescriptor ()
+{
+ if (m_master_fd >= 0)
+ {
+ ::close (m_master_fd);
+ m_master_fd = invalid_fd;
+ }
+}
+
+//----------------------------------------------------------------------
+// Close the slave file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseSlaveFileDescriptor ()
+{
+ if (m_slave_fd >= 0)
+ {
+ ::close (m_slave_fd);
+ m_slave_fd = invalid_fd;
+ }
+}
+
+//----------------------------------------------------------------------
+// Open the first available pseudo terminal with OFLAG as the
+// permissions. The file descriptor is stored in this object and can
+// be accessed with the MasterFileDescriptor() accessor. The
+// ownership of the master file descriptor can be released using
+// the ReleaseMasterFileDescriptor() accessor. If this object has
+// a valid master files descriptor when its destructor is called, it
+// will close the master file descriptor, therefore clients must
+// call ReleaseMasterFileDescriptor() if they wish to use the master
+// file descriptor after this object is out of scope or destroyed.
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ // Open the master side of a pseudo terminal
+ m_master_fd = ::posix_openpt (oflag);
+ if (m_master_fd < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ return false;
+ }
+
+ // Grant access to the slave pseudo terminal
+ if (::grantpt (m_master_fd) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ CloseMasterFileDescriptor ();
+ return false;
+ }
+
+ // Clear the lock flag on the slave pseudo terminal
+ if (::unlockpt (m_master_fd) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ CloseMasterFileDescriptor ();
+ return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------
+// Open the slave pseudo terminal for the current master pseudo
+// terminal. A master pseudo terminal should already be valid prior to
+// calling this function (see OpenFirstAvailableMaster()).
+// The file descriptor is stored this object's member variables and can
+// be accessed via the GetSlaveFileDescriptor(), or released using the
+// ReleaseSlaveFileDescriptor() member function.
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ CloseSlaveFileDescriptor();
+
+ // Open the master side of a pseudo terminal
+ const char *slave_name = GetSlaveName (error_str, error_len);
+
+ if (slave_name == NULL)
+ return false;
+
+ m_slave_fd = ::open (slave_name, oflag);
+
+ if (m_slave_fd < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ return false;
+ }
+
+ return true;
+}
+
+
+
+//----------------------------------------------------------------------
+// Get the name of the slave pseudo terminal. A master pseudo terminal
+// should already be valid prior to calling this function (see
+// OpenFirstAvailableMaster()).
+//
+// RETURNS:
+// NULL if no valid master pseudo terminal or if ptsname() fails.
+// The name of the slave pseudo terminal as a NULL terminated C string
+// that comes from static memory, so a copy of the string should be
+// made as subsequent calls can change this value.
+//----------------------------------------------------------------------
+const char*
+PseudoTerminal::GetSlaveName (char *error_str, size_t error_len) const
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ if (m_master_fd < 0)
+ {
+ if (error_str)
+ ::snprintf (error_str, error_len, "%s", "master file descriptor is invalid");
+ return NULL;
+ }
+ const char *slave_name = ::ptsname (m_master_fd);
+
+ if (error_str && slave_name == NULL)
+ ::strerror_r (errno, error_str, error_len);
+
+ return slave_name;
+}
+
+
+//----------------------------------------------------------------------
+// Fork a child process and have its stdio routed to a pseudo terminal.
+//
+// In the parent process when a valid pid is returned, the master file
+// descriptor can be used as a read/write access to stdio of the
+// child process.
+//
+// In the child process the stdin/stdout/stderr will already be routed
+// to the slave pseudo terminal and the master file descriptor will be
+// closed as it is no longer needed by the child process.
+//
+// This class will close the file descriptors for the master/slave
+// when the destructor is called, so be sure to call
+// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any
+// file descriptors are going to be used past the lifespan of this
+// object.
+//
+// RETURNS:
+// in the parent process: the pid of the child, or -1 if fork fails
+// in the child process: zero
+//----------------------------------------------------------------------
+lldb::pid_t
+PseudoTerminal::Fork (char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len))
+ {
+ // Successfully opened our master pseudo terminal
+
+ pid = ::fork ();
+ if (pid < 0)
+ {
+ // Fork failed
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ }
+ else if (pid == 0)
+ {
+ // Child Process
+ ::setsid();
+
+ if (OpenSlave (O_RDWR, error_str, error_len))
+ {
+ // Successfully opened slave
+ // We are done with the master in the child process so lets close it
+ CloseMasterFileDescriptor ();
+
+#if defined(TIOCSCTTY)
+ // Acquire the controlling terminal
+ if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ }
+#endif
+ // Duplicate all stdio file descriptors to the slave pseudo terminal
+ if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+
+ if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+
+ if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+ }
+ }
+ else
+ {
+ // Parent Process
+ // Do nothing and let the pid get returned!
+ }
+ }
+ return pid;
+}
+
+//----------------------------------------------------------------------
+// The master file descriptor accessor. This object retains ownership
+// of the master file descriptor when this accessor is used. Use
+// ReleaseMasterFileDescriptor() if you wish this object to release
+// ownership of the master file descriptor.
+//
+// Returns the master file descriptor, or -1 if the master file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetMasterFileDescriptor () const
+{
+ return m_master_fd;
+}
+
+//----------------------------------------------------------------------
+// The slave file descriptor accessor.
+//
+// Returns the slave file descriptor, or -1 if the slave file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetSlaveFileDescriptor () const
+{
+ return m_slave_fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the master pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// master file descriptor if the ownership isn't released using this
+// call and the master file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseMasterFileDescriptor ()
+{
+ // Release ownership of the master pseudo terminal file
+ // descriptor without closing it. (the destructor for this
+ // class will close it otherwise!)
+ int fd = m_master_fd;
+ m_master_fd = invalid_fd;
+ return fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the slave pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// slave file descriptor if the ownership isn't released using this
+// call and the slave file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseSlaveFileDescriptor ()
+{
+ // Release ownership of the slave pseudo terminal file
+ // descriptor without closing it (the destructor for this
+ // class will close it otherwise!)
+ int fd = m_slave_fd;
+ m_slave_fd = invalid_fd;
+ return fd;
+}
+
OpenPOWER on IntegriCloud