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
close_cb(uv_handle_t * handle)62 static void close_cb(uv_handle_t* handle) {
63 printf("close_cb\n");
64 close_cb_called++;
65 }
66
exit_cb(uv_process_t * process,int64_t exit_status,int term_signal)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
fail_cb(uv_process_t * process,int64_t exit_status,int term_signal)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
kill_cb(uv_process_t * process,int64_t exit_status,int term_signal)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
detach_failure_cb(uv_process_t * process,int64_t exit_status,int term_signal)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
on_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)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
on_read(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)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
on_read_once(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)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
write_cb(uv_write_t * req,int status)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
init_process_options(char * test,uv_exit_cb exit_cb)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
timer_cb(uv_timer_t * handle)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
timer_counter_cb(uv_timer_t * handle)181 static void timer_counter_cb(uv_timer_t* handle) {
182 ++timer_counter;
183 }
184 #endif
185
186
TEST_IMPL(spawn_fails)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
TEST_IMPL(spawn_fails_check_for_waitpid_cleanup)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
TEST_IMPL(spawn_empty_env)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_LIBRARY_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
TEST_IMPL(spawn_exit_code)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
TEST_IMPL(spawn_stdout)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
TEST_IMPL(spawn_stdout_to_file)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
TEST_IMPL(spawn_stdout_and_stderr_to_file)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
TEST_IMPL(spawn_stdout_and_stderr_to_file2)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
TEST_IMPL(spawn_stdout_and_stderr_to_file_swap)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
TEST_IMPL(spawn_stdin)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
TEST_IMPL(spawn_stdio_greater_than_3)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
spawn_tcp_server_helper(void)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
TEST_IMPL(spawn_tcp_server)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
TEST_IMPL(spawn_ignored_stdio)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
TEST_IMPL(spawn_and_kill)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
TEST_IMPL(spawn_preserve_env)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
TEST_IMPL(spawn_detached)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
TEST_IMPL(spawn_and_kill_with_std)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
TEST_IMPL(spawn_and_ping)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
TEST_IMPL(spawn_same_stdout_stderr)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
TEST_IMPL(spawn_closed_process_io)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
TEST_IMPL(kill)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
TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows)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
TEST_IMPL(argument_escaping)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
TEST_IMPL(environment_creation)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 */
TEST_IMPL(spawn_with_an_odd_path)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
TEST_IMPL(spawn_setuid_setgid)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
TEST_IMPL(spawn_setuid_fails)1419 TEST_IMPL(spawn_setuid_fails) {
1420 int r;
1421
1422 /* if root, become nobody. */
1423 /* On IBMi PASE, there is no nobody user. */
1424 #ifndef __PASE__
1425 uv_uid_t uid = getuid();
1426 if (uid == 0) {
1427 struct passwd* pw;
1428 pw = getpwnam("nobody");
1429 ASSERT(pw != NULL);
1430 ASSERT(0 == setgid(pw->pw_gid));
1431 ASSERT(0 == setuid(pw->pw_uid));
1432 }
1433 #endif /* !__PASE__ */
1434
1435 init_process_options("spawn_helper1", fail_cb);
1436
1437 options.flags |= UV_PROCESS_SETUID;
1438 /* On IBMi PASE, there is no root user. User may grant
1439 * root-like privileges, including setting uid to 0.
1440 */
1441 #if defined(__PASE__)
1442 options.uid = -1;
1443 #else
1444 options.uid = 0;
1445 #endif
1446
1447 /* These flags should be ignored on Unices. */
1448 options.flags |= UV_PROCESS_WINDOWS_HIDE;
1449 options.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE;
1450 options.flags |= UV_PROCESS_WINDOWS_HIDE_GUI;
1451 options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
1452
1453 r = uv_spawn(uv_default_loop(), &process, &options);
1454 #if defined(__CYGWIN__) || defined(__PASE__)
1455 ASSERT(r == UV_EINVAL);
1456 #else
1457 ASSERT(r == UV_EPERM);
1458 #endif
1459
1460 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1461 ASSERT(r == 0);
1462
1463 ASSERT(close_cb_called == 0);
1464
1465 MAKE_VALGRIND_HAPPY();
1466 return 0;
1467 }
1468
1469
TEST_IMPL(spawn_setgid_fails)1470 TEST_IMPL(spawn_setgid_fails) {
1471 int r;
1472
1473 /* if root, become nobody. */
1474 /* On IBMi PASE, there is no nobody user. */
1475 #ifndef __PASE__
1476 uv_uid_t uid = getuid();
1477 if (uid == 0) {
1478 struct passwd* pw;
1479 pw = getpwnam("nobody");
1480 ASSERT(pw != NULL);
1481 ASSERT(0 == setgid(pw->pw_gid));
1482 ASSERT(0 == setuid(pw->pw_uid));
1483 }
1484 #endif /* !__PASE__ */
1485
1486 init_process_options("spawn_helper1", fail_cb);
1487
1488 options.flags |= UV_PROCESS_SETGID;
1489 /* On IBMi PASE, there is no root user. User may grant
1490 * root-like privileges, including setting gid to 0.
1491 */
1492 #if defined(__MVS__) || defined(__PASE__)
1493 options.gid = -1;
1494 #else
1495 options.gid = 0;
1496 #endif
1497
1498 r = uv_spawn(uv_default_loop(), &process, &options);
1499 #if defined(__CYGWIN__) || defined(__MVS__) || defined(__PASE__)
1500 ASSERT(r == UV_EINVAL);
1501 #else
1502 ASSERT(r == UV_EPERM);
1503 #endif
1504
1505 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1506 ASSERT(r == 0);
1507
1508 ASSERT(close_cb_called == 0);
1509
1510 MAKE_VALGRIND_HAPPY();
1511 return 0;
1512 }
1513 #endif
1514
1515
1516 #ifdef _WIN32
1517
exit_cb_unexpected(uv_process_t * process,int64_t exit_status,int term_signal)1518 static void exit_cb_unexpected(uv_process_t* process,
1519 int64_t exit_status,
1520 int term_signal) {
1521 ASSERT(0 && "should not have been called");
1522 }
1523
1524
TEST_IMPL(spawn_setuid_fails)1525 TEST_IMPL(spawn_setuid_fails) {
1526 int r;
1527
1528 init_process_options("spawn_helper1", exit_cb_unexpected);
1529
1530 options.flags |= UV_PROCESS_SETUID;
1531 options.uid = (uv_uid_t) -42424242;
1532
1533 r = uv_spawn(uv_default_loop(), &process, &options);
1534 ASSERT(r == UV_ENOTSUP);
1535
1536 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1537 ASSERT(r == 0);
1538
1539 ASSERT(close_cb_called == 0);
1540
1541 MAKE_VALGRIND_HAPPY();
1542 return 0;
1543 }
1544
1545
TEST_IMPL(spawn_setgid_fails)1546 TEST_IMPL(spawn_setgid_fails) {
1547 int r;
1548
1549 init_process_options("spawn_helper1", exit_cb_unexpected);
1550
1551 options.flags |= UV_PROCESS_SETGID;
1552 options.gid = (uv_gid_t) -42424242;
1553
1554 r = uv_spawn(uv_default_loop(), &process, &options);
1555 ASSERT(r == UV_ENOTSUP);
1556
1557 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1558 ASSERT(r == 0);
1559
1560 ASSERT(close_cb_called == 0);
1561
1562 MAKE_VALGRIND_HAPPY();
1563 return 0;
1564 }
1565 #endif
1566
1567
TEST_IMPL(spawn_auto_unref)1568 TEST_IMPL(spawn_auto_unref) {
1569 init_process_options("spawn_helper1", NULL);
1570 ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1571 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1572 ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
1573 uv_close((uv_handle_t*) &process, NULL);
1574 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1575 ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
1576 MAKE_VALGRIND_HAPPY();
1577 return 0;
1578 }
1579
1580
1581 #ifndef _WIN32
TEST_IMPL(spawn_fs_open)1582 TEST_IMPL(spawn_fs_open) {
1583 int fd;
1584 uv_fs_t fs_req;
1585 uv_pipe_t in;
1586 uv_write_t write_req;
1587 uv_buf_t buf;
1588 uv_stdio_container_t stdio[1];
1589
1590 fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
1591 ASSERT(fd >= 0);
1592 uv_fs_req_cleanup(&fs_req);
1593
1594 init_process_options("spawn_helper8", exit_cb);
1595
1596 ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
1597
1598 options.stdio = stdio;
1599 options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
1600 options.stdio[0].data.stream = (uv_stream_t*) ∈
1601 options.stdio_count = 1;
1602
1603 ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1604
1605 buf = uv_buf_init((char*) &fd, sizeof(fd));
1606 ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
1607
1608 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1609 ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
1610
1611 ASSERT(exit_cb_called == 1);
1612 ASSERT(close_cb_called == 2); /* One for `in`, one for process */
1613
1614 MAKE_VALGRIND_HAPPY();
1615 return 0;
1616 }
1617 #endif /* !_WIN32 */
1618
1619
1620 #ifndef _WIN32
TEST_IMPL(closed_fd_events)1621 TEST_IMPL(closed_fd_events) {
1622 uv_stdio_container_t stdio[3];
1623 uv_pipe_t pipe_handle;
1624 int fd[2];
1625
1626 /* create a pipe and share it with a child process */
1627 ASSERT(0 == pipe(fd));
1628
1629 /* spawn_helper4 blocks indefinitely. */
1630 init_process_options("spawn_helper4", exit_cb);
1631 options.stdio_count = 3;
1632 options.stdio = stdio;
1633 options.stdio[0].flags = UV_INHERIT_FD;
1634 options.stdio[0].data.fd = fd[0];
1635 options.stdio[1].flags = UV_IGNORE;
1636 options.stdio[2].flags = UV_IGNORE;
1637
1638 ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
1639 uv_unref((uv_handle_t*) &process);
1640
1641 /* read from the pipe with uv */
1642 ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
1643 ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
1644 fd[0] = -1;
1645
1646 ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
1647
1648 ASSERT(1 == write(fd[1], "", 1));
1649
1650 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
1651
1652 /* should have received just one byte */
1653 ASSERT(output_used == 1);
1654
1655 /* close the pipe and see if we still get events */
1656 uv_close((uv_handle_t*) &pipe_handle, close_cb);
1657
1658 ASSERT(1 == write(fd[1], "", 1));
1659
1660 ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
1661 ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
1662
1663 /* see if any spurious events interrupt the timer */
1664 if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
1665 /* have to run again to really trigger the timer */
1666 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
1667
1668 ASSERT(timer_counter == 1);
1669
1670 /* cleanup */
1671 ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
1672 ASSERT(0 == close(fd[1]));
1673
1674 MAKE_VALGRIND_HAPPY();
1675 return 0;
1676 }
1677 #endif /* !_WIN32 */
1678
TEST_IMPL(spawn_reads_child_path)1679 TEST_IMPL(spawn_reads_child_path) {
1680 int r;
1681 int len;
1682 char file[64];
1683 char path[1024];
1684 char* env[3];
1685
1686 /* Need to carry over the dynamic linker path when the test runner is
1687 * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
1688 */
1689 #if defined(__APPLE__)
1690 static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
1691 #elif defined __MVS__
1692 static const char dyld_path_var[] = "LIBPATH";
1693 #else
1694 static const char dyld_path_var[] = "LD_LIBRARY_PATH";
1695 #endif
1696
1697 /* Set up the process, but make sure that the file to run is relative and
1698 * requires a lookup into PATH. */
1699 init_process_options("spawn_helper1", exit_cb);
1700
1701 /* Set up the PATH env variable */
1702 for (len = strlen(exepath);
1703 exepath[len - 1] != '/' && exepath[len - 1] != '\\';
1704 len--);
1705 strcpy(file, exepath + len);
1706 exepath[len] = 0;
1707 strcpy(path, "PATH=");
1708 strcpy(path + 5, exepath);
1709 #if defined(__CYGWIN__) || defined(__MSYS__)
1710 /* Carry over the dynamic linker path in case the test runner
1711 is linked against cyguv-1.dll or msys-uv-1.dll, see above. */
1712 {
1713 char* syspath = getenv("PATH");
1714 if (syspath != NULL) {
1715 strcat(path, ":");
1716 strcat(path, syspath);
1717 }
1718 }
1719 #endif
1720
1721 env[0] = path;
1722 env[1] = getenv(dyld_path_var);
1723 env[2] = NULL;
1724
1725 if (env[1] != NULL) {
1726 static char buf[1024 + sizeof(dyld_path_var)];
1727 snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
1728 env[1] = buf;
1729 }
1730
1731 options.file = file;
1732 options.args[0] = file;
1733 options.env = env;
1734
1735 r = uv_spawn(uv_default_loop(), &process, &options);
1736 ASSERT(r == 0);
1737
1738 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
1739 ASSERT(r == 0);
1740
1741 ASSERT(exit_cb_called == 1);
1742 ASSERT(close_cb_called == 1);
1743
1744 MAKE_VALGRIND_HAPPY();
1745 return 0;
1746 }
1747
1748 #ifndef _WIN32
mpipe(int * fds)1749 static int mpipe(int *fds) {
1750 if (pipe(fds) == -1)
1751 return -1;
1752 if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
1753 fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
1754 close(fds[0]);
1755 close(fds[1]);
1756 return -1;
1757 }
1758 return 0;
1759 }
1760 #else
mpipe(int * fds)1761 static int mpipe(int *fds) {
1762 SECURITY_ATTRIBUTES attr;
1763 HANDLE readh, writeh;
1764 attr.nLength = sizeof(attr);
1765 attr.lpSecurityDescriptor = NULL;
1766 attr.bInheritHandle = FALSE;
1767 if (!CreatePipe(&readh, &writeh, &attr, 0))
1768 return -1;
1769 fds[0] = _open_osfhandle((intptr_t)readh, 0);
1770 fds[1] = _open_osfhandle((intptr_t)writeh, 0);
1771 if (fds[0] == -1 || fds[1] == -1) {
1772 CloseHandle(readh);
1773 CloseHandle(writeh);
1774 return -1;
1775 }
1776 return 0;
1777 }
1778 #endif /* !_WIN32 */
1779
TEST_IMPL(spawn_inherit_streams)1780 TEST_IMPL(spawn_inherit_streams) {
1781 uv_process_t child_req;
1782 uv_stdio_container_t child_stdio[2];
1783 int fds_stdin[2];
1784 int fds_stdout[2];
1785 uv_pipe_t pipe_stdin_child;
1786 uv_pipe_t pipe_stdout_child;
1787 uv_pipe_t pipe_stdin_parent;
1788 uv_pipe_t pipe_stdout_parent;
1789 unsigned char ubuf[OUTPUT_SIZE - 1];
1790 uv_buf_t buf;
1791 unsigned int i;
1792 int r;
1793 int bidir;
1794 uv_write_t write_req;
1795 uv_loop_t* loop;
1796
1797 init_process_options("spawn_helper9", exit_cb);
1798
1799 loop = uv_default_loop();
1800 ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
1801 ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
1802 ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
1803 ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
1804
1805 ASSERT(mpipe(fds_stdin) != -1);
1806 ASSERT(mpipe(fds_stdout) != -1);
1807
1808 ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
1809 ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
1810 ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
1811 ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
1812 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child));
1813 ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child));
1814 ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent));
1815 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent));
1816 /* Some systems (SVR4) open a bidirectional pipe, most don't. */
1817 bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child);
1818 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir);
1819 ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir);
1820 ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir);
1821
1822 child_stdio[0].flags = UV_INHERIT_STREAM;
1823 child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
1824
1825 child_stdio[1].flags = UV_INHERIT_STREAM;
1826 child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
1827
1828 options.stdio = child_stdio;
1829 options.stdio_count = 2;
1830
1831 ASSERT(uv_spawn(loop, &child_req, &options) == 0);
1832
1833 uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
1834 uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
1835
1836 buf = uv_buf_init((char*)ubuf, sizeof ubuf);
1837 for (i = 0; i < sizeof ubuf; ++i)
1838 ubuf[i] = i & 255u;
1839 memset(output, 0, sizeof ubuf);
1840
1841 r = uv_write(&write_req,
1842 (uv_stream_t*)&pipe_stdin_parent,
1843 &buf,
1844 1,
1845 write_cb);
1846 ASSERT(r == 0);
1847
1848 r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
1849 ASSERT(r == 0);
1850
1851 r = uv_run(loop, UV_RUN_DEFAULT);
1852 ASSERT(r == 0);
1853
1854 ASSERT(exit_cb_called == 1);
1855 ASSERT(close_cb_called == 3);
1856
1857 r = memcmp(ubuf, output, sizeof ubuf);
1858 ASSERT(r == 0);
1859
1860 MAKE_VALGRIND_HAPPY();
1861 return 0;
1862 }
1863
TEST_IMPL(spawn_quoted_path)1864 TEST_IMPL(spawn_quoted_path) {
1865 #ifndef _WIN32
1866 RETURN_SKIP("Test for Windows");
1867 #else
1868 char* quoted_path_env[2];
1869 args[0] = "not_existing";
1870 args[1] = NULL;
1871 options.file = args[0];
1872 options.args = args;
1873 options.exit_cb = exit_cb;
1874 options.flags = 0;
1875 /* We test if search_path works correctly with semicolons in quoted path. We
1876 * will use an invalid drive, so we are sure no executable is spawned. */
1877 quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other";
1878 quoted_path_env[1] = NULL;
1879 options.env = quoted_path_env;
1880
1881 /* We test if libuv will not segfault. */
1882 uv_spawn(uv_default_loop(), &process, &options);
1883
1884 MAKE_VALGRIND_HAPPY();
1885 return 0;
1886 #endif
1887 }
1888
1889 /* Helper for child process of spawn_inherit_streams */
1890 #ifndef _WIN32
spawn_stdin_stdout(void)1891 void spawn_stdin_stdout(void) {
1892 char buf[1024];
1893 char* pbuf;
1894 for (;;) {
1895 ssize_t r, w, c;
1896 do {
1897 r = read(0, buf, sizeof buf);
1898 } while (r == -1 && errno == EINTR);
1899 if (r == 0) {
1900 return;
1901 }
1902 ASSERT(r > 0);
1903 c = r;
1904 pbuf = buf;
1905 while (c) {
1906 do {
1907 w = write(1, pbuf, (size_t)c);
1908 } while (w == -1 && errno == EINTR);
1909 ASSERT(w >= 0);
1910 pbuf = pbuf + w;
1911 c = c - w;
1912 }
1913 }
1914 }
1915 #else
spawn_stdin_stdout(void)1916 void spawn_stdin_stdout(void) {
1917 char buf[1024];
1918 char* pbuf;
1919 HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
1920 HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
1921 ASSERT(h_stdin != INVALID_HANDLE_VALUE);
1922 ASSERT(h_stdout != INVALID_HANDLE_VALUE);
1923 for (;;) {
1924 DWORD n_read;
1925 DWORD n_written;
1926 DWORD to_write;
1927 if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
1928 ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
1929 return;
1930 }
1931 to_write = n_read;
1932 pbuf = buf;
1933 while (to_write) {
1934 ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
1935 to_write -= n_written;
1936 pbuf += n_written;
1937 }
1938 }
1939 }
1940 #endif /* !_WIN32 */
1941