| #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(); |
| } |