xref: /openbsd-src/gnu/llvm/lldb/source/Host/common/Terminal.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- Terminal.cpp ------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Host/Terminal.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Host/Config.h"
12061da546Spatrick #include "lldb/Host/PosixApi.h"
13061da546Spatrick #include "llvm/ADT/STLExtras.h"
14061da546Spatrick 
15be691f3bSpatrick #include <csignal>
16061da546Spatrick #include <fcntl.h>
17*f6aab3d8Srobert #include <optional>
18061da546Spatrick 
19061da546Spatrick #if LLDB_ENABLE_TERMIOS
20061da546Spatrick #include <termios.h>
21061da546Spatrick #endif
22061da546Spatrick 
23061da546Spatrick using namespace lldb_private;
24061da546Spatrick 
25*f6aab3d8Srobert struct Terminal::Data {
26*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
27*f6aab3d8Srobert   struct termios m_termios; ///< Cached terminal state information.
28*f6aab3d8Srobert #endif
29*f6aab3d8Srobert };
30*f6aab3d8Srobert 
IsATerminal() const31061da546Spatrick bool Terminal::IsATerminal() const { return m_fd >= 0 && ::isatty(m_fd); }
32061da546Spatrick 
33*f6aab3d8Srobert #if !LLDB_ENABLE_TERMIOS
termiosMissingError()34*f6aab3d8Srobert static llvm::Error termiosMissingError() {
35*f6aab3d8Srobert   return llvm::createStringError(llvm::inconvertibleErrorCode(),
36*f6aab3d8Srobert                                  "termios support missing in LLDB");
37061da546Spatrick }
38061da546Spatrick #endif
39*f6aab3d8Srobert 
GetData()40*f6aab3d8Srobert llvm::Expected<Terminal::Data> Terminal::GetData() {
41*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
42*f6aab3d8Srobert   if (!FileDescriptorIsValid())
43*f6aab3d8Srobert     return llvm::createStringError(llvm::inconvertibleErrorCode(),
44*f6aab3d8Srobert                                    "invalid fd");
45*f6aab3d8Srobert 
46*f6aab3d8Srobert   if (!IsATerminal())
47*f6aab3d8Srobert     return llvm::createStringError(llvm::inconvertibleErrorCode(),
48*f6aab3d8Srobert                                    "fd not a terminal");
49*f6aab3d8Srobert 
50*f6aab3d8Srobert   Data data;
51*f6aab3d8Srobert   if (::tcgetattr(m_fd, &data.m_termios) != 0)
52*f6aab3d8Srobert     return llvm::createStringError(
53*f6aab3d8Srobert         std::error_code(errno, std::generic_category()),
54*f6aab3d8Srobert         "unable to get teletype attributes");
55*f6aab3d8Srobert   return data;
56*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
57*f6aab3d8Srobert   return termiosMissingError();
58*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
59061da546Spatrick }
60061da546Spatrick 
SetData(const Terminal::Data & data)61*f6aab3d8Srobert llvm::Error Terminal::SetData(const Terminal::Data &data) {
62*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
63*f6aab3d8Srobert   assert(FileDescriptorIsValid());
64*f6aab3d8Srobert   assert(IsATerminal());
65*f6aab3d8Srobert 
66*f6aab3d8Srobert   if (::tcsetattr(m_fd, TCSANOW, &data.m_termios) != 0)
67*f6aab3d8Srobert     return llvm::createStringError(
68*f6aab3d8Srobert         std::error_code(errno, std::generic_category()),
69*f6aab3d8Srobert         "unable to set teletype attributes");
70*f6aab3d8Srobert   return llvm::Error::success();
71*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
72*f6aab3d8Srobert   return termiosMissingError();
73*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
74*f6aab3d8Srobert }
75*f6aab3d8Srobert 
SetEcho(bool enabled)76*f6aab3d8Srobert llvm::Error Terminal::SetEcho(bool enabled) {
77*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
78*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
79*f6aab3d8Srobert   if (!data)
80*f6aab3d8Srobert     return data.takeError();
81*f6aab3d8Srobert 
82*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
83*f6aab3d8Srobert   fd_termios.c_lflag &= ~ECHO;
84*f6aab3d8Srobert   if (enabled)
85*f6aab3d8Srobert     fd_termios.c_lflag |= ECHO;
86*f6aab3d8Srobert   return SetData(data.get());
87*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
88*f6aab3d8Srobert   return termiosMissingError();
89*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
90*f6aab3d8Srobert }
91*f6aab3d8Srobert 
SetCanonical(bool enabled)92*f6aab3d8Srobert llvm::Error Terminal::SetCanonical(bool enabled) {
93*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
94*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
95*f6aab3d8Srobert   if (!data)
96*f6aab3d8Srobert     return data.takeError();
97*f6aab3d8Srobert 
98*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
99*f6aab3d8Srobert   fd_termios.c_lflag &= ~ICANON;
100*f6aab3d8Srobert   if (enabled)
101*f6aab3d8Srobert     fd_termios.c_lflag |= ICANON;
102*f6aab3d8Srobert   return SetData(data.get());
103*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
104*f6aab3d8Srobert   return termiosMissingError();
105*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
106*f6aab3d8Srobert }
107*f6aab3d8Srobert 
SetRaw()108*f6aab3d8Srobert llvm::Error Terminal::SetRaw() {
109*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
110*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
111*f6aab3d8Srobert   if (!data)
112*f6aab3d8Srobert     return data.takeError();
113*f6aab3d8Srobert 
114*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
115*f6aab3d8Srobert   ::cfmakeraw(&fd_termios);
116*f6aab3d8Srobert 
117*f6aab3d8Srobert   // Make sure only one character is needed to return from a read
118*f6aab3d8Srobert   // (cfmakeraw() doesn't do this on NetBSD)
119*f6aab3d8Srobert   fd_termios.c_cc[VMIN] = 1;
120*f6aab3d8Srobert   fd_termios.c_cc[VTIME] = 0;
121*f6aab3d8Srobert 
122*f6aab3d8Srobert   return SetData(data.get());
123*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
124*f6aab3d8Srobert   return termiosMissingError();
125*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
126*f6aab3d8Srobert }
127*f6aab3d8Srobert 
128*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
baudRateToConst(unsigned int baud_rate)129*f6aab3d8Srobert static std::optional<speed_t> baudRateToConst(unsigned int baud_rate) {
130*f6aab3d8Srobert   switch (baud_rate) {
131*f6aab3d8Srobert #if defined(B50)
132*f6aab3d8Srobert   case 50:
133*f6aab3d8Srobert     return B50;
134*f6aab3d8Srobert #endif
135*f6aab3d8Srobert #if defined(B75)
136*f6aab3d8Srobert   case 75:
137*f6aab3d8Srobert     return B75;
138*f6aab3d8Srobert #endif
139*f6aab3d8Srobert #if defined(B110)
140*f6aab3d8Srobert   case 110:
141*f6aab3d8Srobert     return B110;
142*f6aab3d8Srobert #endif
143*f6aab3d8Srobert #if defined(B134)
144*f6aab3d8Srobert   case 134:
145*f6aab3d8Srobert     return B134;
146*f6aab3d8Srobert #endif
147*f6aab3d8Srobert #if defined(B150)
148*f6aab3d8Srobert   case 150:
149*f6aab3d8Srobert     return B150;
150*f6aab3d8Srobert #endif
151*f6aab3d8Srobert #if defined(B200)
152*f6aab3d8Srobert   case 200:
153*f6aab3d8Srobert     return B200;
154*f6aab3d8Srobert #endif
155*f6aab3d8Srobert #if defined(B300)
156*f6aab3d8Srobert   case 300:
157*f6aab3d8Srobert     return B300;
158*f6aab3d8Srobert #endif
159*f6aab3d8Srobert #if defined(B600)
160*f6aab3d8Srobert   case 600:
161*f6aab3d8Srobert     return B600;
162*f6aab3d8Srobert #endif
163*f6aab3d8Srobert #if defined(B1200)
164*f6aab3d8Srobert   case 1200:
165*f6aab3d8Srobert     return B1200;
166*f6aab3d8Srobert #endif
167*f6aab3d8Srobert #if defined(B1800)
168*f6aab3d8Srobert   case 1800:
169*f6aab3d8Srobert     return B1800;
170*f6aab3d8Srobert #endif
171*f6aab3d8Srobert #if defined(B2400)
172*f6aab3d8Srobert   case 2400:
173*f6aab3d8Srobert     return B2400;
174*f6aab3d8Srobert #endif
175*f6aab3d8Srobert #if defined(B4800)
176*f6aab3d8Srobert   case 4800:
177*f6aab3d8Srobert     return B4800;
178*f6aab3d8Srobert #endif
179*f6aab3d8Srobert #if defined(B9600)
180*f6aab3d8Srobert   case 9600:
181*f6aab3d8Srobert     return B9600;
182*f6aab3d8Srobert #endif
183*f6aab3d8Srobert #if defined(B19200)
184*f6aab3d8Srobert   case 19200:
185*f6aab3d8Srobert     return B19200;
186*f6aab3d8Srobert #endif
187*f6aab3d8Srobert #if defined(B38400)
188*f6aab3d8Srobert   case 38400:
189*f6aab3d8Srobert     return B38400;
190*f6aab3d8Srobert #endif
191*f6aab3d8Srobert #if defined(B57600)
192*f6aab3d8Srobert   case 57600:
193*f6aab3d8Srobert     return B57600;
194*f6aab3d8Srobert #endif
195*f6aab3d8Srobert #if defined(B115200)
196*f6aab3d8Srobert   case 115200:
197*f6aab3d8Srobert     return B115200;
198*f6aab3d8Srobert #endif
199*f6aab3d8Srobert #if defined(B230400)
200*f6aab3d8Srobert   case 230400:
201*f6aab3d8Srobert     return B230400;
202*f6aab3d8Srobert #endif
203*f6aab3d8Srobert #if defined(B460800)
204*f6aab3d8Srobert   case 460800:
205*f6aab3d8Srobert     return B460800;
206*f6aab3d8Srobert #endif
207*f6aab3d8Srobert #if defined(B500000)
208*f6aab3d8Srobert   case 500000:
209*f6aab3d8Srobert     return B500000;
210*f6aab3d8Srobert #endif
211*f6aab3d8Srobert #if defined(B576000)
212*f6aab3d8Srobert   case 576000:
213*f6aab3d8Srobert     return B576000;
214*f6aab3d8Srobert #endif
215*f6aab3d8Srobert #if defined(B921600)
216*f6aab3d8Srobert   case 921600:
217*f6aab3d8Srobert     return B921600;
218*f6aab3d8Srobert #endif
219*f6aab3d8Srobert #if defined(B1000000)
220*f6aab3d8Srobert   case 1000000:
221*f6aab3d8Srobert     return B1000000;
222*f6aab3d8Srobert #endif
223*f6aab3d8Srobert #if defined(B1152000)
224*f6aab3d8Srobert   case 1152000:
225*f6aab3d8Srobert     return B1152000;
226*f6aab3d8Srobert #endif
227*f6aab3d8Srobert #if defined(B1500000)
228*f6aab3d8Srobert   case 1500000:
229*f6aab3d8Srobert     return B1500000;
230*f6aab3d8Srobert #endif
231*f6aab3d8Srobert #if defined(B2000000)
232*f6aab3d8Srobert   case 2000000:
233*f6aab3d8Srobert     return B2000000;
234*f6aab3d8Srobert #endif
235*f6aab3d8Srobert #if defined(B76800)
236*f6aab3d8Srobert   case 76800:
237*f6aab3d8Srobert     return B76800;
238*f6aab3d8Srobert #endif
239*f6aab3d8Srobert #if defined(B153600)
240*f6aab3d8Srobert   case 153600:
241*f6aab3d8Srobert     return B153600;
242*f6aab3d8Srobert #endif
243*f6aab3d8Srobert #if defined(B307200)
244*f6aab3d8Srobert   case 307200:
245*f6aab3d8Srobert     return B307200;
246*f6aab3d8Srobert #endif
247*f6aab3d8Srobert #if defined(B614400)
248*f6aab3d8Srobert   case 614400:
249*f6aab3d8Srobert     return B614400;
250*f6aab3d8Srobert #endif
251*f6aab3d8Srobert #if defined(B2500000)
252*f6aab3d8Srobert   case 2500000:
253*f6aab3d8Srobert     return B2500000;
254*f6aab3d8Srobert #endif
255*f6aab3d8Srobert #if defined(B3000000)
256*f6aab3d8Srobert   case 3000000:
257*f6aab3d8Srobert     return B3000000;
258*f6aab3d8Srobert #endif
259*f6aab3d8Srobert #if defined(B3500000)
260*f6aab3d8Srobert   case 3500000:
261*f6aab3d8Srobert     return B3500000;
262*f6aab3d8Srobert #endif
263*f6aab3d8Srobert #if defined(B4000000)
264*f6aab3d8Srobert   case 4000000:
265*f6aab3d8Srobert     return B4000000;
266*f6aab3d8Srobert #endif
267*f6aab3d8Srobert   default:
268*f6aab3d8Srobert     return std::nullopt;
269*f6aab3d8Srobert   }
270*f6aab3d8Srobert }
271*f6aab3d8Srobert #endif
272*f6aab3d8Srobert 
SetBaudRate(unsigned int baud_rate)273*f6aab3d8Srobert llvm::Error Terminal::SetBaudRate(unsigned int baud_rate) {
274*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
275*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
276*f6aab3d8Srobert   if (!data)
277*f6aab3d8Srobert     return data.takeError();
278*f6aab3d8Srobert 
279*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
280*f6aab3d8Srobert   std::optional<speed_t> val = baudRateToConst(baud_rate);
281*f6aab3d8Srobert   if (!val) // invalid value
282*f6aab3d8Srobert     return llvm::createStringError(llvm::inconvertibleErrorCode(),
283*f6aab3d8Srobert                                    "baud rate %d unsupported by the platform",
284*f6aab3d8Srobert                                    baud_rate);
285*f6aab3d8Srobert   if (::cfsetispeed(&fd_termios, *val) != 0)
286*f6aab3d8Srobert     return llvm::createStringError(
287*f6aab3d8Srobert         std::error_code(errno, std::generic_category()),
288*f6aab3d8Srobert         "setting input baud rate failed");
289*f6aab3d8Srobert   if (::cfsetospeed(&fd_termios, *val) != 0)
290*f6aab3d8Srobert     return llvm::createStringError(
291*f6aab3d8Srobert         std::error_code(errno, std::generic_category()),
292*f6aab3d8Srobert         "setting output baud rate failed");
293*f6aab3d8Srobert   return SetData(data.get());
294*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
295*f6aab3d8Srobert   return termiosMissingError();
296*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
297*f6aab3d8Srobert }
298*f6aab3d8Srobert 
SetStopBits(unsigned int stop_bits)299*f6aab3d8Srobert llvm::Error Terminal::SetStopBits(unsigned int stop_bits) {
300*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
301*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
302*f6aab3d8Srobert   if (!data)
303*f6aab3d8Srobert     return data.takeError();
304*f6aab3d8Srobert 
305*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
306*f6aab3d8Srobert   switch (stop_bits) {
307*f6aab3d8Srobert   case 1:
308*f6aab3d8Srobert     fd_termios.c_cflag &= ~CSTOPB;
309*f6aab3d8Srobert     break;
310*f6aab3d8Srobert   case 2:
311*f6aab3d8Srobert     fd_termios.c_cflag |= CSTOPB;
312*f6aab3d8Srobert     break;
313*f6aab3d8Srobert   default:
314*f6aab3d8Srobert     return llvm::createStringError(
315*f6aab3d8Srobert         llvm::inconvertibleErrorCode(),
316*f6aab3d8Srobert         "invalid stop bit count: %d (must be 1 or 2)", stop_bits);
317*f6aab3d8Srobert   }
318*f6aab3d8Srobert   return SetData(data.get());
319*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
320*f6aab3d8Srobert   return termiosMissingError();
321*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
322*f6aab3d8Srobert }
323*f6aab3d8Srobert 
SetParity(Terminal::Parity parity)324*f6aab3d8Srobert llvm::Error Terminal::SetParity(Terminal::Parity parity) {
325*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
326*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
327*f6aab3d8Srobert   if (!data)
328*f6aab3d8Srobert     return data.takeError();
329*f6aab3d8Srobert 
330*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
331*f6aab3d8Srobert   fd_termios.c_cflag &= ~(
332*f6aab3d8Srobert #if defined(CMSPAR)
333*f6aab3d8Srobert       CMSPAR |
334*f6aab3d8Srobert #endif
335*f6aab3d8Srobert       PARENB | PARODD);
336*f6aab3d8Srobert 
337*f6aab3d8Srobert   if (parity != Parity::No) {
338*f6aab3d8Srobert     fd_termios.c_cflag |= PARENB;
339*f6aab3d8Srobert     if (parity == Parity::Odd || parity == Parity::Mark)
340*f6aab3d8Srobert       fd_termios.c_cflag |= PARODD;
341*f6aab3d8Srobert     if (parity == Parity::Mark || parity == Parity::Space) {
342*f6aab3d8Srobert #if defined(CMSPAR)
343*f6aab3d8Srobert       fd_termios.c_cflag |= CMSPAR;
344*f6aab3d8Srobert #else
345*f6aab3d8Srobert       return llvm::createStringError(
346*f6aab3d8Srobert           llvm::inconvertibleErrorCode(),
347*f6aab3d8Srobert           "space/mark parity is not supported by the platform");
348*f6aab3d8Srobert #endif
349*f6aab3d8Srobert     }
350*f6aab3d8Srobert   }
351*f6aab3d8Srobert   return SetData(data.get());
352*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
353*f6aab3d8Srobert   return termiosMissingError();
354*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
355*f6aab3d8Srobert }
356*f6aab3d8Srobert 
SetParityCheck(Terminal::ParityCheck parity_check)357*f6aab3d8Srobert llvm::Error Terminal::SetParityCheck(Terminal::ParityCheck parity_check) {
358*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
359*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
360*f6aab3d8Srobert   if (!data)
361*f6aab3d8Srobert     return data.takeError();
362*f6aab3d8Srobert 
363*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
364*f6aab3d8Srobert   fd_termios.c_iflag &= ~(IGNPAR | PARMRK | INPCK);
365*f6aab3d8Srobert 
366*f6aab3d8Srobert   if (parity_check != ParityCheck::No) {
367*f6aab3d8Srobert     fd_termios.c_iflag |= INPCK;
368*f6aab3d8Srobert     if (parity_check == ParityCheck::Ignore)
369*f6aab3d8Srobert       fd_termios.c_iflag |= IGNPAR;
370*f6aab3d8Srobert     else if (parity_check == ParityCheck::Mark)
371*f6aab3d8Srobert       fd_termios.c_iflag |= PARMRK;
372*f6aab3d8Srobert   }
373*f6aab3d8Srobert   return SetData(data.get());
374*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
375*f6aab3d8Srobert   return termiosMissingError();
376*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
377*f6aab3d8Srobert }
378*f6aab3d8Srobert 
SetHardwareFlowControl(bool enabled)379*f6aab3d8Srobert llvm::Error Terminal::SetHardwareFlowControl(bool enabled) {
380*f6aab3d8Srobert #if LLDB_ENABLE_TERMIOS
381*f6aab3d8Srobert   llvm::Expected<Data> data = GetData();
382*f6aab3d8Srobert   if (!data)
383*f6aab3d8Srobert     return data.takeError();
384*f6aab3d8Srobert 
385*f6aab3d8Srobert #if defined(CRTSCTS)
386*f6aab3d8Srobert   struct termios &fd_termios = data->m_termios;
387*f6aab3d8Srobert   fd_termios.c_cflag &= ~CRTSCTS;
388*f6aab3d8Srobert   if (enabled)
389*f6aab3d8Srobert     fd_termios.c_cflag |= CRTSCTS;
390*f6aab3d8Srobert   return SetData(data.get());
391*f6aab3d8Srobert #else  // !defined(CRTSCTS)
392*f6aab3d8Srobert   if (enabled)
393*f6aab3d8Srobert     return llvm::createStringError(
394*f6aab3d8Srobert         llvm::inconvertibleErrorCode(),
395*f6aab3d8Srobert         "hardware flow control is not supported by the platform");
396*f6aab3d8Srobert   return llvm::Error::success();
397*f6aab3d8Srobert #endif // defined(CRTSCTS)
398*f6aab3d8Srobert #else // !LLDB_ENABLE_TERMIOS
399*f6aab3d8Srobert   return termiosMissingError();
400*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
401*f6aab3d8Srobert }
402*f6aab3d8Srobert 
TerminalState(Terminal term,bool save_process_group)403*f6aab3d8Srobert TerminalState::TerminalState(Terminal term, bool save_process_group)
404*f6aab3d8Srobert     : m_tty(term) {
405*f6aab3d8Srobert   Save(term, save_process_group);
406*f6aab3d8Srobert }
407*f6aab3d8Srobert 
~TerminalState()408*f6aab3d8Srobert TerminalState::~TerminalState() { Restore(); }
409061da546Spatrick 
Clear()410061da546Spatrick void TerminalState::Clear() {
411061da546Spatrick   m_tty.Clear();
412061da546Spatrick   m_tflags = -1;
413*f6aab3d8Srobert   m_data.reset();
414061da546Spatrick   m_process_group = -1;
415061da546Spatrick }
416061da546Spatrick 
Save(Terminal term,bool save_process_group)417*f6aab3d8Srobert bool TerminalState::Save(Terminal term, bool save_process_group) {
418*f6aab3d8Srobert   Clear();
419*f6aab3d8Srobert   m_tty = term;
420061da546Spatrick   if (m_tty.IsATerminal()) {
421061da546Spatrick #if LLDB_ENABLE_POSIX
422*f6aab3d8Srobert     int fd = m_tty.GetFileDescriptor();
423061da546Spatrick     m_tflags = ::fcntl(fd, F_GETFL, 0);
424061da546Spatrick #if LLDB_ENABLE_TERMIOS
425*f6aab3d8Srobert     std::unique_ptr<Terminal::Data> new_data{new Terminal::Data()};
426*f6aab3d8Srobert     if (::tcgetattr(fd, &new_data->m_termios) == 0)
427*f6aab3d8Srobert       m_data = std::move(new_data);
428*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
429061da546Spatrick     if (save_process_group)
430*f6aab3d8Srobert       m_process_group = ::tcgetpgrp(fd);
431*f6aab3d8Srobert #endif // LLDB_ENABLE_POSIX
432061da546Spatrick   }
433061da546Spatrick   return IsValid();
434061da546Spatrick }
435061da546Spatrick 
Restore() const436061da546Spatrick bool TerminalState::Restore() const {
437061da546Spatrick #if LLDB_ENABLE_POSIX
438061da546Spatrick   if (IsValid()) {
439061da546Spatrick     const int fd = m_tty.GetFileDescriptor();
440061da546Spatrick     if (TFlagsIsValid())
441061da546Spatrick       fcntl(fd, F_SETFL, m_tflags);
442061da546Spatrick 
443061da546Spatrick #if LLDB_ENABLE_TERMIOS
444061da546Spatrick     if (TTYStateIsValid())
445*f6aab3d8Srobert       tcsetattr(fd, TCSANOW, &m_data->m_termios);
446*f6aab3d8Srobert #endif // LLDB_ENABLE_TERMIOS
447061da546Spatrick 
448061da546Spatrick     if (ProcessGroupIsValid()) {
449061da546Spatrick       // Save the original signal handler.
450061da546Spatrick       void (*saved_sigttou_callback)(int) = nullptr;
451061da546Spatrick       saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN);
452061da546Spatrick       // Set the process group
453061da546Spatrick       tcsetpgrp(fd, m_process_group);
454061da546Spatrick       // Restore the original signal handler.
455061da546Spatrick       signal(SIGTTOU, saved_sigttou_callback);
456061da546Spatrick     }
457061da546Spatrick     return true;
458061da546Spatrick   }
459*f6aab3d8Srobert #endif // LLDB_ENABLE_POSIX
460061da546Spatrick   return false;
461061da546Spatrick }
462061da546Spatrick 
IsValid() const463061da546Spatrick bool TerminalState::IsValid() const {
464061da546Spatrick   return m_tty.FileDescriptorIsValid() &&
465*f6aab3d8Srobert          (TFlagsIsValid() || TTYStateIsValid() || ProcessGroupIsValid());
466061da546Spatrick }
467061da546Spatrick 
TFlagsIsValid() const468061da546Spatrick bool TerminalState::TFlagsIsValid() const { return m_tflags != -1; }
469061da546Spatrick 
TTYStateIsValid() const470*f6aab3d8Srobert bool TerminalState::TTYStateIsValid() const { return bool(m_data); }
471061da546Spatrick 
ProcessGroupIsValid() const472061da546Spatrick bool TerminalState::ProcessGroupIsValid() const {
473061da546Spatrick   return static_cast<int32_t>(m_process_group) != -1;
474061da546Spatrick }
475