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