xref: /freebsd/contrib/atf/atf-sh/atf-sh.cpp (revision 0677dfd1)
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