//===-- TTYState.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/Core/TTYState.h" #include #include #include using namespace lldb_private; //---------------------------------------------------------------------- // Default constructor //---------------------------------------------------------------------- TTYState::TTYState() : m_fd(-1), m_tflags(-1), m_ttystate_err(-1), m_ttystate(), m_process_group(-1) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- TTYState::~TTYState() { } //---------------------------------------------------------------------- // Save the current state of the TTY for the file descriptor "fd" // and if "save_process_group" is true, attempt to save the process // group info for the TTY. //---------------------------------------------------------------------- bool TTYState::Save (int fd, bool save_process_group) { if (fd >= 0 && ::isatty (fd)) { m_fd = fd; m_tflags = ::fcntl (fd, F_GETFL, 0); m_ttystate_err = ::tcgetattr (fd, &m_ttystate); if (save_process_group) m_process_group = ::tcgetpgrp (0); else m_process_group = -1; } else { m_fd = -1; m_tflags = -1; m_ttystate_err = -1; m_process_group = -1; } return m_ttystate_err == 0; } //---------------------------------------------------------------------- // Restore the state of the TTY using the cached values from a // previous call to Save(). //---------------------------------------------------------------------- bool TTYState::Restore () const { int result = 0; if (IsValid()) { if (TFlagsIsValid()) result = fcntl (m_fd, F_SETFL, m_tflags); if (TTYStateIsValid()) result = tcsetattr (m_fd, TCSANOW, &m_ttystate); if (ProcessGroupIsValid()) { // Save the original signal handler. void (*saved_sigttou_callback) (int) = NULL; saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN); // Set the process group result = tcsetpgrp (m_fd, m_process_group); // Restore the original signal handler. signal (SIGTTOU, saved_sigttou_callback); } return true; } return false; } //---------------------------------------------------------------------- // Returns true if this object has valid saved TTY state settings // that can be used to restore a previous state. //---------------------------------------------------------------------- bool TTYState::IsValid() const { return (m_fd >= 0) && (TFlagsIsValid() || TTYStateIsValid()); } //---------------------------------------------------------------------- // Returns true if m_tflags is valid //---------------------------------------------------------------------- bool TTYState::TFlagsIsValid() const { return m_tflags != -1; } //---------------------------------------------------------------------- // Returns true if m_ttystate is valid //---------------------------------------------------------------------- bool TTYState::TTYStateIsValid() const { return m_ttystate_err == 0; } //---------------------------------------------------------------------- // Returns true if m_process_group is valid //---------------------------------------------------------------------- bool TTYState::ProcessGroupIsValid() const { return m_process_group != -1; } //------------------------------------------------------------------ // Constructor //------------------------------------------------------------------ TTYStateSwitcher::TTYStateSwitcher () : m_currentState(UINT32_MAX) { } //------------------------------------------------------------------ // Destructor //------------------------------------------------------------------ TTYStateSwitcher::~TTYStateSwitcher () { } //------------------------------------------------------------------ // Returns the number of states that this switcher contains //------------------------------------------------------------------ uint32_t TTYStateSwitcher::GetNumberOfStates() const { return sizeof(m_ttystates)/sizeof(TTYState); } //------------------------------------------------------------------ // Restore the state at index "idx". // // Returns true if the restore was successful, false otherwise. //------------------------------------------------------------------ bool TTYStateSwitcher::Restore (uint32_t idx) const { const uint32_t num_states = GetNumberOfStates(); if (idx >= num_states) return false; // See if we already are in this state? if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid()) return true; // Set the state to match the index passed in and only update the // current state if there are no errors. if (m_ttystates[idx].Restore()) { m_currentState = idx; return true; } // We failed to set the state. The tty state was invalid or not // initialized. return false; } //------------------------------------------------------------------ // Save the state at index "idx" for file descriptor "fd" and // save the process group if requested. // // Returns true if the restore was successful, false otherwise. //------------------------------------------------------------------ bool TTYStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group) { const uint32_t num_states = GetNumberOfStates(); if (idx < num_states) return m_ttystates[idx].Save(fd, save_process_group); return false; }