File: | /rootdir/_build/../src/pty.cc |
Warning: | line 211, column 30 Value stored to 'errsv' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (C) 2001,2002 Red Hat, Inc. |
3 | * Copyright © 2009, 2010, 2019 Christian Persch |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 3 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public |
16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | */ |
19 | |
20 | /** |
21 | * SECTION: bte-pty |
22 | * @short_description: Functions for starting a new process on a new pseudo-terminal and for |
23 | * manipulating pseudo-terminals |
24 | * |
25 | * The terminal widget uses these functions to start commands with new controlling |
26 | * pseudo-terminals and to resize pseudo-terminals. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | |
31 | #include "pty.hh" |
32 | |
33 | #include "libc-glue.hh" |
34 | |
35 | #include <bte/bte.h> |
36 | #include "bteptyinternal.hh" |
37 | |
38 | #include <assert.h> |
39 | #include <sys/types.h> |
40 | #include <sys/ioctl.h> |
41 | #include <sys/socket.h> |
42 | #ifdef HAVE_SYS_TERMIOS_H |
43 | #include <sys/termios.h> |
44 | #endif |
45 | #include <errno(*__errno_location ()).h> |
46 | #include <fcntl.h> |
47 | #include <limits.h> |
48 | #ifdef HAVE_SYS_SYSLIMITS_H |
49 | #include <sys/syslimits.h> |
50 | #endif |
51 | #include <signal.h> |
52 | #include <pthread.h> |
53 | #include <stdio.h> |
54 | #include <stdlib.h> |
55 | #include <string.h> |
56 | #ifdef HAVE_TERMIOS_H |
57 | #include <termios.h> |
58 | #endif |
59 | #include <unistd.h> |
60 | #ifdef HAVE_UTIL_H |
61 | #include <util.h> |
62 | #endif |
63 | #ifdef HAVE_PTY_H |
64 | #include <pty.h> |
65 | #endif |
66 | #if defined(__sun) && defined(HAVE_STROPTS_H) |
67 | #include <stropts.h> |
68 | #endif |
69 | #include <glib.h> |
70 | #include <gio/gio.h> |
71 | #include "debug.h" |
72 | |
73 | #include <glib/gi18n-lib.h> |
74 | |
75 | #include "glib-glue.hh" |
76 | |
77 | #include "btedefines.hh" |
78 | |
79 | #include "missing.hh" |
80 | |
81 | namespace bte::base { |
82 | |
83 | Pty* |
84 | Pty::ref() noexcept |
85 | { |
86 | g_atomic_int_inc(&m_refcount)(__extension__ ({ static_assert (sizeof *(&m_refcount) == sizeof (gint), "Expression evaluates to false"); (void) (0 ? *(&m_refcount) ^ *(&m_refcount) : 1); (void) __atomic_fetch_add ((&m_refcount), 1, 5); })); |
87 | return this; |
88 | } |
89 | |
90 | void |
91 | Pty::unref() noexcept |
92 | { |
93 | if (g_atomic_int_dec_and_test(&m_refcount)(__extension__ ({ static_assert (sizeof *(&m_refcount) == sizeof (gint), "Expression evaluates to false"); (void) (0 ? *(&m_refcount) ^ *(&m_refcount) : 1); __atomic_fetch_sub ((&m_refcount), 1, 5) == 1; }))) |
94 | delete this; |
95 | } |
96 | |
97 | int |
98 | Pty::get_peer(bool cloexec) const noexcept |
99 | { |
100 | if (!m_pty_fd) |
101 | return -1; |
102 | |
103 | /* FIXME? else if (m_flags & BTE_PTY_NO_CTTTY) |
104 | * No session and no controlling TTY wanted, do we need to lose our controlling TTY, |
105 | * perhaps by open("/dev/tty") + ioctl(TIOCNOTTY) ? |
106 | */ |
107 | |
108 | /* Now open the PTY peer. Note that this also makes the PTY our controlling TTY. */ |
109 | auto const fd_flags = int{O_RDWR02 | |
110 | ((m_flags & BTE_PTY_NO_CTTY) ? O_NOCTTY0400 : 0) | |
111 | (cloexec ? O_CLOEXEC02000000 : 0)}; |
112 | |
113 | auto peer_fd = bte::libc::FD{}; |
114 | |
115 | #ifdef __linux__1 |
116 | peer_fd = ioctl(m_pty_fd.get(), TIOCGPTPEER(((0U) << (((0 +8)+8)+14)) | ((('T')) << (0 +8)) | (((0x41)) << 0) | ((0) << ((0 +8)+8))), fd_flags); |
117 | /* Note: According to the kernel's own tests (tools/testing/selftests/filesystems/devpts_pts.c), |
118 | * the error returned when the running kernel does not support this ioctl should be EINVAL. |
119 | * However it appears that the actual error returned is ENOTTY. So we check for both of them. |
120 | * See issue#182. |
121 | */ |
122 | if (!peer_fd && |
123 | errno(*__errno_location ()) != EINVAL22 && |
124 | errno(*__errno_location ()) != ENOTTY25) { |
125 | auto errsv = bte::libc::ErrnoSaver{}; |
126 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
127 | "ioctl(TIOCGPTPEER)", g_strerror(errsv))do { } while(0); |
128 | return -1; |
129 | } |
130 | |
131 | /* Fall back to ptsname + open */ |
132 | #endif |
133 | |
134 | if (!peer_fd) { |
135 | auto const name = ptsname(m_pty_fd.get()); |
136 | if (name == nullptr) { |
137 | auto errsv = bte::libc::ErrnoSaver{}; |
138 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
139 | "ptsname", g_strerror(errsv))do { } while(0); |
140 | return -1; |
141 | } |
142 | |
143 | _bte_debug_print (BTE_DEBUG_PTY,do { } while(0) |
144 | "Setting up child pty: master FD = %d name = %s\n",do { } while(0) |
145 | m_pty_fd.get(), name)do { } while(0); |
146 | |
147 | peer_fd = ::open(name, fd_flags); |
148 | if (!peer_fd) { |
149 | auto errsv = bte::libc::ErrnoSaver{}; |
150 | _bte_debug_print (BTE_DEBUG_PTY, "Failed to open PTY: %s\n",do { } while(0) |
151 | g_strerror(errsv))do { } while(0); |
152 | return -1; |
153 | } |
154 | } |
155 | |
156 | assert(bool(peer_fd))(static_cast <bool> (bool(peer_fd)) ? void (0) : __assert_fail ("bool(peer_fd)", "../src/pty.cc", 156, __extension__ __PRETTY_FUNCTION__ )); |
157 | |
158 | #if defined(__sun) && defined(HAVE_STROPTS_H) |
159 | /* See https://illumos.org/man/7i/streamio */ |
160 | if (isastream (peer_fd.get()) == 1) { |
161 | /* https://illumos.org/man/7m/ptem */ |
162 | if ((ioctl(peer_fd.get(), I_FIND, "ptem") == 0) && |
163 | (ioctl(peer_fd.get(), I_PUSH, "ptem") == -1)) { |
164 | return -1; |
165 | } |
166 | /* https://illumos.org/man/7m/ldterm */ |
167 | if ((ioctl(peer_fd.get(), I_FIND, "ldterm") == 0) && |
168 | (ioctl(peer_fd.get(), I_PUSH, "ldterm") == -1)) { |
169 | return -1; |
170 | } |
171 | /* https://illumos.org/man/7m/ttcompat */ |
172 | if ((ioctl(peer_fd.get(), I_FIND, "ttcompat") == 0) && |
173 | (ioctl(peer_fd.get(), I_PUSH, "ttcompat") == -1)) { |
174 | return -1; |
175 | } |
176 | } |
177 | #endif |
178 | |
179 | return peer_fd.release(); |
180 | } |
181 | |
182 | void |
183 | Pty::child_setup() const noexcept |
184 | { |
185 | /* Unblock all signals */ |
186 | sigset_t set; |
187 | sigemptyset(&set); |
188 | if (pthread_sigmask(SIG_SETMASK2, &set, nullptr) == -1) { |
189 | auto errsv = bte::libc::ErrnoSaver{}; |
190 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
191 | "pthread_sigmask", g_strerror(errsv))do { } while(0); |
192 | _exit(127); |
193 | } |
194 | |
195 | /* Reset the handlers for all signals to their defaults. The parent |
196 | * (or one of the libraries it links to) may have changed one to be ignored. |
197 | */ |
198 | for (int n = 1; n < NSIG(64 + 1); n++) { |
199 | if (n == SIGSTOP19 || n == SIGKILL9) |
200 | continue; |
201 | |
202 | signal(n, SIG_DFL((__sighandler_t) 0)); |
203 | } |
204 | |
205 | if (!(m_flags & BTE_PTY_NO_SESSION)) { |
206 | /* This starts a new session; we become its process-group leader, |
207 | * and lose our controlling TTY. |
208 | */ |
209 | _bte_debug_print (BTE_DEBUG_PTY, "Starting new session\n")do { } while(0); |
210 | if (setsid() == -1) { |
211 | auto errsv = bte::libc::ErrnoSaver{}; |
Value stored to 'errsv' during its initialization is never read | |
212 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
213 | "setsid", g_strerror(errsv))do { } while(0); |
214 | _exit(127); |
215 | } |
216 | } |
217 | |
218 | auto peer_fd = get_peer(); |
219 | if (peer_fd == -1) |
220 | _exit(127); |
221 | |
222 | #ifdef TIOCSCTTY0x540E |
223 | /* On linux, opening the PTY peer above already made it our controlling TTY (since |
224 | * previously there was none, after the setsid() call). However, it appears that e.g. |
225 | * on *BSD, that doesn't happen, so we need this explicit ioctl here. |
226 | */ |
227 | if (!(m_flags & BTE_PTY_NO_CTTY)) { |
228 | if (ioctl(peer_fd, TIOCSCTTY0x540E, peer_fd) != 0) { |
229 | auto errsv = bte::libc::ErrnoSaver{}; |
230 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
231 | "ioctl(TIOCSCTTY)", g_strerror(errsv))do { } while(0); |
232 | _exit(127); |
233 | } |
234 | } |
235 | #endif |
236 | |
237 | /* now setup child I/O through the tty */ |
238 | if (peer_fd != STDIN_FILENO0) { |
239 | if (dup2(peer_fd, STDIN_FILENO0) != STDIN_FILENO0){ |
240 | _exit (127); |
241 | } |
242 | } |
243 | if (peer_fd != STDOUT_FILENO1) { |
244 | if (dup2(peer_fd, STDOUT_FILENO1) != STDOUT_FILENO1){ |
245 | _exit (127); |
246 | } |
247 | } |
248 | if (peer_fd != STDERR_FILENO2) { |
249 | if (dup2(peer_fd, STDERR_FILENO2) != STDERR_FILENO2){ |
250 | _exit (127); |
251 | } |
252 | } |
253 | |
254 | /* If the peer FD has not been consumed above as one of the stdio descriptors, |
255 | * need to close it now so that it doesn't leak to the child. |
256 | */ |
257 | if (peer_fd != STDIN_FILENO0 && |
258 | peer_fd != STDOUT_FILENO1 && |
259 | peer_fd != STDERR_FILENO2) { |
260 | close(peer_fd); |
261 | } |
262 | |
263 | /* Now set the TERM environment variable */ |
264 | /* FIXME: Setting environment here seems to have no effect, the merged envp2 will override on exec. |
265 | * By the way, we'd need to set the one from there, if any. */ |
266 | g_setenv("TERM", BTE_TERMINFO_NAME"xterm-256color", TRUE(!(0))); |
267 | |
268 | char version[7]; |
269 | g_snprintf (version, sizeof (version), "%u", BTE_VERSION_NUMERIC(((0)) * 10000 + ((64)) * 100 + ((0)))); |
270 | g_setenv ("BTE_VERSION", version, TRUE(!(0))); |
271 | } |
272 | |
273 | /* |
274 | * Pty::set_size: |
275 | * @rows: the desired number of rows |
276 | * @columns: the desired number of columns |
277 | * @cell_height_px: the height of a cell in px, or 0 for undetermined |
278 | * @cell_width_px: the width of a cell in px, or 0 for undetermined |
279 | * |
280 | * Attempts to resize the pseudo terminal's window size. If successful, the |
281 | * OS kernel will send #SIGWINCH to the child process group. |
282 | * |
283 | * Returns: %true on success, or %false on error with errno set |
284 | */ |
285 | bool |
286 | Pty::set_size(int rows, |
287 | int columns, |
288 | int cell_height_px, |
289 | int cell_width_px) const noexcept |
290 | { |
291 | auto master = fd(); |
292 | |
293 | struct winsize size; |
294 | memset(&size, 0, sizeof(size)); |
295 | size.ws_row = rows > 0 ? rows : 24; |
296 | size.ws_col = columns > 0 ? columns : 80; |
297 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
298 | "Setting size on fd %d to (%d,%d).\n",do { } while(0) |
299 | master, columns, rows)do { } while(0); |
300 | auto ret = ioctl(master, TIOCSWINSZ0x5414, &size); |
301 | |
302 | if (ret != 0) { |
303 | auto errsv = bte::libc::ErrnoSaver{}; |
304 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
305 | "Failed to set size on %d: %s\n",do { } while(0) |
306 | master, g_strerror(errsv))do { } while(0); |
307 | } |
308 | |
309 | return ret == 0; |
310 | } |
311 | |
312 | /* |
313 | * Pty::get_size: |
314 | * @rows: (out) (allow-none): a location to store the number of rows, or %NULL |
315 | * @columns: (out) (allow-none): a location to store the number of columns, or %NULL |
316 | * |
317 | * Reads the pseudo terminal's window size. |
318 | * |
319 | * If getting the window size failed, @error will be set to a #GIOError. |
320 | * |
321 | * Returns: %true on success, or %false on error with errno set |
322 | */ |
323 | bool |
324 | Pty::get_size(int* rows, |
325 | int* columns) const noexcept |
326 | { |
327 | auto master = fd(); |
328 | |
329 | struct winsize size; |
330 | memset(&size, 0, sizeof(size)); |
331 | auto ret = ioctl(master, TIOCGWINSZ0x5413, &size); |
332 | if (ret == 0) { |
333 | if (columns != nullptr) { |
334 | *columns = size.ws_col; |
335 | } |
336 | if (rows != nullptr) { |
337 | *rows = size.ws_row; |
338 | } |
339 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
340 | "Size on fd %d is (%d,%d).\n",do { } while(0) |
341 | master, size.ws_col, size.ws_row)do { } while(0); |
342 | return true; |
343 | } |
344 | |
345 | auto errsv = bte::libc::ErrnoSaver{}; |
346 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
347 | "Failed to read size from fd %d: %s\n",do { } while(0) |
348 | master, g_strerror(errsv))do { } while(0); |
349 | |
350 | return false; |
351 | } |
352 | |
353 | static int |
354 | fd_set_cpkt(bte::libc::FD& fd) |
355 | { |
356 | /* tty_ioctl(4) -> every read() gives an extra byte at the beginning |
357 | * notifying us of stop/start (^S/^Q) events. */ |
358 | int one = 1; |
359 | return ioctl(fd.get(), TIOCPKT0x5420, &one); |
360 | } |
361 | |
362 | static int |
363 | fd_setup(bte::libc::FD& fd) |
364 | { |
365 | if (grantpt(fd.get()) != 0) { |
366 | auto errsv = bte::libc::ErrnoSaver{}; |
367 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
368 | "grantpt", g_strerror(errsv))do { } while(0); |
369 | return -1; |
370 | } |
371 | |
372 | if (unlockpt(fd.get()) != 0) { |
373 | auto errsv = bte::libc::ErrnoSaver{}; |
374 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
375 | "unlockpt", g_strerror(errsv))do { } while(0); |
376 | return -1; |
377 | } |
378 | |
379 | if (bte::libc::fd_set_cloexec(fd.get()) < 0) { |
380 | auto errsv = bte::libc::ErrnoSaver{}; |
381 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
382 | "%s failed: %s",do { } while(0) |
383 | "Setting CLOEXEC flag", g_strerror(errsv))do { } while(0); |
384 | return -1; |
385 | } |
386 | |
387 | if (bte::libc::fd_set_nonblock(fd.get()) < 0) { |
388 | auto errsv = bte::libc::ErrnoSaver{}; |
389 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
390 | "%s failed: %s",do { } while(0) |
391 | "Setting O_NONBLOCK flag", g_strerror(errsv))do { } while(0); |
392 | return -1; |
393 | } |
394 | |
395 | if (fd_set_cpkt(fd) < 0) { |
396 | auto errsv = bte::libc::ErrnoSaver{}; |
397 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
398 | "%s failed: %s",do { } while(0) |
399 | "ioctl(TIOCPKT)", g_strerror(errsv))do { } while(0); |
400 | return -1; |
401 | } |
402 | |
403 | return 0; |
404 | } |
405 | |
406 | /* |
407 | * _bte_pty_open_posix: |
408 | * @pty: a #BtePty |
409 | * @error: a location to store a #GError, or %NULL |
410 | * |
411 | * Opens a new file descriptor to a new PTY master. |
412 | * |
413 | * Returns: the new PTY's master FD, or -1 |
414 | */ |
415 | static bte::libc::FD |
416 | _bte_pty_open_posix(void) |
417 | { |
418 | /* Attempt to open the master. */ |
419 | auto fd = bte::libc::FD{posix_openpt(O_RDWR02 | O_NOCTTY0400 | O_NONBLOCK04000 | O_CLOEXEC02000000)}; |
420 | #ifndef __linux__1 |
421 | /* Other kernels may not support CLOEXEC or NONBLOCK above, so try to fall back */ |
422 | bool need_cloexec = false, need_nonblocking = false; |
423 | if (!fd && errno(*__errno_location ()) == EINVAL22) { |
424 | /* Try without NONBLOCK and apply the flag afterward */ |
425 | need_nonblocking = true; |
426 | fd = posix_openpt(O_RDWR02 | O_NOCTTY0400 | O_CLOEXEC02000000); |
427 | if (!fd && errno(*__errno_location ()) == EINVAL22) { |
428 | /* Try without CLOEXEC and apply the flag afterwards */ |
429 | need_cloexec = true; |
430 | fd = posix_openpt(O_RDWR02 | O_NOCTTY0400); |
431 | } |
432 | } |
433 | #endif /* !linux */ |
434 | |
435 | if (!fd) { |
436 | auto errsv = bte::libc::ErrnoSaver{}; |
437 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
438 | "%s failed: %s",do { } while(0) |
439 | "posix_openpt", g_strerror(errsv))do { } while(0); |
440 | return {}; |
441 | } |
442 | |
443 | #ifndef __linux__1 |
444 | if (need_cloexec && bte::libc::fd_set_cloexec(fd.get()) < 0) { |
445 | auto errsv = bte::libc::ErrnoSaver{}; |
446 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
447 | "%s failed: %s",do { } while(0) |
448 | "Setting CLOEXEC flag", g_strerror(errsv))do { } while(0); |
449 | return {}; |
450 | } |
451 | |
452 | if (need_nonblocking && bte::libc::fd_set_nonblock(fd.get()) < 0) { |
453 | auto errsv = bte::libc::ErrnoSaver{}; |
454 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
455 | "%s failed: %s",do { } while(0) |
456 | "Setting NONBLOCK flag", g_strerror(errsv))do { } while(0); |
457 | return {}; |
458 | } |
459 | #endif /* !linux */ |
460 | |
461 | if (fd_set_cpkt(fd) < 0) { |
462 | auto errsv = bte::libc::ErrnoSaver{}; |
463 | _bte_debug_print(BTE_DEBUG_PTY,do { } while(0) |
464 | "%s failed: %s",do { } while(0) |
465 | "ioctl(TIOCPKT)", g_strerror(errsv))do { } while(0); |
466 | return {}; |
467 | } |
468 | |
469 | if (grantpt(fd.get()) != 0) { |
470 | auto errsv = bte::libc::ErrnoSaver{}; |
471 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
472 | "grantpt", g_strerror(errsv))do { } while(0); |
473 | return {}; |
474 | } |
475 | |
476 | if (unlockpt(fd.get()) != 0) { |
477 | auto errsv = bte::libc::ErrnoSaver{}; |
478 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s\n",do { } while(0) |
479 | "unlockpt", g_strerror(errsv))do { } while(0); |
480 | return {}; |
481 | } |
482 | |
483 | _bte_debug_print(BTE_DEBUG_PTY, "Allocated pty on fd %d.\n", fd.get())do { } while(0); |
484 | |
485 | return fd; |
486 | } |
487 | |
488 | static bte::libc::FD |
489 | _bte_pty_open_foreign(int masterfd /* consumed */) |
490 | { |
491 | auto fd = bte::libc::FD{masterfd}; |
492 | if (!fd) { |
493 | errno(*__errno_location ()) = EBADF9; |
494 | return {}; |
495 | } |
496 | |
497 | if (fd_setup(fd) < 0) |
498 | return {}; |
499 | |
500 | return fd; |
501 | } |
502 | |
503 | /* |
504 | * Pty::set_utf8: |
505 | * @utf8: whether or not the pty is in UTF-8 mode |
506 | * |
507 | * Tells the kernel whether the terminal is UTF-8 or not, in case it can make |
508 | * use of the info. Linux 2.6.5 or so defines IUTF8 to make the line |
509 | * discipline do multibyte backspace correctly. |
510 | * |
511 | * Returns: %true on success, or %false on error with errno set |
512 | */ |
513 | bool |
514 | Pty::set_utf8(bool utf8) const noexcept |
515 | { |
516 | #ifdef IUTF80040000 |
517 | struct termios tio; |
518 | if (tcgetattr(fd(), &tio) == -1) { |
519 | auto errsv = bte::libc::ErrnoSaver{}; |
520 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s",do { } while(0) |
521 | "tcgetattr", g_strerror(errsv))do { } while(0); |
522 | return false; |
523 | } |
524 | |
525 | auto saved_cflag = tio.c_iflag; |
526 | if (utf8) { |
527 | tio.c_iflag |= IUTF80040000; |
528 | } else { |
529 | tio.c_iflag &= ~IUTF80040000; |
530 | } |
531 | |
532 | /* Only set the flag if it changes */ |
533 | if (saved_cflag != tio.c_iflag && |
534 | tcsetattr(fd(), TCSANOW0, &tio) == -1) { |
535 | auto errsv = bte::libc::ErrnoSaver{}; |
536 | _bte_debug_print(BTE_DEBUG_PTY, "%s failed: %s",do { } while(0) |
537 | "tcsetattr", g_strerror(errsv))do { } while(0); |
538 | return false; |
539 | } |
540 | #endif |
541 | |
542 | return true; |
543 | } |
544 | |
545 | Pty* |
546 | Pty::create(BtePtyFlags flags) |
547 | { |
548 | auto fd = _bte_pty_open_posix(); |
549 | if (!fd) |
550 | return nullptr; |
551 | |
552 | return new Pty{std::move(fd), flags}; |
553 | } |
554 | |
555 | Pty* |
556 | Pty::create_foreign(int foreign_fd, |
557 | BtePtyFlags flags) |
558 | { |
559 | auto fd = _bte_pty_open_foreign(foreign_fd); |
560 | if (!fd) |
561 | return nullptr; |
562 | |
563 | return new Pty{std::move(fd), flags}; |
564 | } |
565 | |
566 | } // namespace bte::base |