diff options
author | Manuel Bentele | 2020-10-23 15:18:01 +0200 |
---|---|---|
committer | Manuel Bentele | 2020-10-23 15:18:01 +0200 |
commit | dbb41ce2b7f309d394054a6bd1e33afd578798a5 (patch) | |
tree | 6a31092063d9f2fb5ac5720ec6759040e793c3d5 /src/kernel/tests/lib/tst_cmd.c | |
parent | Set Linux kernel version to unknown if it is not detectable (diff) | |
download | xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.gz xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.xz xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.zip |
Move the source code of all xloop components to the common 'src' directory
Diffstat (limited to 'src/kernel/tests/lib/tst_cmd.c')
-rw-r--r-- | src/kernel/tests/lib/tst_cmd.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/kernel/tests/lib/tst_cmd.c b/src/kernel/tests/lib/tst_cmd.c new file mode 100644 index 0000000..7446249 --- /dev/null +++ b/src/kernel/tests/lib/tst_cmd.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Alexey Kodanev <alexey.kodanev@oracle.com> + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include "test.h" +#include "tst_cmd.h" + +#define OPEN_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) +#define OPEN_FLAGS (O_WRONLY | O_APPEND | O_CREAT) + +int tst_cmd_fds_(void (cleanup_fn)(void), + const char *const argv[], + int stdout_fd, + int stderr_fd, + enum tst_cmd_flags flags) +{ + int rc; + + if (argv == NULL || argv[0] == NULL) { + tst_brkm(TBROK, cleanup_fn, + "argument list is empty at %s:%d", __FILE__, __LINE__); + return -1; + } + + /* + * The tst_sig() install poisoned signal handlers for all signals the + * test is not expected to get. + * + * So we temporarily disable the handler for sigchild we get after our + * child exits so that we don't have to disable it in each test that + * uses this interface. + */ + void *old_handler = signal(SIGCHLD, SIG_DFL); + + char path[PATH_MAX]; + + if (tst_get_path(argv[0], path, sizeof(path))) { + if (flags & TST_CMD_TCONF_ON_MISSING) + tst_brkm(TCONF, cleanup_fn, "Couldn't find '%s' in $PATH at %s:%d", argv[0], + __FILE__, __LINE__); + else + return 255; + } + + pid_t pid = vfork(); + if (pid == -1) { + tst_brkm(TBROK | TERRNO, cleanup_fn, "vfork failed at %s:%d", + __FILE__, __LINE__); + return -1; + } + if (!pid) { + /* redirecting stdout and stderr if needed */ + if (stdout_fd != -1) { + close(STDOUT_FILENO); + dup2(stdout_fd, STDOUT_FILENO); + } + + if (stderr_fd != -1) { + close(STDERR_FILENO); + dup2(stderr_fd, STDERR_FILENO); + } + + execvp(argv[0], (char *const *)argv); + _exit(254); + } + + int ret = -1; + if (waitpid(pid, &ret, 0) != pid) { + tst_brkm(TBROK | TERRNO, cleanup_fn, "waitpid failed at %s:%d", + __FILE__, __LINE__); + return -1; + } + + signal(SIGCHLD, old_handler); + + if (!WIFEXITED(ret)) { + tst_brkm(TBROK, cleanup_fn, "failed to exec cmd '%s' at %s:%d", + argv[0], __FILE__, __LINE__); + return -1; + } + + rc = WEXITSTATUS(ret); + + if (!(flags & TST_CMD_PASS_RETVAL) && rc) { + tst_brkm(TBROK, cleanup_fn, + "'%s' exited with a non-zero code %d at %s:%d", + argv[0], rc, __FILE__, __LINE__); + return -1; + } + + return rc; +} + +int tst_cmd_(void (cleanup_fn)(void), + const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags) +{ + int stdout_fd = -1; + int stderr_fd = -1; + int rc; + + if (stdout_path != NULL) { + stdout_fd = open(stdout_path, + OPEN_FLAGS, OPEN_MODE); + + if (stdout_fd == -1) + tst_resm(TWARN | TERRNO, + "open() on %s failed at %s:%d", + stdout_path, __FILE__, __LINE__); + } + + if (stderr_path != NULL) { + stderr_fd = open(stderr_path, + OPEN_FLAGS, OPEN_MODE); + + if (stderr_fd == -1) + tst_resm(TWARN | TERRNO, + "open() on %s failed at %s:%d", + stderr_path, __FILE__, __LINE__); + } + + rc = tst_cmd_fds(cleanup_fn, argv, stdout_fd, stderr_fd, flags); + + if ((stdout_fd != -1) && (close(stdout_fd) == -1)) + tst_resm(TWARN | TERRNO, + "close() on %s failed at %s:%d", + stdout_path, __FILE__, __LINE__); + + if ((stderr_fd != -1) && (close(stderr_fd) == -1)) + tst_resm(TWARN | TERRNO, + "close() on %s failed at %s:%d", + stderr_path, __FILE__, __LINE__); + + return rc; +} + +int tst_system(const char *command) +{ + int ret = 0; + + /* + *Temporarily disable SIGCHLD of user defined handler, so the + *system(3) function will not cause unexpected SIGCHLD signal + *callback function for test cases. + */ + void *old_handler = signal(SIGCHLD, SIG_DFL); + + ret = system(command); + + signal(SIGCHLD, old_handler); + return ret; +} |