atf_error_t atf_env_set(const char *name, const char *val) { atf_error_t err; #if defined(HAVE_SETENV) if (setenv(name, val, 1) == -1) err = atf_libc_error(errno, "Cannot set environment variable " "'%s' to '%s'", name, val); else err = atf_no_error(); #elif defined(HAVE_PUTENV) char *buf; err = atf_text_format(&buf, "%s=%s", name, val); if (!atf_is_error(err)) { if (putenv(buf) == -1) err = atf_libc_error(errno, "Cannot set environment variable " "'%s' to '%s'", name, val); free(buf); } #else # error "Don't know how to set an environment variable." #endif return err; }
/* * 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. */ atf_error_t atf_fs_eaccess(const atf_fs_path_t *p, int mode) { atf_error_t err; struct stat st; bool ok; PRE(mode & atf_fs_access_f || mode & atf_fs_access_r || mode & atf_fs_access_w || mode & atf_fs_access_x); if (lstat(atf_fs_path_cstring(p), &st) == -1) { err = atf_libc_error(errno, "Cannot get information from file %s", 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()) { if (!ok && !(mode & atf_fs_access_x)) { /* Allow root to read/write any file. */ ok = true; } if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { /* Allow root to execute the file if any of its execution bits * are set. */ ok = true; } } else { if (!ok && (atf_user_euid() == st.st_uid)) { ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) || ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) || ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR)); } if (!ok && atf_user_is_member_of_group(st.st_gid)) { ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) || ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) || ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP)); } if (!ok && ((atf_user_euid() != st.st_uid) && !atf_user_is_member_of_group(st.st_gid))) { ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) || ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) || ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH)); } } if (!ok) err = atf_libc_error(EACCES, "Access check failed"); out: return err; }
atf_error_t atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p) { atf_error_t err; const char *pstr = atf_fs_path_cstring(p); if (lstat(pstr, &st->m_sb) == -1) { err = atf_libc_error(errno, "Cannot get information of %s; " "lstat(2) failed", pstr); } else { int type = st->m_sb.st_mode & S_IFMT; err = atf_no_error(); switch (type) { case S_IFBLK: st->m_type = atf_fs_stat_blk_type; break; case S_IFCHR: st->m_type = atf_fs_stat_chr_type; break; case S_IFDIR: st->m_type = atf_fs_stat_dir_type; break; case S_IFIFO: st->m_type = atf_fs_stat_fifo_type; break; case S_IFLNK: st->m_type = atf_fs_stat_lnk_type; break; case S_IFREG: st->m_type = atf_fs_stat_reg_type; break; case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break; #if defined(S_IFWHT) case S_IFWHT: st->m_type = atf_fs_stat_wht_type; break; #endif default: err = unknown_type_error(pstr, type); } } return err; }
ATF_TC_BODY(libc_new, tc) { atf_error_t err; err = atf_libc_error(ENOMEM, "Test message 1"); ATF_REQUIRE(atf_error_is(err, "libc")); ATF_REQUIRE_EQ(atf_libc_error_code(err), ENOMEM); ATF_REQUIRE(strcmp(atf_libc_error_msg(err), "Test message 1") == 0); atf_error_free(err); err = atf_libc_error(EPERM, "%s message %d", "Test", 2); ATF_REQUIRE(atf_error_is(err, "libc")); ATF_REQUIRE_EQ(atf_libc_error_code(err), EPERM); ATF_REQUIRE(strcmp(atf_libc_error_msg(err), "Test message 2") == 0); atf_error_free(err); }
atf_error_t atf_text_to_long(const char *str, long *l) { atf_error_t err; char *endptr; long tmp; errno = 0; tmp = strtol(str, &endptr, 10); if (str[0] == '\0' || *endptr != '\0') err = atf_libc_error(EINVAL, "'%s' is not a number", str); else if (errno == ERANGE || (tmp == LONG_MAX || tmp == LONG_MIN)) err = atf_libc_error(ERANGE, "'%s' is out of range", str); else { *l = tmp; err = atf_no_error(); } return err; }
static atf_error_t child_connect(const stream_prepare_t *sp, int procfd) { atf_error_t err; const int type = atf_process_stream_type(sp->m_sb); if (type == atf_process_stream_type_capture) { close(sp->m_pipefds[0]); err = safe_dup(sp->m_pipefds[1], procfd); } else if (type == atf_process_stream_type_connect) { if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1) err = atf_libc_error(errno, "Cannot connect descriptor %d to %d", sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd); else err = atf_no_error(); } else if (type == atf_process_stream_type_inherit) { err = atf_no_error(); } else if (type == atf_process_stream_type_redirect_fd) { err = safe_dup(sp->m_sb->m_fd, procfd); } else if (type == atf_process_stream_type_redirect_path) { int aux = open(atf_fs_path_cstring(sp->m_sb->m_path), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (aux == -1) err = atf_libc_error(errno, "Could not create %s", atf_fs_path_cstring(sp->m_sb->m_path)); else { err = safe_dup(aux, procfd); if (atf_is_error(err)) close(aux); } } else { UNREACHABLE; err = atf_no_error(); } return err; }
ATF_TC_BODY(libc_format, tc) { atf_error_t err; char buf[1024]; err = atf_libc_error(ENOMEM, "Test message 1"); atf_error_format(err, buf, sizeof(buf)); ATF_REQUIRE(strstr(buf, strerror(ENOMEM)) != NULL); ATF_REQUIRE(strstr(buf, "Test message 1") != NULL); atf_error_free(err); err = atf_libc_error(EPERM, "Test message 2"); atf_error_format(err, buf, sizeof(buf)); ATF_REQUIRE(strstr(buf, strerror(EPERM)) != NULL); ATF_REQUIRE(strstr(buf, "Test message 2") != NULL); atf_error_free(err); err = atf_libc_error(EPERM, "%s message %d", "Test", 3); atf_error_format(err, buf, sizeof(buf)); ATF_REQUIRE(strstr(buf, strerror(EPERM)) != NULL); ATF_REQUIRE(strstr(buf, "Test message 3") != NULL); atf_error_free(err); }
atf_error_t atf_fs_unlink(const atf_fs_path_t *p) { atf_error_t err; const char *path; path = atf_fs_path_cstring(p); if (unlink(path) != 0) err = atf_libc_error(errno, "Cannot unlink file: '%s'", path); else err = atf_no_error(); return err; }
static atf_error_t fork_with_streams(atf_process_child_t *c, void (*start)(void *), const atf_process_stream_t *outsb, const atf_process_stream_t *errsb, void *v) { atf_error_t err; stream_prepare_t outsp; stream_prepare_t errsp; pid_t pid; err = stream_prepare_init(&outsp, outsb); if (atf_is_error(err)) goto out; err = stream_prepare_init(&errsp, errsb); if (atf_is_error(err)) goto err_outpipe; pid = fork(); if (pid == -1) { err = atf_libc_error(errno, "Failed to fork"); goto err_errpipe; } if (pid == 0) { do_child(start, v, &outsp, &errsp); UNREACHABLE; abort(); err = atf_no_error(); } else { err = do_parent(c, pid, &outsp, &errsp); if (atf_is_error(err)) goto err_errpipe; } goto out; err_errpipe: stream_prepare_fini(&errsp); err_outpipe: stream_prepare_fini(&outsp); out: return err; }
atf_error_t atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s) { atf_error_t err; int status; if (waitpid(c->m_pid, &status, 0) == -1) err = atf_libc_error(errno, "Failed waiting for process %d", c->m_pid); else { atf_process_child_fini(c); err = atf_process_status_init(s, status); } return err; }
static atf_error_t do_mkdtemp(char *tmpl) { atf_error_t err; PRE(strstr(tmpl, "XXXXXX") != NULL); if (mkdtemp(tmpl) == NULL) err = atf_libc_error(errno, "Cannot create temporary directory " "with template '%s'", tmpl); else err = atf_no_error(); return err; }
static atf_error_t do_mkstemp(char *tmpl, int *fdout) { atf_error_t err; PRE(strstr(tmpl, "XXXXXX") != NULL); *fdout = mkstemp(tmpl); if (*fdout == -1) err = atf_libc_error(errno, "Cannot create temporary file " "with template '%s'", tmpl); else err = atf_no_error(); return err; }
static atf_error_t safe_dup(const int oldfd, const int newfd) { atf_error_t err; if (oldfd != newfd) { if (dup2(oldfd, newfd) == -1) { err = atf_libc_error(errno, "Could not allocate file descriptor"); } else { close(oldfd); err = atf_no_error(); } } else err = atf_no_error(); return err; }
atf_error_t atf_fs_rmdir(const atf_fs_path_t *p) { atf_error_t err; if (rmdir(atf_fs_path_cstring(p))) { if (errno == EEXIST) { /* 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. */ errno = ENOTEMPTY; } err = atf_libc_error(errno, "Cannot remove directory"); } else err = atf_no_error(); return err; }
atf_error_t atf_text_to_bool(const char *str, bool *b) { atf_error_t err; if (strcasecmp(str, "yes") == 0 || strcasecmp(str, "true") == 0) { *b = true; err = atf_no_error(); } else if (strcasecmp(str, "no") == 0 || strcasecmp(str, "false") == 0) { *b = false; err = atf_no_error(); } else { /* XXX Not really a libc error. */ err = atf_libc_error(EINVAL, "Cannot convert string '%s' " "to boolean", str); } return err; }
atf_error_t atf_fs_getcwd(atf_fs_path_t *p) { atf_error_t err; char *cwd; #if defined(HAVE_GETCWD_DYN) cwd = getcwd(NULL, 0); #else cwd = getcwd(NULL, MAXPATHLEN); #endif if (cwd == NULL) { err = atf_libc_error(errno, "Cannot determine current directory"); goto out; } err = atf_fs_path_init_fmt(p, "%s", cwd); free(cwd); out: return err; }
static atf_error_t stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb) { atf_error_t err; const int type = atf_process_stream_type(sb); sp->m_sb = sb; sp->m_pipefds_ok = false; if (type == atf_process_stream_type_capture) { if (pipe(sp->m_pipefds) == -1) err = atf_libc_error(errno, "Failed to create pipe"); else { err = atf_no_error(); sp->m_pipefds_ok = true; } } else err = atf_no_error(); return err; }
ATF_TC_BODY(aio_large_read_test, tc) { char pathname[PATH_MAX]; struct aiocb cb, *cbp; ssize_t nread; size_t len; int fd; #ifdef __LP64__ int clamped; #endif ATF_REQUIRE_KERNEL_MODULE("aio"); ATF_REQUIRE_UNSAFE_AIO(); #ifdef __LP64__ len = sizeof(clamped); if (sysctlbyname("debug.iosize_max_clamp", &clamped, &len, NULL, 0) == -1) atf_libc_error(errno, "Failed to read debug.iosize_max_clamp"); #endif /* Determine the maximum supported read(2) size. */ len = SSIZE_MAX; #ifdef __LP64__ if (clamped) len = INT_MAX; #endif strcpy(pathname, PATH_TEMPLATE); fd = mkstemp(pathname); ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); unlink(pathname); memset(&cb, 0, sizeof(cb)); cb.aio_nbytes = len; cb.aio_fildes = fd; cb.aio_buf = NULL; if (aio_read(&cb) == -1) atf_tc_fail("aio_read() of maximum read size failed: %s", strerror(errno)); nread = aio_waitcomplete(&cbp, NULL); if (nread == -1) atf_tc_fail("aio_waitcomplete() failed: %s", strerror(errno)); if (nread != 0) atf_tc_fail("aio_read() from empty file returned data: %zd", nread); memset(&cb, 0, sizeof(cb)); cb.aio_nbytes = len + 1; cb.aio_fildes = fd; cb.aio_buf = NULL; if (aio_read(&cb) == -1) { if (errno == EINVAL) goto finished; atf_tc_fail("aio_read() of too large read size failed: %s", strerror(errno)); } nread = aio_waitcomplete(&cbp, NULL); if (nread == -1) { if (errno == EINVAL) goto finished; atf_tc_fail("aio_waitcomplete() failed: %s", strerror(errno)); } atf_tc_fail("aio_read() of too large read size returned: %zd", nread); finished: close(fd); }