1240116Smarcel// 2240116Smarcel// Automated Testing Framework (atf) 3240116Smarcel// 4240116Smarcel// Copyright (c) 2007 The NetBSD Foundation, Inc. 5240116Smarcel// All rights reserved. 6240116Smarcel// 7240116Smarcel// Redistribution and use in source and binary forms, with or without 8240116Smarcel// modification, are permitted provided that the following conditions 9240116Smarcel// are met: 10240116Smarcel// 1. Redistributions of source code must retain the above copyright 11240116Smarcel// notice, this list of conditions and the following disclaimer. 12240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel// notice, this list of conditions and the following disclaimer in the 14240116Smarcel// documentation and/or other materials provided with the distribution. 15240116Smarcel// 16240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel// 29240116Smarcel 30240116Smarcel#if defined(HAVE_CONFIG_H) 31240116Smarcel#include "bconfig.h" 32240116Smarcel#endif 33240116Smarcel 34240116Smarcelextern "C" { 35240116Smarcel#include <sys/param.h> 36240116Smarcel#include <sys/types.h> 37240116Smarcel#include <sys/mount.h> 38240116Smarcel#include <sys/stat.h> 39240116Smarcel#include <sys/wait.h> 40240116Smarcel#include <dirent.h> 41240116Smarcel#include <libgen.h> 42240116Smarcel#include <unistd.h> 43240116Smarcel} 44240116Smarcel 45240116Smarcel#include <cerrno> 46240116Smarcel#include <cstdlib> 47240116Smarcel#include <cstring> 48240116Smarcel 49240116Smarcelextern "C" { 50240116Smarcel#include "../../atf-c/error.h" 51240116Smarcel} 52240116Smarcel 53240116Smarcel#include "../utils.hpp" 54240116Smarcel 55240116Smarcel#include "exceptions.hpp" 56240116Smarcel#include "env.hpp" 57240116Smarcel#include "fs.hpp" 58240116Smarcel#include "process.hpp" 59240116Smarcel#include "sanity.hpp" 60240116Smarcel#include "text.hpp" 61240116Smarcel 62240116Smarcelnamespace impl = atf::fs; 63240116Smarcel#define IMPL_NAME "atf::fs" 64240116Smarcel 65240116Smarcel// ------------------------------------------------------------------------ 66240116Smarcel// Auxiliary functions. 67240116Smarcel// ------------------------------------------------------------------------ 68240116Smarcel 69240116Smarcelstatic bool safe_access(const impl::path&, int, int); 70240116Smarcel 71240116Smarcel//! 72240116Smarcel//! \brief A controlled version of access(2). 73240116Smarcel//! 74240116Smarcel//! This function reimplements the standard access(2) system call to 75240116Smarcel//! safely control its exit status and raise an exception in case of 76240116Smarcel//! failure. 77240116Smarcel//! 78240116Smarcelstatic 79240116Smarcelbool 80240116Smarcelsafe_access(const impl::path& p, int mode, int experr) 81240116Smarcel{ 82240116Smarcel bool ok; 83240116Smarcel 84240116Smarcel atf_error_t err = atf_fs_eaccess(p.c_path(), mode); 85240116Smarcel if (atf_is_error(err)) { 86240116Smarcel if (atf_error_is(err, "libc")) { 87240116Smarcel if (atf_libc_error_code(err) == experr) { 88240116Smarcel atf_error_free(err); 89240116Smarcel ok = false; 90240116Smarcel } else { 91240116Smarcel atf::throw_atf_error(err); 92240116Smarcel // XXX Silence warning; maybe throw_atf_error should be 93240116Smarcel // an exception and not a function. 94240116Smarcel ok = false; 95240116Smarcel } 96240116Smarcel } else { 97240116Smarcel atf::throw_atf_error(err); 98240116Smarcel // XXX Silence warning; maybe throw_atf_error should be 99240116Smarcel // an exception and not a function. 100240116Smarcel ok = false; 101240116Smarcel } 102240116Smarcel } else 103240116Smarcel ok = true; 104240116Smarcel 105240116Smarcel return ok; 106240116Smarcel} 107240116Smarcel 108240116Smarcel// ------------------------------------------------------------------------ 109240116Smarcel// The "path" class. 110240116Smarcel// ------------------------------------------------------------------------ 111240116Smarcel 112240116Smarcelimpl::path::path(const std::string& s) 113240116Smarcel{ 114240116Smarcel atf_error_t err = atf_fs_path_init_fmt(&m_path, "%s", s.c_str()); 115240116Smarcel if (atf_is_error(err)) 116240116Smarcel throw_atf_error(err); 117240116Smarcel} 118240116Smarcel 119240116Smarcelimpl::path::path(const path& p) 120240116Smarcel{ 121240116Smarcel atf_error_t err = atf_fs_path_copy(&m_path, &p.m_path); 122240116Smarcel if (atf_is_error(err)) 123240116Smarcel throw_atf_error(err); 124240116Smarcel} 125240116Smarcel 126240116Smarcelimpl::path::path(const atf_fs_path_t *p) 127240116Smarcel{ 128240116Smarcel atf_error_t err = atf_fs_path_copy(&m_path, p); 129240116Smarcel if (atf_is_error(err)) 130240116Smarcel throw_atf_error(err); 131240116Smarcel} 132240116Smarcel 133240116Smarcelimpl::path::~path(void) 134240116Smarcel{ 135240116Smarcel atf_fs_path_fini(&m_path); 136240116Smarcel} 137240116Smarcel 138240116Smarcelconst char* 139240116Smarcelimpl::path::c_str(void) 140240116Smarcel const 141240116Smarcel{ 142240116Smarcel return atf_fs_path_cstring(&m_path); 143240116Smarcel} 144240116Smarcel 145240116Smarcelconst atf_fs_path_t* 146240116Smarcelimpl::path::c_path(void) 147240116Smarcel const 148240116Smarcel{ 149240116Smarcel return &m_path; 150240116Smarcel} 151240116Smarcel 152240116Smarcelstd::string 153240116Smarcelimpl::path::str(void) 154240116Smarcel const 155240116Smarcel{ 156240116Smarcel return c_str(); 157240116Smarcel} 158240116Smarcel 159240116Smarcelbool 160240116Smarcelimpl::path::is_absolute(void) 161240116Smarcel const 162240116Smarcel{ 163240116Smarcel return atf_fs_path_is_absolute(&m_path); 164240116Smarcel} 165240116Smarcel 166240116Smarcelbool 167240116Smarcelimpl::path::is_root(void) 168240116Smarcel const 169240116Smarcel{ 170240116Smarcel return atf_fs_path_is_root(&m_path); 171240116Smarcel} 172240116Smarcel 173240116Smarcelimpl::path 174240116Smarcelimpl::path::branch_path(void) 175240116Smarcel const 176240116Smarcel{ 177240116Smarcel atf_fs_path_t bp; 178240116Smarcel atf_error_t err; 179240116Smarcel 180240116Smarcel err = atf_fs_path_branch_path(&m_path, &bp); 181240116Smarcel if (atf_is_error(err)) 182240116Smarcel throw_atf_error(err); 183240116Smarcel 184240116Smarcel path p(atf_fs_path_cstring(&bp)); 185240116Smarcel atf_fs_path_fini(&bp); 186240116Smarcel return p; 187240116Smarcel} 188240116Smarcel 189240116Smarcelstd::string 190240116Smarcelimpl::path::leaf_name(void) 191240116Smarcel const 192240116Smarcel{ 193240116Smarcel atf_dynstr_t ln; 194240116Smarcel atf_error_t err; 195240116Smarcel 196240116Smarcel err = atf_fs_path_leaf_name(&m_path, &ln); 197240116Smarcel if (atf_is_error(err)) 198240116Smarcel throw_atf_error(err); 199240116Smarcel 200240116Smarcel std::string s(atf_dynstr_cstring(&ln)); 201240116Smarcel atf_dynstr_fini(&ln); 202240116Smarcel return s; 203240116Smarcel} 204240116Smarcel 205240116Smarcelimpl::path 206240116Smarcelimpl::path::to_absolute(void) 207240116Smarcel const 208240116Smarcel{ 209240116Smarcel atf_fs_path_t pa; 210240116Smarcel 211240116Smarcel atf_error_t err = atf_fs_path_to_absolute(&m_path, &pa); 212240116Smarcel if (atf_is_error(err)) 213240116Smarcel throw_atf_error(err); 214240116Smarcel 215240116Smarcel path p(atf_fs_path_cstring(&pa)); 216240116Smarcel atf_fs_path_fini(&pa); 217240116Smarcel return p; 218240116Smarcel} 219240116Smarcel 220240116Smarcelimpl::path& 221240116Smarcelimpl::path::operator=(const path& p) 222240116Smarcel{ 223240116Smarcel atf_fs_path_t tmp; 224240116Smarcel 225240116Smarcel atf_error_t err = atf_fs_path_init_fmt(&tmp, "%s", p.c_str()); 226240116Smarcel if (atf_is_error(err)) 227240116Smarcel throw_atf_error(err); 228240116Smarcel else { 229240116Smarcel atf_fs_path_fini(&m_path); 230240116Smarcel m_path = tmp; 231240116Smarcel } 232240116Smarcel 233240116Smarcel return *this; 234240116Smarcel} 235240116Smarcel 236240116Smarcelbool 237240116Smarcelimpl::path::operator==(const path& p) 238240116Smarcel const 239240116Smarcel{ 240240116Smarcel return atf_equal_fs_path_fs_path(&m_path, &p.m_path); 241240116Smarcel} 242240116Smarcel 243240116Smarcelbool 244240116Smarcelimpl::path::operator!=(const path& p) 245240116Smarcel const 246240116Smarcel{ 247240116Smarcel return !atf_equal_fs_path_fs_path(&m_path, &p.m_path); 248240116Smarcel} 249240116Smarcel 250240116Smarcelimpl::path 251240116Smarcelimpl::path::operator/(const std::string& p) 252240116Smarcel const 253240116Smarcel{ 254240116Smarcel path p2 = *this; 255240116Smarcel 256240116Smarcel atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", p.c_str()); 257240116Smarcel if (atf_is_error(err)) 258240116Smarcel throw_atf_error(err); 259240116Smarcel 260240116Smarcel return p2; 261240116Smarcel} 262240116Smarcel 263240116Smarcelimpl::path 264240116Smarcelimpl::path::operator/(const path& p) 265240116Smarcel const 266240116Smarcel{ 267240116Smarcel path p2 = *this; 268240116Smarcel 269240116Smarcel atf_error_t err = atf_fs_path_append_fmt(&p2.m_path, "%s", 270240116Smarcel atf_fs_path_cstring(&p.m_path)); 271240116Smarcel if (atf_is_error(err)) 272240116Smarcel throw_atf_error(err); 273240116Smarcel 274240116Smarcel return p2; 275240116Smarcel} 276240116Smarcel 277240116Smarcelbool 278240116Smarcelimpl::path::operator<(const path& p) 279240116Smarcel const 280240116Smarcel{ 281240116Smarcel const char *s1 = atf_fs_path_cstring(&m_path); 282240116Smarcel const char *s2 = atf_fs_path_cstring(&p.m_path); 283240116Smarcel return std::strcmp(s1, s2) < 0; 284240116Smarcel} 285240116Smarcel 286240116Smarcel// ------------------------------------------------------------------------ 287240116Smarcel// The "file_info" class. 288240116Smarcel// ------------------------------------------------------------------------ 289240116Smarcel 290240116Smarcelconst int impl::file_info::blk_type = atf_fs_stat_blk_type; 291240116Smarcelconst int impl::file_info::chr_type = atf_fs_stat_chr_type; 292240116Smarcelconst int impl::file_info::dir_type = atf_fs_stat_dir_type; 293240116Smarcelconst int impl::file_info::fifo_type = atf_fs_stat_fifo_type; 294240116Smarcelconst int impl::file_info::lnk_type = atf_fs_stat_lnk_type; 295240116Smarcelconst int impl::file_info::reg_type = atf_fs_stat_reg_type; 296240116Smarcelconst int impl::file_info::sock_type = atf_fs_stat_sock_type; 297240116Smarcelconst int impl::file_info::wht_type = atf_fs_stat_wht_type; 298240116Smarcel 299240116Smarcelimpl::file_info::file_info(const path& p) 300240116Smarcel{ 301240116Smarcel atf_error_t err; 302240116Smarcel 303240116Smarcel err = atf_fs_stat_init(&m_stat, p.c_path()); 304240116Smarcel if (atf_is_error(err)) 305240116Smarcel throw_atf_error(err); 306240116Smarcel} 307240116Smarcel 308240116Smarcelimpl::file_info::file_info(const file_info& fi) 309240116Smarcel{ 310240116Smarcel atf_fs_stat_copy(&m_stat, &fi.m_stat); 311240116Smarcel} 312240116Smarcel 313240116Smarcelimpl::file_info::~file_info(void) 314240116Smarcel{ 315240116Smarcel atf_fs_stat_fini(&m_stat); 316240116Smarcel} 317240116Smarcel 318240116Smarceldev_t 319240116Smarcelimpl::file_info::get_device(void) 320240116Smarcel const 321240116Smarcel{ 322240116Smarcel return atf_fs_stat_get_device(&m_stat); 323240116Smarcel} 324240116Smarcel 325240116Smarcelino_t 326240116Smarcelimpl::file_info::get_inode(void) 327240116Smarcel const 328240116Smarcel{ 329240116Smarcel return atf_fs_stat_get_inode(&m_stat); 330240116Smarcel} 331240116Smarcel 332240116Smarcelmode_t 333240116Smarcelimpl::file_info::get_mode(void) 334240116Smarcel const 335240116Smarcel{ 336240116Smarcel return atf_fs_stat_get_mode(&m_stat); 337240116Smarcel} 338240116Smarcel 339240116Smarceloff_t 340240116Smarcelimpl::file_info::get_size(void) 341240116Smarcel const 342240116Smarcel{ 343240116Smarcel return atf_fs_stat_get_size(&m_stat); 344240116Smarcel} 345240116Smarcel 346240116Smarcelint 347240116Smarcelimpl::file_info::get_type(void) 348240116Smarcel const 349240116Smarcel{ 350240116Smarcel return atf_fs_stat_get_type(&m_stat); 351240116Smarcel} 352240116Smarcel 353240116Smarcelbool 354240116Smarcelimpl::file_info::is_owner_readable(void) 355240116Smarcel const 356240116Smarcel{ 357240116Smarcel return atf_fs_stat_is_owner_readable(&m_stat); 358240116Smarcel} 359240116Smarcel 360240116Smarcelbool 361240116Smarcelimpl::file_info::is_owner_writable(void) 362240116Smarcel const 363240116Smarcel{ 364240116Smarcel return atf_fs_stat_is_owner_writable(&m_stat); 365240116Smarcel} 366240116Smarcel 367240116Smarcelbool 368240116Smarcelimpl::file_info::is_owner_executable(void) 369240116Smarcel const 370240116Smarcel{ 371240116Smarcel return atf_fs_stat_is_owner_executable(&m_stat); 372240116Smarcel} 373240116Smarcel 374240116Smarcelbool 375240116Smarcelimpl::file_info::is_group_readable(void) 376240116Smarcel const 377240116Smarcel{ 378240116Smarcel return atf_fs_stat_is_group_readable(&m_stat); 379240116Smarcel} 380240116Smarcel 381240116Smarcelbool 382240116Smarcelimpl::file_info::is_group_writable(void) 383240116Smarcel const 384240116Smarcel{ 385240116Smarcel return atf_fs_stat_is_group_writable(&m_stat); 386240116Smarcel} 387240116Smarcel 388240116Smarcelbool 389240116Smarcelimpl::file_info::is_group_executable(void) 390240116Smarcel const 391240116Smarcel{ 392240116Smarcel return atf_fs_stat_is_group_executable(&m_stat); 393240116Smarcel} 394240116Smarcel 395240116Smarcelbool 396240116Smarcelimpl::file_info::is_other_readable(void) 397240116Smarcel const 398240116Smarcel{ 399240116Smarcel return atf_fs_stat_is_other_readable(&m_stat); 400240116Smarcel} 401240116Smarcel 402240116Smarcelbool 403240116Smarcelimpl::file_info::is_other_writable(void) 404240116Smarcel const 405240116Smarcel{ 406240116Smarcel return atf_fs_stat_is_other_writable(&m_stat); 407240116Smarcel} 408240116Smarcel 409240116Smarcelbool 410240116Smarcelimpl::file_info::is_other_executable(void) 411240116Smarcel const 412240116Smarcel{ 413240116Smarcel return atf_fs_stat_is_other_executable(&m_stat); 414240116Smarcel} 415240116Smarcel 416240116Smarcel// ------------------------------------------------------------------------ 417240116Smarcel// The "directory" class. 418240116Smarcel// ------------------------------------------------------------------------ 419240116Smarcel 420240116Smarcelimpl::directory::directory(const path& p) 421240116Smarcel{ 422240116Smarcel DIR* dp = ::opendir(p.c_str()); 423240116Smarcel if (dp == NULL) 424240116Smarcel throw system_error(IMPL_NAME "::directory::directory(" + 425240116Smarcel p.str() + ")", "opendir(3) failed", errno); 426240116Smarcel 427240116Smarcel struct dirent* dep; 428240116Smarcel while ((dep = ::readdir(dp)) != NULL) { 429240116Smarcel path entryp = p / dep->d_name; 430240116Smarcel insert(value_type(dep->d_name, file_info(entryp))); 431240116Smarcel } 432240116Smarcel 433240116Smarcel if (::closedir(dp) == -1) 434240116Smarcel throw system_error(IMPL_NAME "::directory::directory(" + 435240116Smarcel p.str() + ")", "closedir(3) failed", errno); 436240116Smarcel} 437240116Smarcel 438240116Smarcelstd::set< std::string > 439240116Smarcelimpl::directory::names(void) 440240116Smarcel const 441240116Smarcel{ 442240116Smarcel std::set< std::string > ns; 443240116Smarcel 444240116Smarcel for (const_iterator iter = begin(); iter != end(); iter++) 445240116Smarcel ns.insert((*iter).first); 446240116Smarcel 447240116Smarcel return ns; 448240116Smarcel} 449240116Smarcel 450240116Smarcel// ------------------------------------------------------------------------ 451240116Smarcel// Free functions. 452240116Smarcel// ------------------------------------------------------------------------ 453240116Smarcel 454240116Smarcelbool 455240116Smarcelimpl::exists(const path& p) 456240116Smarcel{ 457240116Smarcel atf_error_t err; 458240116Smarcel bool b; 459240116Smarcel 460240116Smarcel err = atf_fs_exists(p.c_path(), &b); 461240116Smarcel if (atf_is_error(err)) 462240116Smarcel throw_atf_error(err); 463240116Smarcel 464240116Smarcel return b; 465240116Smarcel} 466240116Smarcel 467240116Smarcelbool 468240116Smarcelimpl::have_prog_in_path(const std::string& prog) 469240116Smarcel{ 470240116Smarcel PRE(prog.find('/') == std::string::npos); 471240116Smarcel 472240116Smarcel // Do not bother to provide a default value for PATH. If it is not 473240116Smarcel // there something is broken in the user's environment. 474240116Smarcel if (!atf::env::has("PATH")) 475240116Smarcel throw std::runtime_error("PATH not defined in the environment"); 476240116Smarcel std::vector< std::string > dirs = 477240116Smarcel atf::text::split(atf::env::get("PATH"), ":"); 478240116Smarcel 479240116Smarcel bool found = false; 480240116Smarcel for (std::vector< std::string >::const_iterator iter = dirs.begin(); 481240116Smarcel !found && iter != dirs.end(); iter++) { 482240116Smarcel const path& dir = path(*iter); 483240116Smarcel 484240116Smarcel if (is_executable(dir / prog)) 485240116Smarcel found = true; 486240116Smarcel } 487240116Smarcel return found; 488240116Smarcel} 489240116Smarcel 490240116Smarcelbool 491240116Smarcelimpl::is_executable(const path& p) 492240116Smarcel{ 493240116Smarcel if (!exists(p)) 494240116Smarcel return false; 495240116Smarcel return safe_access(p, atf_fs_access_x, EACCES); 496240116Smarcel} 497240116Smarcel 498240116Smarcelvoid 499240116Smarcelimpl::remove(const path& p) 500240116Smarcel{ 501240116Smarcel if (file_info(p).get_type() == file_info::dir_type) 502240116Smarcel throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")", 503240116Smarcel "Is a directory", 504240116Smarcel EPERM); 505240116Smarcel if (::unlink(p.c_str()) == -1) 506240116Smarcel throw atf::system_error(IMPL_NAME "::remove(" + p.str() + ")", 507240116Smarcel "unlink(" + p.str() + ") failed", 508240116Smarcel errno); 509240116Smarcel} 510240116Smarcel 511240116Smarcelvoid 512240116Smarcelimpl::rmdir(const path& p) 513240116Smarcel{ 514240116Smarcel atf_error_t err = atf_fs_rmdir(p.c_path()); 515240116Smarcel if (atf_is_error(err)) 516240116Smarcel throw_atf_error(err); 517240116Smarcel} 518