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