Rizin
unix-like reverse engineering framework and cli tools
tty.c
Go to the documentation of this file.
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "internal.h"
24 #include "spinlock.h"
25 
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <termios.h>
30 #include <errno.h>
31 #include <sys/ioctl.h>
32 
33 #if defined(__MVS__) && !defined(IMAXBEL)
34 #define IMAXBEL 0
35 #endif
36 
37 #if defined(__PASE__)
38 /* On IBM i PASE, for better compatibility with running interactive programs in
39  * a 5250 environment, isatty() will return true for the stdin/stdout/stderr
40  * streams created by QSH/QP2TERM.
41  *
42  * For more, see docs on PASE_STDIO_ISATTY in
43  * https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
44  *
45  * This behavior causes problems for Node as it expects that if isatty() returns
46  * true that TTY ioctls will be supported by that fd (which is not an
47  * unreasonable expectation) and when they don't it crashes with assertion
48  * errors.
49  *
50  * Here, we create our own version of isatty() that uses ioctl() to identify
51  * whether the fd is *really* a TTY or not.
52  */
53 static int isreallyatty(int file) {
54  int rc;
55 
56  rc = !ioctl(file, TXISATTY + 0x81, NULL);
57  if (!rc && errno != EBADF)
58  errno = ENOTTY;
59 
60  return rc;
61 }
62 #define isatty(fd) isreallyatty(fd)
63 #endif
64 
65 static int orig_termios_fd = -1;
66 static struct termios orig_termios;
68 
69 static int uv__tty_is_slave(const int fd) {
70  int result;
71 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
72  int dummy;
73 
74  result = ioctl(fd, TIOCGPTN, &dummy) != 0;
75 #elif defined(__APPLE__)
76  char dummy[256];
77 
78  result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
79 #elif defined(__NetBSD__)
80  /*
81  * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
82  * device name for both descriptors, the master one and slave one.
83  *
84  * Implement function to compare major device number with pts devices.
85  *
86  * The major numbers are machine-dependent, on NetBSD/amd64 they are
87  * respectively:
88  * - master tty: ptc - major 6
89  * - slave tty: pts - major 5
90  */
91 
92  struct stat sb;
93  /* Lookup device's major for the pts driver and cache it. */
94  static devmajor_t pts = NODEVMAJOR;
95 
96  if (pts == NODEVMAJOR) {
97  pts = getdevmajor("pts", S_IFCHR);
98  if (pts == NODEVMAJOR)
99  abort();
100  }
101 
102  /* Lookup stat structure behind the file descriptor. */
103  if (fstat(fd, &sb) != 0)
104  abort();
105 
106  /* Assert character device. */
107  if (!S_ISCHR(sb.st_mode))
108  abort();
109 
110  /* Assert valid major. */
111  if (major(sb.st_rdev) == NODEVMAJOR)
112  abort();
113 
114  result = (pts == major(sb.st_rdev));
115 #else
116  /* Fallback to ptsname
117  */
118  result = ptsname(fd) == NULL;
119 #endif
120  return result;
121 }
122 
123 int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
125  int flags;
126  int newfd;
127  int r;
128  int saved_flags;
129  int mode;
130  char path[256];
131  (void)unused; /* deprecated parameter is no longer needed */
132 
133  /* File descriptors that refer to files cannot be monitored with epoll.
134  * That restriction also applies to character devices like /dev/random
135  * (but obviously not /dev/tty.)
136  */
138  if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
139  return UV_EINVAL;
140 
141  flags = 0;
142  newfd = -1;
143 
144  /* Save the fd flags in case we need to restore them due to an error. */
145  do
146  saved_flags = fcntl(fd, F_GETFL);
147  while (saved_flags == -1 && errno == EINTR);
148 
149  if (saved_flags == -1)
150  return UV__ERR(errno);
151  mode = saved_flags & O_ACCMODE;
152 
153  /* Reopen the file descriptor when it refers to a tty. This lets us put the
154  * tty in non-blocking mode without affecting other processes that share it
155  * with us.
156  *
157  * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
158  * affects fd 1 of `cat` because both file descriptors refer to the same
159  * struct file in the kernel. When we reopen our fd 0, it points to a
160  * different struct file, hence changing its properties doesn't affect
161  * other processes.
162  */
163  if (type == UV_TTY) {
164  /* Reopening a pty in master mode won't work either because the reopened
165  * pty will be in slave mode (*BSD) or reopening will allocate a new
166  * master/slave pair (Linux). Therefore check if the fd points to a
167  * slave device.
168  */
169  if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
171  else
172  r = -1;
173 
174  if (r < 0) {
175  /* fallback to using blocking writes */
176  if (mode != O_RDONLY)
178  goto skip;
179  }
180 
181  newfd = r;
182 
183  r = uv__dup2_cloexec(newfd, fd);
184  if (r < 0 && r != UV_EINVAL) {
185  /* EINVAL means newfd == fd which could conceivably happen if another
186  * thread called close(fd) between our calls to isatty() and open().
187  * That's a rather unlikely event but let's handle it anyway.
188  */
189  uv__close(newfd);
190  return r;
191  }
192 
193  fd = newfd;
194  }
195 
196 skip:
197  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
198 
199  /* If anything fails beyond this point we need to remove the handle from
200  * the handle queue, since it was added by uv__handle_init in uv_stream_init.
201  */
202 
204  uv__nonblock(fd, 1);
205 
206 #if defined(__APPLE__)
207  r = uv__stream_try_select((uv_stream_t*) tty, &fd);
208  if (r) {
209  int rc = r;
210  if (newfd != -1)
211  uv__close(newfd);
212  QUEUE_REMOVE(&tty->handle_queue);
213  do
214  r = fcntl(fd, F_SETFL, saved_flags);
215  while (r == -1 && errno == EINTR);
216  return rc;
217  }
218 #endif
219 
220  if (mode != O_WRONLY)
222  if (mode != O_RDONLY)
224 
226  tty->mode = UV_TTY_MODE_NORMAL;
227 
228  return 0;
229 }
230 
231 static void uv__tty_make_raw(struct termios* tio) {
232  assert(tio != NULL);
233 
234 #if defined __sun || defined __MVS__
235  /*
236  * This implementation of cfmakeraw for Solaris and derivatives is taken from
237  * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
238  */
239  tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
240  IGNCR | ICRNL | IXON);
241  tio->c_oflag &= ~OPOST;
242  tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
243  tio->c_cflag &= ~(CSIZE | PARENB);
244  tio->c_cflag |= CS8;
245 #else
246  cfmakeraw(tio);
247 #endif /* #ifdef __sun */
248 }
249 
251  struct termios tmp;
252  int fd;
253 
254  if (tty->mode == (int) mode)
255  return 0;
256 
257  fd = uv__stream_fd(tty);
258  if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
259  if (tcgetattr(fd, &tty->orig_termios))
260  return UV__ERR(errno);
261 
262  /* This is used for uv_tty_reset_mode() */
263  uv_spinlock_lock(&termios_spinlock);
264  if (orig_termios_fd == -1) {
265  orig_termios = tty->orig_termios;
267  }
268  uv_spinlock_unlock(&termios_spinlock);
269  }
270 
271  tmp = tty->orig_termios;
272  switch (mode) {
273  case UV_TTY_MODE_NORMAL:
274  break;
275  case UV_TTY_MODE_RAW:
276  tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
277  tmp.c_oflag |= (ONLCR);
278  tmp.c_cflag |= (CS8);
279  tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
280  tmp.c_cc[VMIN] = 1;
281  tmp.c_cc[VTIME] = 0;
282  break;
283  case UV_TTY_MODE_IO:
285  break;
286  }
287 
288  /* Apply changes after draining */
289  if (tcsetattr(fd, TCSADRAIN, &tmp))
290  return UV__ERR(errno);
291 
292  tty->mode = mode;
293  return 0;
294 }
295 
296 
298  struct winsize ws;
299  int err;
300 
301  do
303  while (err == -1 && errno == EINTR);
304 
305  if (err == -1)
306  return UV__ERR(errno);
307 
308  *width = ws.ws_col;
309  *height = ws.ws_row;
310 
311  return 0;
312 }
313 
314 
316  struct sockaddr sa;
317  struct stat s;
318  socklen_t len;
319  int type;
320 
321  if (file < 0)
322  return UV_UNKNOWN_HANDLE;
323 
324  if (isatty(file))
325  return UV_TTY;
326 
327  if (fstat(file, &s))
328  return UV_UNKNOWN_HANDLE;
329 
330  if (S_ISREG(s.st_mode))
331  return UV_FILE;
332 
333  if (S_ISCHR(s.st_mode))
334  return UV_FILE; /* XXX UV_NAMED_PIPE? */
335 
336  if (S_ISFIFO(s.st_mode))
337  return UV_NAMED_PIPE;
338 
339  if (!S_ISSOCK(s.st_mode))
340  return UV_UNKNOWN_HANDLE;
341 
342  len = sizeof(type);
343  if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
344  return UV_UNKNOWN_HANDLE;
345 
346  len = sizeof(sa);
347  if (getsockname(file, &sa, &len))
348  return UV_UNKNOWN_HANDLE;
349 
350  if (type == SOCK_DGRAM)
351  if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
352  return UV_UDP;
353 
354  if (type == SOCK_STREAM) {
355 #if defined(_AIX) || defined(__DragonFly__)
356  /* on AIX/DragonFly the getsockname call returns an empty sa structure
357  * for sockets of type AF_UNIX. For all other types it will
358  * return a properly filled in structure.
359  */
360  if (len == 0)
361  return UV_NAMED_PIPE;
362 #endif /* defined(_AIX) || defined(__DragonFly__) */
363 
364  if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
365  return UV_TCP;
366  if (sa.sa_family == AF_UNIX)
367  return UV_NAMED_PIPE;
368  }
369 
370  return UV_UNKNOWN_HANDLE;
371 }
372 
373 
374 /* This function is async signal-safe, meaning that it's safe to call from
375  * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
376  * critical section when the signal was raised.
377  */
378 int uv_tty_reset_mode(void) {
379  int saved_errno;
380  int err;
381 
382  saved_errno = errno;
383  if (!uv_spinlock_trylock(&termios_spinlock))
384  return UV_EBUSY; /* In uv_tty_set_mode(). */
385 
386  err = 0;
387  if (orig_termios_fd != -1)
388  if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
389  err = UV__ERR(errno);
390 
391  uv_spinlock_unlock(&termios_spinlock);
392  errno = saved_errno;
393 
394  return err;
395 }
396 
398 }
399 
401  return UV_ENOTSUP;
402 }
size_t len
Definition: 6502dis.c:15
static bool err
Definition: armass.c:435
static SblHeader sb
Definition: bin_mbn.c:26
#define S_ISREG(mode)
Definition: compat.h:191
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset fstat
Definition: sflib.h:107
static static sync static getppid static getegid const char static filename ioctl
Definition: sflib.h:62
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags fcntl
Definition: sflib.h:79
#define UV__ERR(x)
Definition: errno.h:29
#define major(dev)
Definition: fsmagic.c:56
void skip(file *in, unsigned n)
Definition: gzappend.c:202
const char int mode
Definition: ioapi.h:137
assert(limit<=UINT32_MAX/2)
int type
Definition: mipsasm.c:17
#define QUEUE_REMOVE(q)
Definition: queue.h:101
static RzSocket * s
Definition: rtr.c:28
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define F_GETFL
Definition: sftypes.h:506
#define CS8
Definition: sftypes.h:942
#define OPOST
Definition: sftypes.h:886
#define AF_UNIX
Definition: sftypes.h:285
#define O_WRONLY
Definition: sftypes.h:487
#define O_NOCTTY
Definition: sftypes.h:491
#define IGNBRK
Definition: sftypes.h:870
#define TIOCGWINSZ
Definition: sftypes.h:721
#define EINTR
Definition: sftypes.h:114
#define O_ACCMODE
Definition: sftypes.h:485
#define BRKINT
Definition: sftypes.h:871
#define ISIG
Definition: sftypes.h:970
#define VMIN
Definition: sftypes.h:857
#define ICANON
Definition: sftypes.h:971
#define VTIME
Definition: sftypes.h:856
unsigned int socklen_t
Definition: sftypes.h:219
#define PARMRK
Definition: sftypes.h:873
#define IXON
Definition: sftypes.h:880
#define O_RDONLY
Definition: sftypes.h:486
#define TCSANOW
Definition: sftypes.h:998
@ SOCK_DGRAM
Definition: sftypes.h:227
@ SOCK_STREAM
Definition: sftypes.h:224
#define SO_TYPE
Definition: sftypes.h:431
#define SOL_SOCKET
Definition: sftypes.h:427
#define ONLCR
Definition: sftypes.h:888
#define AF_INET
Definition: sftypes.h:287
#define IMAXBEL
Definition: sftypes.h:883
#define AF_INET6
Definition: sftypes.h:295
#define ECHO
Definition: sftypes.h:973
#define IGNCR
Definition: sftypes.h:877
#define IEXTEN
Definition: sftypes.h:984
#define INPCK
Definition: sftypes.h:874
#define ENOTTY
Definition: sftypes.h:135
#define PARENB
Definition: sftypes.h:945
#define EBADF
Definition: sftypes.h:119
#define INLCR
Definition: sftypes.h:876
#define TCSADRAIN
Definition: sftypes.h:999
#define CSIZE
Definition: sftypes.h:938
#define ECHONL
Definition: sftypes.h:976
#define ICRNL
Definition: sftypes.h:878
#define TIOCGPTN
Definition: sftypes.h:745
#define F_SETFL
Definition: sftypes.h:507
#define ISTRIP
Definition: sftypes.h:875
#define UV_SPINLOCK_INITIALIZER
Definition: spinlock.h:22
Definition: gzappend.c:170
Definition: sftypes.h:80
Definition: dis.h:43
tcflag_t c_cflag
Definition: sftypes.h:844
tcflag_t c_iflag
Definition: sftypes.h:842
tcflag_t c_lflag
Definition: sftypes.h:845
tcflag_t c_oflag
Definition: sftypes.h:843
Definition: uv.h:1780
Definition: uv.h:714
unsigned short ws_row
Definition: sftypes.h:784
unsigned short ws_col
Definition: sftypes.h:785
uv_loop_t * loop
Definition: main.c:7
int width
Definition: main.c:10
int height
Definition: main.c:10
uv_tty_t tty
Definition: main.c:7
int uv__open_cloexec(const char *path, int flags)
Definition: core.c:1003
int uv__dup2_cloexec(int oldfd, int newfd)
Definition: core.c:1031
int uv__close(int fd)
Definition: core.c:569
int uv__stream_open(uv_stream_t *, int fd, int flags)
Definition: stream.c:406
#define uv__stream_fd(handle)
Definition: internal.h:282
#define uv__nonblock
Definition: internal.h:170
void uv__stream_init(uv_loop_t *loop, uv_stream_t *stream, uv_handle_type type)
Definition: stream.c:85
static int orig_termios_fd
Definition: tty.c:65
static struct termios orig_termios
Definition: tty.c:66
static int uv__tty_is_slave(const int fd)
Definition: tty.c:69
uv_handle_type uv_guess_handle(uv_file file)
Definition: tty.c:315
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state)
Definition: tty.c:397
static uv_spinlock_t termios_spinlock
Definition: tty.c:67
int uv_tty_get_winsize(uv_tty_t *tty, int *width, int *height)
Definition: tty.c:297
int uv_tty_set_mode(uv_tty_t *tty, uv_tty_mode_t mode)
Definition: tty.c:250
int uv_tty_get_vterm_state(uv_tty_vtermstate_t *state)
Definition: tty.c:400
static void uv__tty_make_raw(struct termios *tio)
Definition: tty.c:231
int uv_tty_init(uv_loop_t *loop, uv_tty_t *tty, int fd, int unused)
Definition: tty.c:123
int uv_tty_reset_mode(void)
Definition: tty.c:378
int uv_file
Definition: unix.h:128
@ UV_HANDLE_BLOCKING_WRITES
Definition: uv-common.h:98
@ UV_HANDLE_WRITABLE
Definition: uv-common.h:93
@ UV_HANDLE_READABLE
Definition: uv-common.h:92
uv_tty_mode_t
Definition: uv.h:720
@ UV_TTY_MODE_IO
Definition: uv.h:726
@ UV_TTY_MODE_NORMAL
Definition: uv.h:722
@ UV_TTY_MODE_RAW
Definition: uv.h:724
uv_handle_type
Definition: uv.h:189
@ UV_FILE
Definition: uv.h:194
@ UV_UNKNOWN_HANDLE
Definition: uv.h:190
uv_tty_vtermstate_t
Definition: uv.h:729
static const z80_opcode fd[]
Definition: z80_tab.h:997