Mercurial
comparison third_party/libuv/test/test-spawn.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 1 | |
| 2 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. | |
| 3 * | |
| 4 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 5 * of this software and associated documentation files (the "Software"), to | |
| 6 * deal in the Software without restriction, including without limitation the | |
| 7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
| 8 * sell copies of the Software, and to permit persons to whom the Software is | |
| 9 * furnished to do so, subject to the following conditions: | |
| 10 * | |
| 11 * The above copyright notice and this permission notice shall be included in | |
| 12 * all copies or substantial portions of the Software. | |
| 13 * | |
| 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
| 20 * IN THE SOFTWARE. | |
| 21 */ | |
| 22 | |
| 23 #include "uv.h" | |
| 24 #include "task.h" | |
| 25 #include <errno.h> | |
| 26 #include <fcntl.h> | |
| 27 #include <stdio.h> | |
| 28 #include <stdlib.h> | |
| 29 #include <string.h> | |
| 30 | |
| 31 #ifdef _WIN32 | |
| 32 # include <shellapi.h> | |
| 33 # include <wchar.h> | |
| 34 typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE); | |
| 35 # define unlink _unlink | |
| 36 # define putenv _putenv | |
| 37 # define close _close | |
| 38 #else | |
| 39 # include <unistd.h> | |
| 40 # include <sys/wait.h> | |
| 41 #endif | |
| 42 | |
| 43 | |
| 44 static int close_cb_called; | |
| 45 static int exit_cb_called; | |
| 46 static uv_process_t process; | |
| 47 static uv_timer_t timer; | |
| 48 static uv_process_options_t options; | |
| 49 static char exepath[1024]; | |
| 50 static size_t exepath_size = 1024; | |
| 51 static char* args[5]; | |
| 52 static int no_term_signal; | |
| 53 static int timer_counter; | |
| 54 static uv_tcp_t tcp_server; | |
| 55 | |
| 56 #define OUTPUT_SIZE 1024 | |
| 57 static char output[OUTPUT_SIZE]; | |
| 58 static int output_used; | |
| 59 | |
| 60 | |
| 61 static void close_cb(uv_handle_t* handle) { | |
| 62 printf("close_cb\n"); | |
| 63 close_cb_called++; | |
| 64 } | |
| 65 | |
| 66 static void exit_cb(uv_process_t* process, | |
| 67 int64_t exit_status, | |
| 68 int term_signal) { | |
| 69 printf("exit_cb\n"); | |
| 70 exit_cb_called++; | |
| 71 ASSERT_EQ(1, exit_status); | |
| 72 ASSERT_OK(term_signal); | |
| 73 uv_close((uv_handle_t*) process, close_cb); | |
| 74 } | |
| 75 | |
| 76 | |
| 77 static void fail_cb(uv_process_t* process, | |
| 78 int64_t exit_status, | |
| 79 int term_signal) { | |
| 80 ASSERT(0 && "fail_cb called"); | |
| 81 } | |
| 82 | |
| 83 | |
| 84 static void kill_cb(uv_process_t* process, | |
| 85 int64_t exit_status, | |
| 86 int term_signal) { | |
| 87 int err; | |
| 88 | |
| 89 printf("exit_cb\n"); | |
| 90 exit_cb_called++; | |
| 91 #ifdef _WIN32 | |
| 92 ASSERT_EQ(1, exit_status); | |
| 93 #else | |
| 94 ASSERT_OK(exit_status); | |
| 95 #endif | |
| 96 #if defined(__APPLE__) || defined(__MVS__) | |
| 97 /* | |
| 98 * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a | |
| 99 * process that is still starting up kills it with SIGKILL instead of SIGTERM. | |
| 100 * See: https://github.com/libuv/libuv/issues/1226 | |
| 101 */ | |
| 102 ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL); | |
| 103 #else | |
| 104 ASSERT(no_term_signal || term_signal == SIGTERM); | |
| 105 #endif | |
| 106 uv_close((uv_handle_t*) process, close_cb); | |
| 107 | |
| 108 /* | |
| 109 * Sending signum == 0 should check if the | |
| 110 * child process is still alive, not kill it. | |
| 111 * This process should be dead. | |
| 112 */ | |
| 113 err = uv_kill(process->pid, 0); | |
| 114 ASSERT_EQ(err, UV_ESRCH); | |
| 115 } | |
| 116 | |
| 117 static void detach_failure_cb(uv_process_t* process, | |
| 118 int64_t exit_status, | |
| 119 int term_signal) { | |
| 120 printf("detach_cb\n"); | |
| 121 exit_cb_called++; | |
| 122 } | |
| 123 | |
| 124 static void on_alloc(uv_handle_t* handle, | |
| 125 size_t suggested_size, | |
| 126 uv_buf_t* buf) { | |
| 127 buf->base = output + output_used; | |
| 128 buf->len = OUTPUT_SIZE - output_used; | |
| 129 } | |
| 130 | |
| 131 | |
| 132 static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { | |
| 133 if (nread > 0) { | |
| 134 output_used += nread; | |
| 135 } else if (nread < 0) { | |
| 136 ASSERT_EQ(nread, UV_EOF); | |
| 137 uv_close((uv_handle_t*) tcp, close_cb); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 | |
| 142 static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { | |
| 143 uv_read_stop(tcp); | |
| 144 on_read(tcp, nread, buf); | |
| 145 } | |
| 146 | |
| 147 | |
| 148 static void write_cb(uv_write_t* req, int status) { | |
| 149 ASSERT_OK(status); | |
| 150 uv_close((uv_handle_t*) req->handle, close_cb); | |
| 151 } | |
| 152 | |
| 153 | |
| 154 static void write_null_cb(uv_write_t* req, int status) { | |
| 155 ASSERT_OK(status); | |
| 156 } | |
| 157 | |
| 158 | |
| 159 static void init_process_options(char* test, uv_exit_cb exit_cb) { | |
| 160 /* Note spawn_helper1 defined in test/run-tests.c */ | |
| 161 int r = uv_exepath(exepath, &exepath_size); | |
| 162 ASSERT_OK(r); | |
| 163 exepath[exepath_size] = '\0'; | |
| 164 args[0] = exepath; | |
| 165 args[1] = test; | |
| 166 args[2] = NULL; | |
| 167 args[3] = NULL; | |
| 168 args[4] = NULL; | |
| 169 options.file = exepath; | |
| 170 options.args = args; | |
| 171 options.exit_cb = exit_cb; | |
| 172 options.flags = 0; | |
| 173 } | |
| 174 | |
| 175 | |
| 176 static void timer_cb(uv_timer_t* handle) { | |
| 177 uv_process_kill(&process, SIGTERM); | |
| 178 uv_close((uv_handle_t*) handle, close_cb); | |
| 179 } | |
| 180 | |
| 181 | |
| 182 static void timer_counter_cb(uv_timer_t* handle) { | |
| 183 ++timer_counter; | |
| 184 } | |
| 185 | |
| 186 | |
| 187 TEST_IMPL(spawn_fails) { | |
| 188 int r; | |
| 189 | |
| 190 init_process_options("", fail_cb); | |
| 191 options.file = options.args[0] = "program-that-had-better-not-exist"; | |
| 192 | |
| 193 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 194 ASSERT(r == UV_ENOENT || r == UV_EACCES); | |
| 195 ASSERT_OK(uv_is_active((uv_handle_t*) &process)); | |
| 196 uv_close((uv_handle_t*) &process, NULL); | |
| 197 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 198 | |
| 199 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 200 return 0; | |
| 201 } | |
| 202 | |
| 203 | |
| 204 #ifndef _WIN32 | |
| 205 TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { | |
| 206 int r; | |
| 207 int status; | |
| 208 int err; | |
| 209 | |
| 210 init_process_options("", fail_cb); | |
| 211 options.file = options.args[0] = "program-that-had-better-not-exist"; | |
| 212 | |
| 213 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 214 ASSERT(r == UV_ENOENT || r == UV_EACCES); | |
| 215 ASSERT_OK(uv_is_active((uv_handle_t*) &process)); | |
| 216 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 217 | |
| 218 /* verify the child is successfully cleaned up within libuv */ | |
| 219 do | |
| 220 err = waitpid(process.pid, &status, 0); | |
| 221 while (err == -1 && errno == EINTR); | |
| 222 | |
| 223 ASSERT_EQ(err, -1); | |
| 224 ASSERT_EQ(errno, ECHILD); | |
| 225 | |
| 226 uv_close((uv_handle_t*) &process, NULL); | |
| 227 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 228 | |
| 229 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 230 return 0; | |
| 231 } | |
| 232 #endif | |
| 233 | |
| 234 | |
| 235 TEST_IMPL(spawn_empty_env) { | |
| 236 char* env[1]; | |
| 237 | |
| 238 /* The autotools dynamic library build requires the presence of | |
| 239 * DYLD_LIBARY_PATH (macOS) or LD_LIBRARY_PATH/LIBPATH (other Unices) | |
| 240 * in the environment, but of course that doesn't work with | |
| 241 * the empty environment that we're testing here. | |
| 242 */ | |
| 243 if (NULL != getenv("DYLD_LIBRARY_PATH") || | |
| 244 NULL != getenv("LD_LIBRARY_PATH") || | |
| 245 NULL != getenv("LIBPATH")) { | |
| 246 RETURN_SKIP("doesn't work with DYLD_LIBRARY_PATH/LD_LIBRARY_PATH/LIBPATH"); | |
| 247 } | |
| 248 | |
| 249 init_process_options("spawn_helper1", exit_cb); | |
| 250 options.env = env; | |
| 251 env[0] = NULL; | |
| 252 | |
| 253 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 254 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 255 | |
| 256 ASSERT_EQ(1, exit_cb_called); | |
| 257 ASSERT_EQ(1, close_cb_called); | |
| 258 | |
| 259 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 260 return 0; | |
| 261 } | |
| 262 | |
| 263 | |
| 264 TEST_IMPL(spawn_exit_code) { | |
| 265 int r; | |
| 266 | |
| 267 init_process_options("spawn_helper1", exit_cb); | |
| 268 | |
| 269 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 270 ASSERT_OK(r); | |
| 271 | |
| 272 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 273 ASSERT_OK(r); | |
| 274 | |
| 275 ASSERT_EQ(1, exit_cb_called); | |
| 276 ASSERT_EQ(1, close_cb_called); | |
| 277 | |
| 278 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 279 return 0; | |
| 280 } | |
| 281 | |
| 282 | |
| 283 TEST_IMPL(spawn_stdout) { | |
| 284 int r; | |
| 285 uv_pipe_t out; | |
| 286 uv_stdio_container_t stdio[2]; | |
| 287 | |
| 288 init_process_options("spawn_helper2", exit_cb); | |
| 289 | |
| 290 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 291 options.stdio = stdio; | |
| 292 options.stdio[0].flags = UV_IGNORE; | |
| 293 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 294 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 295 options.stdio_count = 2; | |
| 296 | |
| 297 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 298 ASSERT_OK(r); | |
| 299 | |
| 300 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 301 ASSERT_OK(r); | |
| 302 | |
| 303 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 304 ASSERT_OK(r); | |
| 305 | |
| 306 ASSERT_EQ(1, exit_cb_called); | |
| 307 ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ | |
| 308 printf("output is: %s", output); | |
| 309 ASSERT_OK(strcmp("hello world\n", output)); | |
| 310 | |
| 311 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 312 return 0; | |
| 313 } | |
| 314 | |
| 315 | |
| 316 TEST_IMPL(spawn_stdout_to_file) { | |
| 317 int r; | |
| 318 uv_file file; | |
| 319 uv_fs_t fs_req; | |
| 320 uv_stdio_container_t stdio[2]; | |
| 321 uv_buf_t buf; | |
| 322 | |
| 323 /* Setup. */ | |
| 324 unlink("stdout_file"); | |
| 325 | |
| 326 init_process_options("spawn_helper2", exit_cb); | |
| 327 | |
| 328 r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, | |
| 329 S_IRUSR | S_IWUSR, NULL); | |
| 330 ASSERT_NE(r, -1); | |
| 331 uv_fs_req_cleanup(&fs_req); | |
| 332 | |
| 333 file = r; | |
| 334 | |
| 335 options.stdio = stdio; | |
| 336 options.stdio[0].flags = UV_IGNORE; | |
| 337 options.stdio[1].flags = UV_INHERIT_FD; | |
| 338 options.stdio[1].data.fd = file; | |
| 339 options.stdio_count = 2; | |
| 340 | |
| 341 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 342 ASSERT_OK(r); | |
| 343 | |
| 344 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 345 ASSERT_OK(r); | |
| 346 | |
| 347 ASSERT_EQ(1, exit_cb_called); | |
| 348 ASSERT_EQ(1, close_cb_called); | |
| 349 | |
| 350 buf = uv_buf_init(output, sizeof(output)); | |
| 351 r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); | |
| 352 ASSERT_EQ(12, r); | |
| 353 uv_fs_req_cleanup(&fs_req); | |
| 354 | |
| 355 r = uv_fs_close(NULL, &fs_req, file, NULL); | |
| 356 ASSERT_OK(r); | |
| 357 uv_fs_req_cleanup(&fs_req); | |
| 358 | |
| 359 printf("output is: %s", output); | |
| 360 ASSERT_OK(strcmp("hello world\n", output)); | |
| 361 | |
| 362 /* Cleanup. */ | |
| 363 unlink("stdout_file"); | |
| 364 | |
| 365 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 366 return 0; | |
| 367 } | |
| 368 | |
| 369 | |
| 370 TEST_IMPL(spawn_stdout_and_stderr_to_file) { | |
| 371 int r; | |
| 372 uv_file file; | |
| 373 uv_fs_t fs_req; | |
| 374 uv_stdio_container_t stdio[3]; | |
| 375 uv_buf_t buf; | |
| 376 | |
| 377 /* Setup. */ | |
| 378 unlink("stdout_file"); | |
| 379 | |
| 380 init_process_options("spawn_helper6", exit_cb); | |
| 381 | |
| 382 r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, | |
| 383 S_IRUSR | S_IWUSR, NULL); | |
| 384 ASSERT_NE(r, -1); | |
| 385 uv_fs_req_cleanup(&fs_req); | |
| 386 | |
| 387 file = r; | |
| 388 | |
| 389 options.stdio = stdio; | |
| 390 options.stdio[0].flags = UV_IGNORE; | |
| 391 options.stdio[1].flags = UV_INHERIT_FD; | |
| 392 options.stdio[1].data.fd = file; | |
| 393 options.stdio[2].flags = UV_INHERIT_FD; | |
| 394 options.stdio[2].data.fd = file; | |
| 395 options.stdio_count = 3; | |
| 396 | |
| 397 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 398 ASSERT_OK(r); | |
| 399 | |
| 400 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 401 ASSERT_OK(r); | |
| 402 | |
| 403 ASSERT_EQ(1, exit_cb_called); | |
| 404 ASSERT_EQ(1, close_cb_called); | |
| 405 | |
| 406 buf = uv_buf_init(output, sizeof(output)); | |
| 407 r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); | |
| 408 ASSERT_EQ(27, r); | |
| 409 uv_fs_req_cleanup(&fs_req); | |
| 410 | |
| 411 r = uv_fs_close(NULL, &fs_req, file, NULL); | |
| 412 ASSERT_OK(r); | |
| 413 uv_fs_req_cleanup(&fs_req); | |
| 414 | |
| 415 printf("output is: %s", output); | |
| 416 ASSERT_OK(strcmp("hello world\nhello errworld\n", output)); | |
| 417 | |
| 418 /* Cleanup. */ | |
| 419 unlink("stdout_file"); | |
| 420 | |
| 421 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 422 return 0; | |
| 423 } | |
| 424 | |
| 425 | |
| 426 TEST_IMPL(spawn_stdout_and_stderr_to_file2) { | |
| 427 #ifndef _WIN32 | |
| 428 int r; | |
| 429 uv_file file; | |
| 430 uv_fs_t fs_req; | |
| 431 uv_stdio_container_t stdio[3]; | |
| 432 uv_buf_t buf; | |
| 433 | |
| 434 /* Setup. */ | |
| 435 unlink("stdout_file"); | |
| 436 | |
| 437 init_process_options("spawn_helper6", exit_cb); | |
| 438 | |
| 439 /* Replace stderr with our file */ | |
| 440 r = uv_fs_open(NULL, | |
| 441 &fs_req, | |
| 442 "stdout_file", | |
| 443 O_CREAT | O_RDWR, | |
| 444 S_IRUSR | S_IWUSR, | |
| 445 NULL); | |
| 446 ASSERT_NE(r, -1); | |
| 447 uv_fs_req_cleanup(&fs_req); | |
| 448 file = dup2(r, STDERR_FILENO); | |
| 449 ASSERT_NE(file, -1); | |
| 450 | |
| 451 options.stdio = stdio; | |
| 452 options.stdio[0].flags = UV_IGNORE; | |
| 453 options.stdio[1].flags = UV_INHERIT_FD; | |
| 454 options.stdio[1].data.fd = file; | |
| 455 options.stdio[2].flags = UV_INHERIT_FD; | |
| 456 options.stdio[2].data.fd = file; | |
| 457 options.stdio_count = 3; | |
| 458 | |
| 459 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 460 ASSERT_OK(r); | |
| 461 | |
| 462 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 463 ASSERT_OK(r); | |
| 464 | |
| 465 ASSERT_EQ(1, exit_cb_called); | |
| 466 ASSERT_EQ(1, close_cb_called); | |
| 467 | |
| 468 buf = uv_buf_init(output, sizeof(output)); | |
| 469 r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); | |
| 470 ASSERT_EQ(27, r); | |
| 471 uv_fs_req_cleanup(&fs_req); | |
| 472 | |
| 473 r = uv_fs_close(NULL, &fs_req, file, NULL); | |
| 474 ASSERT_OK(r); | |
| 475 uv_fs_req_cleanup(&fs_req); | |
| 476 | |
| 477 printf("output is: %s", output); | |
| 478 ASSERT_OK(strcmp("hello world\nhello errworld\n", output)); | |
| 479 | |
| 480 /* Cleanup. */ | |
| 481 unlink("stdout_file"); | |
| 482 | |
| 483 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 484 return 0; | |
| 485 #else | |
| 486 RETURN_SKIP("Unix only test"); | |
| 487 #endif | |
| 488 } | |
| 489 | |
| 490 | |
| 491 TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) { | |
| 492 #ifndef _WIN32 | |
| 493 int r; | |
| 494 uv_file stdout_file; | |
| 495 uv_file stderr_file; | |
| 496 uv_fs_t fs_req; | |
| 497 uv_stdio_container_t stdio[3]; | |
| 498 uv_buf_t buf; | |
| 499 | |
| 500 /* Setup. */ | |
| 501 unlink("stdout_file"); | |
| 502 unlink("stderr_file"); | |
| 503 | |
| 504 init_process_options("spawn_helper6", exit_cb); | |
| 505 | |
| 506 /* open 'stdout_file' and replace STDOUT_FILENO with it */ | |
| 507 r = uv_fs_open(NULL, | |
| 508 &fs_req, | |
| 509 "stdout_file", | |
| 510 O_CREAT | O_RDWR, | |
| 511 S_IRUSR | S_IWUSR, | |
| 512 NULL); | |
| 513 ASSERT_NE(r, -1); | |
| 514 uv_fs_req_cleanup(&fs_req); | |
| 515 stdout_file = dup2(r, STDOUT_FILENO); | |
| 516 ASSERT_NE(stdout_file, -1); | |
| 517 | |
| 518 /* open 'stderr_file' and replace STDERR_FILENO with it */ | |
| 519 r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR, | |
| 520 S_IRUSR | S_IWUSR, NULL); | |
| 521 ASSERT_NE(r, -1); | |
| 522 uv_fs_req_cleanup(&fs_req); | |
| 523 stderr_file = dup2(r, STDERR_FILENO); | |
| 524 ASSERT_NE(stderr_file, -1); | |
| 525 | |
| 526 /* now we're going to swap them: the child process' stdout will be our | |
| 527 * stderr_file and vice versa */ | |
| 528 options.stdio = stdio; | |
| 529 options.stdio[0].flags = UV_IGNORE; | |
| 530 options.stdio[1].flags = UV_INHERIT_FD; | |
| 531 options.stdio[1].data.fd = stderr_file; | |
| 532 options.stdio[2].flags = UV_INHERIT_FD; | |
| 533 options.stdio[2].data.fd = stdout_file; | |
| 534 options.stdio_count = 3; | |
| 535 | |
| 536 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 537 ASSERT_OK(r); | |
| 538 | |
| 539 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 540 ASSERT_OK(r); | |
| 541 | |
| 542 ASSERT_EQ(1, exit_cb_called); | |
| 543 ASSERT_EQ(1, close_cb_called); | |
| 544 | |
| 545 buf = uv_buf_init(output, sizeof(output)); | |
| 546 | |
| 547 /* check the content of stdout_file */ | |
| 548 r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL); | |
| 549 ASSERT_GE(r, 15); | |
| 550 uv_fs_req_cleanup(&fs_req); | |
| 551 | |
| 552 r = uv_fs_close(NULL, &fs_req, stdout_file, NULL); | |
| 553 ASSERT_OK(r); | |
| 554 uv_fs_req_cleanup(&fs_req); | |
| 555 | |
| 556 printf("output is: %s", output); | |
| 557 ASSERT_OK(strncmp("hello errworld\n", output, 15)); | |
| 558 | |
| 559 /* check the content of stderr_file */ | |
| 560 r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL); | |
| 561 ASSERT_GE(r, 12); | |
| 562 uv_fs_req_cleanup(&fs_req); | |
| 563 | |
| 564 r = uv_fs_close(NULL, &fs_req, stderr_file, NULL); | |
| 565 ASSERT_OK(r); | |
| 566 uv_fs_req_cleanup(&fs_req); | |
| 567 | |
| 568 printf("output is: %s", output); | |
| 569 ASSERT_OK(strncmp("hello world\n", output, 12)); | |
| 570 | |
| 571 /* Cleanup. */ | |
| 572 unlink("stdout_file"); | |
| 573 unlink("stderr_file"); | |
| 574 | |
| 575 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 576 return 0; | |
| 577 #else | |
| 578 RETURN_SKIP("Unix only test"); | |
| 579 #endif | |
| 580 } | |
| 581 | |
| 582 | |
| 583 TEST_IMPL(spawn_stdin) { | |
| 584 int r; | |
| 585 uv_pipe_t out; | |
| 586 uv_pipe_t in; | |
| 587 uv_write_t write_req; | |
| 588 uv_buf_t buf; | |
| 589 uv_stdio_container_t stdio[2]; | |
| 590 char buffer[] = "hello-from-spawn_stdin"; | |
| 591 | |
| 592 init_process_options("spawn_helper3", exit_cb); | |
| 593 | |
| 594 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 595 uv_pipe_init(uv_default_loop(), &in, 0); | |
| 596 options.stdio = stdio; | |
| 597 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 598 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 599 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 600 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 601 options.stdio_count = 2; | |
| 602 | |
| 603 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 604 ASSERT_OK(r); | |
| 605 | |
| 606 buf.base = buffer; | |
| 607 buf.len = sizeof(buffer); | |
| 608 r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); | |
| 609 ASSERT_OK(r); | |
| 610 | |
| 611 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 612 ASSERT_OK(r); | |
| 613 | |
| 614 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 615 ASSERT_OK(r); | |
| 616 | |
| 617 ASSERT_EQ(1, exit_cb_called); | |
| 618 ASSERT_EQ(3, close_cb_called); /* Once for process twice for the pipe. */ | |
| 619 ASSERT_OK(strcmp(buffer, output)); | |
| 620 | |
| 621 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 622 return 0; | |
| 623 } | |
| 624 | |
| 625 | |
| 626 TEST_IMPL(spawn_stdio_greater_than_3) { | |
| 627 int r; | |
| 628 uv_pipe_t pipe; | |
| 629 uv_stdio_container_t stdio[4]; | |
| 630 | |
| 631 init_process_options("spawn_helper5", exit_cb); | |
| 632 | |
| 633 uv_pipe_init(uv_default_loop(), &pipe, 0); | |
| 634 options.stdio = stdio; | |
| 635 options.stdio[0].flags = UV_IGNORE; | |
| 636 options.stdio[1].flags = UV_IGNORE; | |
| 637 options.stdio[2].flags = UV_IGNORE; | |
| 638 options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 639 options.stdio[3].data.stream = (uv_stream_t*) &pipe; | |
| 640 options.stdio_count = 4; | |
| 641 | |
| 642 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 643 ASSERT_OK(r); | |
| 644 | |
| 645 r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read); | |
| 646 ASSERT_OK(r); | |
| 647 | |
| 648 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 649 ASSERT_OK(r); | |
| 650 | |
| 651 ASSERT_EQ(1, exit_cb_called); | |
| 652 ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ | |
| 653 printf("output from stdio[3] is: %s", output); | |
| 654 ASSERT_OK(strcmp("fourth stdio!\n", output)); | |
| 655 | |
| 656 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 657 return 0; | |
| 658 } | |
| 659 | |
| 660 | |
| 661 int spawn_tcp_server_helper(void) { | |
| 662 uv_tcp_t tcp; | |
| 663 uv_os_sock_t handle; | |
| 664 int r; | |
| 665 | |
| 666 r = uv_tcp_init(uv_default_loop(), &tcp); | |
| 667 ASSERT_OK(r); | |
| 668 | |
| 669 #ifdef _WIN32 | |
| 670 handle = _get_osfhandle(3); | |
| 671 #else | |
| 672 handle = 3; | |
| 673 #endif | |
| 674 r = uv_tcp_open(&tcp, handle); | |
| 675 ASSERT_OK(r); | |
| 676 | |
| 677 /* Make sure that we can listen on a socket that was | |
| 678 * passed down from the parent process | |
| 679 */ | |
| 680 r = uv_listen((uv_stream_t*) &tcp, SOMAXCONN, NULL); | |
| 681 ASSERT_OK(r); | |
| 682 | |
| 683 return 1; | |
| 684 } | |
| 685 | |
| 686 | |
| 687 TEST_IMPL(spawn_tcp_server) { | |
| 688 uv_stdio_container_t stdio[4]; | |
| 689 struct sockaddr_in addr; | |
| 690 int fd; | |
| 691 int r; | |
| 692 #ifdef _WIN32 | |
| 693 uv_os_fd_t handle; | |
| 694 #endif | |
| 695 | |
| 696 init_process_options("spawn_tcp_server_helper", exit_cb); | |
| 697 | |
| 698 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); | |
| 699 | |
| 700 fd = -1; | |
| 701 r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET); | |
| 702 ASSERT_OK(r); | |
| 703 r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); | |
| 704 ASSERT_OK(r); | |
| 705 #ifdef _WIN32 | |
| 706 r = uv_fileno((uv_handle_t*) &tcp_server, &handle); | |
| 707 fd = _open_osfhandle((intptr_t) handle, 0); | |
| 708 #else | |
| 709 r = uv_fileno((uv_handle_t*) &tcp_server, &fd); | |
| 710 #endif | |
| 711 ASSERT_OK(r); | |
| 712 ASSERT_GT(fd, 0); | |
| 713 | |
| 714 options.stdio = stdio; | |
| 715 options.stdio[0].flags = UV_INHERIT_FD; | |
| 716 options.stdio[0].data.fd = 0; | |
| 717 options.stdio[1].flags = UV_INHERIT_FD; | |
| 718 options.stdio[1].data.fd = 1; | |
| 719 options.stdio[2].flags = UV_INHERIT_FD; | |
| 720 options.stdio[2].data.fd = 2; | |
| 721 options.stdio[3].flags = UV_INHERIT_FD; | |
| 722 options.stdio[3].data.fd = fd; | |
| 723 options.stdio_count = 4; | |
| 724 | |
| 725 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 726 ASSERT_OK(r); | |
| 727 | |
| 728 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 729 ASSERT_OK(r); | |
| 730 | |
| 731 ASSERT_EQ(1, exit_cb_called); | |
| 732 ASSERT_EQ(1, close_cb_called); | |
| 733 | |
| 734 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 735 return 0; | |
| 736 } | |
| 737 | |
| 738 | |
| 739 TEST_IMPL(spawn_ignored_stdio) { | |
| 740 int r; | |
| 741 | |
| 742 init_process_options("spawn_helper6", exit_cb); | |
| 743 | |
| 744 options.stdio = NULL; | |
| 745 options.stdio_count = 0; | |
| 746 | |
| 747 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 748 ASSERT_OK(r); | |
| 749 | |
| 750 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 751 ASSERT_OK(r); | |
| 752 | |
| 753 ASSERT_EQ(1, exit_cb_called); | |
| 754 ASSERT_EQ(1, close_cb_called); | |
| 755 | |
| 756 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 757 return 0; | |
| 758 } | |
| 759 | |
| 760 | |
| 761 TEST_IMPL(spawn_and_kill) { | |
| 762 int r; | |
| 763 | |
| 764 init_process_options("spawn_helper4", kill_cb); | |
| 765 | |
| 766 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 767 ASSERT_OK(r); | |
| 768 | |
| 769 r = uv_timer_init(uv_default_loop(), &timer); | |
| 770 ASSERT_OK(r); | |
| 771 | |
| 772 r = uv_timer_start(&timer, timer_cb, 500, 0); | |
| 773 ASSERT_OK(r); | |
| 774 | |
| 775 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 776 ASSERT_OK(r); | |
| 777 | |
| 778 ASSERT_EQ(1, exit_cb_called); | |
| 779 ASSERT_EQ(2, close_cb_called); /* Once for process and once for timer. */ | |
| 780 | |
| 781 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 782 return 0; | |
| 783 } | |
| 784 | |
| 785 | |
| 786 TEST_IMPL(spawn_preserve_env) { | |
| 787 int r; | |
| 788 uv_pipe_t out; | |
| 789 uv_stdio_container_t stdio[2]; | |
| 790 | |
| 791 init_process_options("spawn_helper7", exit_cb); | |
| 792 | |
| 793 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 794 options.stdio = stdio; | |
| 795 options.stdio[0].flags = UV_IGNORE; | |
| 796 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 797 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 798 options.stdio_count = 2; | |
| 799 | |
| 800 r = putenv("ENV_TEST=testval"); | |
| 801 ASSERT_OK(r); | |
| 802 | |
| 803 /* Explicitly set options.env to NULL to test for env clobbering. */ | |
| 804 options.env = NULL; | |
| 805 | |
| 806 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 807 ASSERT_OK(r); | |
| 808 | |
| 809 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 810 ASSERT_OK(r); | |
| 811 | |
| 812 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 813 ASSERT_OK(r); | |
| 814 | |
| 815 ASSERT_EQ(1, exit_cb_called); | |
| 816 ASSERT_EQ(2, close_cb_called); | |
| 817 | |
| 818 printf("output is: %s", output); | |
| 819 ASSERT_OK(strcmp("testval", output)); | |
| 820 | |
| 821 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 822 return 0; | |
| 823 } | |
| 824 | |
| 825 | |
| 826 TEST_IMPL(spawn_detached) { | |
| 827 int r; | |
| 828 | |
| 829 init_process_options("spawn_helper4", detach_failure_cb); | |
| 830 | |
| 831 options.flags |= UV_PROCESS_DETACHED; | |
| 832 | |
| 833 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 834 ASSERT_OK(r); | |
| 835 | |
| 836 uv_unref((uv_handle_t*) &process); | |
| 837 | |
| 838 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 839 ASSERT_OK(r); | |
| 840 | |
| 841 ASSERT_OK(exit_cb_called); | |
| 842 | |
| 843 ASSERT_EQ(process.pid, uv_process_get_pid(&process)); | |
| 844 | |
| 845 r = uv_kill(process.pid, 0); | |
| 846 ASSERT_OK(r); | |
| 847 | |
| 848 r = uv_kill(process.pid, SIGTERM); | |
| 849 ASSERT_OK(r); | |
| 850 | |
| 851 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 852 return 0; | |
| 853 } | |
| 854 | |
| 855 TEST_IMPL(spawn_and_kill_with_std) { | |
| 856 int r; | |
| 857 uv_pipe_t in, out, err; | |
| 858 uv_write_t write; | |
| 859 char message[] = "Nancy's joining me because the message this evening is " | |
| 860 "not my message but ours."; | |
| 861 uv_buf_t buf; | |
| 862 uv_stdio_container_t stdio[3]; | |
| 863 | |
| 864 init_process_options("spawn_helper4", kill_cb); | |
| 865 | |
| 866 r = uv_pipe_init(uv_default_loop(), &in, 0); | |
| 867 ASSERT_OK(r); | |
| 868 | |
| 869 r = uv_pipe_init(uv_default_loop(), &out, 0); | |
| 870 ASSERT_OK(r); | |
| 871 | |
| 872 r = uv_pipe_init(uv_default_loop(), &err, 0); | |
| 873 ASSERT_OK(r); | |
| 874 | |
| 875 options.stdio = stdio; | |
| 876 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 877 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 878 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 879 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 880 options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 881 options.stdio[2].data.stream = (uv_stream_t*) &err; | |
| 882 options.stdio_count = 3; | |
| 883 | |
| 884 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 885 ASSERT_OK(r); | |
| 886 | |
| 887 buf = uv_buf_init(message, sizeof message); | |
| 888 r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb); | |
| 889 ASSERT_OK(r); | |
| 890 | |
| 891 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 892 ASSERT_OK(r); | |
| 893 | |
| 894 r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read); | |
| 895 ASSERT_OK(r); | |
| 896 | |
| 897 r = uv_timer_init(uv_default_loop(), &timer); | |
| 898 ASSERT_OK(r); | |
| 899 | |
| 900 r = uv_timer_start(&timer, timer_cb, 500, 0); | |
| 901 ASSERT_OK(r); | |
| 902 | |
| 903 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 904 ASSERT_OK(r); | |
| 905 | |
| 906 ASSERT_EQ(1, exit_cb_called); | |
| 907 ASSERT_EQ(5, close_cb_called); /* process x 1, timer x 1, stdio x 3. */ | |
| 908 | |
| 909 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 910 return 0; | |
| 911 } | |
| 912 | |
| 913 | |
| 914 TEST_IMPL(spawn_and_ping) { | |
| 915 uv_write_t write_req; | |
| 916 uv_pipe_t in, out; | |
| 917 uv_buf_t buf; | |
| 918 uv_stdio_container_t stdio[2]; | |
| 919 int r; | |
| 920 | |
| 921 init_process_options("spawn_helper3", exit_cb); | |
| 922 buf = uv_buf_init("TEST", 4); | |
| 923 | |
| 924 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 925 uv_pipe_init(uv_default_loop(), &in, 0); | |
| 926 options.stdio = stdio; | |
| 927 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 928 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 929 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 930 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 931 options.stdio_count = 2; | |
| 932 | |
| 933 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 934 ASSERT_OK(r); | |
| 935 | |
| 936 /* Sending signum == 0 should check if the | |
| 937 * child process is still alive, not kill it. | |
| 938 */ | |
| 939 r = uv_process_kill(&process, 0); | |
| 940 ASSERT_OK(r); | |
| 941 | |
| 942 r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); | |
| 943 ASSERT_OK(r); | |
| 944 | |
| 945 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 946 ASSERT_OK(r); | |
| 947 | |
| 948 ASSERT_OK(exit_cb_called); | |
| 949 | |
| 950 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 951 ASSERT_OK(r); | |
| 952 | |
| 953 ASSERT_EQ(1, exit_cb_called); | |
| 954 ASSERT_OK(strcmp(output, "TEST")); | |
| 955 | |
| 956 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 957 return 0; | |
| 958 } | |
| 959 | |
| 960 | |
| 961 TEST_IMPL(spawn_same_stdout_stderr) { | |
| 962 uv_write_t write_req; | |
| 963 uv_pipe_t in, out; | |
| 964 uv_buf_t buf; | |
| 965 uv_stdio_container_t stdio[3]; | |
| 966 int r; | |
| 967 | |
| 968 init_process_options("spawn_helper3", exit_cb); | |
| 969 buf = uv_buf_init("TEST", 4); | |
| 970 | |
| 971 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 972 uv_pipe_init(uv_default_loop(), &in, 0); | |
| 973 options.stdio = stdio; | |
| 974 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 975 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 976 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 977 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 978 options.stdio_count = 2; | |
| 979 | |
| 980 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 981 ASSERT_OK(r); | |
| 982 | |
| 983 /* Sending signum == 0 should check if the | |
| 984 * child process is still alive, not kill it. | |
| 985 */ | |
| 986 r = uv_process_kill(&process, 0); | |
| 987 ASSERT_OK(r); | |
| 988 | |
| 989 r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); | |
| 990 ASSERT_OK(r); | |
| 991 | |
| 992 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 993 ASSERT_OK(r); | |
| 994 | |
| 995 ASSERT_OK(exit_cb_called); | |
| 996 | |
| 997 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 998 ASSERT_OK(r); | |
| 999 | |
| 1000 ASSERT_EQ(1, exit_cb_called); | |
| 1001 ASSERT_OK(strcmp(output, "TEST")); | |
| 1002 | |
| 1003 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1004 return 0; | |
| 1005 } | |
| 1006 | |
| 1007 | |
| 1008 TEST_IMPL(spawn_closed_process_io) { | |
| 1009 uv_pipe_t in; | |
| 1010 uv_write_t write_req; | |
| 1011 uv_buf_t buf; | |
| 1012 uv_stdio_container_t stdio[2]; | |
| 1013 static char buffer[] = "hello-from-spawn_stdin\n"; | |
| 1014 | |
| 1015 init_process_options("spawn_helper3", exit_cb); | |
| 1016 | |
| 1017 uv_pipe_init(uv_default_loop(), &in, 0); | |
| 1018 options.stdio = stdio; | |
| 1019 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 1020 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 1021 options.stdio_count = 1; | |
| 1022 | |
| 1023 close(0); /* Close process stdin. */ | |
| 1024 | |
| 1025 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1026 | |
| 1027 buf = uv_buf_init(buffer, sizeof(buffer)); | |
| 1028 ASSERT_OK(uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb)); | |
| 1029 | |
| 1030 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1031 | |
| 1032 ASSERT_EQ(1, exit_cb_called); | |
| 1033 ASSERT_EQ(2, close_cb_called); /* process, child stdin */ | |
| 1034 | |
| 1035 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1036 return 0; | |
| 1037 } | |
| 1038 | |
| 1039 | |
| 1040 TEST_IMPL(kill) { | |
| 1041 int r; | |
| 1042 | |
| 1043 #ifdef _WIN32 | |
| 1044 no_term_signal = 1; | |
| 1045 #endif | |
| 1046 | |
| 1047 init_process_options("spawn_helper4", kill_cb); | |
| 1048 | |
| 1049 /* Verify that uv_spawn() resets the signal disposition. */ | |
| 1050 #ifndef _WIN32 | |
| 1051 { | |
| 1052 sigset_t set; | |
| 1053 sigemptyset(&set); | |
| 1054 sigaddset(&set, SIGTERM); | |
| 1055 ASSERT_OK(pthread_sigmask(SIG_BLOCK, &set, NULL)); | |
| 1056 } | |
| 1057 ASSERT_PTR_NE(SIG_ERR, signal(SIGTERM, SIG_IGN)); | |
| 1058 #endif | |
| 1059 | |
| 1060 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1061 ASSERT_OK(r); | |
| 1062 | |
| 1063 #ifndef _WIN32 | |
| 1064 { | |
| 1065 sigset_t set; | |
| 1066 sigemptyset(&set); | |
| 1067 sigaddset(&set, SIGTERM); | |
| 1068 ASSERT_OK(pthread_sigmask(SIG_UNBLOCK, &set, NULL)); | |
| 1069 } | |
| 1070 ASSERT_PTR_NE(SIG_ERR, signal(SIGTERM, SIG_DFL)); | |
| 1071 #endif | |
| 1072 | |
| 1073 /* Sending signum == 0 should check if the | |
| 1074 * child process is still alive, not kill it. | |
| 1075 */ | |
| 1076 r = uv_kill(process.pid, 0); | |
| 1077 ASSERT_OK(r); | |
| 1078 | |
| 1079 /* Kill the process. */ | |
| 1080 r = uv_kill(process.pid, SIGTERM); | |
| 1081 ASSERT_OK(r); | |
| 1082 | |
| 1083 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1084 ASSERT_OK(r); | |
| 1085 | |
| 1086 ASSERT_EQ(1, exit_cb_called); | |
| 1087 ASSERT_EQ(1, close_cb_called); | |
| 1088 | |
| 1089 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1090 return 0; | |
| 1091 } | |
| 1092 | |
| 1093 | |
| 1094 #ifdef _WIN32 | |
| 1095 TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { | |
| 1096 int r; | |
| 1097 uv_pipe_t out; | |
| 1098 char name[64]; | |
| 1099 HANDLE pipe_handle; | |
| 1100 uv_stdio_container_t stdio[2]; | |
| 1101 | |
| 1102 init_process_options("spawn_helper2", exit_cb); | |
| 1103 | |
| 1104 uv_pipe_init(uv_default_loop(), &out, 0); | |
| 1105 options.stdio = stdio; | |
| 1106 options.stdio[0].flags = UV_IGNORE; | |
| 1107 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; | |
| 1108 options.stdio[1].data.stream = (uv_stream_t*) &out; | |
| 1109 options.stdio_count = 2; | |
| 1110 | |
| 1111 /* Create a pipe that'll cause a collision. */ | |
| 1112 snprintf(name, | |
| 1113 sizeof(name), | |
| 1114 "\\\\.\\pipe\\uv\\%p-%lu", | |
| 1115 &out, | |
| 1116 GetCurrentProcessId()); | |
| 1117 pipe_handle = CreateNamedPipeA(name, | |
| 1118 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, | |
| 1119 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, | |
| 1120 10, | |
| 1121 65536, | |
| 1122 65536, | |
| 1123 0, | |
| 1124 NULL); | |
| 1125 ASSERT_PTR_NE(pipe_handle, INVALID_HANDLE_VALUE); | |
| 1126 | |
| 1127 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1128 ASSERT_OK(r); | |
| 1129 | |
| 1130 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); | |
| 1131 ASSERT_OK(r); | |
| 1132 | |
| 1133 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1134 ASSERT_OK(r); | |
| 1135 | |
| 1136 ASSERT_EQ(1, exit_cb_called); | |
| 1137 ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ | |
| 1138 printf("output is: %s", output); | |
| 1139 ASSERT_OK(strcmp("hello world\n", output)); | |
| 1140 | |
| 1141 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1142 return 0; | |
| 1143 } | |
| 1144 | |
| 1145 | |
| 1146 #if !defined(USING_UV_SHARED) | |
| 1147 int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr); | |
| 1148 WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target); | |
| 1149 | |
| 1150 TEST_IMPL(argument_escaping) { | |
| 1151 const WCHAR* test_str[] = { | |
| 1152 L"", | |
| 1153 L"HelloWorld", | |
| 1154 L"Hello World", | |
| 1155 L"Hello\"World", | |
| 1156 L"Hello World\\", | |
| 1157 L"Hello\\\"World", | |
| 1158 L"Hello\\World", | |
| 1159 L"Hello\\\\World", | |
| 1160 L"Hello World\\", | |
| 1161 L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"" | |
| 1162 }; | |
| 1163 const int count = sizeof(test_str) / sizeof(*test_str); | |
| 1164 WCHAR** test_output; | |
| 1165 WCHAR* command_line; | |
| 1166 WCHAR** cracked; | |
| 1167 size_t total_size = 0; | |
| 1168 int i; | |
| 1169 int num_args; | |
| 1170 int result; | |
| 1171 | |
| 1172 char* verbatim[] = { | |
| 1173 "cmd.exe", | |
| 1174 "/c", | |
| 1175 "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"", | |
| 1176 NULL | |
| 1177 }; | |
| 1178 WCHAR* verbatim_output; | |
| 1179 WCHAR* non_verbatim_output; | |
| 1180 | |
| 1181 test_output = calloc(count, sizeof(WCHAR*)); | |
| 1182 ASSERT_NOT_NULL(test_output); | |
| 1183 for (i = 0; i < count; ++i) { | |
| 1184 test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR)); | |
| 1185 quote_cmd_arg(test_str[i], test_output[i]); | |
| 1186 wprintf(L"input : %s\n", test_str[i]); | |
| 1187 wprintf(L"output: %s\n", test_output[i]); | |
| 1188 total_size += wcslen(test_output[i]) + 1; | |
| 1189 } | |
| 1190 command_line = calloc(total_size + 1, sizeof(WCHAR)); | |
| 1191 ASSERT_NOT_NULL(command_line); | |
| 1192 for (i = 0; i < count; ++i) { | |
| 1193 wcscat(command_line, test_output[i]); | |
| 1194 wcscat(command_line, L" "); | |
| 1195 } | |
| 1196 command_line[total_size - 1] = L'\0'; | |
| 1197 | |
| 1198 wprintf(L"command_line: %s\n", command_line); | |
| 1199 | |
| 1200 cracked = CommandLineToArgvW(command_line, &num_args); | |
| 1201 for (i = 0; i < num_args; ++i) { | |
| 1202 wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]); | |
| 1203 ASSERT_OK(wcscmp(test_str[i], cracked[i])); | |
| 1204 } | |
| 1205 | |
| 1206 LocalFree(cracked); | |
| 1207 for (i = 0; i < count; ++i) { | |
| 1208 free(test_output[i]); | |
| 1209 } | |
| 1210 free(test_output); | |
| 1211 | |
| 1212 result = make_program_args(verbatim, 1, &verbatim_output); | |
| 1213 ASSERT_OK(result); | |
| 1214 result = make_program_args(verbatim, 0, &non_verbatim_output); | |
| 1215 ASSERT_OK(result); | |
| 1216 | |
| 1217 wprintf(L" verbatim_output: %s\n", verbatim_output); | |
| 1218 wprintf(L"non_verbatim_output: %s\n", non_verbatim_output); | |
| 1219 | |
| 1220 ASSERT_OK(wcscmp(verbatim_output, | |
| 1221 L"cmd.exe /c c:\\path\\to\\node.exe --eval " | |
| 1222 L"\"require('c:\\\\path\\\\to\\\\test.js')\"")); | |
| 1223 ASSERT_OK(wcscmp(non_verbatim_output, | |
| 1224 L"cmd.exe /c \"c:\\path\\to\\node.exe --eval " | |
| 1225 L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"")); | |
| 1226 | |
| 1227 free(verbatim_output); | |
| 1228 free(non_verbatim_output); | |
| 1229 | |
| 1230 return 0; | |
| 1231 } | |
| 1232 | |
| 1233 int make_program_env(char** env_block, WCHAR** dst_ptr); | |
| 1234 | |
| 1235 TEST_IMPL(environment_creation) { | |
| 1236 size_t i; | |
| 1237 char* environment[] = { | |
| 1238 "FOO=BAR", | |
| 1239 "SYSTEM=ROOT", /* substring of a supplied var name */ | |
| 1240 "SYSTEMROOTED=OMG", /* supplied var name is a substring */ | |
| 1241 "TEMP=C:\\Temp", | |
| 1242 "INVALID", | |
| 1243 "BAZ=QUX", | |
| 1244 "B_Z=QUX", | |
| 1245 "B\xe2\x82\xacZ=QUX", | |
| 1246 "B\xf0\x90\x80\x82Z=QUX", | |
| 1247 "B\xef\xbd\xa1Z=QUX", | |
| 1248 "B\xf0\xa3\x91\x96Z=QUX", | |
| 1249 "BAZ", /* repeat, invalid variable */ | |
| 1250 NULL | |
| 1251 }; | |
| 1252 WCHAR* wenvironment[] = { | |
| 1253 L"BAZ=QUX", | |
| 1254 L"B_Z=QUX", | |
| 1255 L"B\x20acZ=QUX", | |
| 1256 L"B\xd800\xdc02Z=QUX", | |
| 1257 L"B\xd84d\xdc56Z=QUX", | |
| 1258 L"B\xff61Z=QUX", | |
| 1259 L"FOO=BAR", | |
| 1260 L"SYSTEM=ROOT", /* substring of a supplied var name */ | |
| 1261 L"SYSTEMROOTED=OMG", /* supplied var name is a substring */ | |
| 1262 L"TEMP=C:\\Temp", | |
| 1263 }; | |
| 1264 WCHAR* from_env[] = { | |
| 1265 /* list should be kept in sync with list | |
| 1266 * in process.c, minus variables in wenvironment */ | |
| 1267 L"HOMEDRIVE", | |
| 1268 L"HOMEPATH", | |
| 1269 L"LOGONSERVER", | |
| 1270 L"PATH", | |
| 1271 L"USERDOMAIN", | |
| 1272 L"USERNAME", | |
| 1273 L"USERPROFILE", | |
| 1274 L"SYSTEMDRIVE", | |
| 1275 L"SYSTEMROOT", | |
| 1276 L"WINDIR", | |
| 1277 /* test for behavior in the absence of a | |
| 1278 * required-environment variable: */ | |
| 1279 L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST", | |
| 1280 }; | |
| 1281 int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0}; | |
| 1282 int found_in_usr_env[ARRAY_SIZE(from_env)] = {0}; | |
| 1283 WCHAR *expected[ARRAY_SIZE(from_env)]; | |
| 1284 int result; | |
| 1285 WCHAR* str; | |
| 1286 WCHAR* prev; | |
| 1287 WCHAR* env; | |
| 1288 | |
| 1289 for (i = 0; i < ARRAY_SIZE(from_env); i++) { | |
| 1290 /* copy expected additions to environment locally */ | |
| 1291 size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0); | |
| 1292 if (len == 0) { | |
| 1293 found_in_usr_env[i] = 1; | |
| 1294 str = malloc(1 * sizeof(WCHAR)); | |
| 1295 *str = 0; | |
| 1296 expected[i] = str; | |
| 1297 } else { | |
| 1298 size_t name_len = wcslen(from_env[i]); | |
| 1299 str = malloc((name_len+1+len) * sizeof(WCHAR)); | |
| 1300 wmemcpy(str, from_env[i], name_len); | |
| 1301 expected[i] = str; | |
| 1302 str += name_len; | |
| 1303 *str++ = L'='; | |
| 1304 GetEnvironmentVariableW(from_env[i], str, len); | |
| 1305 } | |
| 1306 } | |
| 1307 | |
| 1308 result = make_program_env(environment, &env); | |
| 1309 ASSERT_OK(result); | |
| 1310 | |
| 1311 for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) { | |
| 1312 int found = 0; | |
| 1313 #if 0 | |
| 1314 _cputws(str); | |
| 1315 putchar('\n'); | |
| 1316 #endif | |
| 1317 for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) { | |
| 1318 if (!wcscmp(str, wenvironment[i])) { | |
| 1319 ASSERT(!found_in_loc_env[i]); | |
| 1320 found_in_loc_env[i] = 1; | |
| 1321 found = 1; | |
| 1322 } | |
| 1323 } | |
| 1324 for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) { | |
| 1325 if (!wcscmp(str, expected[i])) { | |
| 1326 ASSERT(!found_in_usr_env[i]); | |
| 1327 found_in_usr_env[i] = 1; | |
| 1328 found = 1; | |
| 1329 } | |
| 1330 } | |
| 1331 if (prev) { /* verify sort order */ | |
| 1332 ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE)); | |
| 1333 } | |
| 1334 ASSERT(found); /* verify that we expected this variable */ | |
| 1335 } | |
| 1336 | |
| 1337 /* verify that we found all expected variables */ | |
| 1338 for (i = 0; i < ARRAY_SIZE(wenvironment); i++) { | |
| 1339 ASSERT(found_in_loc_env[i]); | |
| 1340 } | |
| 1341 for (i = 0; i < ARRAY_SIZE(expected); i++) { | |
| 1342 ASSERT(found_in_usr_env[i]); | |
| 1343 } | |
| 1344 | |
| 1345 return 0; | |
| 1346 } | |
| 1347 #endif | |
| 1348 | |
| 1349 /* Regression test for issue #909 */ | |
| 1350 TEST_IMPL(spawn_with_an_odd_path) { | |
| 1351 int r; | |
| 1352 | |
| 1353 char newpath[2048]; | |
| 1354 char *path = getenv("PATH"); | |
| 1355 ASSERT_NOT_NULL(path); | |
| 1356 snprintf(newpath, 2048, ";.;%s", path); | |
| 1357 SetEnvironmentVariable("PATH", newpath); | |
| 1358 | |
| 1359 init_process_options("", exit_cb); | |
| 1360 options.file = options.args[0] = "program-that-had-better-not-exist"; | |
| 1361 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1362 ASSERT(r == UV_ENOENT || r == UV_EACCES); | |
| 1363 ASSERT_OK(uv_is_active((uv_handle_t*) &process)); | |
| 1364 uv_close((uv_handle_t*) &process, NULL); | |
| 1365 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1366 | |
| 1367 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1368 return 0; | |
| 1369 } | |
| 1370 | |
| 1371 | |
| 1372 TEST_IMPL(spawn_no_path) { | |
| 1373 char* env[1]; | |
| 1374 WCHAR* old_path = NULL; | |
| 1375 DWORD old_path_len; | |
| 1376 | |
| 1377 if ((old_path_len = GetEnvironmentVariableW(L"PATH", NULL, 0)) > 0) { | |
| 1378 old_path = malloc(old_path_len * sizeof(WCHAR)); | |
| 1379 GetEnvironmentVariableW(L"PATH", old_path, old_path_len); | |
| 1380 SetEnvironmentVariableW(L"PATH", NULL); | |
| 1381 } | |
| 1382 | |
| 1383 init_process_options("spawn_helper1", exit_cb); | |
| 1384 options.env = env; | |
| 1385 env[0] = NULL; | |
| 1386 | |
| 1387 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1388 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1389 | |
| 1390 ASSERT_EQ(1, exit_cb_called); | |
| 1391 ASSERT_EQ(1, close_cb_called); | |
| 1392 | |
| 1393 SetEnvironmentVariableW(L"PATH", old_path); | |
| 1394 | |
| 1395 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1396 return 0; | |
| 1397 } | |
| 1398 | |
| 1399 | |
| 1400 TEST_IMPL(spawn_no_ext) { | |
| 1401 char new_exepath[1024]; | |
| 1402 | |
| 1403 init_process_options("spawn_helper1", exit_cb); | |
| 1404 options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; | |
| 1405 snprintf(new_exepath, sizeof(new_exepath), "%.*s_no_ext", | |
| 1406 (int) (exepath_size - sizeof(".exe") + 1), | |
| 1407 exepath); | |
| 1408 options.file = options.args[0] = new_exepath; | |
| 1409 | |
| 1410 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1411 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1412 | |
| 1413 ASSERT_EQ(1, exit_cb_called); | |
| 1414 ASSERT_EQ(1, close_cb_called); | |
| 1415 | |
| 1416 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1417 return 0; | |
| 1418 } | |
| 1419 | |
| 1420 | |
| 1421 TEST_IMPL(spawn_path_no_ext) { | |
| 1422 int r; | |
| 1423 int len; | |
| 1424 int file_len; | |
| 1425 char file[64]; | |
| 1426 char path[1024]; | |
| 1427 char* env[2]; | |
| 1428 | |
| 1429 /* Set up the process, but make sure that the file to run is relative and | |
| 1430 * requires a lookup into PATH. */ | |
| 1431 init_process_options("spawn_helper1", exit_cb); | |
| 1432 options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; | |
| 1433 | |
| 1434 /* Set up the PATH env variable */ | |
| 1435 for (len = strlen(exepath), file_len = 0; | |
| 1436 exepath[len - 1] != '/' && exepath[len - 1] != '\\'; | |
| 1437 len--, file_len++); | |
| 1438 snprintf(file, sizeof(file), "%.*s_no_ext", | |
| 1439 (int) (file_len - sizeof(".exe") + 1), | |
| 1440 exepath + len); | |
| 1441 exepath[len] = 0; | |
| 1442 snprintf(path, sizeof(path), "PATH=%s", exepath); | |
| 1443 | |
| 1444 env[0] = path; | |
| 1445 env[1] = NULL; | |
| 1446 | |
| 1447 options.file = options.args[0] = file; | |
| 1448 options.env = env; | |
| 1449 | |
| 1450 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1451 ASSERT(r == UV_ENOENT || r == UV_EACCES); | |
| 1452 ASSERT_OK(uv_is_active((uv_handle_t*) &process)); | |
| 1453 uv_close((uv_handle_t*) &process, NULL); | |
| 1454 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1455 | |
| 1456 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1457 return 0; | |
| 1458 } | |
| 1459 #endif | |
| 1460 | |
| 1461 #ifndef _WIN32 | |
| 1462 TEST_IMPL(spawn_setuid_setgid) { | |
| 1463 int r; | |
| 1464 struct passwd* pw; | |
| 1465 char uidstr[10]; | |
| 1466 char gidstr[10]; | |
| 1467 | |
| 1468 /* if not root, then this will fail. */ | |
| 1469 uv_uid_t uid = getuid(); | |
| 1470 if (uid != 0) { | |
| 1471 RETURN_SKIP("It should be run as root user"); | |
| 1472 } | |
| 1473 | |
| 1474 init_process_options("spawn_helper_setuid_setgid", exit_cb); | |
| 1475 | |
| 1476 /* become the "nobody" user. */ | |
| 1477 pw = getpwnam("nobody"); | |
| 1478 ASSERT_NOT_NULL(pw); | |
| 1479 options.uid = pw->pw_uid; | |
| 1480 options.gid = pw->pw_gid; | |
| 1481 snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); | |
| 1482 snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); | |
| 1483 options.args[2] = uidstr; | |
| 1484 options.args[3] = gidstr; | |
| 1485 options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID; | |
| 1486 | |
| 1487 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1488 if (r == UV_EACCES) | |
| 1489 RETURN_SKIP("user 'nobody' cannot access the test runner"); | |
| 1490 | |
| 1491 ASSERT_OK(r); | |
| 1492 | |
| 1493 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1494 ASSERT_OK(r); | |
| 1495 | |
| 1496 ASSERT_EQ(1, exit_cb_called); | |
| 1497 ASSERT_EQ(1, close_cb_called); | |
| 1498 | |
| 1499 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1500 return 0; | |
| 1501 } | |
| 1502 #endif | |
| 1503 | |
| 1504 | |
| 1505 #ifndef _WIN32 | |
| 1506 TEST_IMPL(spawn_setuid_fails) { | |
| 1507 int r; | |
| 1508 | |
| 1509 /* if root, become nobody. */ | |
| 1510 /* On IBMi PASE, there is no nobody user. */ | |
| 1511 #ifndef __PASE__ | |
| 1512 uv_uid_t uid = getuid(); | |
| 1513 if (uid == 0) { | |
| 1514 struct passwd* pw; | |
| 1515 pw = getpwnam("nobody"); | |
| 1516 ASSERT_NOT_NULL(pw); | |
| 1517 ASSERT_OK(setgid(pw->pw_gid)); | |
| 1518 ASSERT_OK(setuid(pw->pw_uid)); | |
| 1519 } | |
| 1520 #endif /* !__PASE__ */ | |
| 1521 | |
| 1522 init_process_options("spawn_helper1", fail_cb); | |
| 1523 | |
| 1524 options.flags |= UV_PROCESS_SETUID; | |
| 1525 /* On IBMi PASE, there is no root user. User may grant | |
| 1526 * root-like privileges, including setting uid to 0. | |
| 1527 */ | |
| 1528 #if defined(__PASE__) | |
| 1529 options.uid = -1; | |
| 1530 #else | |
| 1531 options.uid = 0; | |
| 1532 #endif | |
| 1533 | |
| 1534 /* These flags should be ignored on Unices. */ | |
| 1535 options.flags |= UV_PROCESS_WINDOWS_HIDE; | |
| 1536 options.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE; | |
| 1537 options.flags |= UV_PROCESS_WINDOWS_HIDE_GUI; | |
| 1538 options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; | |
| 1539 | |
| 1540 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1541 #if defined(__CYGWIN__) | |
| 1542 ASSERT_EQ(r, UV_EINVAL); | |
| 1543 #else | |
| 1544 ASSERT_EQ(r, UV_EPERM); | |
| 1545 #endif | |
| 1546 | |
| 1547 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1548 ASSERT_OK(r); | |
| 1549 | |
| 1550 ASSERT_OK(close_cb_called); | |
| 1551 | |
| 1552 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1553 return 0; | |
| 1554 } | |
| 1555 | |
| 1556 | |
| 1557 TEST_IMPL(spawn_setgid_fails) { | |
| 1558 int r; | |
| 1559 | |
| 1560 /* if root, become nobody. */ | |
| 1561 /* On IBMi PASE, there is no nobody user. */ | |
| 1562 #ifndef __PASE__ | |
| 1563 uv_uid_t uid = getuid(); | |
| 1564 if (uid == 0) { | |
| 1565 struct passwd* pw; | |
| 1566 pw = getpwnam("nobody"); | |
| 1567 ASSERT_NOT_NULL(pw); | |
| 1568 ASSERT_OK(setgid(pw->pw_gid)); | |
| 1569 ASSERT_OK(setuid(pw->pw_uid)); | |
| 1570 } | |
| 1571 #endif /* !__PASE__ */ | |
| 1572 | |
| 1573 init_process_options("spawn_helper1", fail_cb); | |
| 1574 | |
| 1575 options.flags |= UV_PROCESS_SETGID; | |
| 1576 /* On IBMi PASE, there is no root user. User may grant | |
| 1577 * root-like privileges, including setting gid to 0. | |
| 1578 */ | |
| 1579 #if defined(__MVS__) || defined(__PASE__) | |
| 1580 options.gid = -1; | |
| 1581 #else | |
| 1582 options.gid = 0; | |
| 1583 #endif | |
| 1584 | |
| 1585 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1586 #if defined(__CYGWIN__) || defined(__MVS__) | |
| 1587 ASSERT_EQ(r, UV_EINVAL); | |
| 1588 #else | |
| 1589 ASSERT_EQ(r, UV_EPERM); | |
| 1590 #endif | |
| 1591 | |
| 1592 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1593 ASSERT_OK(r); | |
| 1594 | |
| 1595 ASSERT_OK(close_cb_called); | |
| 1596 | |
| 1597 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1598 return 0; | |
| 1599 } | |
| 1600 #endif | |
| 1601 | |
| 1602 | |
| 1603 #ifdef _WIN32 | |
| 1604 | |
| 1605 static void exit_cb_unexpected(uv_process_t* process, | |
| 1606 int64_t exit_status, | |
| 1607 int term_signal) { | |
| 1608 ASSERT(0 && "should not have been called"); | |
| 1609 } | |
| 1610 | |
| 1611 | |
| 1612 TEST_IMPL(spawn_setuid_fails) { | |
| 1613 int r; | |
| 1614 | |
| 1615 init_process_options("spawn_helper1", exit_cb_unexpected); | |
| 1616 | |
| 1617 options.flags |= UV_PROCESS_SETUID; | |
| 1618 options.uid = (uv_uid_t) -42424242; | |
| 1619 | |
| 1620 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1621 ASSERT_EQ(r, UV_ENOTSUP); | |
| 1622 | |
| 1623 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1624 ASSERT_OK(r); | |
| 1625 | |
| 1626 ASSERT_OK(close_cb_called); | |
| 1627 | |
| 1628 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1629 return 0; | |
| 1630 } | |
| 1631 | |
| 1632 | |
| 1633 TEST_IMPL(spawn_setgid_fails) { | |
| 1634 int r; | |
| 1635 | |
| 1636 init_process_options("spawn_helper1", exit_cb_unexpected); | |
| 1637 | |
| 1638 options.flags |= UV_PROCESS_SETGID; | |
| 1639 options.gid = (uv_gid_t) -42424242; | |
| 1640 | |
| 1641 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1642 ASSERT_EQ(r, UV_ENOTSUP); | |
| 1643 | |
| 1644 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1645 ASSERT_OK(r); | |
| 1646 | |
| 1647 ASSERT_OK(close_cb_called); | |
| 1648 | |
| 1649 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1650 return 0; | |
| 1651 } | |
| 1652 #endif | |
| 1653 | |
| 1654 | |
| 1655 TEST_IMPL(spawn_auto_unref) { | |
| 1656 init_process_options("spawn_helper1", NULL); | |
| 1657 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1658 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1659 ASSERT_OK(uv_is_closing((uv_handle_t*) &process)); | |
| 1660 uv_close((uv_handle_t*) &process, NULL); | |
| 1661 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1662 ASSERT_EQ(1, uv_is_closing((uv_handle_t*) &process)); | |
| 1663 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1664 return 0; | |
| 1665 } | |
| 1666 | |
| 1667 | |
| 1668 TEST_IMPL(spawn_fs_open) { | |
| 1669 int r; | |
| 1670 uv_os_fd_t fd; | |
| 1671 uv_os_fd_t dup_fd; | |
| 1672 uv_fs_t fs_req; | |
| 1673 uv_pipe_t in; | |
| 1674 uv_write_t write_req; | |
| 1675 uv_write_t write_req2; | |
| 1676 uv_buf_t buf; | |
| 1677 uv_stdio_container_t stdio[1]; | |
| 1678 #ifdef _WIN32 | |
| 1679 const char dev_null[] = "NUL"; | |
| 1680 HMODULE kernelbase_module; | |
| 1681 sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */ | |
| 1682 #else | |
| 1683 const char dev_null[] = "/dev/null"; | |
| 1684 #endif | |
| 1685 | |
| 1686 r = uv_fs_open(NULL, &fs_req, dev_null, UV_FS_O_RDWR, 0, NULL); | |
| 1687 ASSERT_NE(r, -1); | |
| 1688 fd = uv_get_osfhandle((uv_file) fs_req.result); | |
| 1689 uv_fs_req_cleanup(&fs_req); | |
| 1690 | |
| 1691 init_process_options("spawn_helper8", exit_cb); | |
| 1692 | |
| 1693 ASSERT_OK(uv_pipe_init(uv_default_loop(), &in, 0)); | |
| 1694 | |
| 1695 options.stdio = stdio; | |
| 1696 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; | |
| 1697 options.stdio[0].data.stream = (uv_stream_t*) ∈ | |
| 1698 options.stdio_count = 1; | |
| 1699 | |
| 1700 /* make an inheritable copy */ | |
| 1701 #ifdef _WIN32 | |
| 1702 ASSERT_NE(0, DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd, | |
| 1703 0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS)); | |
| 1704 kernelbase_module = GetModuleHandleA("kernelbase.dll"); | |
| 1705 pCompareObjectHandles = (sCompareObjectHandles) | |
| 1706 GetProcAddress(kernelbase_module, "CompareObjectHandles"); | |
| 1707 ASSERT_NE(pCompareObjectHandles == NULL || | |
| 1708 pCompareObjectHandles(fd, dup_fd), | |
| 1709 0); | |
| 1710 #else | |
| 1711 dup_fd = dup(fd); | |
| 1712 #endif | |
| 1713 | |
| 1714 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1715 | |
| 1716 buf = uv_buf_init((char*) &fd, sizeof(fd)); | |
| 1717 ASSERT_OK(uv_write(&write_req, | |
| 1718 (uv_stream_t*) &in, | |
| 1719 &buf, | |
| 1720 1, | |
| 1721 write_null_cb)); | |
| 1722 | |
| 1723 buf = uv_buf_init((char*) &dup_fd, sizeof(fd)); | |
| 1724 ASSERT_OK(uv_write(&write_req2, (uv_stream_t*) &in, &buf, 1, write_cb)); | |
| 1725 | |
| 1726 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 1727 ASSERT_OK(uv_fs_close(NULL, &fs_req, r, NULL)); | |
| 1728 | |
| 1729 ASSERT_EQ(1, exit_cb_called); | |
| 1730 ASSERT_EQ(2, close_cb_called); /* One for `in`, one for process */ | |
| 1731 | |
| 1732 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1733 return 0; | |
| 1734 } | |
| 1735 | |
| 1736 | |
| 1737 TEST_IMPL(closed_fd_events) { | |
| 1738 uv_stdio_container_t stdio[3]; | |
| 1739 uv_pipe_t pipe_handle; | |
| 1740 uv_fs_t req; | |
| 1741 uv_buf_t bufs[1]; | |
| 1742 uv_file fd[2]; | |
| 1743 bufs[0] = uv_buf_init("", 1); | |
| 1744 | |
| 1745 /* create a pipe and share it with a child process */ | |
| 1746 ASSERT_OK(uv_pipe(fd, 0, 0)); | |
| 1747 ASSERT_GT(fd[0], 2); | |
| 1748 ASSERT_GT(fd[1], 2); | |
| 1749 | |
| 1750 /* spawn_helper4 blocks indefinitely. */ | |
| 1751 init_process_options("spawn_helper4", exit_cb); | |
| 1752 options.stdio_count = 3; | |
| 1753 options.stdio = stdio; | |
| 1754 options.stdio[0].flags = UV_INHERIT_FD; | |
| 1755 options.stdio[0].data.fd = fd[0]; | |
| 1756 options.stdio[1].flags = UV_IGNORE; | |
| 1757 options.stdio[2].flags = UV_IGNORE; | |
| 1758 | |
| 1759 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 1760 uv_unref((uv_handle_t*) &process); | |
| 1761 | |
| 1762 /* read from the pipe with uv */ | |
| 1763 ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); | |
| 1764 ASSERT_OK(uv_pipe_open(&pipe_handle, fd[0])); | |
| 1765 /* uv_pipe_open() takes ownership of the file descriptor. */ | |
| 1766 fd[0] = -1; | |
| 1767 | |
| 1768 ASSERT_OK(uv_read_start((uv_stream_t*) &pipe_handle, | |
| 1769 on_alloc, | |
| 1770 on_read_once)); | |
| 1771 | |
| 1772 ASSERT_EQ(1, uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); | |
| 1773 ASSERT_EQ(1, req.result); | |
| 1774 uv_fs_req_cleanup(&req); | |
| 1775 | |
| 1776 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); | |
| 1777 | |
| 1778 /* should have received just one byte */ | |
| 1779 ASSERT_EQ(1, output_used); | |
| 1780 | |
| 1781 /* close the pipe and see if we still get events */ | |
| 1782 uv_close((uv_handle_t*) &pipe_handle, close_cb); | |
| 1783 | |
| 1784 ASSERT_EQ(1, uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); | |
| 1785 ASSERT_EQ(1, req.result); | |
| 1786 uv_fs_req_cleanup(&req); | |
| 1787 | |
| 1788 ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); | |
| 1789 ASSERT_OK(uv_timer_start(&timer, timer_counter_cb, 10, 0)); | |
| 1790 | |
| 1791 /* see if any spurious events interrupt the timer */ | |
| 1792 if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE)) | |
| 1793 /* have to run again to really trigger the timer */ | |
| 1794 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); | |
| 1795 | |
| 1796 ASSERT_EQ(1, timer_counter); | |
| 1797 | |
| 1798 /* cleanup */ | |
| 1799 ASSERT_OK(uv_process_kill(&process, SIGTERM)); | |
| 1800 #ifdef _WIN32 | |
| 1801 ASSERT_OK(_close(fd[1])); | |
| 1802 #else | |
| 1803 ASSERT_OK(close(fd[1])); | |
| 1804 #endif | |
| 1805 | |
| 1806 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1807 return 0; | |
| 1808 } | |
| 1809 | |
| 1810 | |
| 1811 TEST_IMPL(spawn_reads_child_path) { | |
| 1812 int r; | |
| 1813 int len; | |
| 1814 char file[64]; | |
| 1815 char path[1024]; | |
| 1816 char* env[3]; | |
| 1817 | |
| 1818 /* Need to carry over the dynamic linker path when the test runner is | |
| 1819 * linked against libuv.so, see https://github.com/libuv/libuv/issues/85. | |
| 1820 */ | |
| 1821 #if defined(__APPLE__) | |
| 1822 static const char dyld_path_var[] = "DYLD_LIBRARY_PATH"; | |
| 1823 #elif defined(__MVS__) || defined(__PASE__) | |
| 1824 static const char dyld_path_var[] = "LIBPATH"; | |
| 1825 #else | |
| 1826 static const char dyld_path_var[] = "LD_LIBRARY_PATH"; | |
| 1827 #endif | |
| 1828 | |
| 1829 /* Set up the process, but make sure that the file to run is relative and | |
| 1830 * requires a lookup into PATH. */ | |
| 1831 init_process_options("spawn_helper1", exit_cb); | |
| 1832 | |
| 1833 /* Set up the PATH env variable */ | |
| 1834 for (len = strlen(exepath); | |
| 1835 exepath[len - 1] != '/' && exepath[len - 1] != '\\'; | |
| 1836 len--); | |
| 1837 strcpy(file, exepath + len); | |
| 1838 exepath[len] = 0; | |
| 1839 strcpy(path, "PATH="); | |
| 1840 strcpy(path + 5, exepath); | |
| 1841 #if defined(__CYGWIN__) || defined(__MSYS__) | |
| 1842 /* Carry over the dynamic linker path in case the test runner | |
| 1843 is linked against cyguv-1.dll or msys-uv-1.dll, see above. */ | |
| 1844 { | |
| 1845 char* syspath = getenv("PATH"); | |
| 1846 if (syspath != NULL) { | |
| 1847 strcat(path, ":"); | |
| 1848 strcat(path, syspath); | |
| 1849 } | |
| 1850 } | |
| 1851 #endif | |
| 1852 | |
| 1853 env[0] = path; | |
| 1854 env[1] = getenv(dyld_path_var); | |
| 1855 env[2] = NULL; | |
| 1856 | |
| 1857 if (env[1] != NULL) { | |
| 1858 static char buf[1024 + sizeof(dyld_path_var)]; | |
| 1859 snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]); | |
| 1860 env[1] = buf; | |
| 1861 } | |
| 1862 | |
| 1863 options.file = file; | |
| 1864 options.args[0] = file; | |
| 1865 options.env = env; | |
| 1866 | |
| 1867 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1868 ASSERT_OK(r); | |
| 1869 | |
| 1870 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 1871 ASSERT_OK(r); | |
| 1872 | |
| 1873 ASSERT_EQ(1, exit_cb_called); | |
| 1874 ASSERT_EQ(1, close_cb_called); | |
| 1875 | |
| 1876 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1877 return 0; | |
| 1878 } | |
| 1879 | |
| 1880 TEST_IMPL(spawn_inherit_streams) { | |
| 1881 uv_process_t child_req; | |
| 1882 uv_stdio_container_t child_stdio[2]; | |
| 1883 int fds_stdin[2]; | |
| 1884 int fds_stdout[2]; | |
| 1885 uv_pipe_t pipe_stdin_child; | |
| 1886 uv_pipe_t pipe_stdout_child; | |
| 1887 uv_pipe_t pipe_stdin_parent; | |
| 1888 uv_pipe_t pipe_stdout_parent; | |
| 1889 unsigned char ubuf[OUTPUT_SIZE - 1]; | |
| 1890 uv_buf_t buf; | |
| 1891 unsigned int i; | |
| 1892 int r; | |
| 1893 int bidir; | |
| 1894 uv_write_t write_req; | |
| 1895 uv_loop_t* loop; | |
| 1896 | |
| 1897 init_process_options("spawn_helper9", exit_cb); | |
| 1898 | |
| 1899 loop = uv_default_loop(); | |
| 1900 ASSERT_OK(uv_pipe_init(loop, &pipe_stdin_child, 0)); | |
| 1901 ASSERT_OK(uv_pipe_init(loop, &pipe_stdout_child, 0)); | |
| 1902 ASSERT_OK(uv_pipe_init(loop, &pipe_stdin_parent, 0)); | |
| 1903 ASSERT_OK(uv_pipe_init(loop, &pipe_stdout_parent, 0)); | |
| 1904 | |
| 1905 ASSERT_OK(uv_pipe(fds_stdin, 0, 0)); | |
| 1906 ASSERT_OK(uv_pipe(fds_stdout, 0, 0)); | |
| 1907 | |
| 1908 ASSERT_OK(uv_pipe_open(&pipe_stdin_child, fds_stdin[0])); | |
| 1909 ASSERT_OK(uv_pipe_open(&pipe_stdout_child, fds_stdout[1])); | |
| 1910 ASSERT_OK(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1])); | |
| 1911 ASSERT_OK(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0])); | |
| 1912 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child)); | |
| 1913 ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child)); | |
| 1914 ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent)); | |
| 1915 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent)); | |
| 1916 /* Some systems (SVR4) open a bidirectional pipe, most don't. */ | |
| 1917 bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child); | |
| 1918 ASSERT_EQ(uv_is_readable((uv_stream_t*) &pipe_stdout_child), bidir); | |
| 1919 ASSERT_EQ(uv_is_readable((uv_stream_t*) &pipe_stdin_parent), bidir); | |
| 1920 ASSERT_EQ(uv_is_writable((uv_stream_t*) &pipe_stdout_parent), bidir); | |
| 1921 | |
| 1922 child_stdio[0].flags = UV_INHERIT_STREAM; | |
| 1923 child_stdio[0].data.stream = (uv_stream_t *) &pipe_stdin_child; | |
| 1924 | |
| 1925 child_stdio[1].flags = UV_INHERIT_STREAM; | |
| 1926 child_stdio[1].data.stream = (uv_stream_t *) &pipe_stdout_child; | |
| 1927 | |
| 1928 options.stdio = child_stdio; | |
| 1929 options.stdio_count = 2; | |
| 1930 | |
| 1931 ASSERT_OK(uv_spawn(loop, &child_req, &options)); | |
| 1932 | |
| 1933 uv_close((uv_handle_t*) &pipe_stdin_child, NULL); | |
| 1934 uv_close((uv_handle_t*) &pipe_stdout_child, NULL); | |
| 1935 | |
| 1936 buf = uv_buf_init((char*) ubuf, sizeof ubuf); | |
| 1937 for (i = 0; i < sizeof ubuf; ++i) | |
| 1938 ubuf[i] = i & 255u; | |
| 1939 memset(output, 0, sizeof ubuf); | |
| 1940 | |
| 1941 r = uv_write(&write_req, | |
| 1942 (uv_stream_t*) &pipe_stdin_parent, | |
| 1943 &buf, | |
| 1944 1, | |
| 1945 write_cb); | |
| 1946 ASSERT_OK(r); | |
| 1947 | |
| 1948 r = uv_read_start((uv_stream_t*) &pipe_stdout_parent, on_alloc, on_read); | |
| 1949 ASSERT_OK(r); | |
| 1950 | |
| 1951 r = uv_run(loop, UV_RUN_DEFAULT); | |
| 1952 ASSERT_OK(r); | |
| 1953 | |
| 1954 ASSERT_EQ(1, exit_cb_called); | |
| 1955 ASSERT_EQ(3, close_cb_called); | |
| 1956 | |
| 1957 r = memcmp(ubuf, output, sizeof ubuf); | |
| 1958 ASSERT_OK(r); | |
| 1959 | |
| 1960 MAKE_VALGRIND_HAPPY(loop); | |
| 1961 return 0; | |
| 1962 } | |
| 1963 | |
| 1964 TEST_IMPL(spawn_quoted_path) { | |
| 1965 #ifndef _WIN32 | |
| 1966 RETURN_SKIP("Test for Windows"); | |
| 1967 #else | |
| 1968 char* quoted_path_env[2]; | |
| 1969 args[0] = "not_existing"; | |
| 1970 args[1] = NULL; | |
| 1971 options.file = args[0]; | |
| 1972 options.args = args; | |
| 1973 options.exit_cb = exit_cb; | |
| 1974 options.flags = 0; | |
| 1975 /* We test if search_path works correctly with semicolons in quoted path. We | |
| 1976 * will use an invalid drive, so we are sure no executable is spawned. */ | |
| 1977 quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; | |
| 1978 quoted_path_env[1] = NULL; | |
| 1979 options.env = quoted_path_env; | |
| 1980 | |
| 1981 /* We test if libuv will not segfault. */ | |
| 1982 uv_spawn(uv_default_loop(), &process, &options); | |
| 1983 | |
| 1984 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 1985 return 0; | |
| 1986 #endif | |
| 1987 } | |
| 1988 | |
| 1989 TEST_IMPL(spawn_exercise_sigchld_issue) { | |
| 1990 int r; | |
| 1991 int i; | |
| 1992 uv_process_options_t dummy_options = {0}; | |
| 1993 uv_process_t dummy_processes[100]; | |
| 1994 char* args[2]; | |
| 1995 | |
| 1996 init_process_options("spawn_helper1", exit_cb); | |
| 1997 | |
| 1998 r = uv_spawn(uv_default_loop(), &process, &options); | |
| 1999 ASSERT_OK(r); | |
| 2000 | |
| 2001 // This test exercises a bug in the darwin kernel that causes SIGCHLD not to | |
| 2002 // be delivered sometimes. Calling posix_spawn many times increases the | |
| 2003 // likelihood of encountering this issue, so spin a few times to make this | |
| 2004 // test more reliable. | |
| 2005 dummy_options.file = args[0] = "program-that-had-better-not-exist"; | |
| 2006 args[1] = NULL; | |
| 2007 dummy_options.args = args; | |
| 2008 dummy_options.exit_cb = fail_cb; | |
| 2009 dummy_options.flags = 0; | |
| 2010 for (i = 0; i < 100; i++) { | |
| 2011 r = uv_spawn(uv_default_loop(), &dummy_processes[i], &dummy_options); | |
| 2012 if (r != UV_ENOENT) | |
| 2013 ASSERT_EQ(r, UV_EACCES); | |
| 2014 uv_close((uv_handle_t*) &dummy_processes[i], close_cb); | |
| 2015 } | |
| 2016 | |
| 2017 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 2018 ASSERT_OK(r); | |
| 2019 | |
| 2020 ASSERT_EQ(1, exit_cb_called); | |
| 2021 ASSERT_EQ(101, close_cb_called); | |
| 2022 | |
| 2023 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 2024 return 0; | |
| 2025 } | |
| 2026 | |
| 2027 /* Helper for child process of spawn_inherit_streams */ | |
| 2028 #ifndef _WIN32 | |
| 2029 void spawn_stdin_stdout(void) { | |
| 2030 char buf[1024]; | |
| 2031 char* pbuf; | |
| 2032 for (;;) { | |
| 2033 ssize_t r, w, c; | |
| 2034 do { | |
| 2035 r = read(0, buf, sizeof buf); | |
| 2036 } while (r == -1 && errno == EINTR); | |
| 2037 if (r == 0) { | |
| 2038 return; | |
| 2039 } | |
| 2040 ASSERT_GT(r, 0); | |
| 2041 c = r; | |
| 2042 pbuf = buf; | |
| 2043 while (c) { | |
| 2044 do { | |
| 2045 w = write(1, pbuf, (size_t)c); | |
| 2046 } while (w == -1 && errno == EINTR); | |
| 2047 ASSERT_GE(w, 0); | |
| 2048 pbuf = pbuf + w; | |
| 2049 c = c - w; | |
| 2050 } | |
| 2051 } | |
| 2052 } | |
| 2053 #else | |
| 2054 void spawn_stdin_stdout(void) { | |
| 2055 char buf[1024]; | |
| 2056 char* pbuf; | |
| 2057 HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE); | |
| 2058 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); | |
| 2059 ASSERT_PTR_NE(h_stdin, INVALID_HANDLE_VALUE); | |
| 2060 ASSERT_PTR_NE(h_stdout, INVALID_HANDLE_VALUE); | |
| 2061 for (;;) { | |
| 2062 DWORD n_read; | |
| 2063 DWORD n_written; | |
| 2064 DWORD to_write; | |
| 2065 if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) { | |
| 2066 ASSERT_EQ(GetLastError(), ERROR_BROKEN_PIPE); | |
| 2067 return; | |
| 2068 } | |
| 2069 to_write = n_read; | |
| 2070 pbuf = buf; | |
| 2071 while (to_write) { | |
| 2072 ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL)); | |
| 2073 to_write -= n_written; | |
| 2074 pbuf += n_written; | |
| 2075 } | |
| 2076 } | |
| 2077 } | |
| 2078 #endif /* !_WIN32 */ | |
| 2079 | |
| 2080 TEST_IMPL(spawn_relative_path) { | |
| 2081 char* sep; | |
| 2082 | |
| 2083 init_process_options("spawn_helper1", exit_cb); | |
| 2084 | |
| 2085 exepath_size = sizeof(exepath) - 2; | |
| 2086 ASSERT_OK(uv_exepath(exepath, &exepath_size)); | |
| 2087 exepath[exepath_size] = '\0'; | |
| 2088 | |
| 2089 /* Poor man's basename(3). */ | |
| 2090 sep = strrchr(exepath, '/'); | |
| 2091 if (sep == NULL) | |
| 2092 sep = strrchr(exepath, '\\'); | |
| 2093 ASSERT_NOT_NULL(sep); | |
| 2094 | |
| 2095 /* Split into dirname and basename and make basename relative. */ | |
| 2096 memmove(sep + 2, sep, 1 + strlen(sep)); | |
| 2097 sep[0] = '\0'; | |
| 2098 sep[1] = '.'; | |
| 2099 sep[2] = '/'; | |
| 2100 | |
| 2101 options.cwd = exepath; | |
| 2102 options.file = options.args[0] = sep + 1; | |
| 2103 | |
| 2104 ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); | |
| 2105 ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); | |
| 2106 | |
| 2107 ASSERT_EQ(1, exit_cb_called); | |
| 2108 ASSERT_EQ(1, close_cb_called); | |
| 2109 | |
| 2110 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 2111 return 0; | |
| 2112 } |