/* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* ---------------------------------------------------------------------
* Prototypes for auxiliary functions.
* --------------------------------------------------------------------- */
static mode_t current_umask(void);
static atf_error_t do_mkdtemp(char *);
static void replace_contents(atf_fs_path_t *, const char *);
static const char *stat_type_to_string(const int);
/* ---------------------------------------------------------------------
* The "invalid_umask" error type.
* --------------------------------------------------------------------- */
struct invalid_umask_error_data {
/* One of atf_fs_stat_*_type. */
int m_type;
/* The original path causing the error. */
/* XXX: Ideally this would be an atf_fs_path_t, but if we create it
* from the error constructor, we cannot delete the path later on.
* Can't remember why atf_error_new does not take a hook for
* deletion. */
/* The umask that caused the error. */
};
static
void
{
"it will not have enough access rights due to the current "
}
static
const mode_t failing_mask)
{
return err;
}
/* ---------------------------------------------------------------------
* The "unknown_file_type" error type.
* --------------------------------------------------------------------- */
struct unknown_type_error_data {
const char *m_path;
int m_type;
};
static
void
{
}
static
{
return err;
}
/* ---------------------------------------------------------------------
* Auxiliary functions.
* --------------------------------------------------------------------- */
static
bool
{
}
static
{
char *str;
err = atf_no_memory_error();
else {
err = atf_no_error();
}
return err;
}
static
current_umask(void)
{
return current;
}
static
{
"with template '%s'", tmpl);
else
err = atf_no_error();
return err;
}
static
{
if (*fdout == -1)
"with template '%s'", tmpl);
else
err = atf_no_error();
return err;
}
static
{
const char *ptr;
char *last;
bool first;
PRE(atf_dynstr_length(d) == 0);
if (p[0] == '/')
else
err = atf_no_error();
first = true;
first = false;
}
}
return err;
}
static
{
char *str;
err = atf_dynstr_init(d);
if (atf_is_error(err))
goto out;
if (atf_is_error(err))
atf_dynstr_fini(d);
else {
}
out:
return err;
}
static
void
{
atf_dynstr_clear(&p->m_data);
}
static
const char *
{
const char *str;
if (type == atf_fs_stat_blk_type)
str = "block device";
else if (type == atf_fs_stat_chr_type)
str = "character device";
else if (type == atf_fs_stat_dir_type)
str = "directory";
else if (type == atf_fs_stat_fifo_type)
str = "named pipe";
else if (type == atf_fs_stat_lnk_type)
str = "symbolic link";
else if (type == atf_fs_stat_reg_type)
str = "regular file";
else if (type == atf_fs_stat_sock_type)
str = "socket";
else if (type == atf_fs_stat_wht_type)
str = "whiteout";
else {
}
return str;
}
/* ---------------------------------------------------------------------
* The "atf_fs_path" type.
* --------------------------------------------------------------------- */
/*
*/
{
return err;
}
{
return err;
}
{
}
void
{
atf_dynstr_fini(&p->m_data);
}
/*
* Getters.
*/
{
if (endpos == atf_dynstr_npos)
else if (endpos == 0)
else
#if defined(HAVE_CONST_DIRNAME)
#endif /* defined(HAVE_CONST_DIRNAME) */
return err;
}
const char *
{
return atf_dynstr_cstring(&p->m_data);
}
{
if (begpos == atf_dynstr_npos)
begpos = 0;
else
begpos++;
#if defined(HAVE_CONST_BASENAME)
#endif /* defined(HAVE_CONST_BASENAME) */
return err;
}
bool
{
}
bool
{
}
/*
* Modifiers.
*/
{
if (!atf_is_error(err)) {
}
return err;
}
{
return err;
}
{
}
{
PRE(!atf_fs_path_is_absolute(p));
if (atf_is_error(err))
goto out;
if (atf_is_error(err))
out:
return err;
}
/*
* Operators.
*/
const atf_fs_path_t *p2)
{
}
/* ---------------------------------------------------------------------
* The "atf_fs_path" type.
* --------------------------------------------------------------------- */
/*
* Constants.
*/
/*
*/
{
"lstat(2) failed", pstr);
} else {
err = atf_no_error();
switch (type) {
#if defined(S_IFWHT)
#endif
default:
}
}
return err;
}
void
{
}
void
{
}
/*
* Getters.
*/
{
}
{
}
{
}
{
}
int
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
bool
{
}
/* ---------------------------------------------------------------------
* Free functions.
* --------------------------------------------------------------------- */
/*
* An implementation of access(2) but using the effective user value
* instead of the real one. Also avoids false positives for root when
* asking for execute permissions, which appear in SunOS.
*/
{
bool ok;
atf_fs_path_cstring(p));
goto out;
}
err = atf_no_error();
/* Early return if we are only checking for existence and the file
* exists (stat call returned). */
if (mode & atf_fs_access_f)
goto out;
ok = false;
if (atf_user_is_root()) {
ok = true;
}
/* Allow root to execute the file if any of its execution bits
* are set. */
ok = true;
}
} else {
}
}
}
}
if (!ok)
out:
return err;
}
{
if (atf_is_error(err)) {
err = atf_no_error();
*b = false;
}
} else
*b = true;
return err;
}
{
char *cwd;
#if defined(HAVE_GETCWD_DYN)
#else
#endif
goto out;
}
out:
return err;
}
{
char *buf;
goto out;
}
if (atf_is_error(err))
goto out;
if (atf_is_error(err))
goto out_buf;
replace_contents(p, buf);
out:
return err;
}
{
char *buf;
int fd;
goto out;
}
if (atf_is_error(err))
goto out;
if (atf_is_error(err))
goto out_buf;
replace_contents(p, buf);
out:
return err;
}
{
if (rmdir(atf_fs_path_cstring(p))) {
/* Some operating systems (e.g. OpenSolaris 200906) return
* EEXIST instead of ENOTEMPTY for non-empty directories.
* Homogenize the return value so that callers don't need
* to bother about differences in operating systems. */
}
} else
err = atf_no_error();
return err;
}
{
const char *path;
path = atf_fs_path_cstring(p);
else
err = atf_no_error();
return err;
}