1c243e490SMarcel Moolenaar // Copyright (c) 2010 The NetBSD Foundation, Inc.
2c243e490SMarcel Moolenaar // All rights reserved.
3c243e490SMarcel Moolenaar //
4c243e490SMarcel Moolenaar // Redistribution and use in source and binary forms, with or without
5c243e490SMarcel Moolenaar // modification, are permitted provided that the following conditions
6c243e490SMarcel Moolenaar // are met:
7c243e490SMarcel Moolenaar // 1. Redistributions of source code must retain the above copyright
8c243e490SMarcel Moolenaar // notice, this list of conditions and the following disclaimer.
9c243e490SMarcel Moolenaar // 2. Redistributions in binary form must reproduce the above copyright
10c243e490SMarcel Moolenaar // notice, this list of conditions and the following disclaimer in the
11c243e490SMarcel Moolenaar // documentation and/or other materials provided with the distribution.
12c243e490SMarcel Moolenaar //
13c243e490SMarcel Moolenaar // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14c243e490SMarcel Moolenaar // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15c243e490SMarcel Moolenaar // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16c243e490SMarcel Moolenaar // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c243e490SMarcel Moolenaar // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18c243e490SMarcel Moolenaar // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c243e490SMarcel Moolenaar // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20c243e490SMarcel Moolenaar // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21c243e490SMarcel Moolenaar // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22c243e490SMarcel Moolenaar // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23c243e490SMarcel Moolenaar // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24c243e490SMarcel Moolenaar // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25c243e490SMarcel Moolenaar
26c243e490SMarcel Moolenaar extern "C" {
27c243e490SMarcel Moolenaar #include <unistd.h>
28c243e490SMarcel Moolenaar }
29c243e490SMarcel Moolenaar
30c243e490SMarcel Moolenaar #include <cerrno>
31c243e490SMarcel Moolenaar #include <cstdlib>
32c243e490SMarcel Moolenaar #include <cstring>
33c243e490SMarcel Moolenaar #include <iostream>
34c243e490SMarcel Moolenaar
35c243e490SMarcel Moolenaar #include "atf-c++/detail/application.hpp"
36*0677dfd1SJulio Merino #include "atf-c++/detail/env.hpp"
37c243e490SMarcel Moolenaar #include "atf-c++/detail/fs.hpp"
38c243e490SMarcel Moolenaar #include "atf-c++/detail/sanity.hpp"
39c243e490SMarcel Moolenaar
40c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
41c243e490SMarcel Moolenaar // Auxiliary functions.
42c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
43c243e490SMarcel Moolenaar
44c243e490SMarcel Moolenaar namespace {
45c243e490SMarcel Moolenaar
46c243e490SMarcel Moolenaar static
47c243e490SMarcel Moolenaar std::string
fix_plain_name(const char * filename)48c243e490SMarcel Moolenaar fix_plain_name(const char *filename)
49c243e490SMarcel Moolenaar {
50c243e490SMarcel Moolenaar const atf::fs::path filepath(filename);
51c243e490SMarcel Moolenaar if (filepath.branch_path().str() == ".")
52c243e490SMarcel Moolenaar return std::string("./") + filename;
53c243e490SMarcel Moolenaar else
54c243e490SMarcel Moolenaar return std::string(filename);
55c243e490SMarcel Moolenaar }
56c243e490SMarcel Moolenaar
57c243e490SMarcel Moolenaar static
58c243e490SMarcel Moolenaar std::string*
construct_script(const char * filename)59c243e490SMarcel Moolenaar construct_script(const char* filename)
60c243e490SMarcel Moolenaar {
61*0677dfd1SJulio Merino const std::string libexecdir = atf::env::get(
62*0677dfd1SJulio Merino "ATF_LIBEXECDIR", ATF_LIBEXECDIR);
63*0677dfd1SJulio Merino const std::string pkgdatadir = atf::env::get(
64*0677dfd1SJulio Merino "ATF_PKGDATADIR", ATF_PKGDATADIR);
65*0677dfd1SJulio Merino const std::string shell = atf::env::get("ATF_SHELL", ATF_SHELL);
66c243e490SMarcel Moolenaar
67c243e490SMarcel Moolenaar std::string* command = new std::string();
68c243e490SMarcel Moolenaar command->reserve(512);
69c243e490SMarcel Moolenaar (*command) += ("Atf_Check='" + libexecdir + "/atf-check' ; " +
70c243e490SMarcel Moolenaar "Atf_Shell='" + shell + "' ; " +
71c243e490SMarcel Moolenaar ". " + pkgdatadir + "/libatf-sh.subr ; " +
72c243e490SMarcel Moolenaar ". " + fix_plain_name(filename) + " ; " +
73c243e490SMarcel Moolenaar "main \"${@}\"");
74c243e490SMarcel Moolenaar return command;
75c243e490SMarcel Moolenaar }
76c243e490SMarcel Moolenaar
77c243e490SMarcel Moolenaar static
78c243e490SMarcel Moolenaar const char**
construct_argv(const std::string & shell,const int interpreter_argc,const char * const * interpreter_argv)79c243e490SMarcel Moolenaar construct_argv(const std::string& shell, const int interpreter_argc,
80c243e490SMarcel Moolenaar const char* const* interpreter_argv)
81c243e490SMarcel Moolenaar {
82c243e490SMarcel Moolenaar PRE(interpreter_argc >= 1);
83c243e490SMarcel Moolenaar PRE(interpreter_argv[0] != NULL);
84c243e490SMarcel Moolenaar
85c243e490SMarcel Moolenaar const std::string* script = construct_script(interpreter_argv[0]);
86c243e490SMarcel Moolenaar
87c243e490SMarcel Moolenaar const int count = 4 + (interpreter_argc - 1) + 1;
88c243e490SMarcel Moolenaar const char** argv = new const char*[count];
89c243e490SMarcel Moolenaar argv[0] = shell.c_str();
90c243e490SMarcel Moolenaar argv[1] = "-c";
91c243e490SMarcel Moolenaar argv[2] = script->c_str();
92c243e490SMarcel Moolenaar argv[3] = interpreter_argv[0];
93c243e490SMarcel Moolenaar
94c243e490SMarcel Moolenaar for (int i = 1; i < interpreter_argc; i++)
95c243e490SMarcel Moolenaar argv[4 + i - 1] = interpreter_argv[i];
96c243e490SMarcel Moolenaar
97c243e490SMarcel Moolenaar argv[count - 1] = NULL;
98c243e490SMarcel Moolenaar
99c243e490SMarcel Moolenaar return argv;
100c243e490SMarcel Moolenaar }
101c243e490SMarcel Moolenaar
102c243e490SMarcel Moolenaar } // anonymous namespace
103c243e490SMarcel Moolenaar
104c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
105c243e490SMarcel Moolenaar // The "atf_sh" class.
106c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
107c243e490SMarcel Moolenaar
108c243e490SMarcel Moolenaar class atf_sh : public atf::application::app {
109c243e490SMarcel Moolenaar static const char* m_description;
110c243e490SMarcel Moolenaar
111*0677dfd1SJulio Merino atf::fs::path m_shell;
112*0677dfd1SJulio Merino
113*0677dfd1SJulio Merino options_set specific_options(void) const;
114*0677dfd1SJulio Merino void process_option(int, const char*);
115*0677dfd1SJulio Merino
116c243e490SMarcel Moolenaar public:
117c243e490SMarcel Moolenaar atf_sh(void);
118c243e490SMarcel Moolenaar
119c243e490SMarcel Moolenaar int main(void);
120c243e490SMarcel Moolenaar };
121c243e490SMarcel Moolenaar
122c243e490SMarcel Moolenaar const char* atf_sh::m_description =
123c243e490SMarcel Moolenaar "atf-sh is a shell interpreter that extends the functionality of the "
124c243e490SMarcel Moolenaar "system sh(1) with the atf-sh library.";
125c243e490SMarcel Moolenaar
atf_sh(void)126c243e490SMarcel Moolenaar atf_sh::atf_sh(void) :
127*0677dfd1SJulio Merino app(m_description, "atf-sh(1)"),
128*0677dfd1SJulio Merino m_shell(atf::fs::path(atf::env::get("ATF_SHELL", ATF_SHELL)))
129c243e490SMarcel Moolenaar {
130c243e490SMarcel Moolenaar }
131c243e490SMarcel Moolenaar
132*0677dfd1SJulio Merino atf_sh::options_set
specific_options(void) const133*0677dfd1SJulio Merino atf_sh::specific_options(void)
134*0677dfd1SJulio Merino const
135*0677dfd1SJulio Merino {
136*0677dfd1SJulio Merino using atf::application::option;
137*0677dfd1SJulio Merino options_set opts;
138*0677dfd1SJulio Merino
139*0677dfd1SJulio Merino INV(m_shell == atf::fs::path(atf::env::get("ATF_SHELL", ATF_SHELL)));
140*0677dfd1SJulio Merino opts.insert(option('s', "shell", "Path to the shell interpreter to use; "
141*0677dfd1SJulio Merino "default: " + m_shell.str()));
142*0677dfd1SJulio Merino
143*0677dfd1SJulio Merino return opts;
144*0677dfd1SJulio Merino }
145*0677dfd1SJulio Merino
146*0677dfd1SJulio Merino void
process_option(int ch,const char * arg)147*0677dfd1SJulio Merino atf_sh::process_option(int ch, const char* arg)
148*0677dfd1SJulio Merino {
149*0677dfd1SJulio Merino switch (ch) {
150*0677dfd1SJulio Merino case 's':
151*0677dfd1SJulio Merino m_shell = atf::fs::path(arg);
152*0677dfd1SJulio Merino break;
153*0677dfd1SJulio Merino
154*0677dfd1SJulio Merino default:
155*0677dfd1SJulio Merino UNREACHABLE;
156*0677dfd1SJulio Merino }
157*0677dfd1SJulio Merino }
158*0677dfd1SJulio Merino
159c243e490SMarcel Moolenaar int
main(void)160c243e490SMarcel Moolenaar atf_sh::main(void)
161c243e490SMarcel Moolenaar {
162c243e490SMarcel Moolenaar if (m_argc < 1)
163c243e490SMarcel Moolenaar throw atf::application::usage_error("No test program provided");
164c243e490SMarcel Moolenaar
165c243e490SMarcel Moolenaar const atf::fs::path script(m_argv[0]);
166c243e490SMarcel Moolenaar if (!atf::fs::exists(script))
167c243e490SMarcel Moolenaar throw std::runtime_error("The test program '" + script.str() + "' "
168c243e490SMarcel Moolenaar "does not exist");
169c243e490SMarcel Moolenaar
170*0677dfd1SJulio Merino const char** argv = construct_argv(m_shell.str(), m_argc, m_argv);
171c243e490SMarcel Moolenaar // Don't bother keeping track of the memory allocated by construct_argv:
172c243e490SMarcel Moolenaar // we are going to exec or die immediately.
173c243e490SMarcel Moolenaar
174*0677dfd1SJulio Merino const int ret = execv(m_shell.c_str(), const_cast< char** >(argv));
175c243e490SMarcel Moolenaar INV(ret == -1);
176*0677dfd1SJulio Merino std::cerr << "Failed to execute " << m_shell.str() << ": "
177*0677dfd1SJulio Merino << std::strerror(errno) << "\n";
178c243e490SMarcel Moolenaar return EXIT_FAILURE;
179c243e490SMarcel Moolenaar }
180c243e490SMarcel Moolenaar
181c243e490SMarcel Moolenaar int
main(int argc,char * const * argv)182c243e490SMarcel Moolenaar main(int argc, char* const* argv)
183c243e490SMarcel Moolenaar {
184c243e490SMarcel Moolenaar return atf_sh().run(argc, argv);
185c243e490SMarcel Moolenaar }
186