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