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>
44 #include "requirements.hpp"
48 namespace impl
= tools
;
52 typedef std::map
< std::string
, std::string
> vars_map
;
56 has_program(const tools::fs::path
& program
)
60 if (program
.is_absolute()) {
61 found
= tools::fs::is_executable(program
);
63 if (program
.str().find('/') != std::string::npos
)
64 throw std::runtime_error("Relative paths are not allowed "
65 "when searching for a program (" +
68 const std::vector
< std::string
> dirs
= tools::text::split(
69 tools::env::get("PATH"), ":");
70 for (std::vector
< std::string
>::const_iterator iter
= dirs
.begin();
71 !found
&& iter
!= dirs
.end(); iter
++) {
72 const tools::fs::path
& p
= tools::fs::path(*iter
) / program
;
73 if (tools::fs::is_executable(p
))
83 check_arch(const std::string
& arches
)
85 const std::vector
< std::string
> v
= tools::text::split(arches
, " ");
87 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
88 iter
!= v
.end(); iter
++) {
89 if ((*iter
) == tools::config::get("atf_arch"))
94 return "Requires the '" + arches
+ "' architecture";
96 return "Requires one of the '" + arches
+ "' architectures";
101 check_config(const std::string
& variables
, const vars_map
& config
)
103 const std::vector
< std::string
> v
= tools::text::split(variables
, " ");
104 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
105 iter
!= v
.end(); iter
++) {
106 if (config
.find((*iter
)) == config
.end())
107 return "Required configuration variable '" + (*iter
) + "' not "
115 check_files(const std::string
& progs
)
117 const std::vector
< std::string
> v
= tools::text::split(progs
, " ");
118 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
119 iter
!= v
.end(); iter
++) {
120 const tools::fs::path
file(*iter
);
121 if (!file
.is_absolute())
122 throw std::runtime_error("Relative paths are not allowed when "
123 "checking for a required file (" + file
.str() + ")");
124 if (!tools::fs::exists(file
))
125 return "Required file '" + file
.str() + "' not found";
132 check_machine(const std::string
& machines
)
134 const std::vector
< std::string
> v
= tools::text::split(machines
, " ");
136 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
137 iter
!= v
.end(); iter
++) {
138 if ((*iter
) == tools::config::get("atf_machine"))
143 return "Requires the '" + machines
+ "' machine type";
145 return "Requires one of the '" + machines
+ "' machine types";
150 check_memory(const std::string
& raw_memory
)
153 const char* e
= std::strerror(errno
);
154 return "Failed to get sysctl(hw.usermem64) value: " + std::string(e
);
156 const int64_t needed
= tools::text::to_bytes(raw_memory
);
159 std::size_t available_length
= sizeof(available
);
160 if (::sysctlbyname("hw.usermem64", &available
, &available_length
,
162 const char* e
= std::strerror(errno
);
163 return "Failed to get sysctl(hw.usermem64) value: " + std::string(e
);
166 if (available
< needed
) {
167 return "Not enough memory; needed " + tools::text::to_string(needed
) +
168 ", available " + tools::text::to_string(available
);
171 #endif /* !defined(__minix) */
176 check_progs(const std::string
& progs
)
178 const std::vector
< std::string
> v
= tools::text::split(progs
, " ");
179 for (std::vector
< std::string
>::const_iterator iter
= v
.begin();
180 iter
!= v
.end(); iter
++) {
181 if (!has_program(tools::fs::path(*iter
)))
182 return "Required program '" + (*iter
) + "' not found in the PATH";
189 check_user(const std::string
& user
, const vars_map
& config
)
191 if (user
== "root") {
192 if (!tools::user::is_root())
193 return "Requires root privileges";
196 } else if (user
== "unprivileged") {
197 if (tools::user::is_root()) {
198 const vars_map::const_iterator iter
= config
.find(
199 "unprivileged-user");
200 if (iter
== config
.end())
201 return "Requires an unprivileged user and the "
202 "'unprivileged-user' configuration variable is not set";
204 const std::string
& unprivileged_user
= (*iter
).second
;
206 (void)tools::user::get_user_ids(unprivileged_user
);
208 } catch (const std::runtime_error
& e
) {
209 return "Failed to get information for user " +
216 throw std::runtime_error("Invalid value '" + user
+ "' for property "
220 } // anonymous namespace
223 impl::check_requirements(const vars_map
& metadata
,
224 const vars_map
& config
)
226 std::string failure_reason
= "";
228 for (vars_map::const_iterator iter
= metadata
.begin();
229 failure_reason
.empty() && iter
!= metadata
.end(); iter
++) {
230 const std::string
& name
= (*iter
).first
;
231 const std::string
& value
= (*iter
).second
;
232 assert(!value
.empty()); // Enforced by application/X-atf-tp parser.
234 if (name
== "require.arch")
235 failure_reason
= check_arch(value
);
236 else if (name
== "require.config")
237 failure_reason
= check_config(value
, config
);
238 else if (name
== "require.files")
239 failure_reason
= check_files(value
);
240 else if (name
== "require.machine")
241 failure_reason
= check_machine(value
);
242 else if (name
== "require.memory")
243 failure_reason
= check_memory(value
);
244 else if (name
== "require.progs")
245 failure_reason
= check_progs(value
);
246 else if (name
== "require.user")
247 failure_reason
= check_user(value
, config
);
249 // Unknown require.* properties are forbidden by the
250 // application/X-atf-tp parser.
251 assert(failure_reason
.find("require.") != 0);
255 return failure_reason
;
258 std::pair
< int, int >
259 impl::get_required_user(const vars_map
& metadata
,
260 const vars_map
& config
)
262 const vars_map::const_iterator user
= metadata
.find(
264 if (user
== metadata
.end())
265 return std::make_pair(-1, -1);
267 if ((*user
).second
== "unprivileged") {
268 if (tools::user::is_root()) {
269 const vars_map::const_iterator iter
= config
.find(
270 "unprivileged-user");
272 return tools::user::get_user_ids((*iter
).second
);
273 } catch (const std::exception
& e
) {
274 std::abort(); // This has been validated by check_user.
277 return std::make_pair(-1, -1);
280 return std::make_pair(-1, -1);