14bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev/*
24bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
34bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev *
44bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * This program is free software; you can redistribute it and/or
54bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * modify it under the terms of the GNU General Public License as
64bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * published by the Free Software Foundation; either version 2 of
74bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * the License, or (at your option) any later version.
84bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev *
94bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * This program is distributed in the hope that it would be useful,
104bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * but WITHOUT ANY WARRANTY; without even the implied warranty of
114bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
124bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * GNU General Public License for more details.
134bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev *
144bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * You should have received a copy of the GNU General Public License
154bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * along with this program; if not, write the Free Software Foundation,
164bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
174bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev *
184bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
194bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev *
204bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev */
214bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev
22bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh#include <errno.h>
234bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev#include <sys/types.h>
24bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh#include <sys/stat.h>
254bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev#include <sys/wait.h>
26bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh#include <fcntl.h>
274bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev#include <unistd.h>
28989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis#include <signal.h>
294bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev#include "test.h"
304bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev
31bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh#define OPEN_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
32bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh#define OPEN_FLAGS	(O_WRONLY | O_APPEND | O_CREAT)
33bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
34bbdb9f78378c7e038f463efa39d2470e1c51ad54Cyril Hrubisint tst_run_cmd_fds_(void (cleanup_fn)(void),
35e63337a09474e594900efab91d1a3fc7fa332f2eStanislav Kholmanskikh		const char *const argv[],
36bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		int stdout_fd,
37a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh		int stderr_fd,
38a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh		int pass_exit_val)
394bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev{
40a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	int rc;
41a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh
424bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	if (argv == NULL || argv[0] == NULL) {
434bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev		tst_brkm(TBROK, cleanup_fn,
444bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev			"argument list is empty at %s:%d", __FILE__, __LINE__);
454bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	}
464bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev
47989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	/*
48989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 * The tst_sig() install poisoned signal handlers for all signals the
49989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 * test is not expected to get.
50989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 *
51989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 * So we temporarily disable the handler for sigchild we get after our
52989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 * child exits so that we don't have to disable it in each test that
53989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 * uses this interface.
54989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	 */
55989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	void *old_handler = signal(SIGCHLD, SIG_DFL);
56989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis
574bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	pid_t pid = vfork();
584bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	if (pid == -1) {
594bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev		tst_brkm(TBROK | TERRNO, cleanup_fn, "vfork failed at %s:%d",
604bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev			__FILE__, __LINE__);
614bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	}
62bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	if (!pid) {
63bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		/* redirecting stdout and stderr if needed */
64bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		if (stdout_fd != -1) {
65bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			close(STDOUT_FILENO);
66bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			dup2(stdout_fd, STDOUT_FILENO);
67bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		}
68bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
69bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		if (stderr_fd != -1) {
70bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			close(STDERR_FILENO);
71bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			dup2(stderr_fd, STDERR_FILENO);
72bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		}
73bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
743d2deae3a823b33d5d6886f3ee0565329407af7fCyril Hrubis		if (execvp(argv[0], (char *const *)argv)) {
753d2deae3a823b33d5d6886f3ee0565329407af7fCyril Hrubis			if (errno == ENOENT)
763d2deae3a823b33d5d6886f3ee0565329407af7fCyril Hrubis				_exit(255);
773d2deae3a823b33d5d6886f3ee0565329407af7fCyril Hrubis		}
783d2deae3a823b33d5d6886f3ee0565329407af7fCyril Hrubis		_exit(254);
79bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	}
804bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev
814bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	int ret = -1;
824bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	if (waitpid(pid, &ret, 0) != pid) {
83989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis		tst_brkm(TBROK | TERRNO, cleanup_fn, "waitpid failed at %s:%d",
844bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev			__FILE__, __LINE__);
854bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	}
864bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev
87989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis	signal(SIGCHLD, old_handler);
88989d3063aee442c001fac7a61dc6f1b0e9050768Cyril Hrubis
89a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	if (!WIFEXITED(ret)) {
904bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev		tst_brkm(TBROK, cleanup_fn, "failed to exec cmd '%s' at %s:%d",
914bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev			argv[0], __FILE__, __LINE__);
924bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev	}
93a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh
94a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	rc = WEXITSTATUS(ret);
95a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh
96a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	if ((!pass_exit_val) && rc)
97a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh		tst_brkm(TBROK, cleanup_fn,
98a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh			 "'%s' exited with a non-zero code %d at %s:%d",
99a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh			 argv[0], rc, __FILE__, __LINE__);
100a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh
101a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	return rc;
1024bc55ecaa76244f3ba28a91f4fb8b3dac9c744acAlexey Kodanev}
103bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
104bbdb9f78378c7e038f463efa39d2470e1c51ad54Cyril Hrubisint tst_run_cmd_(void (cleanup_fn)(void),
105e63337a09474e594900efab91d1a3fc7fa332f2eStanislav Kholmanskikh		const char *const argv[],
106bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		const char *stdout_path,
107a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh		const char *stderr_path,
108a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh		int pass_exit_val)
109bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh{
110bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	int stdout_fd = -1;
111bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	int stderr_fd = -1;
112a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	int rc;
113bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
114bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	if (stdout_path != NULL) {
115bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		stdout_fd = open(stdout_path,
116bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				OPEN_FLAGS, OPEN_MODE);
117bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
118bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		if (stdout_fd == -1)
119bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			tst_resm(TWARN | TERRNO,
120bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				"open() on %s failed at %s:%d",
121bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				stdout_path, __FILE__, __LINE__);
122bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	}
123bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
124bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	if (stderr_path != NULL) {
125bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		stderr_fd = open(stderr_path,
126bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				OPEN_FLAGS, OPEN_MODE);
127bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
128bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		if (stderr_fd == -1)
129bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			tst_resm(TWARN | TERRNO,
130bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				"open() on %s failed at %s:%d",
131bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh				stderr_path, __FILE__, __LINE__);
132bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	}
133bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
134a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	rc = tst_run_cmd_fds(cleanup_fn, argv, stdout_fd, stderr_fd,
135a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh			     pass_exit_val);
136bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
137bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	if ((stdout_fd != -1) && (close(stdout_fd) == -1))
138bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		tst_resm(TWARN | TERRNO,
139bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			"close() on %s failed at %s:%d",
140bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			stdout_path, __FILE__, __LINE__);
141bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh
142bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh	if ((stderr_fd != -1) && (close(stderr_fd) == -1))
143bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh		tst_resm(TWARN | TERRNO,
144bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			"close() on %s failed at %s:%d",
145bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh			stderr_path, __FILE__, __LINE__);
146a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh
147a648a4d00896726b2bd4e7eb914f8955fe225595Stanislav Kholmanskikh	return rc;
148bee0a9469641d3cc8d29853abb4ba10883b30ba6Stanislav kholmanskikh}
149a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang
150a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wangint tst_system(const char *command)
151a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang{
152a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	int ret = 0;
153a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang
154a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	/*
155a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	 *Temporarily disable SIGCHLD of user defined handler, so the
156a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	 *system(3) function will not cause unexpected SIGCHLD signal
157a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	 *callback function for test cases.
158a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	 */
159a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	void *old_handler = signal(SIGCHLD, SIG_DFL);
160a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang
161a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	ret = system(command);
162a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang
163a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	signal(SIGCHLD, old_handler);
164a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang	return ret;
165a83cbb8ce3db1a0c0bc90dafa669a97bb5632768George Wang}
166