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