diff options
Diffstat (limited to 'third-party/libuv/src/unix/tty.c')
| -rw-r--r-- | third-party/libuv/src/unix/tty.c | 184 | 
1 files changed, 184 insertions, 0 deletions
| diff --git a/third-party/libuv/src/unix/tty.c b/third-party/libuv/src/unix/tty.c new file mode 100644 index 0000000000..ca9459dd0d --- /dev/null +++ b/third-party/libuv/src/unix/tty.c @@ -0,0 +1,184 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" +#include "spinlock.h" + +#include <assert.h> +#include <unistd.h> +#include <termios.h> +#include <errno.h> +#include <sys/ioctl.h> + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + + +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { +  uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); + +#if defined(__APPLE__) +  { +    int err = uv__stream_try_select((uv_stream_t*) tty, &fd); +    if (err) +      return err; +  } +#endif /* defined(__APPLE__) */ + +  if (readable) { +    uv__nonblock(fd, 1); +    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); +  } else { +    /* Note: writable tty we set to blocking mode. */ +    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE); +    tty->flags |= UV_STREAM_BLOCKING; +  } + +  tty->mode = 0; +  return 0; +} + + +int uv_tty_set_mode(uv_tty_t* tty, int mode) { +  struct termios raw; +  int fd; + +  fd = uv__stream_fd(tty); + +  if (mode && tty->mode == 0) {  /* on */ +    if (tcgetattr(fd, &tty->orig_termios)) +      return -errno; + +    /* This is used for uv_tty_reset_mode() */ +    uv_spinlock_lock(&termios_spinlock); +    if (orig_termios_fd == -1) { +      orig_termios = tty->orig_termios; +      orig_termios_fd = fd; +    } +    uv_spinlock_unlock(&termios_spinlock); + +    raw = tty->orig_termios; +    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); +    raw.c_oflag |= (ONLCR); +    raw.c_cflag |= (CS8); +    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); +    raw.c_cc[VMIN] = 1; +    raw.c_cc[VTIME] = 0; + +    /* Put terminal in raw mode after draining */ +    if (tcsetattr(fd, TCSADRAIN, &raw)) +      return -errno; + +    tty->mode = 1; +  } else if (mode == 0 && tty->mode) {  /* off */ +    /* Put terminal in original mode after flushing */ +    if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) +      return -errno; +    tty->mode = 0; +  } + +  return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { +  struct winsize ws; + +  if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws)) +    return -errno; + +  *width = ws.ws_col; +  *height = ws.ws_row; + +  return 0; +} + + +uv_handle_type uv_guess_handle(uv_file file) { +  struct sockaddr sa; +  struct stat s; +  socklen_t len; +  int type; + +  if (file < 0) +    return UV_UNKNOWN_HANDLE; + +  if (isatty(file)) +    return UV_TTY; + +  if (fstat(file, &s)) +    return UV_UNKNOWN_HANDLE; + +  if (S_ISREG(s.st_mode)) +    return UV_FILE; + +  if (S_ISCHR(s.st_mode)) +    return UV_FILE;  /* XXX UV_NAMED_PIPE? */ + +  if (S_ISFIFO(s.st_mode)) +    return UV_NAMED_PIPE; + +  if (!S_ISSOCK(s.st_mode)) +    return UV_UNKNOWN_HANDLE; + +  len = sizeof(type); +  if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) +    return UV_UNKNOWN_HANDLE; + +  len = sizeof(sa); +  if (getsockname(file, &sa, &len)) +    return UV_UNKNOWN_HANDLE; + +  if (type == SOCK_DGRAM) +    if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) +      return UV_UDP; + +  if (type == SOCK_STREAM) { +    if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) +      return UV_TCP; +    if (sa.sa_family == AF_UNIX) +      return UV_NAMED_PIPE; +  } + +  return UV_UNKNOWN_HANDLE; +} + + +/* This function is async signal-safe, meaning that it's safe to call from + * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s + * critical section when the signal was raised. + */ +int uv_tty_reset_mode(void) { +  int err; + +  if (!uv_spinlock_trylock(&termios_spinlock)) +    return -EBUSY;  /* In uv_tty_set_mode(). */ + +  err = 0; +  if (orig_termios_fd != -1) +    if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) +      err = -errno; + +  uv_spinlock_unlock(&termios_spinlock); +  return err; +} | 
