atf-sh.cpp revision 262855
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 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 80static 81const char** 82construct_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 111class atf_sh : public atf::application::app { 112 static const char* m_description; 113 114public: 115 atf_sh(void); 116 117 int main(void); 118}; 119 120const 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 124atf_sh::atf_sh(void) : 125 app(m_description, "atf-sh(1)") 126{ 127} 128 129int 130atf_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 152int 153main(int argc, char* const* argv) 154{ 155 return atf_sh().run(argc, argv); 156} 157