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 <unistd.h>
17#include <sys/signal.h>
18
19TTYState::TTYState() :
20    m_fd(-1),
21    m_tflags(-1),
22    m_ttystateErr(-1),
23    m_processGroup(-1)
24{
25}
26
27TTYState::~TTYState()
28{
29}
30
31bool
32TTYState::GetTTYState (int fd, bool saveProcessGroup)
33{
34    if (fd >= 0 && ::isatty (fd))
35    {
36        m_fd = fd;
37        m_tflags = fcntl (fd, F_GETFL, 0);
38        m_ttystateErr = tcgetattr (fd, &m_ttystate);
39        if (saveProcessGroup)
40            m_processGroup = tcgetpgrp (0);
41        else
42            m_processGroup = -1;
43    }
44    else
45    {
46        m_fd = -1;
47        m_tflags = -1;
48        m_ttystateErr = -1;
49        m_processGroup = -1;
50    }
51    return m_ttystateErr == 0;
52}
53
54bool
55TTYState::SetTTYState () const
56{
57    int result = 0;
58    if (IsValid())
59    {
60        if (TFlagsValid())
61            result = fcntl (m_fd, F_SETFL, m_tflags);
62
63        if (TTYStateValid())
64            result = tcsetattr (m_fd, TCSANOW, &m_ttystate);
65
66        if (ProcessGroupValid())
67        {
68            // Save the original signal handler.
69            void (*saved_sigttou_callback) (int) = NULL;
70            saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
71            // Set the process group
72            result = tcsetpgrp (m_fd, m_processGroup);
73            // Restore the original signal handler.
74            signal (SIGTTOU, saved_sigttou_callback);
75        }
76        return true;
77    }
78    return false;
79}
80
81
82
83TTYStateSwitcher::TTYStateSwitcher() :
84    m_currentState(~0)
85{
86}
87
88TTYStateSwitcher::~TTYStateSwitcher()
89{
90}
91
92bool
93TTYStateSwitcher::GetState(uint32_t idx, int fd, bool saveProcessGroup)
94{
95    if (ValidStateIndex(idx))
96        return m_ttystates[idx].GetTTYState(fd, saveProcessGroup);
97    return false;
98}
99
100bool
101TTYStateSwitcher::SetState(uint32_t idx) const
102{
103    if (!ValidStateIndex(idx))
104        return false;
105
106    // See if we already are in this state?
107    if (ValidStateIndex(m_currentState) && (idx == m_currentState) && m_ttystates[idx].IsValid())
108        return true;
109
110    // Set the state to match the index passed in and only update the
111    // current state if there are no errors.
112    if (m_ttystates[idx].SetTTYState())
113    {
114        m_currentState = idx;
115        return true;
116    }
117
118    // We failed to set the state. The tty state was invalid or not
119    // initialized.
120    return false;
121}
122
123