| | #include "../../unity/unity.h" |
| | #include <locale.h> |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <string.h> |
| | #include <unistd.h> |
| | #include <sys/stat.h> |
| | #include <errno.h> |
| | #include <fcntl.h> |
| | #include "quote.h" |
| |
|
| | |
| | void setUp(void) { |
| | |
| | setlocale(LC_ALL, "C"); |
| | set_quoting_style(NULL, literal_quoting_style); |
| | } |
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | static char* capture_describe_change_output(const char *file, const struct change_status *ch) { |
| | int pipefd[2]; |
| | if (pipe(pipefd) == -1) { |
| | return NULL; |
| | } |
| |
|
| | int saved_stdout = dup(STDOUT_FILENO); |
| | if (saved_stdout == -1) { |
| | close(pipefd[0]); |
| | close(pipefd[1]); |
| | return NULL; |
| | } |
| |
|
| | fflush(stdout); |
| |
|
| | if (dup2(pipefd[1], STDOUT_FILENO) == -1) { |
| | close(saved_stdout); |
| | close(pipefd[0]); |
| | close(pipefd[1]); |
| | return NULL; |
| | } |
| |
|
| | |
| | close(pipefd[1]); |
| |
|
| | |
| | describe_change(file, ch); |
| |
|
| | |
| | fflush(stdout); |
| | if (dup2(saved_stdout, STDOUT_FILENO) == -1) { |
| | |
| | } |
| | close(saved_stdout); |
| |
|
| | |
| | char *buf = NULL; |
| | size_t cap = 0; |
| | size_t len = 0; |
| |
|
| | char tmp[4096]; |
| | ssize_t n; |
| | while ((n = read(pipefd[0], tmp, sizeof tmp)) > 0) { |
| | if (len + (size_t)n + 1 > cap) { |
| | size_t new_cap = (cap == 0 ? 4096 : cap * 2); |
| | while (new_cap < len + (size_t)n + 1) new_cap *= 2; |
| | char *new_buf = (char*)realloc(buf, new_cap); |
| | if (!new_buf) { |
| | free(buf); |
| | close(pipefd[0]); |
| | return NULL; |
| | } |
| | buf = new_buf; |
| | cap = new_cap; |
| | } |
| | memcpy(buf + len, tmp, (size_t)n); |
| | len += (size_t)n; |
| | } |
| | close(pipefd[0]); |
| |
|
| | if (!buf) { |
| | buf = (char*)malloc(1); |
| | if (!buf) return NULL; |
| | len = 0; |
| | } |
| | buf[len] = '\0'; |
| | return buf; |
| | } |
| |
|
| | |
| | void test_describe_change_not_applied(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_NOT_APPLIED; |
| |
|
| | char *out = capture_describe_change_output("file", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING("neither symbolic link file nor referent has been changed\n", out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_describe_change_no_stat(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_NO_STAT; |
| |
|
| | char *out = capture_describe_change_output("missing", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING("missing could not be accessed\n", out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_describe_change_succeeded_basic(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_SUCCEEDED; |
| | ch.old_mode = S_IFREG | 0600; |
| | ch.new_mode = S_IFREG | 0640; |
| |
|
| | char *out = capture_describe_change_output("file", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING( |
| | "mode of file changed from 0600 (rw-------) to 0640 (rw-r-----)\n", |
| | out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_describe_change_failed_basic(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_FAILED; |
| | ch.old_mode = S_IFREG | 0755; |
| | ch.new_mode = S_IFREG | 0700; |
| |
|
| | char *out = capture_describe_change_output("exec", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING( |
| | "failed to change mode of exec from 0755 (rwxr-xr-x) to 0700 (rwx------)\n", |
| | out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_describe_change_no_change_requested_with_setuid(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_NO_CHANGE_REQUESTED; |
| | ch.old_mode = S_IFREG | 0600; |
| | ch.new_mode = S_IFREG | S_ISUID | 0755; |
| |
|
| | char *out = capture_describe_change_output("suidbin", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING( |
| | "mode of suidbin retained as 4755 (rwsr-xr-x)\n", |
| | out); |
| | free(out); |
| | } |
| |
|
| | |
| | void test_describe_change_succeeded_directory(void) { |
| | struct change_status ch; |
| | memset(&ch, 0, sizeof ch); |
| | ch.status = CH_SUCCEEDED; |
| | ch.old_mode = S_IFDIR | 0700; |
| | ch.new_mode = S_IFDIR | 0777; |
| |
|
| | char *out = capture_describe_change_output("dir", &ch); |
| | TEST_ASSERT_NOT_NULL_MESSAGE(out, "Failed to capture output"); |
| | TEST_ASSERT_EQUAL_STRING( |
| | "mode of dir changed from 0700 (rwx------) to 0777 (rwxrwxrwx)\n", |
| | out); |
| | free(out); |
| | } |
| |
|
| | int main(void) { |
| | UNITY_BEGIN(); |
| | RUN_TEST(test_describe_change_not_applied); |
| | RUN_TEST(test_describe_change_no_stat); |
| | RUN_TEST(test_describe_change_succeeded_basic); |
| | RUN_TEST(test_describe_change_failed_basic); |
| | RUN_TEST(test_describe_change_no_change_requested_with_setuid); |
| | RUN_TEST(test_describe_change_succeeded_directory); |
| | return UNITY_END(); |
| | } |