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