1 // 2 // Automated Testing Framework (atf) 3 // 4 // Copyright (c) 2007 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 30 #if defined(HAVE_CONFIG_H) 31 #include "bconfig.h" 32 #endif 33 34 extern "C" { 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/mount.h> 38 #include <sys/stat.h> 39 #include <sys/wait.h> 40 #include <dirent.h> 41 #include <libgen.h> 42 #include <unistd.h> 43 } 44 45 #include <cerrno> 46 #include <cstdlib> 47 #include <cstring> 48 49 extern "C" { 50 #include "../../atf-c/error.h" 51 } 52 53 #include "../utils.hpp" 54 55 #include "exceptions.hpp" 56 #include "env.hpp" 57 #include "fs.hpp" 58 #include "process.hpp" 59 #include "sanity.hpp" 60 #include "text.hpp" 61 62 namespace impl = atf::fs; 63 #define IMPL_NAME "atf::fs" 64 65 // ------------------------------------------------------------------------ 66 // Auxiliary functions. 67 // ------------------------------------------------------------------------ 68 69 static bool safe_access(const impl::path&, int, int); 70 71 //! 72 //! \brief A controlled version of access(2). 73 //! 74 //! This function reimplements the standard access(2) system call to 75 //! safely control its exit status and raise an exception in case of 76 //! failure. 77 //! 78 static 79 bool 80 safe_access(const impl::path& p, int mode, int experr) 81 { 82 bool ok; 83 84 atf_error_t err = atf_fs_eaccess(p.c_path(), mode); 85 if (atf_is_error(err)) { 86 if (atf_error_is(err, "libc")) { 87 if (atf_libc_error_code(err) == experr) { 88 atf_error_free(err); 89 ok = false; 90 } else { 91 atf::throw_atf_error(err); 92 // XXX Silence warning; maybe throw_atf_error should be 93 // an exception and not a function. 94 ok = false; 95 } 96 } else { 97 atf::throw_atf_error(err); 98 // XXX Silence warning; maybe throw_atf_error should be 99 // an exception and not a function. 100 ok = false; 101 } 102 } else 103 ok = true; 104 105 return ok; 106 } 107 108 // ------------------------------------------------------------------------ 109 // The "path" class. 110 // ------------------------------------------------------------------------ 111 112 impl::path::path(const std::string& s) 113 { 114 atf_error_t err = atf_fs_path_init_fmt(&m_path, "%s", s.c_str()); 115 if (atf_is_error(err)) 116 throw_atf_error(err); 117 } 118 119 impl::path::path(const path& p) 120 { 121 atf_error_t err = atf_fs_path_copy(&m_path, &p.m_path); 122 if (atf_is_error(err)) 123 throw_atf_error(err); 124 } 125 126 impl::path::path(const atf_fs_path_t *p) 127 { 128 atf_error_t err = atf_fs_path_copy(&m_path, p); 129 if (atf_is_error(err)) 130 throw_atf_error(err); 131 } 132 133 impl::path::~path(void) 134 { 135 atf_fs_path_fini(&m_path); 136 } 137 138 const char* 139 impl::path::c_str(void) 140 const 141 { 142 return atf_fs_path_cstring(&m_path); 143 } 144 145 const atf_fs_path_t* 146 impl::path::c_path(void) 147 const 148 { 149 return &m_path; 150 } 151 152 std::string 153 impl::path::str(void) 154 const 155 { 156 return c_str(); 157 } 158 159 bool 160 impl::path::is_absolute(void) 161 const 162 { 163 return atf_fs_path_is_absolute(&m_path); 164 } 165 166 bool 167 impl::path::is_root(void) 168 const 169 { 170 return atf_fs_path_is_root(&m_path); 171 } 172 173 impl::path 174 impl::path::branch_path(void) 175 const 176 { 177 atf_fs_path_t bp; 178 atf_error_t err; 179 180 err = atf_fs_path_branch_path(&m_path, &bp); 181 if (atf_is_error(err)) 182 throw_atf_error(err); 183 184 path p(atf_fs_path_cstring(&bp)); 185 atf_fs_path_fini(&bp); 186 return p; 187 } 188 189 std::string 190 impl::path::leaf_name(void) 191 const 192 { 193 atf_dynstr_t ln; 194 atf_error_t err; 195 196 err = atf_fs_path_leaf_name(&m_path, &ln); 197 if (atf_is_error(err)) 198 throw_atf_error(err); 199 200 std::string s(atf_dynstr_cstring(&ln)); 201 atf_dynstr_fini(&ln); 202 return s; 203 } 204 205 impl::path 206 impl::path::to_absolute(void) 207 const 208 { 209 atf_fs_path_t pa; 210 211 atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa); 212 if (atf_is_error(err)) 213 throw_atf_error(err); 214 215 path p(atf_fs_path_cstring(&pa)); 216 atf_fs_path_fini(&pa); 217 return p; 218 } 219 220 impl::path& 221 impl::path::operator=(const path& p) 222 { 223 atf_fs_path_t tmp; 224 225 atf_error_t err = atf_fs_path_init_fmt(&tmp, "%s", p.c_str()); 226 if (atf_is_error(err)) 227 throw_atf_error(err); 228 else { 229 atf_fs_path_fini(&m_path); 230 m_path = tmp; 231 } 232 233 return *this; 234 } 235 236 bool 237 impl::path::operator==(const path& p) 238 const 239 { 240 return atf_equal_fs_path_fs_path(&m_path, &p.m_path); 241 } 242 243 bool 244 impl::path::operator!=(const path& p) 245 const 246 { 247 return !atf_equal_fs_path_fs_path(&m_path, &p.m_path); 248 } 249 250 impl::path 251 impl::path::operator/(const std::string& p) 252 const 253 { 254 path p2 = *this; 255 256 atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", p.c_str()); 257 if (atf_is_error(err)) 258 throw_atf_error(err); 259 260 return p2; 261 } 262 263 impl::path 264 impl::path::operator/(const path& p) 265 const 266 { 267 path p2 = *this; 268 269 atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", 270 atf_fs_path_cstring(&p.m_path)); 271 if (atf_is_error(err)) 272 throw_atf_error(err); 273 274 return p2; 275 } 276 277 bool 278 impl::path::operator<(const path& p) 279 const 280 { 281 const char *s1 = atf_fs_path_cstring(&m_path); 282 const char *s2 = atf_fs_path_cstring(&p.m_path); 283 return std::strcmp(s1, s2) < 0; 284 } 285 286 // ------------------------------------------------------------------------ 287 // The "file_info" class. 288 // ------------------------------------------------------------------------ 289 290 const int impl::file_info::blk_type = atf_fs_stat_blk_type; 291 const int impl::file_info::chr_type = atf_fs_stat_chr_type; 292 const int impl::file_info::dir_type = atf_fs_stat_dir_type; 293 const int impl::file_info::fifo_type = atf_fs_stat_fifo_type; 294 const int impl::file_info::lnk_type = atf_fs_stat_lnk_type; 295 const int impl::file_info::reg_type = atf_fs_stat_reg_type; 296 const int impl::file_info::sock_type = atf_fs_stat_sock_type; 297 const int impl::file_info::wht_type = atf_fs_stat_wht_type; 298 299 impl::file_info::file_info(const path& p) 300 { 301 atf_error_t err; 302 303 err = atf_fs_stat_init(&m_stat, p.c_path()); 304 if (atf_is_error(err)) 305 throw_atf_error(err); 306 } 307 308 impl::file_info::file_info(const file_info& fi) 309 { 310 atf_fs_stat_copy(&m_stat, &fi.m_stat); 311 } 312 313 impl::file_info::~file_info(void) 314 { 315 atf_fs_stat_fini(&m_stat); 316 } 317 318 dev_t 319 impl::file_info::get_device(void) 320 const 321 { 322 return atf_fs_stat_get_device(&m_stat); 323 } 324 325 ino_t 326 impl::file_info::get_inode(void) 327 const 328 { 329 return atf_fs_stat_get_inode(&m_stat); 330 } 331 332 mode_t 333 impl::file_info::get_mode(void) 334 const 335 { 336 return atf_fs_stat_get_mode(&m_stat); 337 } 338 339 off_t 340 impl::file_info::get_size(void) 341 const 342 { 343 return atf_fs_stat_get_size(&m_stat); 344 } 345 346 int 347 impl::file_info::get_type(void) 348 const 349 { 350 return atf_fs_stat_get_type(&m_stat); 351 } 352 353 bool 354 impl::file_info::is_owner_readable(void) 355 const 356 { 357 return atf_fs_stat_is_owner_readable(&m_stat); 358 } 359 360 bool 361 impl::file_info::is_owner_writable(void) 362 const 363 { 364 return atf_fs_stat_is_owner_writable(&m_stat); 365 } 366 367 bool 368 impl::file_info::is_owner_executable(void) 369 const 370 { 371 return atf_fs_stat_is_owner_executable(&m_stat); 372 } 373 374 bool 375 impl::file_info::is_group_readable(void) 376 const 377 { 378 return atf_fs_stat_is_group_readable(&m_stat); 379 } 380 381 bool 382 impl::file_info::is_group_writable(void) 383 const 384 { 385 return atf_fs_stat_is_group_writable(&m_stat); 386 } 387 388 bool 389 impl::file_info::is_group_executable(void) 390 const 391 { 392 return atf_fs_stat_is_group_executable(&m_stat); 393 } 394 395 bool 396 impl::file_info::is_other_readable(void) 397 const 398 { 399 return atf_fs_stat_is_other_readable(&m_stat); 400 } 401 402 bool 403 impl::file_info::is_other_writable(void) 404 const 405 { 406 return atf_fs_stat_is_other_writable(&m_stat); 407 } 408 409 bool 410 impl::file_info::is_other_executable(void) 411 const 412 { 413 return atf_fs_stat_is_other_executable(&m_stat); 414 } 415 416 // ------------------------------------------------------------------------ 417 // The "directory" class. 418 // ------------------------------------------------------------------------ 419 420 impl::directory::directory(const path& p) 421 { 422 DIR* dp = ::opendir(p.c_str()); 423 if (dp == NULL) 424 throw system_error(IMPL_NAME "::directory::directory(" + 425 p.str() + ")", "opendir(3) failed", errno); 426 427 struct dirent* dep; 428 while ((dep = ::readdir(dp)) != NULL) { 429 path entryp = p / dep->d_name; 430 insert(value_type(dep->d_name, file_info(entryp))); 431 } 432 433 if (::closedir(dp) == -1) 434 throw system_error(IMPL_NAME "::directory::directory(" + 435 p.str() + ")", "closedir(3) failed", errno); 436 } 437 438 std::set< std::string > 439 impl::directory::names(void) 440 const 441 { 442 std::set< std::string > ns; 443 444 for (const_iterator iter = begin(); iter != end(); iter++) 445 ns.insert((*iter).first); 446 447 return ns; 448 } 449 450 // ------------------------------------------------------------------------ 451 // Free functions. 452 // ------------------------------------------------------------------------ 453 454 bool 455 impl::exists(const path& p) 456 { 457 atf_error_t err; 458 bool b; 459 460 err = atf_fs_exists(p.c_path(), &b); 461 if (atf_is_error(err)) 462 throw_atf_error(err); 463 464 return b; 465 } 466 467 bool 468 impl::have_prog_in_path(const std::string& prog) 469 { 470 PRE(prog.find('/') == std::string::npos); 471 472 // Do not bother to provide a default value for PATH. If it is not 473 // there something is broken in the user's environment. 474 if (!atf::env::has("PATH")) 475 throw std::runtime_error("PATH not defined in the environment"); 476 std::vector< std::string > dirs = 477 atf::text::split(atf::env::get("PATH"), ":"); 478 479 bool found = false; 480 for (std::vector< std::string >::const_iterator iter = dirs.begin(); 481 !found && iter != dirs.end(); iter++) { 482 const path& dir = path(*iter); 483 484 if (is_executable(dir / prog)) 485 found = true; 486 } 487 return found; 488 } 489 490 bool 491 impl::is_executable(const path& p) 492 { 493 if (!exists(p)) 494 return false; 495 return safe_access(p, atf_fs_access_x, EACCES); 496 } 497 498 void 499 impl::remove(const path& p) 500 { 501 if (file_info(p).get_type() == file_info::dir_type) 502 throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")", 503 "Is a directory", 504 EPERM); 505 if (::unlink(p.c_str()) == -1) 506 throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")", 507 "unlink(" + p.str() + ") failed", 508 errno); 509 } 510 511 void 512 impl::rmdir(const path& p) 513 { 514 atf_error_t err = atf_fs_rmdir(p.c_path()); 515 if (atf_is_error(err)) 516 throw_atf_error(err); 517 } 518