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 30extern "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 49namespace { 50 51static 52std::string 53fix_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 62static 63std::string* 64construct_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 69 std::string* command = new std::string(); 70 command->reserve(512); 71 (*command) += ("Atf_Check='" + libexecdir + "/atf-check' ; " + 72 ". " + pkgdatadir + "/libatf-sh.subr ; " + 73 ". " + fix_plain_name(filename) + " ; " + 74 "main \"${@}\""); 75 return command; 76} 77 78static 79const char** 80construct_argv(const std::string& shell, const int interpreter_argc, 81 const char* const* interpreter_argv) 82{ 83 PRE(interpreter_argc >= 1); 84 PRE(interpreter_argv[0] != NULL); 85 86 const std::string* script = construct_script(interpreter_argv[0]); 87 88 const int count = 4 + (interpreter_argc - 1) + 1; 89 const char** argv = new const char*[count]; 90 argv[0] = shell.c_str(); 91 argv[1] = "-c"; 92 argv[2] = script->c_str(); 93 argv[3] = interpreter_argv[0]; 94 95 for (int i = 1; i < interpreter_argc; i++) 96 argv[4 + i - 1] = interpreter_argv[i]; 97 98 argv[count - 1] = NULL; 99 100 return argv; 101} 102 103} // anonymous namespace 104 105// ------------------------------------------------------------------------ 106// The "atf_sh" class. 107// ------------------------------------------------------------------------ 108 109class atf_sh : public atf::application::app { 110 static const char* m_description; 111 112public: 113 atf_sh(void); 114 115 int main(void); 116}; 117 118const char* atf_sh::m_description = 119 "atf-sh is a shell interpreter that extends the functionality of the " 120 "system sh(1) with the atf-sh library."; 121 122atf_sh::atf_sh(void) : 123 app(m_description, "atf-sh(1)", "atf(7)") 124{ 125} 126 127int 128atf_sh::main(void) 129{ 130 if (m_argc < 1) 131 throw atf::application::usage_error("No test program provided"); 132 133 const atf::fs::path script(m_argv[0]); 134 if (!atf::fs::exists(script)) 135 throw std::runtime_error("The test program '" + script.str() + "' " 136 "does not exist"); 137 138 const std::string shell = atf::config::get("atf_shell"); 139 const char** argv = construct_argv(shell, m_argc, m_argv); 140 // Don't bother keeping track of the memory allocated by construct_argv: 141 // we are going to exec or die immediately. 142 143 const int ret = execv(shell.c_str(), const_cast< char** >(argv)); 144 INV(ret == -1); 145 std::cerr << "Failed to execute " << shell << ": " << std::strerror(errno) 146 << "\n"; 147 return EXIT_FAILURE; 148} 149 150int 151main(int argc, char* const* argv) 152{ 153 return atf_sh().run(argc, argv); 154} 155