Blame test/test-spawn.c

Packit b5b901
Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "task.h"
Packit b5b901
#include <errno.h>
Packit b5b901
#include <fcntl.h>
Packit b5b901
#include <stdio.h>
Packit b5b901
#include <stdlib.h>
Packit b5b901
#include <string.h>
Packit b5b901
Packit b5b901
#ifdef _WIN32
Packit b5b901
# if defined(__MINGW32__)
Packit b5b901
#  include <basetyps.h>
Packit b5b901
# endif
Packit b5b901
# include <shellapi.h>
Packit b5b901
# include <wchar.h>
Packit b5b901
#else
Packit b5b901
# include <unistd.h>
Packit b5b901
# include <sys/wait.h>
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
static int close_cb_called;
Packit b5b901
static int exit_cb_called;
Packit b5b901
static uv_process_t process;
Packit b5b901
static uv_timer_t timer;
Packit b5b901
static uv_process_options_t options;
Packit b5b901
static char exepath[1024];
Packit b5b901
static size_t exepath_size = 1024;
Packit b5b901
static char* args[5];
Packit b5b901
static int no_term_signal;
Packit b5b901
static int timer_counter;
Packit b5b901
static uv_tcp_t tcp_server;
Packit b5b901
Packit b5b901
#define OUTPUT_SIZE 1024
Packit b5b901
static char output[OUTPUT_SIZE];
Packit b5b901
static int output_used;
Packit b5b901
Packit b5b901
Packit b5b901
static void close_cb(uv_handle_t* handle) {
Packit b5b901
  printf("close_cb\n");
Packit b5b901
  close_cb_called++;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void exit_cb(uv_process_t* process,
Packit b5b901
                    int64_t exit_status,
Packit b5b901
                    int term_signal) {
Packit b5b901
  printf("exit_cb\n");
Packit b5b901
  exit_cb_called++;
Packit b5b901
  ASSERT(exit_status == 1);
Packit b5b901
  ASSERT(term_signal == 0);
Packit b5b901
  uv_close((uv_handle_t*)process, close_cb);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void fail_cb(uv_process_t* process,
Packit b5b901
                    int64_t exit_status,
Packit b5b901
                    int term_signal) {
Packit b5b901
  ASSERT(0 && "fail_cb called");
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void kill_cb(uv_process_t* process,
Packit b5b901
                    int64_t exit_status,
Packit b5b901
                    int term_signal) {
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  printf("exit_cb\n");
Packit b5b901
  exit_cb_called++;
Packit b5b901
#ifdef _WIN32
Packit b5b901
  ASSERT(exit_status == 1);
Packit b5b901
#else
Packit b5b901
  ASSERT(exit_status == 0);
Packit b5b901
#endif
Packit b5b901
#if defined(__APPLE__) || defined(__MVS__)
Packit b5b901
  /*
Packit b5b901
   * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a
Packit b5b901
   * process that is still starting up kills it with SIGKILL instead of SIGTERM.
Packit b5b901
   * See: https://github.com/libuv/libuv/issues/1226
Packit b5b901
   */
Packit b5b901
  ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL);
Packit b5b901
#else
Packit b5b901
  ASSERT(no_term_signal || term_signal == SIGTERM);
Packit b5b901
#endif
Packit b5b901
  uv_close((uv_handle_t*)process, close_cb);
Packit b5b901
Packit b5b901
  /*
Packit b5b901
   * Sending signum == 0 should check if the
Packit b5b901
   * child process is still alive, not kill it.
Packit b5b901
   * This process should be dead.
Packit b5b901
   */
Packit b5b901
  err = uv_kill(process->pid, 0);
Packit b5b901
  ASSERT(err == UV_ESRCH);
Packit b5b901
}
Packit b5b901
Packit b5b901
static void detach_failure_cb(uv_process_t* process,
Packit b5b901
                              int64_t exit_status,
Packit b5b901
                              int term_signal) {
Packit b5b901
  printf("detach_cb\n");
Packit b5b901
  exit_cb_called++;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void on_alloc(uv_handle_t* handle,
Packit b5b901
                     size_t suggested_size,
Packit b5b901
                     uv_buf_t* buf) {
Packit b5b901
  buf->base = output + output_used;
Packit b5b901
  buf->len = OUTPUT_SIZE - output_used;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
Packit b5b901
  if (nread > 0) {
Packit b5b901
    output_used += nread;
Packit b5b901
  } else if (nread < 0) {
Packit b5b901
    ASSERT(nread == UV_EOF);
Packit b5b901
    uv_close((uv_handle_t*)tcp, close_cb);
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
Packit b5b901
  uv_read_stop(tcp);
Packit b5b901
  on_read(tcp, nread, buf);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void write_cb(uv_write_t* req, int status) {
Packit b5b901
  ASSERT(status == 0);
Packit b5b901
  uv_close((uv_handle_t*)req->handle, close_cb);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void init_process_options(char* test, uv_exit_cb exit_cb) {
Packit b5b901
  /* Note spawn_helper1 defined in test/run-tests.c */
Packit b5b901
  int r = uv_exepath(exepath, &exepath_size);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  exepath[exepath_size] = '\0';
Packit b5b901
  args[0] = exepath;
Packit b5b901
  args[1] = test;
Packit b5b901
  args[2] = NULL;
Packit b5b901
  args[3] = NULL;
Packit b5b901
  args[4] = NULL;
Packit b5b901
  options.file = exepath;
Packit b5b901
  options.args = args;
Packit b5b901
  options.exit_cb = exit_cb;
Packit b5b901
  options.flags = 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void timer_cb(uv_timer_t* handle) {
Packit b5b901
  uv_process_kill(&process, /* SIGTERM */ 15);
Packit b5b901
  uv_close((uv_handle_t*)handle, close_cb);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void timer_counter_cb(uv_timer_t* handle) {
Packit b5b901
  ++timer_counter;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_fails) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("", fail_cb);
Packit b5b901
  options.file = options.args[0] = "program-that-had-better-not-exist";
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == UV_ENOENT || r == UV_EACCES);
Packit b5b901
  ASSERT(0 == uv_is_active((uv_handle_t*) &process));
Packit b5b901
  uv_close((uv_handle_t*) &process, NULL);
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
Packit b5b901
  int r;
Packit b5b901
  int status;
Packit b5b901
  int err;
Packit b5b901
Packit b5b901
  init_process_options("", fail_cb);
Packit b5b901
  options.file = options.args[0] = "program-that-had-better-not-exist";
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == UV_ENOENT || r == UV_EACCES);
Packit b5b901
  ASSERT(0 == uv_is_active((uv_handle_t*) &process));
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
Packit b5b901
  /* verify the child is successfully cleaned up within libuv */
Packit b5b901
  do
Packit b5b901
    err = waitpid(process.pid, &status, 0);
Packit b5b901
  while (err == -1 && errno == EINTR);
Packit b5b901
Packit b5b901
  ASSERT(err == -1);
Packit b5b901
  ASSERT(errno == ECHILD);
Packit b5b901
Packit b5b901
  uv_close((uv_handle_t*) &process, NULL);
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_exit_code) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper1", exit_cb);
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdout) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t out;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper2", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("hello world\n", output) == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdout_to_file) {
Packit b5b901
  int r;
Packit b5b901
  uv_file file;
Packit b5b901
  uv_fs_t fs_req;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  /* Setup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper2", exit_cb);
Packit b5b901
Packit b5b901
  r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
Packit b5b901
      S_IRUSR | S_IWUSR, NULL);
Packit b5b901
  ASSERT(r != -1);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  file = r;
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[1].data.fd = file;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  buf = uv_buf_init(output, sizeof(output));
Packit b5b901
  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
Packit b5b901
  ASSERT(r == 12);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &fs_req, file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("hello world\n", output) == 0);
Packit b5b901
Packit b5b901
  /* Cleanup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdout_and_stderr_to_file) {
Packit b5b901
  int r;
Packit b5b901
  uv_file file;
Packit b5b901
  uv_fs_t fs_req;
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  /* Setup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper6", exit_cb);
Packit b5b901
Packit b5b901
  r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
Packit b5b901
      S_IRUSR | S_IWUSR, NULL);
Packit b5b901
  ASSERT(r != -1);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  file = r;
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[1].data.fd = file;
Packit b5b901
  options.stdio[2].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[2].data.fd = file;
Packit b5b901
  options.stdio_count = 3;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  buf = uv_buf_init(output, sizeof(output));
Packit b5b901
  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
Packit b5b901
  ASSERT(r == 27);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &fs_req, file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
Packit b5b901
Packit b5b901
  /* Cleanup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
Packit b5b901
#ifndef _WIN32
Packit b5b901
  int r;
Packit b5b901
  uv_file file;
Packit b5b901
  uv_fs_t fs_req;
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  /* Setup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper6", exit_cb);
Packit b5b901
Packit b5b901
  /* Replace stderr with our file */
Packit b5b901
  r = uv_fs_open(NULL,
Packit b5b901
                 &fs_req,
Packit b5b901
                 "stdout_file",
Packit b5b901
                 O_CREAT | O_RDWR,
Packit b5b901
                 S_IRUSR | S_IWUSR,
Packit b5b901
                 NULL);
Packit b5b901
  ASSERT(r != -1);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
  file = dup2(r, STDERR_FILENO);
Packit b5b901
  ASSERT(file != -1);
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[1].data.fd = file;
Packit b5b901
  options.stdio[2].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[2].data.fd = file;
Packit b5b901
  options.stdio_count = 3;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  buf = uv_buf_init(output, sizeof(output));
Packit b5b901
  r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
Packit b5b901
  ASSERT(r == 27);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &fs_req, file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
Packit b5b901
Packit b5b901
  /* Cleanup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
#else
Packit b5b901
  RETURN_SKIP("Unix only test");
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
Packit b5b901
#ifndef _WIN32
Packit b5b901
  int r;
Packit b5b901
  uv_file stdout_file;
Packit b5b901
  uv_file stderr_file;
Packit b5b901
  uv_fs_t fs_req;
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  /* Setup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
  unlink("stderr_file");
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper6", exit_cb);
Packit b5b901
Packit b5b901
  /* open 'stdout_file' and replace STDOUT_FILENO with it */
Packit b5b901
  r = uv_fs_open(NULL,
Packit b5b901
                 &fs_req,
Packit b5b901
                 "stdout_file",
Packit b5b901
                 O_CREAT | O_RDWR,
Packit b5b901
                 S_IRUSR | S_IWUSR,
Packit b5b901
                 NULL);
Packit b5b901
  ASSERT(r != -1);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
  stdout_file = dup2(r, STDOUT_FILENO);
Packit b5b901
  ASSERT(stdout_file != -1);
Packit b5b901
Packit b5b901
  /* open 'stderr_file' and replace STDERR_FILENO with it */
Packit b5b901
  r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
Packit b5b901
      S_IRUSR | S_IWUSR, NULL);
Packit b5b901
  ASSERT(r != -1);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
  stderr_file = dup2(r, STDERR_FILENO);
Packit b5b901
  ASSERT(stderr_file != -1);
Packit b5b901
Packit b5b901
  /* now we're going to swap them: the child process' stdout will be our
Packit b5b901
   * stderr_file and vice versa */
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[1].data.fd = stderr_file;
Packit b5b901
  options.stdio[2].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[2].data.fd = stdout_file;
Packit b5b901
  options.stdio_count = 3;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  buf = uv_buf_init(output, sizeof(output));
Packit b5b901
Packit b5b901
  /* check the content of stdout_file */
Packit b5b901
  r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
Packit b5b901
  ASSERT(r >= 15);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strncmp("hello errworld\n", output, 15) == 0);
Packit b5b901
Packit b5b901
  /* check the content of stderr_file */
Packit b5b901
  r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
Packit b5b901
  ASSERT(r >= 12);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strncmp("hello world\n", output, 12) == 0);
Packit b5b901
Packit b5b901
  /* Cleanup. */
Packit b5b901
  unlink("stdout_file");
Packit b5b901
  unlink("stderr_file");
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
#else
Packit b5b901
  RETURN_SKIP("Unix only test");
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdin) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t out;
Packit b5b901
  uv_pipe_t in;
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
  char buffer[] = "hello-from-spawn_stdin";
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper3", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  uv_pipe_init(uv_default_loop(), &in, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*)∈
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  buf.base = buffer;
Packit b5b901
  buf.len = sizeof(buffer);
Packit b5b901
  r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
Packit b5b901
  ASSERT(strcmp(buffer, output) == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_stdio_greater_than_3) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t pipe;
Packit b5b901
  uv_stdio_container_t stdio[4];
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper5", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &pipe, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_IGNORE;
Packit b5b901
  options.stdio[2].flags = UV_IGNORE;
Packit b5b901
  options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[3].data.stream = (uv_stream_t*)&pip;;
Packit b5b901
  options.stdio_count = 4;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
Packit b5b901
  printf("output from stdio[3] is: %s", output);
Packit b5b901
  ASSERT(strcmp("fourth stdio!\n", output) == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int spawn_tcp_server_helper(void) {
Packit b5b901
  uv_tcp_t tcp;
Packit b5b901
  uv_os_sock_t handle;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  r = uv_tcp_init(uv_default_loop(), &tcp;;
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
#ifdef _WIN32
Packit b5b901
  handle = _get_osfhandle(3);
Packit b5b901
#else
Packit b5b901
  handle = 3;
Packit b5b901
#endif
Packit b5b901
  r = uv_tcp_open(&tcp, handle);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  /* Make sure that we can listen on a socket that was
Packit b5b901
   * passed down from the parent process
Packit b5b901
   */
Packit b5b901
  r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  return 1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_tcp_server) {
Packit b5b901
  uv_stdio_container_t stdio[4];
Packit b5b901
  struct sockaddr_in addr;
Packit b5b901
  int fd;
Packit b5b901
  int r;
Packit b5b901
#ifdef _WIN32
Packit b5b901
  uv_os_fd_t handle;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  init_process_options("spawn_tcp_server_helper", exit_cb);
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
Packit b5b901
Packit b5b901
  fd = -1;
Packit b5b901
  r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
#ifdef _WIN32
Packit b5b901
  r = uv_fileno((uv_handle_t*)&tcp_server, &handle);
Packit b5b901
  fd = _open_osfhandle((intptr_t) handle, 0);
Packit b5b901
#else
Packit b5b901
  r = uv_fileno((uv_handle_t*)&tcp_server, &fd;;
Packit b5b901
 #endif
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  ASSERT(fd > 0);
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[0].data.fd = 0;
Packit b5b901
  options.stdio[1].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[1].data.fd = 1;
Packit b5b901
  options.stdio[2].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[2].data.fd = 2;
Packit b5b901
  options.stdio[3].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[3].data.fd = fd;
Packit b5b901
  options.stdio_count = 4;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_ignored_stdio) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper6", exit_cb);
Packit b5b901
Packit b5b901
  options.stdio = NULL;
Packit b5b901
  options.stdio_count = 0;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_and_kill) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper4", kill_cb);
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_init(uv_default_loop(), &timer;;
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_start(&timer, timer_cb, 500, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_preserve_env) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t out;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper7", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*) &out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = putenv("ENV_TEST=testval");
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  /* Explicitly set options.env to NULL to test for env clobbering. */
Packit b5b901
  options.env = NULL;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2);
Packit b5b901
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("testval", output) == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_detached) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper4", detach_failure_cb);
Packit b5b901
Packit b5b901
  options.flags |= UV_PROCESS_DETACHED;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  uv_unref((uv_handle_t*)&process);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 0);
Packit b5b901
Packit b5b901
  ASSERT(process.pid == uv_process_get_pid(&process));
Packit b5b901
Packit b5b901
  r = uv_kill(process.pid, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_kill(process.pid, 15);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_and_kill_with_std) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t in, out, err;
Packit b5b901
  uv_write_t write;
Packit b5b901
  char message[] = "Nancy's joining me because the message this evening is "
Packit b5b901
                   "not my message but ours.";
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper4", kill_cb);
Packit b5b901
Packit b5b901
  r = uv_pipe_init(uv_default_loop(), &in, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_pipe_init(uv_default_loop(), &err, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*)∈
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[2].data.stream = (uv_stream_t*)&err;
Packit b5b901
  options.stdio_count = 3;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  buf = uv_buf_init(message, sizeof message);
Packit b5b901
  r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_init(uv_default_loop(), &timer;;
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_start(&timer, timer_cb, 500, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_and_ping) {
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_pipe_t in, out;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper3", exit_cb);
Packit b5b901
  buf = uv_buf_init("TEST", 4);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  uv_pipe_init(uv_default_loop(), &in, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*)∈
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  /* Sending signum == 0 should check if the
Packit b5b901
   * child process is still alive, not kill it.
Packit b5b901
   */
Packit b5b901
  r = uv_process_kill(&process, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(strcmp(output, "TEST") == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_same_stdout_stderr) {
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_pipe_t in, out;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper3", exit_cb);
Packit b5b901
  buf = uv_buf_init("TEST", 4);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  uv_pipe_init(uv_default_loop(), &in, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*)∈
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  /* Sending signum == 0 should check if the
Packit b5b901
   * child process is still alive, not kill it.
Packit b5b901
   */
Packit b5b901
  r = uv_process_kill(&process, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(strcmp(output, "TEST") == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_closed_process_io) {
Packit b5b901
  uv_pipe_t in;
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
  static char buffer[] = "hello-from-spawn_stdin\n";
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper3", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &in, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*) ∈
Packit b5b901
  options.stdio_count = 1;
Packit b5b901
Packit b5b901
  close(0); /* Close process stdin. */
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
Packit b5b901
Packit b5b901
  buf = uv_buf_init(buffer, sizeof(buffer));
Packit b5b901
  ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2); /* process, child stdin */
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(kill) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
#ifdef _WIN32
Packit b5b901
  no_term_signal = 1;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper4", kill_cb);
Packit b5b901
Packit b5b901
  /* Verify that uv_spawn() resets the signal disposition. */
Packit b5b901
#ifndef _WIN32
Packit b5b901
  {
Packit b5b901
    sigset_t set;
Packit b5b901
    sigemptyset(&set);
Packit b5b901
    sigaddset(&set, SIGTERM);
Packit b5b901
    ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL));
Packit b5b901
  }
Packit b5b901
  ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN));
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
  {
Packit b5b901
    sigset_t set;
Packit b5b901
    sigemptyset(&set);
Packit b5b901
    sigaddset(&set, SIGTERM);
Packit b5b901
    ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL));
Packit b5b901
  }
Packit b5b901
  ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL));
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  /* Sending signum == 0 should check if the
Packit b5b901
   * child process is still alive, not kill it.
Packit b5b901
   */
Packit b5b901
  r = uv_kill(process.pid, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  /* Kill the process. */
Packit b5b901
  r = uv_kill(process.pid, /* SIGTERM */ 15);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#ifdef _WIN32
Packit b5b901
TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
Packit b5b901
  int r;
Packit b5b901
  uv_pipe_t out;
Packit b5b901
  char name[64];
Packit b5b901
  HANDLE pipe_handle;
Packit b5b901
  uv_stdio_container_t stdio[2];
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper2", exit_cb);
Packit b5b901
Packit b5b901
  uv_pipe_init(uv_default_loop(), &out, 0);
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_IGNORE;
Packit b5b901
  options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
Packit b5b901
  options.stdio[1].data.stream = (uv_stream_t*)&out;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  /* Create a pipe that'll cause a collision. */
Packit b5b901
  snprintf(name,
Packit b5b901
           sizeof(name),
Packit b5b901
           "\\\\.\\pipe\\uv\\%p-%d",
Packit b5b901
           &out,
Packit b5b901
           GetCurrentProcessId());
Packit b5b901
  pipe_handle = CreateNamedPipeA(name,
Packit b5b901
                                PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
Packit b5b901
                                PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
Packit b5b901
                                10,
Packit b5b901
                                65536,
Packit b5b901
                                65536,
Packit b5b901
                                0,
Packit b5b901
                                NULL);
Packit b5b901
  ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
Packit b5b901
  printf("output is: %s", output);
Packit b5b901
  ASSERT(strcmp("hello world\n", output) == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#if !defined(USING_UV_SHARED)
Packit b5b901
int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
Packit b5b901
WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
Packit b5b901
Packit b5b901
TEST_IMPL(argument_escaping) {
Packit b5b901
  const WCHAR* test_str[] = {
Packit b5b901
    L"",
Packit b5b901
    L"HelloWorld",
Packit b5b901
    L"Hello World",
Packit b5b901
    L"Hello\"World",
Packit b5b901
    L"Hello World\\",
Packit b5b901
    L"Hello\\\"World",
Packit b5b901
    L"Hello\\World",
Packit b5b901
    L"Hello\\\\World",
Packit b5b901
    L"Hello World\\",
Packit b5b901
    L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
Packit b5b901
  };
Packit b5b901
  const int count = sizeof(test_str) / sizeof(*test_str);
Packit b5b901
  WCHAR** test_output;
Packit b5b901
  WCHAR* command_line;
Packit b5b901
  WCHAR** cracked;
Packit b5b901
  size_t total_size = 0;
Packit b5b901
  int i;
Packit b5b901
  int num_args;
Packit b5b901
  int result;
Packit b5b901
Packit b5b901
  char* verbatim[] = {
Packit b5b901
    "cmd.exe",
Packit b5b901
    "/c",
Packit b5b901
    "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
Packit b5b901
    NULL
Packit b5b901
  };
Packit b5b901
  WCHAR* verbatim_output;
Packit b5b901
  WCHAR* non_verbatim_output;
Packit b5b901
Packit b5b901
  test_output = calloc(count, sizeof(WCHAR*));
Packit b5b901
  ASSERT(test_output != NULL);
Packit b5b901
  for (i = 0; i < count; ++i) {
Packit b5b901
    test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
Packit b5b901
    quote_cmd_arg(test_str[i], test_output[i]);
Packit b5b901
    wprintf(L"input : %s\n", test_str[i]);
Packit b5b901
    wprintf(L"output: %s\n", test_output[i]);
Packit b5b901
    total_size += wcslen(test_output[i]) + 1;
Packit b5b901
  }
Packit b5b901
  command_line = calloc(total_size + 1, sizeof(WCHAR));
Packit b5b901
  ASSERT(command_line != NULL);
Packit b5b901
  for (i = 0; i < count; ++i) {
Packit b5b901
    wcscat(command_line, test_output[i]);
Packit b5b901
    wcscat(command_line, L" ");
Packit b5b901
  }
Packit b5b901
  command_line[total_size - 1] = L'\0';
Packit b5b901
Packit b5b901
  wprintf(L"command_line: %s\n", command_line);
Packit b5b901
Packit b5b901
  cracked = CommandLineToArgvW(command_line, &num_args);
Packit b5b901
  for (i = 0; i < num_args; ++i) {
Packit b5b901
    wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
Packit b5b901
    ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  LocalFree(cracked);
Packit b5b901
  for (i = 0; i < count; ++i) {
Packit b5b901
    free(test_output[i]);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  result = make_program_args(verbatim, 1, &verbatim_output);
Packit b5b901
  ASSERT(result == 0);
Packit b5b901
  result = make_program_args(verbatim, 0, &non_verbatim_output);
Packit b5b901
  ASSERT(result == 0);
Packit b5b901
Packit b5b901
  wprintf(L"    verbatim_output: %s\n", verbatim_output);
Packit b5b901
  wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
Packit b5b901
Packit b5b901
  ASSERT(wcscmp(verbatim_output,
Packit b5b901
                L"cmd.exe /c c:\\path\\to\\node.exe --eval "
Packit b5b901
                L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
Packit b5b901
  ASSERT(wcscmp(non_verbatim_output,
Packit b5b901
                L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
Packit b5b901
                L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
Packit b5b901
Packit b5b901
  free(verbatim_output);
Packit b5b901
  free(non_verbatim_output);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
int make_program_env(char** env_block, WCHAR** dst_ptr);
Packit b5b901
Packit b5b901
TEST_IMPL(environment_creation) {
Packit b5b901
  int i;
Packit b5b901
  char* environment[] = {
Packit b5b901
    "FOO=BAR",
Packit b5b901
    "SYSTEM=ROOT", /* substring of a supplied var name */
Packit b5b901
    "SYSTEMROOTED=OMG", /* supplied var name is a substring */
Packit b5b901
    "TEMP=C:\\Temp",
Packit b5b901
    "INVALID",
Packit b5b901
    "BAZ=QUX",
Packit b5b901
    "B_Z=QUX",
Packit b5b901
    "B\xe2\x82\xacZ=QUX",
Packit b5b901
    "B\xf0\x90\x80\x82Z=QUX",
Packit b5b901
    "B\xef\xbd\xa1Z=QUX",
Packit b5b901
    "B\xf0\xa3\x91\x96Z=QUX",
Packit b5b901
    "BAZ", /* repeat, invalid variable */
Packit b5b901
    NULL
Packit b5b901
  };
Packit b5b901
  WCHAR* wenvironment[] = {
Packit b5b901
    L"BAZ=QUX",
Packit b5b901
    L"B_Z=QUX",
Packit b5b901
    L"B\x20acZ=QUX",
Packit b5b901
    L"B\xd800\xdc02Z=QUX",
Packit b5b901
    L"B\xd84d\xdc56Z=QUX",
Packit b5b901
    L"B\xff61Z=QUX",
Packit b5b901
    L"FOO=BAR",
Packit b5b901
    L"SYSTEM=ROOT", /* substring of a supplied var name */
Packit b5b901
    L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
Packit b5b901
    L"TEMP=C:\\Temp",
Packit b5b901
  };
Packit b5b901
  WCHAR* from_env[] = {
Packit b5b901
    /* list should be kept in sync with list
Packit b5b901
     * in process.c, minus variables in wenvironment */
Packit b5b901
    L"HOMEDRIVE",
Packit b5b901
    L"HOMEPATH",
Packit b5b901
    L"LOGONSERVER",
Packit b5b901
    L"PATH",
Packit b5b901
    L"USERDOMAIN",
Packit b5b901
    L"USERNAME",
Packit b5b901
    L"USERPROFILE",
Packit b5b901
    L"SYSTEMDRIVE",
Packit b5b901
    L"SYSTEMROOT",
Packit b5b901
    L"WINDIR",
Packit b5b901
    /* test for behavior in the absence of a
Packit b5b901
     * required-environment variable: */
Packit b5b901
    L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
Packit b5b901
  };
Packit b5b901
  int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
Packit b5b901
  int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
Packit b5b901
  WCHAR *expected[ARRAY_SIZE(from_env)];
Packit b5b901
  int result;
Packit b5b901
  WCHAR* str;
Packit b5b901
  WCHAR* prev;
Packit b5b901
  WCHAR* env;
Packit b5b901
Packit b5b901
  for (i = 0; i < ARRAY_SIZE(from_env); i++) {
Packit b5b901
      /* copy expected additions to environment locally */
Packit b5b901
      size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
Packit b5b901
      if (len == 0) {
Packit b5b901
        found_in_usr_env[i] = 1;
Packit b5b901
        str = malloc(1 * sizeof(WCHAR));
Packit b5b901
        *str = 0;
Packit b5b901
        expected[i] = str;
Packit b5b901
      } else {
Packit b5b901
        size_t name_len = wcslen(from_env[i]);
Packit b5b901
        str = malloc((name_len+1+len) * sizeof(WCHAR));
Packit b5b901
        wmemcpy(str, from_env[i], name_len);
Packit b5b901
        expected[i] = str;
Packit b5b901
        str += name_len;
Packit b5b901
        *str++ = L'=';
Packit b5b901
        GetEnvironmentVariableW(from_env[i], str, len);
Packit b5b901
     }
Packit b5b901
  }
Packit b5b901
Packit b5b901
  result = make_program_env(environment, &env;;
Packit b5b901
  ASSERT(result == 0);
Packit b5b901
Packit b5b901
  for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
Packit b5b901
    int found = 0;
Packit b5b901
#if 0
Packit b5b901
    _cputws(str);
Packit b5b901
    putchar('\n');
Packit b5b901
#endif
Packit b5b901
    for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
Packit b5b901
      if (!wcscmp(str, wenvironment[i])) {
Packit b5b901
        ASSERT(!found_in_loc_env[i]);
Packit b5b901
        found_in_loc_env[i] = 1;
Packit b5b901
        found = 1;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
    for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
Packit b5b901
      if (!wcscmp(str, expected[i])) {
Packit b5b901
        ASSERT(!found_in_usr_env[i]);
Packit b5b901
        found_in_usr_env[i] = 1;
Packit b5b901
        found = 1;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
    if (prev) { /* verify sort order -- requires Vista */
Packit b5b901
#if _WIN32_WINNT >= 0x0600 && \
Packit b5b901
    (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
Packit b5b901
      ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
Packit b5b901
#endif
Packit b5b901
    }
Packit b5b901
    ASSERT(found); /* verify that we expected this variable */
Packit b5b901
  }
Packit b5b901
Packit b5b901
  /* verify that we found all expected variables */
Packit b5b901
  for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
Packit b5b901
    ASSERT(found_in_loc_env[i]);
Packit b5b901
  }
Packit b5b901
  for (i = 0; i < ARRAY_SIZE(expected); i++) {
Packit b5b901
    ASSERT(found_in_usr_env[i]);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
/* Regression test for issue #909 */
Packit b5b901
TEST_IMPL(spawn_with_an_odd_path) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  char newpath[2048];
Packit b5b901
  char *path = getenv("PATH");
Packit b5b901
  ASSERT(path != NULL);
Packit b5b901
  snprintf(newpath, 2048, ";.;%s", path);
Packit b5b901
  SetEnvironmentVariable("PATH", newpath);
Packit b5b901
Packit b5b901
  init_process_options("", exit_cb);
Packit b5b901
  options.file = options.args[0] = "program-that-had-better-not-exist";
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == UV_ENOENT || r == UV_EACCES);
Packit b5b901
  ASSERT(0 == uv_is_active((uv_handle_t*) &process));
Packit b5b901
  uv_close((uv_handle_t*) &process, NULL);
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
TEST_IMPL(spawn_setuid_setgid) {
Packit b5b901
  int r;
Packit b5b901
  struct passwd* pw;
Packit b5b901
  char uidstr[10];
Packit b5b901
  char gidstr[10];
Packit b5b901
Packit b5b901
  /* if not root, then this will fail. */
Packit b5b901
  uv_uid_t uid = getuid();
Packit b5b901
  if (uid != 0) {
Packit b5b901
    RETURN_SKIP("It should be run as root user");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper_setuid_setgid", exit_cb);
Packit b5b901
Packit b5b901
  /* become the "nobody" user. */
Packit b5b901
  pw = getpwnam("nobody");
Packit b5b901
  ASSERT(pw != NULL);
Packit b5b901
  options.uid = pw->pw_uid;
Packit b5b901
  options.gid = pw->pw_gid;
Packit b5b901
  snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid);
Packit b5b901
  snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid);
Packit b5b901
  options.args[2] = uidstr;
Packit b5b901
  options.args[3] = gidstr;
Packit b5b901
  options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  if (r == UV_EACCES)
Packit b5b901
    RETURN_SKIP("user 'nobody' cannot access the test runner");
Packit b5b901
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
TEST_IMPL(spawn_setuid_fails) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* if root, become nobody. */
Packit b5b901
  uv_uid_t uid = getuid();
Packit b5b901
  if (uid == 0) {
Packit b5b901
    struct passwd* pw;
Packit b5b901
    pw = getpwnam("nobody");
Packit b5b901
    ASSERT(pw != NULL);
Packit b5b901
    ASSERT(0 == setgid(pw->pw_gid));
Packit b5b901
    ASSERT(0 == setuid(pw->pw_uid));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper1", fail_cb);
Packit b5b901
Packit b5b901
  options.flags |= UV_PROCESS_SETUID;
Packit b5b901
  options.uid = 0;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
#if defined(__CYGWIN__)
Packit b5b901
  ASSERT(r == UV_EINVAL);
Packit b5b901
#else
Packit b5b901
  ASSERT(r == UV_EPERM);
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(close_cb_called == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_setgid_fails) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* if root, become nobody. */
Packit b5b901
  uv_uid_t uid = getuid();
Packit b5b901
  if (uid == 0) {
Packit b5b901
    struct passwd* pw;
Packit b5b901
    pw = getpwnam("nobody");
Packit b5b901
    ASSERT(pw != NULL);
Packit b5b901
    ASSERT(0 == setgid(pw->pw_gid));
Packit b5b901
    ASSERT(0 == setuid(pw->pw_uid));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper1", fail_cb);
Packit b5b901
Packit b5b901
  options.flags |= UV_PROCESS_SETGID;
Packit b5b901
#if defined(__MVS__)
Packit b5b901
  options.gid = -1;
Packit b5b901
#else
Packit b5b901
  options.gid = 0;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
#if defined(__CYGWIN__) || defined(__MVS__)
Packit b5b901
  ASSERT(r == UV_EINVAL);
Packit b5b901
#else
Packit b5b901
  ASSERT(r == UV_EPERM);
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(close_cb_called == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
#ifdef _WIN32
Packit b5b901
Packit b5b901
static void exit_cb_unexpected(uv_process_t* process,
Packit b5b901
                               int64_t exit_status,
Packit b5b901
                               int term_signal) {
Packit b5b901
  ASSERT(0 && "should not have been called");
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_setuid_fails) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper1", exit_cb_unexpected);
Packit b5b901
Packit b5b901
  options.flags |= UV_PROCESS_SETUID;
Packit b5b901
  options.uid = (uv_uid_t) -42424242;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == UV_ENOTSUP);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(close_cb_called == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_setgid_fails) {
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper1", exit_cb_unexpected);
Packit b5b901
Packit b5b901
  options.flags |= UV_PROCESS_SETGID;
Packit b5b901
  options.gid = (uv_gid_t) -42424242;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == UV_ENOTSUP);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(close_cb_called == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_auto_unref) {
Packit b5b901
  init_process_options("spawn_helper1", NULL);
Packit b5b901
  ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
  ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
Packit b5b901
  uv_close((uv_handle_t*) &process, NULL);
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
  ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
TEST_IMPL(spawn_fs_open) {
Packit b5b901
  int fd;
Packit b5b901
  uv_fs_t fs_req;
Packit b5b901
  uv_pipe_t in;
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  uv_stdio_container_t stdio[1];
Packit b5b901
Packit b5b901
  fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
Packit b5b901
  ASSERT(fd >= 0);
Packit b5b901
  uv_fs_req_cleanup(&fs_req);
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper8", exit_cb);
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
Packit b5b901
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
Packit b5b901
  options.stdio[0].data.stream = (uv_stream_t*) ∈
Packit b5b901
  options.stdio_count = 1;
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
Packit b5b901
Packit b5b901
  buf = uv_buf_init((char*) &fd, sizeof(fd));
Packit b5b901
  ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
  ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 2);  /* One for `in`, one for process */
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif  /* !_WIN32 */
Packit b5b901
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
TEST_IMPL(closed_fd_events) {
Packit b5b901
  uv_stdio_container_t stdio[3];
Packit b5b901
  uv_pipe_t pipe_handle;
Packit b5b901
  int fd[2];
Packit b5b901
Packit b5b901
  /* create a pipe and share it with a child process */
Packit b5b901
  ASSERT(0 == pipe(fd));
Packit b5b901
Packit b5b901
  /* spawn_helper4 blocks indefinitely. */
Packit b5b901
  init_process_options("spawn_helper4", exit_cb);
Packit b5b901
  options.stdio_count = 3;
Packit b5b901
  options.stdio = stdio;
Packit b5b901
  options.stdio[0].flags = UV_INHERIT_FD;
Packit b5b901
  options.stdio[0].data.fd = fd[0];
Packit b5b901
  options.stdio[1].flags = UV_IGNORE;
Packit b5b901
  options.stdio[2].flags = UV_IGNORE;
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
Packit b5b901
  uv_unref((uv_handle_t*) &process);
Packit b5b901
Packit b5b901
  /* read from the pipe with uv */
Packit b5b901
  ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
Packit b5b901
  ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
Packit b5b901
  fd[0] = -1;
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
Packit b5b901
Packit b5b901
  ASSERT(1 == write(fd[1], "", 1));
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
Packit b5b901
Packit b5b901
  /* should have received just one byte */
Packit b5b901
  ASSERT(output_used == 1);
Packit b5b901
Packit b5b901
  /* close the pipe and see if we still get events */
Packit b5b901
  uv_close((uv_handle_t*) &pipe_handle, close_cb);
Packit b5b901
Packit b5b901
  ASSERT(1 == write(fd[1], "", 1));
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
Packit b5b901
  ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
Packit b5b901
Packit b5b901
  /* see if any spurious events interrupt the timer */
Packit b5b901
  if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
Packit b5b901
    /* have to run again to really trigger the timer */
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
Packit b5b901
Packit b5b901
  ASSERT(timer_counter == 1);
Packit b5b901
Packit b5b901
  /* cleanup */
Packit b5b901
  ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
Packit b5b901
  ASSERT(0 == close(fd[1]));
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif  /* !_WIN32 */
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_reads_child_path) {
Packit b5b901
  int r;
Packit b5b901
  int len;
Packit b5b901
  char file[64];
Packit b5b901
  char path[1024];
Packit b5b901
  char* env[3];
Packit b5b901
Packit b5b901
  /* Need to carry over the dynamic linker path when the test runner is
Packit b5b901
   * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
Packit b5b901
   */
Packit b5b901
#if defined(__APPLE__)
Packit b5b901
  static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
Packit b5b901
#elif defined __MVS__
Packit b5b901
  static const char dyld_path_var[] = "LIBPATH";
Packit b5b901
#else
Packit b5b901
  static const char dyld_path_var[] = "LD_LIBRARY_PATH";
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  /* Set up the process, but make sure that the file to run is relative and
Packit b5b901
   * requires a lookup into PATH. */
Packit b5b901
  init_process_options("spawn_helper1", exit_cb);
Packit b5b901
Packit b5b901
  /* Set up the PATH env variable */
Packit b5b901
  for (len = strlen(exepath);
Packit b5b901
       exepath[len - 1] != '/' && exepath[len - 1] != '\\';
Packit b5b901
       len--);
Packit b5b901
  strcpy(file, exepath + len);
Packit b5b901
  exepath[len] = 0;
Packit b5b901
  strcpy(path, "PATH=");
Packit b5b901
  strcpy(path + 5, exepath);
Packit b5b901
#if defined(__CYGWIN__) || defined(__MSYS__)
Packit b5b901
  /* Carry over the dynamic linker path in case the test runner
Packit b5b901
     is linked against cyguv-1.dll or msys-uv-1.dll, see above.  */
Packit b5b901
  {
Packit b5b901
    char* syspath = getenv("PATH");
Packit b5b901
    if (syspath != NULL) {
Packit b5b901
      strcat(path, ":");
Packit b5b901
      strcat(path, syspath);
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  env[0] = path;
Packit b5b901
  env[1] = getenv(dyld_path_var);
Packit b5b901
  env[2] = NULL;
Packit b5b901
Packit b5b901
  if (env[1] != NULL) {
Packit b5b901
    static char buf[1024 + sizeof(dyld_path_var)];
Packit b5b901
    snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
Packit b5b901
    env[1] = buf;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  options.file = file;
Packit b5b901
  options.args[0] = file;
Packit b5b901
  options.env = env;
Packit b5b901
Packit b5b901
  r = uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 1);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
#ifndef _WIN32
Packit b5b901
static int mpipe(int *fds) {
Packit b5b901
  if (pipe(fds) == -1)
Packit b5b901
    return -1;
Packit b5b901
  if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
Packit b5b901
      fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
Packit b5b901
    close(fds[0]);
Packit b5b901
    close(fds[1]);
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#else
Packit b5b901
static int mpipe(int *fds) {
Packit b5b901
  SECURITY_ATTRIBUTES attr;
Packit b5b901
  HANDLE readh, writeh;
Packit b5b901
  attr.nLength = sizeof(attr);
Packit b5b901
  attr.lpSecurityDescriptor = NULL;
Packit b5b901
  attr.bInheritHandle = FALSE;
Packit b5b901
  if (!CreatePipe(&readh, &writeh, &attr, 0))
Packit b5b901
    return -1;
Packit b5b901
  fds[0] = _open_osfhandle((intptr_t)readh, 0);
Packit b5b901
  fds[1] = _open_osfhandle((intptr_t)writeh, 0);
Packit b5b901
  if (fds[0] == -1 || fds[1] == -1) {
Packit b5b901
    CloseHandle(readh);
Packit b5b901
    CloseHandle(writeh);
Packit b5b901
    return -1;
Packit b5b901
  }
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif /* !_WIN32 */
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_inherit_streams) {
Packit b5b901
  uv_process_t child_req;
Packit b5b901
  uv_stdio_container_t child_stdio[2];
Packit b5b901
  int fds_stdin[2];
Packit b5b901
  int fds_stdout[2];
Packit b5b901
  uv_pipe_t pipe_stdin_child;
Packit b5b901
  uv_pipe_t pipe_stdout_child;
Packit b5b901
  uv_pipe_t pipe_stdin_parent;
Packit b5b901
  uv_pipe_t pipe_stdout_parent;
Packit b5b901
  unsigned char ubuf[OUTPUT_SIZE - 1];
Packit b5b901
  uv_buf_t buf;
Packit b5b901
  unsigned int i;
Packit b5b901
  int r;
Packit b5b901
  int bidir;
Packit b5b901
  uv_write_t write_req;
Packit b5b901
  uv_loop_t* loop;
Packit b5b901
Packit b5b901
  init_process_options("spawn_helper9", exit_cb);
Packit b5b901
Packit b5b901
  loop = uv_default_loop();
Packit b5b901
  ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
Packit b5b901
  ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
Packit b5b901
  ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
Packit b5b901
  ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
Packit b5b901
Packit b5b901
  ASSERT(mpipe(fds_stdin) != -1);
Packit b5b901
  ASSERT(mpipe(fds_stdout) != -1);
Packit b5b901
Packit b5b901
  ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
Packit b5b901
  ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
Packit b5b901
  ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
Packit b5b901
  ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
Packit b5b901
  ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child));
Packit b5b901
  ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child));
Packit b5b901
  ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent));
Packit b5b901
  ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent));
Packit b5b901
  /* Some systems (SVR4) open a bidirectional pipe, most don't. */
Packit b5b901
  bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child);
Packit b5b901
  ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir);
Packit b5b901
  ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir);
Packit b5b901
  ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir);
Packit b5b901
Packit b5b901
  child_stdio[0].flags = UV_INHERIT_STREAM;
Packit b5b901
  child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
Packit b5b901
Packit b5b901
  child_stdio[1].flags = UV_INHERIT_STREAM;
Packit b5b901
  child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
Packit b5b901
Packit b5b901
  options.stdio = child_stdio;
Packit b5b901
  options.stdio_count = 2;
Packit b5b901
Packit b5b901
  ASSERT(uv_spawn(loop, &child_req, &options) == 0);
Packit b5b901
Packit b5b901
  uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
Packit b5b901
  uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
Packit b5b901
Packit b5b901
  buf = uv_buf_init((char*)ubuf, sizeof ubuf);
Packit b5b901
  for (i = 0; i < sizeof ubuf; ++i)
Packit b5b901
    ubuf[i] = i & 255u;
Packit b5b901
  memset(output, 0, sizeof ubuf);
Packit b5b901
Packit b5b901
  r = uv_write(&write_req,
Packit b5b901
               (uv_stream_t*)&pipe_stdin_parent,
Packit b5b901
               &buf,
Packit b5b901
               1,
Packit b5b901
               write_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_run(loop, UV_RUN_DEFAULT);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(exit_cb_called == 1);
Packit b5b901
  ASSERT(close_cb_called == 3);
Packit b5b901
Packit b5b901
  r = memcmp(ubuf, output, sizeof ubuf);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
TEST_IMPL(spawn_quoted_path) {
Packit b5b901
#ifndef _WIN32
Packit b5b901
  RETURN_SKIP("Test for Windows");
Packit b5b901
#else
Packit b5b901
  char* quoted_path_env[2];
Packit b5b901
  args[0] = "not_existing";
Packit b5b901
  args[1] = NULL;
Packit b5b901
  options.file = args[0];
Packit b5b901
  options.args = args;
Packit b5b901
  options.exit_cb = exit_cb;
Packit b5b901
  options.flags = 0;
Packit b5b901
  /* We test if search_path works correctly with semicolons in quoted path. We
Packit b5b901
   * will use an invalid drive, so we are sure no executable is spawned. */
Packit b5b901
  quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other";
Packit b5b901
  quoted_path_env[1] = NULL;
Packit b5b901
  options.env = quoted_path_env;
Packit b5b901
Packit b5b901
  /* We test if libuv will not segfault. */
Packit b5b901
  uv_spawn(uv_default_loop(), &process, &options);
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
/* Helper for child process of spawn_inherit_streams */
Packit b5b901
#ifndef _WIN32
Packit b5b901
int spawn_stdin_stdout(void) {
Packit b5b901
  char buf[1024];
Packit b5b901
  char* pbuf;
Packit b5b901
  for (;;) {
Packit b5b901
    ssize_t r, w, c;
Packit b5b901
    do {
Packit b5b901
      r = read(0, buf, sizeof buf);
Packit b5b901
    } while (r == -1 && errno == EINTR);
Packit b5b901
    if (r == 0) {
Packit b5b901
      return 1;
Packit b5b901
    }
Packit b5b901
    ASSERT(r > 0);
Packit b5b901
    c = r;
Packit b5b901
    pbuf = buf;
Packit b5b901
    while (c) {
Packit b5b901
      do {
Packit b5b901
        w = write(1, pbuf, (size_t)c);
Packit b5b901
      } while (w == -1 && errno == EINTR);
Packit b5b901
      ASSERT(w >= 0);
Packit b5b901
      pbuf = pbuf + w;
Packit b5b901
      c = c - w;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
  return 2;
Packit b5b901
}
Packit b5b901
#else
Packit b5b901
int spawn_stdin_stdout(void) {
Packit b5b901
  char buf[1024];
Packit b5b901
  char* pbuf;
Packit b5b901
  HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
Packit b5b901
  HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
Packit b5b901
  ASSERT(h_stdin != INVALID_HANDLE_VALUE);
Packit b5b901
  ASSERT(h_stdout != INVALID_HANDLE_VALUE);
Packit b5b901
  for (;;) {
Packit b5b901
    DWORD n_read;
Packit b5b901
    DWORD n_written;
Packit b5b901
    DWORD to_write;
Packit b5b901
    if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
Packit b5b901
      ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
Packit b5b901
      return 1;
Packit b5b901
    }
Packit b5b901
    to_write = n_read;
Packit b5b901
    pbuf = buf;
Packit b5b901
    while (to_write) {
Packit b5b901
      ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
Packit b5b901
      to_write -= n_written;
Packit b5b901
      pbuf += n_written;
Packit b5b901
    }
Packit b5b901
  }
Packit b5b901
  return 2;
Packit b5b901
}
Packit b5b901
#endif /* !_WIN32 */