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