1 //===-- TTYState.cpp --------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Created by Greg Clayton on 3/26/07. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "TTYState.h" 15 #include <fcntl.h> 16 #include <sys/signal.h> 17 #include <unistd.h> 18 19 TTYState::TTYState() 20 : m_fd(-1), m_tflags(-1), m_ttystateErr(-1), m_processGroup(-1) {} 21 22 TTYState::~TTYState() {} 23 24 bool TTYState::GetTTYState(int fd, bool saveProcessGroup) { 25 if (fd >= 0 && ::isatty(fd)) { 26 m_fd = fd; 27 m_tflags = fcntl(fd, F_GETFL, 0); 28 m_ttystateErr = tcgetattr(fd, &m_ttystate); 29 if (saveProcessGroup) 30 m_processGroup = tcgetpgrp(0); 31 else 32 m_processGroup = -1; 33 } else { 34 m_fd = -1; 35 m_tflags = -1; 36 m_ttystateErr = -1; 37 m_processGroup = -1; 38 } 39 return m_ttystateErr == 0; 40 } 41 42 bool TTYState::SetTTYState() const { 43 int result = 0; 44 if (IsValid()) { 45 if (TFlagsValid()) 46 result = fcntl(m_fd, F_SETFL, m_tflags); 47 48 if (TTYStateValid()) 49 result = tcsetattr(m_fd, TCSANOW, &m_ttystate); 50 51 if (ProcessGroupValid()) { 52 // Save the original signal handler. 53 void (*saved_sigttou_callback)(int) = NULL; 54 saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN); 55 // Set the process group 56 result = tcsetpgrp(m_fd, m_processGroup); 57 // Restore the original signal handler. 58 signal(SIGTTOU, saved_sigttou_callback); 59 } 60 return true; 61 } 62 return false; 63 } 64 65 TTYStateSwitcher::TTYStateSwitcher() : m_currentState(~0) {} 66 67 TTYStateSwitcher::~TTYStateSwitcher() {} 68 69 bool TTYStateSwitcher::GetState(uint32_t idx, int fd, bool saveProcessGroup) { 70 if (ValidStateIndex(idx)) 71 return m_ttystates[idx].GetTTYState(fd, saveProcessGroup); 72 return false; 73 } 74 75 bool TTYStateSwitcher::SetState(uint32_t idx) const { 76 if (!ValidStateIndex(idx)) 77 return false; 78 79 // See if we already are in this state? 80 if (ValidStateIndex(m_currentState) && (idx == m_currentState) && 81 m_ttystates[idx].IsValid()) 82 return true; 83 84 // Set the state to match the index passed in and only update the 85 // current state if there are no errors. 86 if (m_ttystates[idx].SetTTYState()) { 87 m_currentState = idx; 88 return true; 89 } 90 91 // We failed to set the state. The tty state was invalid or not 92 // initialized. 93 return false; 94 } 95