2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/param.h>
32 #include <sys/sysctl.h>
40 #include "atf-c/defs.h"
43 #include "atf-c++/config.hpp"
45 #include "atf-c++/detail/fs.hpp"
46 #include "atf-c++/detail/env.hpp"
47 #include "atf-c++/detail/sanity.hpp"
48 #include "atf-c++/detail/text.hpp"
50 #include "requirements.hpp"
53 namespace impl
= atf::atf_run
;
59 has_program(const atf::fs::path
& program
)
63 if (program
.is_absolute()) {
64 found
= atf::fs::is_executable(program
);
66 if (program
.str().find('/') != std::string::npos
)
67 throw std::runtime_error("Relative paths are not allowed "
68 "when searching for a program (" +
71 const std::vector
< std::string
> dirs
= atf::text::split(
72 atf::env::get("PATH"), ":");
73 for (std::vector
< std::string
>::const_iterator iter
= dirs
.begin();
74 !found
&& iter
!= dirs
.end(); iter
++) {
75 const atf::fs::path
& p
= atf::fs::path(*iter
) / program
;
76 if (atf::fs::is_executable(p
))
86 check_arch(const std::string
& arches
)
88 const std::vector
< std::string
> v
= atf::text::split(arches
, " ");
90 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
91 iter
!= v
.end(); iter
++) {
92 if ((*iter
) == atf::config::get("atf_arch"))
97 return "Requires the '" + arches
+ "' architecture";
99 return "Requires one of the '" + arches
+ "' architectures";
104 check_config(const std::string
& variables
, const atf::tests::vars_map
& config
)
106 const std::vector
< std::string
> v
= atf::text::split(variables
, " ");
107 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
108 iter
!= v
.end(); iter
++) {
109 if (config
.find((*iter
)) == config
.end())
110 return "Required configuration variable '" + (*iter
) + "' not "
118 check_files(const std::string
& progs
)
120 const std::vector
< std::string
> v
= atf::text::split(progs
, " ");
121 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
122 iter
!= v
.end(); iter
++) {
123 const atf::fs::path
file(*iter
);
124 if (!file
.is_absolute())
125 throw std::runtime_error("Relative paths are not allowed when "
126 "checking for a required file (" + file
.str() + ")");
127 if (!atf::fs::exists(file
))
128 return "Required file '" + file
.str() + "' not found";
135 check_machine(const std::string
& machines
)
137 const std::vector
< std::string
> v
= atf::text::split(machines
, " ");
139 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
140 iter
!= v
.end(); iter
++) {
141 if ((*iter
) == atf::config::get("atf_machine"))
146 return "Requires the '" + machines
+ "' machine type";
148 return "Requires one of the '" + machines
+ "' machine types";
151 #if defined(__APPLE__) || defined(__NetBSD__)
154 check_memory_sysctl(const int64_t needed
, const char* sysctl_variable
)
157 std::size_t available_length
= sizeof(available
);
158 if (::sysctlbyname(sysctl_variable
, &available
, &available_length
,
160 const char* e
= std::strerror(errno
);
161 return "Failed to get sysctl(hw.usermem64) value: " + std::string(e
);
164 if (available
< needed
) {
165 return "Not enough memory; needed " + atf::text::to_string(needed
) +
166 ", available " + atf::text::to_string(available
);
170 # if defined(__APPLE__)
173 check_memory_darwin(const int64_t needed
)
175 return check_memory_sysctl(needed
, "hw.usermem");
177 # elif defined(__NetBSD__)
180 check_memory_netbsd(const int64_t needed
)
182 return check_memory_sysctl(needed
, "hw.usermem64");
185 # error "Conditional error"
190 check_memory_unknown(const int64_t needed ATF_DEFS_ATTRIBUTE_UNUSED
)
198 check_memory(const std::string
& raw_memory
)
200 const int64_t needed
= atf::text::to_bytes(raw_memory
);
202 #if defined(__APPLE__)
203 return check_memory_darwin(needed
);
204 #elif defined(__NetBSD__)
205 return check_memory_netbsd(needed
);
207 return check_memory_unknown(needed
);
213 check_progs(const std::string
& progs
)
215 const std::vector
< std::string
> v
= atf::text::split(progs
, " ");
216 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
217 iter
!= v
.end(); iter
++) {
218 if (!has_program(atf::fs::path(*iter
)))
219 return "Required program '" + (*iter
) + "' not found in the PATH";
226 check_user(const std::string
& user
, const atf::tests::vars_map
& config
)
228 if (user
== "root") {
229 if (!impl::is_root())
230 return "Requires root privileges";
233 } else if (user
== "unprivileged") {
234 if (impl::is_root()) {
235 const atf::tests::vars_map::const_iterator iter
= config
.find(
236 "unprivileged-user");
237 if (iter
== config
.end())
238 return "Requires an unprivileged user and the "
239 "'unprivileged-user' configuration variable is not set";
241 const std::string
& unprivileged_user
= (*iter
).second
;
243 (void)impl::get_user_ids(unprivileged_user
);
245 } catch (const std::runtime_error
& e
) {
246 return "Failed to get information for user " +
253 throw std::runtime_error("Invalid value '" + user
+ "' for property "
257 } // anonymous namespace
260 impl::check_requirements(const atf::tests::vars_map
& metadata
,
261 const atf::tests::vars_map
& config
)
263 std::string failure_reason
= "";
265 for (atf::tests::vars_map::const_iterator iter
= metadata
.begin();
266 failure_reason
.empty() && iter
!= metadata
.end(); iter
++) {
267 const std::string
& name
= (*iter
).first
;
268 const std::string
& value
= (*iter
).second
;
269 INV(!value
.empty()); // Enforced by application/X-atf-tp parser.
271 if (name
== "require.arch")
272 failure_reason
= check_arch(value
);
273 else if (name
== "require.config")
274 failure_reason
= check_config(value
, config
);
275 else if (name
== "require.files")
276 failure_reason
= check_files(value
);
277 else if (name
== "require.machine")
278 failure_reason
= check_machine(value
);
279 else if (name
== "require.memory")
280 failure_reason
= check_memory(value
);
281 else if (name
== "require.progs")
282 failure_reason
= check_progs(value
);
283 else if (name
== "require.user")
284 failure_reason
= check_user(value
, config
);
286 // Unknown require.* properties are forbidden by the
287 // application/X-atf-tp parser.
288 INV(failure_reason
.find("require.") != 0);
292 return failure_reason
;
295 std::pair
< int, int >
296 impl::get_required_user(const atf::tests::vars_map
& metadata
,
297 const atf::tests::vars_map
& config
)
299 const atf::tests::vars_map::const_iterator user
= metadata
.find(
301 if (user
== metadata
.end())
302 return std::make_pair(-1, -1);
304 if ((*user
).second
== "unprivileged") {
305 if (impl::is_root()) {
306 const atf::tests::vars_map::const_iterator iter
= config
.find(
307 "unprivileged-user");
309 return impl::get_user_ids((*iter
).second
);
310 } catch (const std::exception
& e
) {
311 UNREACHABLE
; // This has been validated by check_user.
315 return std::make_pair(-1, -1);
318 return std::make_pair(-1, -1);