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