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