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