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