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