test_child_common.c revision 44703b84feaafa4f0a4f8df11c5a503dcf48616e
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/*
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes Authors:
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes Jakub Hrozek <jhrozek@redhat.com>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes Copyright (C) 2014 Red Hat
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes SSSD tests: Child handlers
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes This program is free software; you can redistribute it and/or modify
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes it under the terms of the GNU General Public License as published by
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes the Free Software Foundation; either version 3 of the License, or
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes (at your option) any later version.
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes This program is distributed in the hope that it will be useful,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes but WITHOUT ANY WARRANTY; without even the implied warranty of
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes GNU General Public License for more details.
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes You should have received a copy of the GNU General Public License
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes along with this program. If not, see <http://www.gnu.org/licenses/>.
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes*/
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include <talloc.h>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include <tevent.h>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include <errno.h>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include <popt.h>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "util/child_common.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "tests/cmocka/common_mock.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#define TEST_BIN "dummy-child"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#define ECHO_STR "Hello child"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstatic int destructor_called;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstruct child_test_ctx {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes int pipefd_to_child[2];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes int pipefd_from_child[2];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct sss_test_ctx *test_ctx;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes};
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid child_test_setup(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno_t ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes check_leaks_push(global_talloc_context);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx = talloc(global_talloc_context, struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_non_null(child_tctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->test_ctx = create_ev_test_ctx(child_tctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_non_null(child_tctx->test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = pipe(child_tctx->pipefd_from_child);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(ret, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes DEBUG(SSSDBG_TRACE_LIBS, "from_child: %d:%d\n",
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_from_child[0],
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_from_child[1]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = pipe(child_tctx->pipefd_to_child);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(ret, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes DEBUG(SSSDBG_TRACE_LIBS, "to_child: %d:%d\n",
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_to_child[0],
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_to_child[1]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes *state = child_tctx;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid child_test_teardown(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes talloc_free(child_tctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes check_leaks_pop(global_talloc_context);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Just make sure the exec works. The child does nothing but exits */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_exec_child(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno_t ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes pid_t child_pid;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes int status;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_pid = fork();
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(child_pid, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (child_pid == 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = exec_child(child_tctx,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_to_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_from_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes CHILD_DIR"/"TEST_BIN, 2);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, EOK);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } else {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes do {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = waitpid(child_pid, &status, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } while (ret == -1 && errno == EINTR);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ret > 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = EIO;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (WIFEXITED(status)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = WEXITSTATUS(status);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } else {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes DEBUG(SSSDBG_FUNC_DATA,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes "Failed to wait for children %d\n", child_pid);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = EIO;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Make sure extra arguments are passed correctly */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_exec_child_extra_args(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno_t ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes pid_t child_pid;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes int status;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes const char *extra_args[] = { "--guitar=george",
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes "--drums=ringo",
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes NULL };
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes setenv("TEST_CHILD_ACTION", "check_extra_args", 1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes child_pid = fork();
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(child_pid, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (child_pid == 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = exec_child_ex(child_tctx,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_to_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_from_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes CHILD_DIR"/"TEST_BIN, 2, extra_args,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes STDIN_FILENO, STDOUT_FILENO);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, EOK);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } else {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes do {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = waitpid(child_pid, &status, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } while (ret == -1 && errno == EINTR);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ret > 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = EIO;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (WIFEXITED(status)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = WEXITSTATUS(status);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } else {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes DEBUG(SSSDBG_FUNC_DATA,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes "Failed to wait for children %d\n", child_pid);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = EIO;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstruct tevent_req *echo_child_write_send(TALLOC_CTX *mem_ctx,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_io_fds *io_fds,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes const char *input);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstatic void echo_child_write_done(struct tevent_req *subreq);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstatic void echo_child_read_done(struct tevent_req *subreq);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesint __real_child_io_destructor(void *ptr);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesint __wrap_child_io_destructor(void *ptr)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes destructor_called = 1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return __real_child_io_destructor(ptr);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Test that writing to the pipes works as expected */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_exec_child_io_destruct(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes struct child_io_fds *io_fds;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds = talloc(child_tctx, struct child_io_fds);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->read_from_child_fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->write_to_child_fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_non_null(io_fds);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes talloc_set_destructor((void *) io_fds, child_io_destructor);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->read_from_child_fd = child_tctx->pipefd_from_child[0];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->write_to_child_fd = child_tctx->pipefd_to_child[1];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes destructor_called = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes talloc_free(io_fds);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(destructor_called, 1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_from_child[0]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(errno, EBADF);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_from_child[1]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(errno, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_to_child[0]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(errno, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_to_child[1]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(errno, EBADF);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_child_cb(int child_status,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct tevent_signal *sige,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes void *pvt);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Test that writing to the pipes works as expected */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_exec_child_handler(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno_t ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes pid_t child_pid;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct sss_child_ctx_old *child_old_ctx;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = unsetenv("TEST_CHILD_ACTION");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_pid = fork();
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(child_pid, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (child_pid == 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = exec_child(child_tctx,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_to_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_tctx->pipefd_from_child,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes CHILD_DIR"/"TEST_BIN, 2);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, EOK);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = child_handler_setup(child_tctx->test_ctx->ev, child_pid,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes test_child_cb, child_tctx, &child_old_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, EOK);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = test_ev_loop(child_tctx->test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(ret, EOK);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_equal(child_tctx->test_ctx->error, 0);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_child_cb(int child_status,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct tevent_signal *sige,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes void *pvt)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_ctx = talloc_get_type(pvt, struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_ctx->test_ctx->error = EIO;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (WIFEXITED(child_status) && WEXITSTATUS(child_status) == 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_ctx->test_ctx->error = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_ctx->test_ctx->done = true;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Test that writing to the pipes works as expected */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid test_exec_child_echo(void **state)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes errno_t ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes pid_t child_pid;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx *child_tctx = talloc_get_type(*state,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_test_ctx);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct tevent_req *req;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct child_io_fds *io_fds;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes setenv("TEST_CHILD_ACTION", "echo", 1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds = talloc(child_tctx, struct child_io_fds);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_non_null(io_fds);
f2f3f241c00a7a4bd597e57a19023940e072918abnicholes io_fds->read_from_child_fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->write_to_child_fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes talloc_set_destructor((void *) io_fds, child_io_destructor);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes child_pid = fork();
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes assert_int_not_equal(child_pid, -1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (child_pid == 0) {
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes ret = exec_child_ex(child_tctx,
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes child_tctx->pipefd_to_child,
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes child_tctx->pipefd_from_child,
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes CHILD_DIR"/"TEST_BIN, 2, NULL,
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes STDIN_FILENO, 3);
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes assert_int_equal(ret, EOK);
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes }
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes DEBUG(SSSDBG_FUNC_DATA, "Forked into %d\n", child_pid);
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->read_from_child_fd = child_tctx->pipefd_from_child[0];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_from_child[1]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes io_fds->write_to_child_fd = child_tctx->pipefd_to_child[1];
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes close(child_tctx->pipefd_to_child[0]);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes fd_nonblocking(io_fds->write_to_child_fd);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes fd_nonblocking(io_fds->read_from_child_fd);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = child_handler_setup(child_tctx->test_ctx->ev, child_pid,
NULL, NULL, NULL);
assert_int_equal(ret, EOK);
req = echo_child_write_send(child_tctx, child_tctx, io_fds, ECHO_STR);
assert_non_null(req);
ret = test_ev_loop(child_tctx->test_ctx);
talloc_free(io_fds);
assert_int_equal(ret, EOK);
}
struct test_exec_echo_state {
struct child_io_fds *io_fds;
struct io_buffer buf;
struct child_test_ctx *child_test_ctx;
};
struct tevent_req *echo_child_write_send(TALLOC_CTX *mem_ctx,
struct child_test_ctx *child_tctx,
struct child_io_fds *io_fds,
const char *input)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct test_exec_echo_state *echo_state;
req = tevent_req_create(mem_ctx, &echo_state, struct test_exec_echo_state);
assert_non_null(req);
echo_state->child_test_ctx = child_tctx;
echo_state->buf.data = (unsigned char *) talloc_strdup(echo_state, input);
assert_non_null(echo_state->buf.data);
echo_state->buf.size = strlen(input) + 1;
echo_state->io_fds = io_fds;
DEBUG(SSSDBG_TRACE_INTERNAL, "Writing..\n");
subreq = write_pipe_send(child_tctx, child_tctx->test_ctx->ev,
echo_state->buf.data, echo_state->buf.size,
echo_state->io_fds->write_to_child_fd);
assert_non_null(subreq);
tevent_req_set_callback(subreq, echo_child_write_done, req);
return req;
}
static void echo_child_write_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct test_exec_echo_state *echo_state;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
echo_state = tevent_req_data(req, struct test_exec_echo_state);
ret = write_pipe_recv(subreq);
DEBUG(SSSDBG_TRACE_INTERNAL, "Writing OK\n");
talloc_zfree(subreq);
assert_int_equal(ret, EOK);
close(echo_state->io_fds->write_to_child_fd);
echo_state->io_fds->write_to_child_fd = -1;
DEBUG(SSSDBG_TRACE_INTERNAL, "Reading..\n");
subreq = read_pipe_send(echo_state,
echo_state->child_test_ctx->test_ctx->ev,
echo_state->io_fds->read_from_child_fd);
assert_non_null(subreq);
tevent_req_set_callback(subreq, echo_child_read_done, req);
}
static void echo_child_read_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct test_exec_echo_state *echo_state;
errno_t ret;
ssize_t len;
uint8_t *buf;
req = tevent_req_callback_data(subreq, struct tevent_req);
echo_state = tevent_req_data(req, struct test_exec_echo_state);
ret = read_pipe_recv(subreq, echo_state, &buf, &len);
talloc_zfree(subreq);
DEBUG(SSSDBG_TRACE_INTERNAL, "Reading OK\n");
assert_int_equal(ret, EOK);
close(echo_state->io_fds->read_from_child_fd);
echo_state->io_fds->read_from_child_fd = -1;
assert_string_equal(buf, echo_state->buf.data);
echo_state->child_test_ctx->test_ctx->done = true;
}
void sss_child_cb(int pid, int wait_status, void *pvt);
/* Just make sure the exec works. The child does nothing but exits */
void test_sss_child(void **state)
{
errno_t ret;
pid_t child_pid;
struct child_test_ctx *child_tctx = talloc_get_type(*state,
struct child_test_ctx);
struct sss_sigchild_ctx *sc_ctx;
struct sss_child_ctx *sss_child;
ret = unsetenv("TEST_CHILD_ACTION");
assert_int_equal(ret, 0);
ret = sss_sigchld_init(child_tctx, child_tctx->test_ctx->ev, &sc_ctx);
assert_int_equal(ret, EOK);
child_pid = fork();
assert_int_not_equal(child_pid, -1);
if (child_pid == 0) {
ret = exec_child(child_tctx,
child_tctx->pipefd_to_child,
child_tctx->pipefd_from_child,
CHILD_DIR"/"TEST_BIN, 2);
assert_int_equal(ret, EOK);
}
ret = sss_child_register(child_tctx, sc_ctx,
child_pid,
sss_child_cb,
child_tctx, &sss_child);
assert_int_equal(ret, EOK);
ret = test_ev_loop(child_tctx->test_ctx);
assert_int_equal(ret, EOK);
assert_int_equal(child_tctx->test_ctx->error, 0);
}
void sss_child_cb(int pid, int wait_status, void *pvt)
{
struct child_test_ctx *child_ctx = talloc_get_type(pvt, struct child_test_ctx);
child_ctx->test_ctx->error = EIO;
if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == 0) {
child_ctx->test_ctx->error = 0;
}
child_ctx->test_ctx->done = true;
}
int main(int argc, const char *argv[])
{
int rv;
poptContext pc;
int opt;
struct poptOption long_options[] = {
POPT_AUTOHELP
SSSD_DEBUG_OPTS
POPT_TABLEEND
};
const UnitTest tests[] = {
unit_test_setup_teardown(test_exec_child,
child_test_setup,
child_test_teardown),
unit_test_setup_teardown(test_exec_child_extra_args,
child_test_setup,
child_test_teardown),
unit_test_setup_teardown(test_exec_child_io_destruct,
child_test_setup,
child_test_teardown),
unit_test_setup_teardown(test_exec_child_handler,
child_test_setup,
child_test_teardown),
unit_test_setup_teardown(test_exec_child_echo,
child_test_setup,
child_test_teardown),
unit_test_setup_teardown(test_sss_child,
child_test_setup,
child_test_teardown),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
debug_level = SSSDBG_INVALID;
pc = poptGetContext(argv[0], argc, argv, long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch(opt) {
default:
fprintf(stderr, "\nInvalid option %s: %s\n\n",
poptBadOption(pc, 0), poptStrerror(opt));
poptPrintUsage(pc, stderr, 0);
return 1;
}
}
poptFreeContext(pc);
DEBUG_CLI_INIT(debug_level);
rv = run_tests(tests);
return rv;
}