4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews/* Copyright (c) 2007 The NetBSD Foundation, Inc.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * All rights reserved.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Redistribution and use in source and binary forms, with or without
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * modification, are permitted provided that the following conditions
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * 1. Redistributions of source code must retain the above copyright
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * notice, this list of conditions and the following disclaimer.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * 2. Redistributions in binary form must reproduce the above copyright
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * notice, this list of conditions and the following disclaimer in the
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * documentation and/or other materials provided with the distribution.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Prototypes for auxiliary functions.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic bool check_umask(const mode_t, const mode_t);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic atf_error_t copy_contents(const atf_fs_path_t *, char **);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic atf_error_t normalize(atf_dynstr_t *, char *);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic void replace_contents(atf_fs_path_t *, const char *);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntstatic const char *stat_type_to_string(const int);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * The "invalid_umask" error type.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* One of atf_fs_stat_*_type. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* The original path causing the error. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * from the error constructor, we cannot delete the path later on.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Can't remember why atf_error_new does not take a hook for
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * deletion. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* The umask that caused the error. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunttypedef struct invalid_umask_error_data invalid_umask_error_data_t;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntinvalid_umask_format(const atf_error_t err, char *buf, size_t buflen)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt snprintf(buf, buflen, "Could not create the temporary %s %s because "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt "it will not have enough access rights due to the current "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntinvalid_umask_error(const atf_fs_path_t *path, const int type,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_error_new("invalid_umask", &data, sizeof(data),
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * The "unknown_file_type" error type.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunttypedef struct unknown_type_error_data unknown_type_error_data_t;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntunknown_type_format(const atf_error_t err, char *buf, size_t buflen)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_error_new("unknown_type", &data, sizeof(data),
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Auxiliary functions.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntcheck_umask(const mode_t exp_mode, const mode_t min_mode)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const mode_t actual_mode = (~current_umask() & exp_mode);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot create temporary directory "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot create temporary file "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (p[0] == '/')
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntnormalize_ap(atf_dynstr_t *d, const char *p, va_list ap)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntreplace_contents(atf_fs_path_t *p, const char *buf)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_dynstr_append_fmt(&p->m_data, "%s", buf);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * The "atf_fs_path" type.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return atf_dynstr_copy(&dest->m_data, &src->m_data);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt else if (endpos == 0)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#endif /* defined(HAVE_CONST_DIRNAME) */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt#endif /* defined(HAVE_CONST_BASENAME) */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Modifiers.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Operators.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntbool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * The "atf_fs_path" type.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Constants.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot get information of %s; "
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFBLK: st->m_type = atf_fs_stat_blk_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFCHR: st->m_type = atf_fs_stat_chr_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFDIR: st->m_type = atf_fs_stat_dir_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFIFO: st->m_type = atf_fs_stat_fifo_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFLNK: st->m_type = atf_fs_stat_lnk_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFREG: st->m_type = atf_fs_stat_reg_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt case S_IFWHT: st->m_type = atf_fs_stat_wht_type; break;
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
a747113422afaa29ce72d2c5ba7f0b7ea9ec2054Evan Huntatf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Huntatf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt/* ---------------------------------------------------------------------
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Free functions.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * --------------------------------------------------------------------- */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * An implementation of access(2) but using the effective user value
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * instead of the real one. Also avoids false positives for root when
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * asking for execute permissions, which appear in SunOS.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt mode & atf_fs_access_w || mode & atf_fs_access_x);
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot get information from file %s",
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* Early return if we are only checking for existence and the file
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * exists (stat call returned). */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* Allow root to read/write any file. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* Allow root to execute the file if any of its execution bits
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * are set. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (!ok && atf_user_is_member_of_group(st.st_gid)) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(EACCES, "Access check failed");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot determine current directory");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt /* Some operating systems (e.g. OpenSolaris 200906) return
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * EEXIST instead of ENOTEMPTY for non-empty directories.
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * Homogenize the return value so that callers don't need
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt * to bother about differences in operating systems. */
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot remove directory");
ef421f66f47224a42073deaf087378c5d0c9952eEvan Hunt err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);