Example #1
0
/* NAME, CMD and ARGS are the name, path to and arguments for the hook
   program that is to be run.  The hook's exit status will be checked,
   and if an error occurred the hook's stderr output will be added to
   the returned error.

   If STDIN_HANDLE is non-null, pass it as the hook's stdin, else pass
   no stdin to the hook.

   If RESULT is non-null, set *RESULT to the stdout of the hook or to
   a zero-length string if the hook generates no output on stdout. */
static svn_error_t *
run_hook_cmd(svn_string_t **result,
             const char *name,
             const char *cmd,
             const char **args,
             const char *const *hooks_env,
             apr_file_t *stdin_handle,
             apr_pool_t *pool)
{
  apr_file_t *null_handle;
  apr_status_t apr_err;
  svn_error_t *err;
  apr_proc_t cmd_proc;

  if (result)
    {
      null_handle = NULL;
    }
  else
    {
      /* Redirect stdout to the null device */
        apr_err = apr_file_open(&null_handle, SVN_NULL_DEVICE_NAME, APR_WRITE,
                                APR_OS_DEFAULT, pool);
        if (apr_err)
          return svn_error_wrap_apr
            (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
    }

  err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args, hooks_env, FALSE,
                          FALSE, stdin_handle, result != NULL, null_handle,
                          TRUE, NULL, pool);

  if (err)
    {
      /* CMD_PROC is not safe to use. Bail. */
      return svn_error_createf
        (SVN_ERR_REPOS_HOOK_FAILURE, err, _("Failed to start '%s' hook"), cmd);
    }
  else
    {
      err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
    }

  /* Hooks are fallible, and so hook failure is "expected" to occur at
     times.  When such a failure happens we still want to close the pipe
     and null file */
  apr_err = apr_file_close(cmd_proc.err);
  if (!err && apr_err)
    return svn_error_wrap_apr
      (apr_err, _("Error closing read end of stderr pipe"));

  if (result)
    {
      svn_stringbuf_t *native_stdout;
      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool));
      apr_err = apr_file_close(cmd_proc.out);
      if (!err && apr_err)
        return svn_error_wrap_apr
          (apr_err, _("Error closing read end of stderr pipe"));

      *result = svn_stringbuf__morph_into_string(native_stdout);
    }
  else
    {
      apr_err = apr_file_close(null_handle);
      if (!err && apr_err)
        return svn_error_wrap_apr(apr_err, _("Error closing null file"));
    }

  return svn_error_trace(err);
}
Example #2
0
/* NAME, CMD and ARGS are the name, path to and arguments for the hook
   program that is to be run.  The hook's exit status will be checked,
   and if an error occurred the hook's stderr output will be added to
   the returned error.

   If STDIN_HANDLE is non-null, pass it as the hook's stdin, else pass
   no stdin to the hook.

   If RESULT is non-null, set *RESULT to the stdout of the hook or to
   a zero-length string if the hook generates no output on stdout. */
static svn_error_t *
run_hook_cmd(svn_string_t **result,
             const char *name,
             const char *cmd,
             const char **args,
             apr_hash_t *hooks_env,
             apr_file_t *stdin_handle,
             apr_pool_t *pool)
{
  apr_file_t *null_handle;
  apr_status_t apr_err;
  svn_error_t *err;
  apr_proc_t cmd_proc = {0};
  apr_pool_t *cmd_pool;
  apr_hash_t *hook_env = NULL;

  if (result)
    {
      null_handle = NULL;
    }
  else
    {
      /* Redirect stdout to the null device */
        apr_err = apr_file_open(&null_handle, SVN_NULL_DEVICE_NAME, APR_WRITE,
                                APR_OS_DEFAULT, pool);
        if (apr_err)
          return svn_error_wrap_apr
            (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
    }

  /* Tie resources allocated for the command to a special pool which we can
   * destroy in order to clean up the stderr pipe opened for the process. */
  cmd_pool = svn_pool_create(pool);

  /* Check if a custom environment is defined for this hook, or else
   * whether a default environment is defined. */
  if (hooks_env)
    {
      hook_env = svn_hash_gets(hooks_env, name);
      if (hook_env == NULL)
        hook_env = svn_hash_gets(hooks_env,
                                 SVN_REPOS__HOOKS_ENV_DEFAULT_SECTION);
    }

  err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args,
                          env_from_env_hash(hook_env, pool, pool),
                          FALSE, FALSE, stdin_handle, result != NULL,
                          null_handle, TRUE, NULL, cmd_pool);
  if (!err)
    err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
  else
    {
      /* The command could not be started for some reason. */
      err = svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, err,
                              _("Failed to start '%s' hook"), cmd);
    }

  /* Hooks are fallible, and so hook failure is "expected" to occur at
     times.  When such a failure happens we still want to close the pipe
     and null file */
  if (!err && result)
    {
      svn_stringbuf_t *native_stdout;
      err = svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool);
      if (!err)
        *result = svn_stringbuf__morph_into_string(native_stdout);
    }

  /* Close resources allocated by svn_io_start_cmd3(), such as the pipe. */
  svn_pool_destroy(cmd_pool);

  /* Close the null handle. */
  if (null_handle)
    {
      apr_err = apr_file_close(null_handle);
      if (!err && apr_err)
        return svn_error_wrap_apr(apr_err, _("Error closing null file"));
    }

  return svn_error_trace(err);
}