1 1.1 christos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 1.1 christos * 3 1.1 christos * Permission is hereby granted, free of charge, to any person obtaining a copy 4 1.1 christos * of this software and associated documentation files (the "Software"), to 5 1.1 christos * deal in the Software without restriction, including without limitation the 6 1.1 christos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 1.1 christos * sell copies of the Software, and to permit persons to whom the Software is 8 1.1 christos * furnished to do so, subject to the following conditions: 9 1.1 christos * 10 1.1 christos * The above copyright notice and this permission notice shall be included in 11 1.1 christos * all copies or substantial portions of the Software. 12 1.1 christos * 13 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 1.1 christos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 1.1 christos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 1.1 christos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 1.1 christos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 1.1 christos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 1.1 christos * IN THE SOFTWARE. 20 1.1 christos */ 21 1.1 christos 22 1.1 christos #include "uv.h" 23 1.1 christos #include "task.h" 24 1.1 christos 25 1.1 christos #ifdef _WIN32 26 1.1 christos # include <io.h> 27 1.1 christos # include <windows.h> 28 1.1 christos #else /* Unix */ 29 1.1 christos # include <fcntl.h> 30 1.1 christos # include <unistd.h> 31 1.1.1.3 christos # if defined(__linux__) && !defined(__ANDROID__) 32 1.1 christos # include <pty.h> 33 1.1 christos # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) 34 1.1 christos # include <util.h> 35 1.1 christos # elif defined(__FreeBSD__) || defined(__DragonFly__) 36 1.1 christos # include <libutil.h> 37 1.1 christos # endif 38 1.1 christos #endif 39 1.1 christos 40 1.1 christos #include <string.h> 41 1.1 christos #include <errno.h> 42 1.1 christos 43 1.1 christos 44 1.1 christos TEST_IMPL(tty) { 45 1.1 christos int r, width, height; 46 1.1 christos int ttyin_fd, ttyout_fd; 47 1.1 christos uv_tty_t tty_in, tty_out; 48 1.1 christos uv_loop_t* loop = uv_default_loop(); 49 1.1 christos 50 1.1 christos /* Make sure we have an FD that refers to a tty */ 51 1.1 christos #ifdef _WIN32 52 1.1 christos HANDLE handle; 53 1.1 christos handle = CreateFileA("conin$", 54 1.1 christos GENERIC_READ | GENERIC_WRITE, 55 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 56 1.1 christos NULL, 57 1.1 christos OPEN_EXISTING, 58 1.1 christos FILE_ATTRIBUTE_NORMAL, 59 1.1 christos NULL); 60 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 61 1.1 christos ttyin_fd = _open_osfhandle((intptr_t) handle, 0); 62 1.1 christos 63 1.1 christos handle = CreateFileA("conout$", 64 1.1 christos GENERIC_READ | GENERIC_WRITE, 65 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 66 1.1 christos NULL, 67 1.1 christos OPEN_EXISTING, 68 1.1 christos FILE_ATTRIBUTE_NORMAL, 69 1.1 christos NULL); 70 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 71 1.1 christos ttyout_fd = _open_osfhandle((intptr_t) handle, 0); 72 1.1 christos 73 1.1 christos #else /* unix */ 74 1.1 christos ttyin_fd = open("/dev/tty", O_RDONLY, 0); 75 1.1 christos if (ttyin_fd < 0) { 76 1.1 christos fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno)); 77 1.1 christos fflush(stderr); 78 1.1 christos return TEST_SKIP; 79 1.1 christos } 80 1.1 christos 81 1.1 christos ttyout_fd = open("/dev/tty", O_WRONLY, 0); 82 1.1 christos if (ttyout_fd < 0) { 83 1.1 christos fprintf(stderr, "Cannot open /dev/tty as write-only: %s\n", strerror(errno)); 84 1.1 christos fflush(stderr); 85 1.1 christos return TEST_SKIP; 86 1.1 christos } 87 1.1 christos #endif 88 1.1 christos 89 1.1.1.3 christos ASSERT_GE(ttyin_fd, 0); 90 1.1.1.3 christos ASSERT_GE(ttyout_fd, 0); 91 1.1 christos 92 1.1.1.3 christos ASSERT_EQ(UV_UNKNOWN_HANDLE, uv_guess_handle(-1)); 93 1.1 christos 94 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); 95 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); 96 1.1 christos 97 1.1.1.3 christos r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ 98 1.1.1.3 christos ASSERT_OK(r); 99 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); 100 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); 101 1.1 christos 102 1.1.1.3 christos r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ 103 1.1.1.3 christos ASSERT_OK(r); 104 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); 105 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); 106 1.1 christos 107 1.1 christos r = uv_tty_get_winsize(&tty_out, &width, &height); 108 1.1.1.3 christos ASSERT_OK(r); 109 1.1 christos 110 1.1 christos printf("width=%d height=%d\n", width, height); 111 1.1 christos 112 1.1 christos if (width == 0 && height == 0) { 113 1.1 christos /* Some environments such as containers or Jenkins behave like this 114 1.1 christos * sometimes */ 115 1.1.1.3 christos MAKE_VALGRIND_HAPPY(loop); 116 1.1 christos return TEST_SKIP; 117 1.1 christos } 118 1.1 christos 119 1.1.1.3 christos ASSERT_GT(width, 0); 120 1.1.1.3 christos ASSERT_GT(height, 0); 121 1.1 christos 122 1.1 christos /* Turn on raw mode. */ 123 1.1 christos r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); 124 1.1.1.3 christos ASSERT_OK(r); 125 1.1 christos 126 1.1 christos /* Turn off raw mode. */ 127 1.1 christos r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_NORMAL); 128 1.1.1.3 christos ASSERT_OK(r); 129 1.1 christos 130 1.1 christos /* Calling uv_tty_reset_mode() repeatedly should not clobber errno. */ 131 1.1 christos errno = 0; 132 1.1.1.3 christos ASSERT_OK(uv_tty_reset_mode()); 133 1.1.1.3 christos ASSERT_OK(uv_tty_reset_mode()); 134 1.1.1.3 christos ASSERT_OK(uv_tty_reset_mode()); 135 1.1.1.3 christos ASSERT_OK(errno); 136 1.1 christos 137 1.1 christos /* TODO check the actual mode! */ 138 1.1 christos 139 1.1 christos uv_close((uv_handle_t*) &tty_in, NULL); 140 1.1 christos uv_close((uv_handle_t*) &tty_out, NULL); 141 1.1 christos 142 1.1 christos uv_run(loop, UV_RUN_DEFAULT); 143 1.1 christos 144 1.1.1.3 christos MAKE_VALGRIND_HAPPY(uv_default_loop()); 145 1.1 christos return 0; 146 1.1 christos } 147 1.1 christos 148 1.1 christos 149 1.1 christos #ifdef _WIN32 150 1.1 christos static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { 151 1.1 christos buf->base = malloc(size); 152 1.1 christos buf->len = size; 153 1.1 christos } 154 1.1 christos 155 1.1 christos static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { 156 1.1 christos if (nread > 0) { 157 1.1.1.3 christos ASSERT_EQ(1, nread ); 158 1.1.1.3 christos ASSERT_EQ(buf->base[0], ' '); 159 1.1 christos uv_close((uv_handle_t*) tty_in, NULL); 160 1.1 christos } else { 161 1.1.1.3 christos ASSERT_OK(nread); 162 1.1 christos } 163 1.1 christos } 164 1.1 christos 165 1.1 christos TEST_IMPL(tty_raw) { 166 1.1 christos int r; 167 1.1 christos int ttyin_fd; 168 1.1 christos uv_tty_t tty_in; 169 1.1 christos uv_loop_t* loop = uv_default_loop(); 170 1.1 christos HANDLE handle; 171 1.1 christos INPUT_RECORD record; 172 1.1 christos DWORD written; 173 1.1 christos 174 1.1 christos /* Make sure we have an FD that refers to a tty */ 175 1.1 christos handle = CreateFileA("conin$", 176 1.1 christos GENERIC_READ | GENERIC_WRITE, 177 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 178 1.1 christos NULL, 179 1.1 christos OPEN_EXISTING, 180 1.1 christos FILE_ATTRIBUTE_NORMAL, 181 1.1 christos NULL); 182 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 183 1.1 christos ttyin_fd = _open_osfhandle((intptr_t) handle, 0); 184 1.1.1.3 christos ASSERT_GE(ttyin_fd, 0); 185 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); 186 1.1 christos 187 1.1.1.3 christos r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ 188 1.1.1.3 christos ASSERT_OK(r); 189 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); 190 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); 191 1.1 christos 192 1.1 christos r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); 193 1.1.1.3 christos ASSERT_OK(r); 194 1.1 christos 195 1.1 christos /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ 196 1.1 christos Sleep(100); 197 1.1 christos 198 1.1 christos /* Turn on raw mode. */ 199 1.1 christos r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); 200 1.1.1.3 christos ASSERT_OK(r); 201 1.1 christos 202 1.1 christos /* Write ' ' that should be read in raw mode */ 203 1.1 christos record.EventType = KEY_EVENT; 204 1.1 christos record.Event.KeyEvent.bKeyDown = TRUE; 205 1.1 christos record.Event.KeyEvent.wRepeatCount = 1; 206 1.1 christos record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; 207 1.1 christos record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); 208 1.1 christos record.Event.KeyEvent.uChar.UnicodeChar = L' '; 209 1.1 christos record.Event.KeyEvent.dwControlKeyState = 0; 210 1.1 christos WriteConsoleInputW(handle, &record, 1, &written); 211 1.1 christos 212 1.1 christos uv_run(loop, UV_RUN_DEFAULT); 213 1.1 christos 214 1.1.1.3 christos MAKE_VALGRIND_HAPPY(loop); 215 1.1 christos return 0; 216 1.1 christos } 217 1.1 christos 218 1.1 christos TEST_IMPL(tty_empty_write) { 219 1.1 christos int r; 220 1.1 christos int ttyout_fd; 221 1.1 christos uv_tty_t tty_out; 222 1.1 christos char dummy[1]; 223 1.1 christos uv_buf_t bufs[1]; 224 1.1 christos uv_loop_t* loop; 225 1.1 christos 226 1.1 christos /* Make sure we have an FD that refers to a tty */ 227 1.1 christos HANDLE handle; 228 1.1 christos 229 1.1 christos loop = uv_default_loop(); 230 1.1 christos 231 1.1 christos handle = CreateFileA("conout$", 232 1.1 christos GENERIC_READ | GENERIC_WRITE, 233 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 234 1.1 christos NULL, 235 1.1 christos OPEN_EXISTING, 236 1.1 christos FILE_ATTRIBUTE_NORMAL, 237 1.1 christos NULL); 238 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 239 1.1 christos ttyout_fd = _open_osfhandle((intptr_t) handle, 0); 240 1.1 christos 241 1.1.1.3 christos ASSERT_GE(ttyout_fd, 0); 242 1.1 christos 243 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); 244 1.1 christos 245 1.1.1.3 christos r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ 246 1.1.1.3 christos ASSERT_OK(r); 247 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); 248 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); 249 1.1 christos 250 1.1 christos bufs[0].len = 0; 251 1.1 christos bufs[0].base = &dummy[0]; 252 1.1 christos 253 1.1 christos r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); 254 1.1.1.3 christos ASSERT_OK(r); 255 1.1 christos 256 1.1 christos uv_close((uv_handle_t*) &tty_out, NULL); 257 1.1 christos 258 1.1 christos uv_run(loop, UV_RUN_DEFAULT); 259 1.1 christos 260 1.1.1.3 christos MAKE_VALGRIND_HAPPY(loop); 261 1.1 christos return 0; 262 1.1 christos } 263 1.1 christos 264 1.1 christos TEST_IMPL(tty_large_write) { 265 1.1 christos int r; 266 1.1 christos int ttyout_fd; 267 1.1 christos uv_tty_t tty_out; 268 1.1 christos char dummy[10000]; 269 1.1 christos uv_buf_t bufs[1]; 270 1.1 christos uv_loop_t* loop; 271 1.1 christos 272 1.1 christos /* Make sure we have an FD that refers to a tty */ 273 1.1 christos HANDLE handle; 274 1.1 christos 275 1.1 christos loop = uv_default_loop(); 276 1.1 christos 277 1.1 christos handle = CreateFileA("conout$", 278 1.1 christos GENERIC_READ | GENERIC_WRITE, 279 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 280 1.1 christos NULL, 281 1.1 christos OPEN_EXISTING, 282 1.1 christos FILE_ATTRIBUTE_NORMAL, 283 1.1 christos NULL); 284 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 285 1.1 christos ttyout_fd = _open_osfhandle((intptr_t) handle, 0); 286 1.1 christos 287 1.1.1.3 christos ASSERT_GE(ttyout_fd, 0); 288 1.1 christos 289 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); 290 1.1 christos 291 1.1.1.3 christos r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ 292 1.1.1.3 christos ASSERT_OK(r); 293 1.1 christos 294 1.1 christos memset(dummy, '.', sizeof(dummy) - 1); 295 1.1 christos dummy[sizeof(dummy) - 1] = '\n'; 296 1.1 christos 297 1.1 christos bufs[0] = uv_buf_init(dummy, sizeof(dummy)); 298 1.1 christos 299 1.1 christos r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); 300 1.1.1.3 christos ASSERT_EQ(10000, r); 301 1.1 christos 302 1.1 christos uv_close((uv_handle_t*) &tty_out, NULL); 303 1.1 christos 304 1.1 christos uv_run(loop, UV_RUN_DEFAULT); 305 1.1 christos 306 1.1.1.3 christos MAKE_VALGRIND_HAPPY(loop); 307 1.1 christos return 0; 308 1.1 christos } 309 1.1 christos 310 1.1 christos TEST_IMPL(tty_raw_cancel) { 311 1.1 christos int r; 312 1.1 christos int ttyin_fd; 313 1.1 christos uv_tty_t tty_in; 314 1.1 christos HANDLE handle; 315 1.1 christos 316 1.1 christos /* Make sure we have an FD that refers to a tty */ 317 1.1 christos handle = CreateFileA("conin$", 318 1.1 christos GENERIC_READ | GENERIC_WRITE, 319 1.1 christos FILE_SHARE_READ | FILE_SHARE_WRITE, 320 1.1 christos NULL, 321 1.1 christos OPEN_EXISTING, 322 1.1 christos FILE_ATTRIBUTE_NORMAL, 323 1.1 christos NULL); 324 1.1.1.3 christos ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); 325 1.1 christos ttyin_fd = _open_osfhandle((intptr_t) handle, 0); 326 1.1.1.3 christos ASSERT_GE(ttyin_fd, 0); 327 1.1.1.3 christos ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); 328 1.1 christos 329 1.1 christos r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ 330 1.1.1.3 christos ASSERT_OK(r); 331 1.1 christos r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); 332 1.1.1.3 christos ASSERT_OK(r); 333 1.1 christos r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); 334 1.1.1.3 christos ASSERT_OK(r); 335 1.1 christos 336 1.1 christos r = uv_read_stop((uv_stream_t*) &tty_in); 337 1.1.1.3 christos ASSERT_OK(r); 338 1.1 christos 339 1.1.1.3 christos MAKE_VALGRIND_HAPPY(uv_default_loop()); 340 1.1 christos return 0; 341 1.1 christos } 342 1.1 christos #endif 343 1.1 christos 344 1.1 christos 345 1.1 christos TEST_IMPL(tty_file) { 346 1.1 christos #ifndef _WIN32 347 1.1 christos uv_loop_t loop; 348 1.1 christos uv_tty_t tty; 349 1.1 christos uv_tty_t tty_ro; 350 1.1 christos uv_tty_t tty_wo; 351 1.1 christos int fd; 352 1.1 christos 353 1.1.1.3 christos ASSERT_OK(uv_loop_init(&loop)); 354 1.1 christos 355 1.1 christos fd = open("test/fixtures/empty_file", O_RDONLY); 356 1.1 christos if (fd != -1) { 357 1.1.1.3 christos ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); 358 1.1.1.3 christos ASSERT_OK(close(fd)); 359 1.1 christos /* test EBADF handling */ 360 1.1.1.3 christos ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); 361 1.1 christos } 362 1.1 christos 363 1.1 christos /* Bug on AIX where '/dev/random' returns 1 from isatty() */ 364 1.1 christos #ifndef _AIX 365 1.1 christos fd = open("/dev/random", O_RDONLY); 366 1.1 christos if (fd != -1) { 367 1.1.1.3 christos ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); 368 1.1.1.3 christos ASSERT_OK(close(fd)); 369 1.1 christos } 370 1.1 christos #endif /* _AIX */ 371 1.1 christos 372 1.1 christos fd = open("/dev/zero", O_RDONLY); 373 1.1 christos if (fd != -1) { 374 1.1.1.3 christos ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); 375 1.1.1.3 christos ASSERT_OK(close(fd)); 376 1.1 christos } 377 1.1 christos 378 1.1 christos fd = open("/dev/tty", O_RDWR); 379 1.1 christos if (fd != -1) { 380 1.1.1.3 christos ASSERT_OK(uv_tty_init(&loop, &tty, fd, 1)); 381 1.1.1.3 christos ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ 382 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &tty)); 383 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &tty)); 384 1.1 christos uv_close((uv_handle_t*) &tty, NULL); 385 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty)); 386 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty)); 387 1.1 christos } 388 1.1 christos 389 1.1 christos fd = open("/dev/tty", O_RDONLY); 390 1.1 christos if (fd != -1) { 391 1.1.1.3 christos ASSERT_OK(uv_tty_init(&loop, &tty_ro, fd, 1)); 392 1.1.1.3 christos ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ 393 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &tty_ro)); 394 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro)); 395 1.1 christos uv_close((uv_handle_t*) &tty_ro, NULL); 396 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty_ro)); 397 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro)); 398 1.1 christos } 399 1.1 christos 400 1.1 christos fd = open("/dev/tty", O_WRONLY); 401 1.1 christos if (fd != -1) { 402 1.1.1.3 christos ASSERT_OK(uv_tty_init(&loop, &tty_wo, fd, 0)); 403 1.1.1.3 christos ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ 404 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo)); 405 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &tty_wo)); 406 1.1 christos uv_close((uv_handle_t*) &tty_wo, NULL); 407 1.1 christos ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo)); 408 1.1 christos ASSERT(!uv_is_writable((uv_stream_t*) &tty_wo)); 409 1.1 christos } 410 1.1 christos 411 1.1 christos 412 1.1.1.3 christos ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); 413 1.1 christos 414 1.1.1.3 christos MAKE_VALGRIND_HAPPY(&loop); 415 1.1 christos #endif 416 1.1 christos return 0; 417 1.1 christos } 418 1.1 christos 419 1.1 christos TEST_IMPL(tty_pty) { 420 1.1.1.2 christos /* TODO(gengjiawen): Fix test on QEMU. */ 421 1.1.1.2 christos #if defined(__QEMU__) 422 1.1.1.2 christos RETURN_SKIP("Test does not currently work in QEMU"); 423 1.1.1.2 christos #endif 424 1.1.1.2 christos #if defined(__ASAN__) 425 1.1.1.2 christos RETURN_SKIP("Test does not currently work in ASAN"); 426 1.1.1.2 christos #endif 427 1.1.1.2 christos 428 1.1 christos #if defined(__APPLE__) || \ 429 1.1 christos defined(__DragonFly__) || \ 430 1.1 christos defined(__FreeBSD__) || \ 431 1.1 christos (defined(__linux__) && !defined(__ANDROID__)) || \ 432 1.1 christos defined(__NetBSD__) || \ 433 1.1 christos defined(__OpenBSD__) 434 1.1 christos int master_fd, slave_fd, r; 435 1.1 christos struct winsize w; 436 1.1 christos uv_loop_t loop; 437 1.1 christos uv_tty_t master_tty, slave_tty; 438 1.1 christos 439 1.1.1.3 christos ASSERT_OK(uv_loop_init(&loop)); 440 1.1 christos 441 1.1 christos r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); 442 1.1 christos if (r != 0) 443 1.1 christos RETURN_SKIP("No pty available, skipping."); 444 1.1 christos 445 1.1.1.3 christos ASSERT_OK(uv_tty_init(&loop, &slave_tty, slave_fd, 0)); 446 1.1.1.3 christos ASSERT_OK(uv_tty_init(&loop, &master_tty, master_fd, 0)); 447 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &slave_tty)); 448 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &slave_tty)); 449 1.1 christos ASSERT(uv_is_readable((uv_stream_t*) &master_tty)); 450 1.1 christos ASSERT(uv_is_writable((uv_stream_t*) &master_tty)); 451 1.1 christos /* Check if the file descriptor was reopened. If it is, 452 1.1 christos * UV_HANDLE_BLOCKING_WRITES (value 0x100000) isn't set on flags. 453 1.1 christos */ 454 1.1.1.3 christos ASSERT_OK((slave_tty.flags & 0x100000)); 455 1.1 christos /* The master_fd of a pty should never be reopened. 456 1.1 christos */ 457 1.1 christos ASSERT(master_tty.flags & 0x100000); 458 1.1.1.3 christos ASSERT_OK(close(slave_fd)); 459 1.1 christos uv_close((uv_handle_t*) &slave_tty, NULL); 460 1.1.1.3 christos ASSERT_OK(close(master_fd)); 461 1.1 christos uv_close((uv_handle_t*) &master_tty, NULL); 462 1.1 christos 463 1.1.1.3 christos ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); 464 1.1 christos 465 1.1.1.3 christos MAKE_VALGRIND_HAPPY(&loop); 466 1.1 christos #endif 467 1.1 christos return 0; 468 1.1 christos } 469