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