1e66f31c5Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2e66f31c5Sopenharmony_ci *
3e66f31c5Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
4e66f31c5Sopenharmony_ci * of this software and associated documentation files (the "Software"), to
5e66f31c5Sopenharmony_ci * deal in the Software without restriction, including without limitation the
6e66f31c5Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7e66f31c5Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
8e66f31c5Sopenharmony_ci * furnished to do so, subject to the following conditions:
9e66f31c5Sopenharmony_ci *
10e66f31c5Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
11e66f31c5Sopenharmony_ci * all copies or substantial portions of the Software.
12e66f31c5Sopenharmony_ci *
13e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14e66f31c5Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15e66f31c5Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16e66f31c5Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17e66f31c5Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18e66f31c5Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19e66f31c5Sopenharmony_ci * IN THE SOFTWARE.
20e66f31c5Sopenharmony_ci */
21e66f31c5Sopenharmony_ci
22e66f31c5Sopenharmony_ci#include "uv.h"
23e66f31c5Sopenharmony_ci#include "internal.h"
24e66f31c5Sopenharmony_ci
25e66f31c5Sopenharmony_ci#include <stdatomic.h>
26e66f31c5Sopenharmony_ci#include <stdlib.h>
27e66f31c5Sopenharmony_ci#include <assert.h>
28e66f31c5Sopenharmony_ci#include <unistd.h>
29e66f31c5Sopenharmony_ci#include <termios.h>
30e66f31c5Sopenharmony_ci#include <errno.h>
31e66f31c5Sopenharmony_ci#include <sys/ioctl.h>
32e66f31c5Sopenharmony_ci
33e66f31c5Sopenharmony_ci#if defined(__MVS__) && !defined(IMAXBEL)
34e66f31c5Sopenharmony_ci#define IMAXBEL 0
35e66f31c5Sopenharmony_ci#endif
36e66f31c5Sopenharmony_ci
37e66f31c5Sopenharmony_ci#if defined(__PASE__)
38e66f31c5Sopenharmony_ci/* On IBM i PASE, for better compatibility with running interactive programs in
39e66f31c5Sopenharmony_ci * a 5250 environment, isatty() will return true for the stdin/stdout/stderr
40e66f31c5Sopenharmony_ci * streams created by QSH/QP2TERM.
41e66f31c5Sopenharmony_ci *
42e66f31c5Sopenharmony_ci * For more, see docs on PASE_STDIO_ISATTY in
43e66f31c5Sopenharmony_ci * https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
44e66f31c5Sopenharmony_ci *
45e66f31c5Sopenharmony_ci * This behavior causes problems for Node as it expects that if isatty() returns
46e66f31c5Sopenharmony_ci * true that TTY ioctls will be supported by that fd (which is not an
47e66f31c5Sopenharmony_ci * unreasonable expectation) and when they don't it crashes with assertion
48e66f31c5Sopenharmony_ci * errors.
49e66f31c5Sopenharmony_ci *
50e66f31c5Sopenharmony_ci * Here, we create our own version of isatty() that uses ioctl() to identify
51e66f31c5Sopenharmony_ci * whether the fd is *really* a TTY or not.
52e66f31c5Sopenharmony_ci */
53e66f31c5Sopenharmony_cistatic int isreallyatty(int file) {
54e66f31c5Sopenharmony_ci  int rc;
55e66f31c5Sopenharmony_ci
56e66f31c5Sopenharmony_ci  rc = !ioctl(file, TXISATTY + 0x81, NULL);
57e66f31c5Sopenharmony_ci  if (!rc && errno != EBADF)
58e66f31c5Sopenharmony_ci      errno = ENOTTY;
59e66f31c5Sopenharmony_ci
60e66f31c5Sopenharmony_ci  return rc;
61e66f31c5Sopenharmony_ci}
62e66f31c5Sopenharmony_ci#define isatty(fd) isreallyatty(fd)
63e66f31c5Sopenharmony_ci#endif
64e66f31c5Sopenharmony_ci
65e66f31c5Sopenharmony_cistatic int orig_termios_fd = -1;
66e66f31c5Sopenharmony_cistatic struct termios orig_termios;
67e66f31c5Sopenharmony_cistatic _Atomic int termios_spinlock;
68e66f31c5Sopenharmony_ci
69e66f31c5Sopenharmony_ciint uv__tcsetattr(int fd, int how, const struct termios *term) {
70e66f31c5Sopenharmony_ci  int rc;
71e66f31c5Sopenharmony_ci
72e66f31c5Sopenharmony_ci  do
73e66f31c5Sopenharmony_ci    rc = tcsetattr(fd, how, term);
74e66f31c5Sopenharmony_ci  while (rc == -1 && errno == EINTR);
75e66f31c5Sopenharmony_ci
76e66f31c5Sopenharmony_ci  if (rc == -1)
77e66f31c5Sopenharmony_ci    return UV__ERR(errno);
78e66f31c5Sopenharmony_ci
79e66f31c5Sopenharmony_ci  return 0;
80e66f31c5Sopenharmony_ci}
81e66f31c5Sopenharmony_ci
82e66f31c5Sopenharmony_cistatic int uv__tty_is_slave(const int fd) {
83e66f31c5Sopenharmony_ci  int result;
84e66f31c5Sopenharmony_ci#if defined(__linux__) || defined(__FreeBSD__)
85e66f31c5Sopenharmony_ci  int dummy;
86e66f31c5Sopenharmony_ci
87e66f31c5Sopenharmony_ci  result = ioctl(fd, TIOCGPTN, &dummy) != 0;
88e66f31c5Sopenharmony_ci#elif defined(__APPLE__)
89e66f31c5Sopenharmony_ci  char dummy[256];
90e66f31c5Sopenharmony_ci
91e66f31c5Sopenharmony_ci  result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
92e66f31c5Sopenharmony_ci#elif defined(__NetBSD__)
93e66f31c5Sopenharmony_ci  /*
94e66f31c5Sopenharmony_ci   * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
95e66f31c5Sopenharmony_ci   * device name for both descriptors, the master one and slave one.
96e66f31c5Sopenharmony_ci   *
97e66f31c5Sopenharmony_ci   * Implement function to compare major device number with pts devices.
98e66f31c5Sopenharmony_ci   *
99e66f31c5Sopenharmony_ci   * The major numbers are machine-dependent, on NetBSD/amd64 they are
100e66f31c5Sopenharmony_ci   * respectively:
101e66f31c5Sopenharmony_ci   *  - master tty: ptc - major 6
102e66f31c5Sopenharmony_ci   *  - slave tty:  pts - major 5
103e66f31c5Sopenharmony_ci   */
104e66f31c5Sopenharmony_ci
105e66f31c5Sopenharmony_ci  struct stat sb;
106e66f31c5Sopenharmony_ci  /* Lookup device's major for the pts driver and cache it. */
107e66f31c5Sopenharmony_ci  static devmajor_t pts = NODEVMAJOR;
108e66f31c5Sopenharmony_ci
109e66f31c5Sopenharmony_ci  if (pts == NODEVMAJOR) {
110e66f31c5Sopenharmony_ci    pts = getdevmajor("pts", S_IFCHR);
111e66f31c5Sopenharmony_ci    if (pts == NODEVMAJOR)
112e66f31c5Sopenharmony_ci      abort();
113e66f31c5Sopenharmony_ci  }
114e66f31c5Sopenharmony_ci
115e66f31c5Sopenharmony_ci  /* Lookup stat structure behind the file descriptor. */
116e66f31c5Sopenharmony_ci  if (uv__fstat(fd, &sb) != 0)
117e66f31c5Sopenharmony_ci    abort();
118e66f31c5Sopenharmony_ci
119e66f31c5Sopenharmony_ci  /* Assert character device. */
120e66f31c5Sopenharmony_ci  if (!S_ISCHR(sb.st_mode))
121e66f31c5Sopenharmony_ci    abort();
122e66f31c5Sopenharmony_ci
123e66f31c5Sopenharmony_ci  /* Assert valid major. */
124e66f31c5Sopenharmony_ci  if (major(sb.st_rdev) == NODEVMAJOR)
125e66f31c5Sopenharmony_ci    abort();
126e66f31c5Sopenharmony_ci
127e66f31c5Sopenharmony_ci  result = (pts == major(sb.st_rdev));
128e66f31c5Sopenharmony_ci#else
129e66f31c5Sopenharmony_ci  /* Fallback to ptsname
130e66f31c5Sopenharmony_ci   */
131e66f31c5Sopenharmony_ci  result = ptsname(fd) == NULL;
132e66f31c5Sopenharmony_ci#endif
133e66f31c5Sopenharmony_ci  return result;
134e66f31c5Sopenharmony_ci}
135e66f31c5Sopenharmony_ci
136e66f31c5Sopenharmony_ciint uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
137e66f31c5Sopenharmony_ci  uv_handle_type type;
138e66f31c5Sopenharmony_ci  int flags;
139e66f31c5Sopenharmony_ci  int newfd;
140e66f31c5Sopenharmony_ci  int r;
141e66f31c5Sopenharmony_ci  int saved_flags;
142e66f31c5Sopenharmony_ci  int mode;
143e66f31c5Sopenharmony_ci  char path[256];
144e66f31c5Sopenharmony_ci  (void)unused; /* deprecated parameter is no longer needed */
145e66f31c5Sopenharmony_ci
146e66f31c5Sopenharmony_ci  /* File descriptors that refer to files cannot be monitored with epoll.
147e66f31c5Sopenharmony_ci   * That restriction also applies to character devices like /dev/random
148e66f31c5Sopenharmony_ci   * (but obviously not /dev/tty.)
149e66f31c5Sopenharmony_ci   */
150e66f31c5Sopenharmony_ci  type = uv_guess_handle(fd);
151e66f31c5Sopenharmony_ci  if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
152e66f31c5Sopenharmony_ci    return UV_EINVAL;
153e66f31c5Sopenharmony_ci
154e66f31c5Sopenharmony_ci  flags = 0;
155e66f31c5Sopenharmony_ci  newfd = -1;
156e66f31c5Sopenharmony_ci
157e66f31c5Sopenharmony_ci  /* Save the fd flags in case we need to restore them due to an error. */
158e66f31c5Sopenharmony_ci  do
159e66f31c5Sopenharmony_ci    saved_flags = fcntl(fd, F_GETFL);
160e66f31c5Sopenharmony_ci  while (saved_flags == -1 && errno == EINTR);
161e66f31c5Sopenharmony_ci
162e66f31c5Sopenharmony_ci  if (saved_flags == -1)
163e66f31c5Sopenharmony_ci    return UV__ERR(errno);
164e66f31c5Sopenharmony_ci  mode = saved_flags & O_ACCMODE;
165e66f31c5Sopenharmony_ci
166e66f31c5Sopenharmony_ci  /* Reopen the file descriptor when it refers to a tty. This lets us put the
167e66f31c5Sopenharmony_ci   * tty in non-blocking mode without affecting other processes that share it
168e66f31c5Sopenharmony_ci   * with us.
169e66f31c5Sopenharmony_ci   *
170e66f31c5Sopenharmony_ci   * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
171e66f31c5Sopenharmony_ci   * affects fd 1 of `cat` because both file descriptors refer to the same
172e66f31c5Sopenharmony_ci   * struct file in the kernel. When we reopen our fd 0, it points to a
173e66f31c5Sopenharmony_ci   * different struct file, hence changing its properties doesn't affect
174e66f31c5Sopenharmony_ci   * other processes.
175e66f31c5Sopenharmony_ci   */
176e66f31c5Sopenharmony_ci  if (type == UV_TTY) {
177e66f31c5Sopenharmony_ci    /* Reopening a pty in master mode won't work either because the reopened
178e66f31c5Sopenharmony_ci     * pty will be in slave mode (*BSD) or reopening will allocate a new
179e66f31c5Sopenharmony_ci     * master/slave pair (Linux). Therefore check if the fd points to a
180e66f31c5Sopenharmony_ci     * slave device.
181e66f31c5Sopenharmony_ci     */
182e66f31c5Sopenharmony_ci    if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
183e66f31c5Sopenharmony_ci      r = uv__open_cloexec(path, mode | O_NOCTTY);
184e66f31c5Sopenharmony_ci    else
185e66f31c5Sopenharmony_ci      r = -1;
186e66f31c5Sopenharmony_ci
187e66f31c5Sopenharmony_ci    if (r < 0) {
188e66f31c5Sopenharmony_ci      /* fallback to using blocking writes */
189e66f31c5Sopenharmony_ci      if (mode != O_RDONLY)
190e66f31c5Sopenharmony_ci        flags |= UV_HANDLE_BLOCKING_WRITES;
191e66f31c5Sopenharmony_ci      goto skip;
192e66f31c5Sopenharmony_ci    }
193e66f31c5Sopenharmony_ci
194e66f31c5Sopenharmony_ci    newfd = r;
195e66f31c5Sopenharmony_ci
196e66f31c5Sopenharmony_ci    r = uv__dup2_cloexec(newfd, fd);
197e66f31c5Sopenharmony_ci    if (r < 0 && r != UV_EINVAL) {
198e66f31c5Sopenharmony_ci      /* EINVAL means newfd == fd which could conceivably happen if another
199e66f31c5Sopenharmony_ci       * thread called close(fd) between our calls to isatty() and open().
200e66f31c5Sopenharmony_ci       * That's a rather unlikely event but let's handle it anyway.
201e66f31c5Sopenharmony_ci       */
202e66f31c5Sopenharmony_ci      uv__close(newfd);
203e66f31c5Sopenharmony_ci      return r;
204e66f31c5Sopenharmony_ci    }
205e66f31c5Sopenharmony_ci
206e66f31c5Sopenharmony_ci    fd = newfd;
207e66f31c5Sopenharmony_ci  }
208e66f31c5Sopenharmony_ci
209e66f31c5Sopenharmony_ciskip:
210e66f31c5Sopenharmony_ci  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
211e66f31c5Sopenharmony_ci
212e66f31c5Sopenharmony_ci  /* If anything fails beyond this point we need to remove the handle from
213e66f31c5Sopenharmony_ci   * the handle queue, since it was added by uv__handle_init in uv_stream_init.
214e66f31c5Sopenharmony_ci   */
215e66f31c5Sopenharmony_ci
216e66f31c5Sopenharmony_ci  if (!(flags & UV_HANDLE_BLOCKING_WRITES))
217e66f31c5Sopenharmony_ci    uv__nonblock(fd, 1);
218e66f31c5Sopenharmony_ci
219e66f31c5Sopenharmony_ci#if defined(__APPLE__)
220e66f31c5Sopenharmony_ci  r = uv__stream_try_select((uv_stream_t*) tty, &fd);
221e66f31c5Sopenharmony_ci  if (r) {
222e66f31c5Sopenharmony_ci    int rc = r;
223e66f31c5Sopenharmony_ci    if (newfd != -1)
224e66f31c5Sopenharmony_ci      uv__close(newfd);
225e66f31c5Sopenharmony_ci    uv__queue_remove(&tty->handle_queue);
226e66f31c5Sopenharmony_ci    do
227e66f31c5Sopenharmony_ci      r = fcntl(fd, F_SETFL, saved_flags);
228e66f31c5Sopenharmony_ci    while (r == -1 && errno == EINTR);
229e66f31c5Sopenharmony_ci    return rc;
230e66f31c5Sopenharmony_ci  }
231e66f31c5Sopenharmony_ci#endif
232e66f31c5Sopenharmony_ci
233e66f31c5Sopenharmony_ci  if (mode != O_WRONLY)
234e66f31c5Sopenharmony_ci    flags |= UV_HANDLE_READABLE;
235e66f31c5Sopenharmony_ci  if (mode != O_RDONLY)
236e66f31c5Sopenharmony_ci    flags |= UV_HANDLE_WRITABLE;
237e66f31c5Sopenharmony_ci
238e66f31c5Sopenharmony_ci  uv__stream_open((uv_stream_t*) tty, fd, flags);
239e66f31c5Sopenharmony_ci  tty->mode = UV_TTY_MODE_NORMAL;
240e66f31c5Sopenharmony_ci
241e66f31c5Sopenharmony_ci  return 0;
242e66f31c5Sopenharmony_ci}
243e66f31c5Sopenharmony_ci
244e66f31c5Sopenharmony_cistatic void uv__tty_make_raw(struct termios* tio) {
245e66f31c5Sopenharmony_ci  assert(tio != NULL);
246e66f31c5Sopenharmony_ci
247e66f31c5Sopenharmony_ci#if defined __sun || defined __MVS__
248e66f31c5Sopenharmony_ci  /*
249e66f31c5Sopenharmony_ci   * This implementation of cfmakeraw for Solaris and derivatives is taken from
250e66f31c5Sopenharmony_ci   * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
251e66f31c5Sopenharmony_ci   */
252e66f31c5Sopenharmony_ci  tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
253e66f31c5Sopenharmony_ci                    IGNCR | ICRNL | IXON);
254e66f31c5Sopenharmony_ci  tio->c_oflag &= ~OPOST;
255e66f31c5Sopenharmony_ci  tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
256e66f31c5Sopenharmony_ci  tio->c_cflag &= ~(CSIZE | PARENB);
257e66f31c5Sopenharmony_ci  tio->c_cflag |= CS8;
258e66f31c5Sopenharmony_ci
259e66f31c5Sopenharmony_ci  /*
260e66f31c5Sopenharmony_ci   * By default, most software expects a pending read to block until at
261e66f31c5Sopenharmony_ci   * least one byte becomes available.  As per termio(7I), this requires
262e66f31c5Sopenharmony_ci   * setting the MIN and TIME parameters appropriately.
263e66f31c5Sopenharmony_ci   *
264e66f31c5Sopenharmony_ci   * As a somewhat unfortunate artifact of history, the MIN and TIME slots
265e66f31c5Sopenharmony_ci   * in the control character array overlap with the EOF and EOL slots used
266e66f31c5Sopenharmony_ci   * for canonical mode processing.  Because the EOF character needs to be
267e66f31c5Sopenharmony_ci   * the ASCII EOT value (aka Control-D), it has the byte value 4.  When
268e66f31c5Sopenharmony_ci   * switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
269e66f31c5Sopenharmony_ci   * reads will block until at least four bytes have been input.
270e66f31c5Sopenharmony_ci   *
271e66f31c5Sopenharmony_ci   * Other platforms with a distinct MIN slot like Linux and FreeBSD appear
272e66f31c5Sopenharmony_ci   * to default to a MIN value of 1, so we'll force that value here:
273e66f31c5Sopenharmony_ci   */
274e66f31c5Sopenharmony_ci  tio->c_cc[VMIN] = 1;
275e66f31c5Sopenharmony_ci  tio->c_cc[VTIME] = 0;
276e66f31c5Sopenharmony_ci#else
277e66f31c5Sopenharmony_ci  cfmakeraw(tio);
278e66f31c5Sopenharmony_ci#endif /* #ifdef __sun */
279e66f31c5Sopenharmony_ci}
280e66f31c5Sopenharmony_ci
281e66f31c5Sopenharmony_ciint uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
282e66f31c5Sopenharmony_ci  struct termios tmp;
283e66f31c5Sopenharmony_ci  int expected;
284e66f31c5Sopenharmony_ci  int fd;
285e66f31c5Sopenharmony_ci  int rc;
286e66f31c5Sopenharmony_ci
287e66f31c5Sopenharmony_ci  if (tty->mode == (int) mode)
288e66f31c5Sopenharmony_ci    return 0;
289e66f31c5Sopenharmony_ci
290e66f31c5Sopenharmony_ci  fd = uv__stream_fd(tty);
291e66f31c5Sopenharmony_ci  if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
292e66f31c5Sopenharmony_ci    do
293e66f31c5Sopenharmony_ci      rc = tcgetattr(fd, &tty->orig_termios);
294e66f31c5Sopenharmony_ci    while (rc == -1 && errno == EINTR);
295e66f31c5Sopenharmony_ci
296e66f31c5Sopenharmony_ci    if (rc == -1)
297e66f31c5Sopenharmony_ci      return UV__ERR(errno);
298e66f31c5Sopenharmony_ci
299e66f31c5Sopenharmony_ci    /* This is used for uv_tty_reset_mode() */
300e66f31c5Sopenharmony_ci    do
301e66f31c5Sopenharmony_ci      expected = 0;
302e66f31c5Sopenharmony_ci    while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1));
303e66f31c5Sopenharmony_ci
304e66f31c5Sopenharmony_ci    if (orig_termios_fd == -1) {
305e66f31c5Sopenharmony_ci      orig_termios = tty->orig_termios;
306e66f31c5Sopenharmony_ci      orig_termios_fd = fd;
307e66f31c5Sopenharmony_ci    }
308e66f31c5Sopenharmony_ci
309e66f31c5Sopenharmony_ci    atomic_store(&termios_spinlock, 0);
310e66f31c5Sopenharmony_ci  }
311e66f31c5Sopenharmony_ci
312e66f31c5Sopenharmony_ci  tmp = tty->orig_termios;
313e66f31c5Sopenharmony_ci  switch (mode) {
314e66f31c5Sopenharmony_ci    case UV_TTY_MODE_NORMAL:
315e66f31c5Sopenharmony_ci      break;
316e66f31c5Sopenharmony_ci    case UV_TTY_MODE_RAW:
317e66f31c5Sopenharmony_ci      tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
318e66f31c5Sopenharmony_ci      tmp.c_oflag |= (ONLCR);
319e66f31c5Sopenharmony_ci      tmp.c_cflag |= (CS8);
320e66f31c5Sopenharmony_ci      tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
321e66f31c5Sopenharmony_ci      tmp.c_cc[VMIN] = 1;
322e66f31c5Sopenharmony_ci      tmp.c_cc[VTIME] = 0;
323e66f31c5Sopenharmony_ci      break;
324e66f31c5Sopenharmony_ci    case UV_TTY_MODE_IO:
325e66f31c5Sopenharmony_ci      uv__tty_make_raw(&tmp);
326e66f31c5Sopenharmony_ci      break;
327e66f31c5Sopenharmony_ci  }
328e66f31c5Sopenharmony_ci
329e66f31c5Sopenharmony_ci  /* Apply changes after draining */
330e66f31c5Sopenharmony_ci  rc = uv__tcsetattr(fd, TCSADRAIN, &tmp);
331e66f31c5Sopenharmony_ci  if (rc == 0)
332e66f31c5Sopenharmony_ci    tty->mode = mode;
333e66f31c5Sopenharmony_ci
334e66f31c5Sopenharmony_ci  return rc;
335e66f31c5Sopenharmony_ci}
336e66f31c5Sopenharmony_ci
337e66f31c5Sopenharmony_ci
338e66f31c5Sopenharmony_ciint uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
339e66f31c5Sopenharmony_ci  struct winsize ws;
340e66f31c5Sopenharmony_ci  int err;
341e66f31c5Sopenharmony_ci
342e66f31c5Sopenharmony_ci  do
343e66f31c5Sopenharmony_ci    err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
344e66f31c5Sopenharmony_ci  while (err == -1 && errno == EINTR);
345e66f31c5Sopenharmony_ci
346e66f31c5Sopenharmony_ci  if (err == -1)
347e66f31c5Sopenharmony_ci    return UV__ERR(errno);
348e66f31c5Sopenharmony_ci
349e66f31c5Sopenharmony_ci  *width = ws.ws_col;
350e66f31c5Sopenharmony_ci  *height = ws.ws_row;
351e66f31c5Sopenharmony_ci
352e66f31c5Sopenharmony_ci  return 0;
353e66f31c5Sopenharmony_ci}
354e66f31c5Sopenharmony_ci
355e66f31c5Sopenharmony_ci
356e66f31c5Sopenharmony_ciuv_handle_type uv_guess_handle(uv_file file) {
357e66f31c5Sopenharmony_ci  struct sockaddr_storage ss;
358e66f31c5Sopenharmony_ci  struct stat s;
359e66f31c5Sopenharmony_ci  socklen_t len;
360e66f31c5Sopenharmony_ci  int type;
361e66f31c5Sopenharmony_ci
362e66f31c5Sopenharmony_ci  if (file < 0)
363e66f31c5Sopenharmony_ci    return UV_UNKNOWN_HANDLE;
364e66f31c5Sopenharmony_ci
365e66f31c5Sopenharmony_ci  if (isatty(file))
366e66f31c5Sopenharmony_ci    return UV_TTY;
367e66f31c5Sopenharmony_ci
368e66f31c5Sopenharmony_ci  if (uv__fstat(file, &s)) {
369e66f31c5Sopenharmony_ci#if defined(__PASE__)
370e66f31c5Sopenharmony_ci    /* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
371e66f31c5Sopenharmony_ci     * an error state. fstat will return EINVAL, getsockname will also return
372e66f31c5Sopenharmony_ci     * EINVAL, even if sockaddr_storage is valid. (If file does not refer to a
373e66f31c5Sopenharmony_ci     * socket, ENOTSOCK is returned instead.)
374e66f31c5Sopenharmony_ci     * In such cases, we will permit the user to open the connection as uv_tcp
375e66f31c5Sopenharmony_ci     * still, so that the user can get immediately notified of the error in
376e66f31c5Sopenharmony_ci     * their read callback and close this fd.
377e66f31c5Sopenharmony_ci     */
378e66f31c5Sopenharmony_ci    len = sizeof(ss);
379e66f31c5Sopenharmony_ci    if (getsockname(file, (struct sockaddr*) &ss, &len)) {
380e66f31c5Sopenharmony_ci      if (errno == EINVAL)
381e66f31c5Sopenharmony_ci        return UV_TCP;
382e66f31c5Sopenharmony_ci    }
383e66f31c5Sopenharmony_ci#endif
384e66f31c5Sopenharmony_ci    return UV_UNKNOWN_HANDLE;
385e66f31c5Sopenharmony_ci  }
386e66f31c5Sopenharmony_ci
387e66f31c5Sopenharmony_ci  if (S_ISREG(s.st_mode))
388e66f31c5Sopenharmony_ci    return UV_FILE;
389e66f31c5Sopenharmony_ci
390e66f31c5Sopenharmony_ci  if (S_ISCHR(s.st_mode))
391e66f31c5Sopenharmony_ci    return UV_FILE;  /* XXX UV_NAMED_PIPE? */
392e66f31c5Sopenharmony_ci
393e66f31c5Sopenharmony_ci  if (S_ISFIFO(s.st_mode))
394e66f31c5Sopenharmony_ci    return UV_NAMED_PIPE;
395e66f31c5Sopenharmony_ci
396e66f31c5Sopenharmony_ci  if (!S_ISSOCK(s.st_mode))
397e66f31c5Sopenharmony_ci    return UV_UNKNOWN_HANDLE;
398e66f31c5Sopenharmony_ci
399e66f31c5Sopenharmony_ci  len = sizeof(ss);
400e66f31c5Sopenharmony_ci  if (getsockname(file, (struct sockaddr*) &ss, &len)) {
401e66f31c5Sopenharmony_ci#if defined(_AIX)
402e66f31c5Sopenharmony_ci    /* On aix receiving RST from TCP instead of FIN immediately puts fd into
403e66f31c5Sopenharmony_ci     * an error state. In such case getsockname will return EINVAL, even if
404e66f31c5Sopenharmony_ci     * sockaddr_storage is valid.
405e66f31c5Sopenharmony_ci     * In such cases, we will permit the user to open the connection as uv_tcp
406e66f31c5Sopenharmony_ci     * still, so that the user can get immediately notified of the error in
407e66f31c5Sopenharmony_ci     * their read callback and close this fd.
408e66f31c5Sopenharmony_ci     */
409e66f31c5Sopenharmony_ci    if (errno == EINVAL) {
410e66f31c5Sopenharmony_ci      return UV_TCP;
411e66f31c5Sopenharmony_ci    }
412e66f31c5Sopenharmony_ci#endif
413e66f31c5Sopenharmony_ci    return UV_UNKNOWN_HANDLE;
414e66f31c5Sopenharmony_ci  }
415e66f31c5Sopenharmony_ci
416e66f31c5Sopenharmony_ci  len = sizeof(type);
417e66f31c5Sopenharmony_ci  if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
418e66f31c5Sopenharmony_ci    return UV_UNKNOWN_HANDLE;
419e66f31c5Sopenharmony_ci
420e66f31c5Sopenharmony_ci  if (type == SOCK_DGRAM)
421e66f31c5Sopenharmony_ci    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
422e66f31c5Sopenharmony_ci      return UV_UDP;
423e66f31c5Sopenharmony_ci
424e66f31c5Sopenharmony_ci  if (type == SOCK_STREAM) {
425e66f31c5Sopenharmony_ci#if defined(_AIX) || defined(__DragonFly__)
426e66f31c5Sopenharmony_ci    /* on AIX/DragonFly the getsockname call returns an empty sa structure
427e66f31c5Sopenharmony_ci     * for sockets of type AF_UNIX.  For all other types it will
428e66f31c5Sopenharmony_ci     * return a properly filled in structure.
429e66f31c5Sopenharmony_ci     */
430e66f31c5Sopenharmony_ci    if (len == 0)
431e66f31c5Sopenharmony_ci      return UV_NAMED_PIPE;
432e66f31c5Sopenharmony_ci#endif /* defined(_AIX) || defined(__DragonFly__) */
433e66f31c5Sopenharmony_ci
434e66f31c5Sopenharmony_ci    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
435e66f31c5Sopenharmony_ci      return UV_TCP;
436e66f31c5Sopenharmony_ci    if (ss.ss_family == AF_UNIX)
437e66f31c5Sopenharmony_ci      return UV_NAMED_PIPE;
438e66f31c5Sopenharmony_ci  }
439e66f31c5Sopenharmony_ci
440e66f31c5Sopenharmony_ci  return UV_UNKNOWN_HANDLE;
441e66f31c5Sopenharmony_ci}
442e66f31c5Sopenharmony_ci
443e66f31c5Sopenharmony_ci
444e66f31c5Sopenharmony_ci/* This function is async signal-safe, meaning that it's safe to call from
445e66f31c5Sopenharmony_ci * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
446e66f31c5Sopenharmony_ci * critical section when the signal was raised.
447e66f31c5Sopenharmony_ci */
448e66f31c5Sopenharmony_ciint uv_tty_reset_mode(void) {
449e66f31c5Sopenharmony_ci  int saved_errno;
450e66f31c5Sopenharmony_ci  int err;
451e66f31c5Sopenharmony_ci
452e66f31c5Sopenharmony_ci  saved_errno = errno;
453e66f31c5Sopenharmony_ci
454e66f31c5Sopenharmony_ci  if (atomic_exchange(&termios_spinlock, 1))
455e66f31c5Sopenharmony_ci    return UV_EBUSY;  /* In uv_tty_set_mode(). */
456e66f31c5Sopenharmony_ci
457e66f31c5Sopenharmony_ci  err = 0;
458e66f31c5Sopenharmony_ci  if (orig_termios_fd != -1)
459e66f31c5Sopenharmony_ci    err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
460e66f31c5Sopenharmony_ci
461e66f31c5Sopenharmony_ci  atomic_store(&termios_spinlock, 0);
462e66f31c5Sopenharmony_ci  errno = saved_errno;
463e66f31c5Sopenharmony_ci
464e66f31c5Sopenharmony_ci  return err;
465e66f31c5Sopenharmony_ci}
466e66f31c5Sopenharmony_ci
467e66f31c5Sopenharmony_civoid uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
468e66f31c5Sopenharmony_ci}
469e66f31c5Sopenharmony_ci
470e66f31c5Sopenharmony_ciint uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
471e66f31c5Sopenharmony_ci  return UV_ENOTSUP;
472e66f31c5Sopenharmony_ci}
473