ATF_TC_BODY(work_directory__env_tmpdir, tc) { char* tmpdir; RE(kyua_fs_make_absolute("worktest", &tmpdir)); ATF_REQUIRE(mkdir(tmpdir, 0755) != -1); RE(kyua_env_set("TMPDIR", tmpdir)); char* work_directory; RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(), &work_directory)); { char* template_test; RE(kyua_fs_concat(&template_test, atf_tc_get_config_var(tc, "srcdir"), "worktest", "template.XXXXXX", NULL)); ATF_REQUIRE(access(template_test, X_OK) == -1); free(template_test); } ATF_REQUIRE(access(work_directory, X_OK) != -1); ATF_REQUIRE(rmdir(tmpdir) == -1); // Not yet empty. RE(kyua_run_work_directory_leave(&work_directory)); ATF_REQUIRE(rmdir(tmpdir) != -1); free(tmpdir); }
ATF_TC_BODY(make_absolute__absolute, tc) { char* absolute; ATF_REQUIRE(!kyua_error_is_set(kyua_fs_make_absolute( "/this/is/absolute", &absolute))); ATF_REQUIRE_STREQ("/this/is/absolute", absolute); free(absolute); }
/// Looks for a core file for the given program. /// /// \param name The basename of the binary that generated the core. /// \param directory The directory from which the program was run. We expect to /// find the core file in this directory. /// \param dead_pid PID of the process that generated the core. This is needed /// in some platforms. /// /// \return The path to the core file if found; otherwise none. char* kyua_stacktrace_find_core(const char* name, const char* directory, const pid_t dead_pid) { char* candidate = NULL; // TODO(jmmv): Other than checking all these defaults, in NetBSD we should // also inspect the value of the kern.defcorename sysctl(2) MIB and use that // as the first candidate. // // In Linux, the way to determine the name is by looking at // /proc/sys/kernel/core_{pattern,uses_pid} as described by core(5). // Unfortunately, there does not seem to be a standard API to parse these // files, which makes checking for core files quite difficult if the // defaults have been modified. // Default NetBSD naming scheme. if (candidate == NULL && MAXCOMLEN > 0) { char truncated[MAXCOMLEN + 1]; candidate = try_core("%s/%s.core", directory, slice(name, truncated, sizeof(truncated))); } // Common naming scheme without the MAXCOMLEN truncation. if (candidate == NULL) candidate = try_core("%s/%s.core", directory, name); // Common naming scheme found in Linux systems. if (candidate == NULL) candidate = try_core("%s/core.%d", directory, (int)dead_pid); // Default Mac OS X naming scheme. if (candidate == NULL) candidate = try_core("/cores/core.%d", (int)dead_pid); // Common naming scheme found in Linux systems. Attempted last due to the // genericity of the core file name. if (candidate == NULL) candidate = try_core("%s/core", directory); if (candidate != NULL) { char* abs_candidate; kyua_error_t error = kyua_fs_make_absolute(candidate, &abs_candidate); if (kyua_error_is_set(error)) { kyua_error_free(error); return candidate; // Return possibly-relative path as a best guess. } else { free(candidate); return abs_candidate; } } else { return candidate; } }
ATF_TC_BODY(make_absolute__relative, tc) { kyua_error_t error; char* absolute; DIR* previous = opendir("."); ATF_REQUIRE(previous != NULL); ATF_REQUIRE(chdir("/usr") != -1); error = kyua_fs_make_absolute("bin/foobar", &absolute); const int previous_fd = dirfd(previous); ATF_REQUIRE(fchdir(previous_fd) != -1); close(previous_fd); ATF_REQUIRE(!kyua_error_is_set(error)); ATF_REQUIRE_STREQ("/usr/bin/foobar", absolute); free(absolute); }
ATF_TC_BODY(work_directory__sanitized, tc) { ATF_REQUIRE(mkdir("foo", 0755) != -1); ATF_REQUIRE(mkdir("foo/bar", 0755) != -1); char* tmpdir; RE(kyua_fs_make_absolute("foo///bar/./", &tmpdir)); RE(kyua_env_set("TMPDIR", tmpdir)); char* work_directory; RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(), &work_directory)); ATF_REQUIRE(strstr(work_directory, "/foo/bar/template.") != NULL); RE(kyua_run_work_directory_leave(&work_directory)); free(tmpdir); }
ATF_TC_BODY(work_directory__permissions_error, tc) { char* tmpdir; RE(kyua_fs_make_absolute("worktest", &tmpdir)); ATF_REQUIRE(mkdir(tmpdir, 0755) != -1); RE(kyua_env_set("TMPDIR", tmpdir)); char* work_directory; const kyua_error_t error = kyua_run_work_directory_enter( "template.XXXXXX", getuid() + 1, getgid(), &work_directory); ATF_REQUIRE(kyua_error_is_set(error)); ATF_REQUIRE(kyua_error_is_type(error, "libc")); ATF_REQUIRE_EQ(EPERM, kyua_libc_error_errno(error)); kyua_error_free(error); ATF_REQUIRE(rmdir(tmpdir) != -1); // Empty; subdirectory not created. free(tmpdir); }
ATF_TC_BODY(sanitize__ok, tc) { ATF_REQUIRE(mkdir("a", 0755) != -1); ATF_REQUIRE(mkdir("a/bc", 0755) != -1); ATF_REQUIRE(mkdir("a/bc/12-34", 0755) != -1); char* sane; ATF_REQUIRE(!kyua_error_is_set(kyua_fs_sanitize( ".//a/bc///12-34", &sane))); char *expected; ATF_REQUIRE(!kyua_error_is_set(kyua_fs_make_absolute( "a/bc/12-34", &expected))); ATF_REQUIRE_STREQ(expected, sane); free(sane); free(expected); }
/// Performs a signal delivery test to the work directory handling code. /// /// \param signo The signal to deliver. static void work_directory_signal_check(const int signo) { char* tmpdir; RE(kyua_fs_make_absolute("worktest", &tmpdir)); ATF_REQUIRE(mkdir(tmpdir, 0755) != -1); RE(kyua_env_set("TMPDIR", tmpdir)); char* work_directory; RE(kyua_run_work_directory_enter("template.XXXXXX", getuid(), getgid(), &work_directory)); kyua_run_params_t run_params; kyua_run_params_init(&run_params); run_params.work_directory = work_directory; pid_t pid; RE(kyua_run_fork(&run_params, &pid)); if (pid == 0) { sleep(run_params.timeout_seconds * 2); abort(); } // This should cause the handled installed by the work_directory management // code to terminate the subprocess so that we get a chance to run the // cleanup code ourselves. kill(getpid(), signo); int status; bool timed_out; RE(kyua_run_wait(pid, &status, &timed_out)); ATF_REQUIRE(!timed_out); ATF_REQUIRE(WIFSIGNALED(status)); ATF_REQUIRE_EQ(SIGKILL, WTERMSIG(status)); ATF_REQUIRE(rmdir(tmpdir) == -1); // Not yet empty. RE(kyua_run_work_directory_leave(&work_directory)); ATF_REQUIRE(rmdir(tmpdir) != -1); free(tmpdir); }