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