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