std::experimental::optional<Command::Result> Command::run() const
	{
		Pipe stdout_pipe, stderr_pipe;

		pid_t pid = fork();
		if (pid == -1)
			return std::experimental::nullopt;

		if (pid == 0)
			child_exec(args, stdout_pipe, stderr_pipe);

		stdout_pipe.close_write_fd();
		stderr_pipe.close_write_fd();

		Result result;
		bool read_success = read_pipes(stdout_pipe, stderr_pipe, result.stdout, result.stderr);

		stdout_pipe.close_read_fd();
		stderr_pipe.close_read_fd();

		int status;
		while (waitpid(pid, &status, 0) == -1)
			if (errno != EINTR)
				return std::experimental::nullopt;

		if (!WIFEXITED(status))
			return std::experimental::nullopt;

		result.exit_code = WEXITSTATUS(status);

		if (result.exit_code == CHILD_SETUP_FAILURE_EXIT_CODE || !read_success)
			return std::experimental::nullopt;

		return result;
	}
Ejemplo n.º 2
0
/// Tests an exec function with no arguments.
///
/// \param tc The calling test case.
/// \param do_exec The exec function to test.
static void
check_exec_no_args(const atf::tests::tc* tc, const exec_function do_exec)
{
    std::auto_ptr< process::child > child = process::child::fork_files(
        child_exec(do_exec, get_helpers(tc), process::args_vector()),
        fs::path("stdout"), fs::path("stderr"));
    const process::status status = child->wait();
    ATF_REQUIRE(status.exited());
    ATF_REQUIRE_EQ(EXIT_FAILURE, status.exitstatus());
    ATF_REQUIRE(atf::utils::grep_file("Must provide a helper name", "stderr"));
}
Ejemplo n.º 3
0
static
void
main_loop(void)
{
  struct pollfd  pollv[1];
  int            i;
  int            e = 0;
  char          *c;

  pollv[0].fd = my_sigpipe[0];
  pollv[0].events = POLLIN;

  for(;;){
      if(flag_term){
          break;
      }

      /* start/restart children: */
      /* deux[0] is logger, check it first: */
      for(i = 0; i < 2; ++i){
          if(deux[i].pid == 0){
              child_exec(i);
          }
      }

      /* poll on sigpipe: */
      sigset_unblock(&my_sigset);
      do{
          e = poll(pollv, 1, -1);
      }while((e == -1) && (errno == EINTR));
      sigset_block(&my_sigset);

      /* consume sigpipe: */
      while(read(my_sigpipe[0], &c, 1) == 1){/*empty*/ ;}

      /* consume dead children: */
      child_wait();
  }

  /* here on SIGTERM: */
  if(deux[1].pid){
      /* harvest deux[1]: */
      waitpid(deux[1].pid, NULL, 0);
  } 
  if(deux[0].pid){
      /* logger should exit on eof: */
      close(my_logpipe[1]);
      do_kill(deux[0].pid, SIGCONT);
      waitpid(deux[0].pid, NULL, 0);
  }

  return;
}
Ejemplo n.º 4
0
int child_start(Widget top, char *cmd, void (*cb)(int) )
{
    int hc = child_init(cmd, 0);
    struct child_stat *child = mls(CLIST, hc);
    child->cb = cb;
    child_exec(hc);
    child->id = XtAppAddInput(XtWidgetToApplicationContext(top),
                              child_read_fd(hc),
                              (XtPointer)  (XtInputReadMask),
                              child_input_cb,(XtPointer) hc );
    return hc;
}
Ejemplo n.º 5
0
int child_startv(Widget top, int cmd_m, void (*cb)(int) )
{
    int l = m_len(cmd_m);
    int i;
    int hc = child_init(STR(cmd_m,0), 0);
    struct child_stat *child = mls(CLIST, hc);
    child->cb = cb;
    for(i=1;i<l;i++) v_kset(child->args, STR(cmd_m, i), -1 );
    child_exec(hc);
    child->id = XtAppAddInput(XtWidgetToApplicationContext(top),
                              child_read_fd(hc),
                              (XtPointer)  (XtInputReadMask),
                              child_input_cb,(XtPointer) hc );
    return hc;
}
Ejemplo n.º 6
0
/// Tests an exec function with some arguments.
///
/// \param tc The calling test case.
/// \param do_exec The exec function to test.
static void
check_exec_some_args(const atf::tests::tc* tc, const exec_function do_exec)
{
    process::args_vector args;
    args.push_back("print-args");
    args.push_back("foo");
    args.push_back("bar");

    std::auto_ptr< process::child > child = process::child::fork_files(
        child_exec(do_exec, get_helpers(tc), args),
        fs::path("stdout"), fs::path("stderr"));
    const process::status status = child->wait();
    ATF_REQUIRE(status.exited());
    ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
    ATF_REQUIRE(atf::utils::grep_file("argv\\[1\\] = print-args", "stdout"));
    ATF_REQUIRE(atf::utils::grep_file("argv\\[2\\] = foo", "stdout"));
    ATF_REQUIRE(atf::utils::grep_file("argv\\[3\\] = bar", "stdout"));
}
Ejemplo n.º 7
0
void
block_spawn(struct block *block, struct click *click)
{
	const unsigned long now = time(NULL);
	int out[2], err[2];

	if (!*COMMAND(block)) {
		bdebug(block, "no command, skipping");
		return;
	}

	if (block->pid > 0) {
		bdebug(block, "process already spawned");
		return;
	}

	if (pipe(out) == -1 || pipe(err) == -1) {
		berrorx(block, "pipe");
		return mark_as_failed(block, strerror(errno));
	}

	if (block->interval == INTER_PERSIST) {
		if (io_signal(out[0], SIGRTMIN))
			return mark_as_failed(block, "event I/O impossible");
	}

	block->pid = fork();
	if (block->pid == -1) {
		berrorx(block, "fork");
		return mark_as_failed(block, strerror(errno));
	}

	/* Child? */
	if (block->pid == 0) {
		/* Error messages are merged into the parent's stderr... */
		child_setup_env(block, click);
		child_reset_signals(block);
		child_redirect_write(block, out, STDOUT_FILENO);
		child_redirect_write(block, err, STDERR_FILENO);
		/* ... until here */
		child_exec(block);
	}

	/*
	 * Note: for non-persistent blocks, no need to set the pipe read end as
	 * non-blocking, since it is meant to be read once the child has exited
	 * (and thus the write end is closed and read is available).
	 */

	/* Parent */
	if (close(out[1]) == -1)
		berrorx(block, "close stdout");
	if (close(err[1]) == -1)
		berrorx(block, "close stderr");

	block->out = out[0];
	block->err = err[0];

	if (!click)
		block->timestamp = now;

	bdebug(block, "forked child %d at %ld", block->pid, now);
}
Ejemplo n.º 8
0
static PyObject *
subprocess_fork_exec(PyObject* self, PyObject *args)
{
    PyObject *gc_module = NULL;
    PyObject *executable_list, *py_fds_to_keep;
    PyObject *env_list, *preexec_fn;
    PyObject *process_args, *converted_args = NULL, *fast_args = NULL;
    PyObject *preexec_fn_args_tuple = NULL;
    int p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite;
    int errpipe_read, errpipe_write, close_fds, restore_signals;
    int call_setsid;
    PyObject *cwd_obj, *cwd_obj2;
    const char *cwd;
    pid_t pid;
    int need_to_reenable_gc = 0;
    char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
    Py_ssize_t arg_num;

    if (!PyArg_ParseTuple(
                args, "OOpOOOiiiiiiiiiiO:fork_exec",
                &process_args, &executable_list, &close_fds, &py_fds_to_keep,
                &cwd_obj, &env_list,
                &p2cread, &p2cwrite, &c2pread, &c2pwrite,
                &errread, &errwrite, &errpipe_read, &errpipe_write,
                &restore_signals, &call_setsid, &preexec_fn))
        return NULL;

    if (close_fds && errpipe_write < 3) {  /* precondition */
        PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3");
        return NULL;
    }
    if (PySequence_Length(py_fds_to_keep) < 0) {
        PyErr_SetString(PyExc_ValueError, "cannot get length of fds_to_keep");
        return NULL;
    }
    if (_sanity_check_python_fd_sequence(py_fds_to_keep)) {
        PyErr_SetString(PyExc_ValueError, "bad value(s) in fds_to_keep");
        return NULL;
    }

    /* We need to call gc.disable() when we'll be calling preexec_fn */
    if (preexec_fn != Py_None) {
        PyObject *result;
        _Py_IDENTIFIER(isenabled);
        _Py_IDENTIFIER(disable);

        gc_module = PyImport_ImportModule("gc");
        if (gc_module == NULL)
            return NULL;
        result = _PyObject_CallMethodId(gc_module, &PyId_isenabled, NULL);
        if (result == NULL) {
            Py_DECREF(gc_module);
            return NULL;
        }
        need_to_reenable_gc = PyObject_IsTrue(result);
        Py_DECREF(result);
        if (need_to_reenable_gc == -1) {
            Py_DECREF(gc_module);
            return NULL;
        }
        result = _PyObject_CallMethodId(gc_module, &PyId_disable, NULL);
        if (result == NULL) {
            Py_DECREF(gc_module);
            return NULL;
        }
        Py_DECREF(result);
    }

    exec_array = _PySequence_BytesToCharpArray(executable_list);
    if (!exec_array) {
        Py_XDECREF(gc_module);
        return NULL;
    }

    /* Convert args and env into appropriate arguments for exec() */
    /* These conversions are done in the parent process to avoid allocating
       or freeing memory in the child process. */
    if (process_args != Py_None) {
        Py_ssize_t num_args;
        /* Equivalent to:  */
        /*  tuple(PyUnicode_FSConverter(arg) for arg in process_args)  */
        fast_args = PySequence_Fast(process_args, "argv must be a tuple");
        if (fast_args == NULL)
            goto cleanup;
        num_args = PySequence_Fast_GET_SIZE(fast_args);
        converted_args = PyTuple_New(num_args);
        if (converted_args == NULL)
            goto cleanup;
        for (arg_num = 0; arg_num < num_args; ++arg_num) {
            PyObject *borrowed_arg, *converted_arg;
            borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num);
            if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0)
                goto cleanup;
            PyTuple_SET_ITEM(converted_args, arg_num, converted_arg);
        }

        argv = _PySequence_BytesToCharpArray(converted_args);
        Py_CLEAR(converted_args);
        Py_CLEAR(fast_args);
        if (!argv)
            goto cleanup;
    }

    if (env_list != Py_None) {
        envp = _PySequence_BytesToCharpArray(env_list);
        if (!envp)
            goto cleanup;
    }

    if (preexec_fn != Py_None) {
        preexec_fn_args_tuple = PyTuple_New(0);
        if (!preexec_fn_args_tuple)
            goto cleanup;
        _PyImport_AcquireLock();
    }

    if (cwd_obj != Py_None) {
        if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0)
            goto cleanup;
        cwd = PyBytes_AsString(cwd_obj2);
    } else {
        cwd = NULL;
        cwd_obj2 = NULL;
    }

    pid = fork();
    if (pid == 0) {
        /* Child process */
        /*
         * Code from here to _exit() must only use async-signal-safe functions,
         * listed at `man 7 signal` or
         * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
         */

        if (preexec_fn != Py_None) {
            /* We'll be calling back into Python later so we need to do this.
             * This call may not be async-signal-safe but neither is calling
             * back into Python.  The user asked us to use hope as a strategy
             * to avoid deadlock... */
            PyOS_AfterFork();
        }

        child_exec(exec_array, argv, envp, cwd,
                   p2cread, p2cwrite, c2pread, c2pwrite,
                   errread, errwrite, errpipe_read, errpipe_write,
                   close_fds, restore_signals, call_setsid,
                   py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
        _exit(255);
        return NULL;  /* Dead code to avoid a potential compiler warning. */
    }
    Py_XDECREF(cwd_obj2);

    if (pid == -1) {
        /* Capture the errno exception before errno can be clobbered. */
        PyErr_SetFromErrno(PyExc_OSError);
    }
    if (preexec_fn != Py_None &&
            _PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) {
        PyErr_SetString(PyExc_RuntimeError,
                        "not holding the import lock");
    }

    /* Parent process */
    if (envp)
        _Py_FreeCharPArray(envp);
    if (argv)
        _Py_FreeCharPArray(argv);
    _Py_FreeCharPArray(exec_array);

    /* Reenable gc in the parent process (or if fork failed). */
    if (need_to_reenable_gc && _enable_gc(gc_module)) {
        Py_XDECREF(gc_module);
        return NULL;
    }
    Py_XDECREF(preexec_fn_args_tuple);
    Py_XDECREF(gc_module);

    if (pid == -1)
        return NULL;  /* fork() failed.  Exception set earlier. */

    return PyLong_FromPid(pid);

cleanup:
    if (envp)
        _Py_FreeCharPArray(envp);
    if (argv)
        _Py_FreeCharPArray(argv);
    _Py_FreeCharPArray(exec_array);
    Py_XDECREF(converted_args);
    Py_XDECREF(fast_args);
    Py_XDECREF(preexec_fn_args_tuple);

    /* Reenable gc if it was disabled. */
    if (need_to_reenable_gc)
        _enable_gc(gc_module);
    Py_XDECREF(gc_module);
    return NULL;
}