=== modified file 'dracut-module/password-agent.c' --- dracut-module/password-agent.c 2019-08-01 17:35:45 +0000 +++ dracut-module/password-agent.c 2019-08-03 10:45:18 +0000 @@ -1017,8 +1017,8 @@ return false; } - if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE - | IN_MOVED_TO | IN_DELETE) + if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO + | IN_MOVED_FROM| IN_DELETE) == -1){ error(0, errno, "Failed to create inotify watch on %s", dir); return false; @@ -1119,7 +1119,7 @@ immediately */ queue->next_run = 1; } - } else if(ievent->mask & IN_DELETE){ + } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){ if(not string_set_add(cancelled_filenames, question_filename)){ error(0, errno, "Could not add question %s to" @@ -3672,6 +3672,78 @@ } static +void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused)) + test_fixture *fixture, + __attribute__((unused)) + gconstpointer + user_data){ + __attribute__((cleanup(cleanup_close))) + const int epoll_fd = epoll_create1(EPOLL_CLOEXEC); + g_assert_cmpint(epoll_fd, >=, 0); + __attribute__((cleanup(cleanup_queue))) + task_queue *queue = create_queue(); + g_assert_nonnull(queue); + __attribute__((cleanup(string_set_clear))) + string_set cancelled_filenames = {}; + const mono_microsecs current_time = 0; + + bool quit_now = false; + buffer password = {}; + bool mandos_client_exited = false; + bool password_is_read = false; + + __attribute__((cleanup(cleanup_string))) + char *tempdir = make_temporary_directory(); + g_assert_nonnull(tempdir); + + __attribute__((cleanup(cleanup_string))) + char *tempfilename = make_temporary_file_in_directory(tempdir); + g_assert_nonnull(tempfilename); + + __attribute__((cleanup(cleanup_string))) + char *targetdir = make_temporary_directory(); + g_assert_nonnull(targetdir); + + __attribute__((cleanup(cleanup_string))) + char *targetfilename = NULL; + g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir, + basename(tempfilename)), >, 0); + g_assert_nonnull(targetfilename); + + g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now, + &password, tempdir, + &cancelled_filenames, + ¤t_time, + &mandos_client_exited, + &password_is_read)); + + g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0); + + const task_context *const added_read_task + = find_matching_task(queue, + (task_context){ .func=read_inotify_event }); + g_assert_nonnull(added_read_task); + + /* "sufficient to read at least one event." - inotify(7) */ + const size_t ievent_size = (sizeof(struct inotify_event) + + NAME_MAX + 1); + struct inotify_event *ievent = malloc(ievent_size); + g_assert_nonnull(ievent); + + ssize_t read_size = read(added_read_task->fd, ievent, ievent_size); + + g_assert_cmpint((int)read_size, >, 0); + g_assert_true(ievent->mask & IN_MOVED_FROM); + g_assert_cmpstr(ievent->name, ==, basename(tempfilename)); + + free(ievent); + + g_assert_cmpint(unlink(targetfilename), ==, 0); + g_assert_cmpint(rmdir(targetdir), ==, 0); + g_assert_cmpint(rmdir(tempdir), ==, 0); +} + +static void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused)) test_fixture *fixture, __attribute__((unused)) @@ -4104,6 +4176,91 @@ })); } +static +void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused)) + test_fixture *fixture, + __attribute__((unused)) + gconstpointer user_data){ + __attribute__((cleanup(cleanup_close))) + const int epoll_fd = epoll_create1(EPOLL_CLOEXEC); + g_assert_cmpint(epoll_fd, >=, 0); + __attribute__((cleanup(string_set_clear))) + string_set cancelled_filenames = {}; + const mono_microsecs current_time = 0; + + int pipefds[2]; + g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0); + + /* "sufficient to read at least one event." - inotify(7) */ + const size_t ievent_max_size = (sizeof(struct inotify_event) + + NAME_MAX + 1); + g_assert_cmpint(ievent_max_size, <=, PIPE_BUF); + struct { + struct inotify_event event; + char name_buffer[NAME_MAX + 1]; + } ievent_buffer; + struct inotify_event *const ievent = &ievent_buffer.event; + + const char dummy_file_name[] = "ask.dummy_file_name"; + ievent->mask = IN_MOVED_FROM; + ievent->len = sizeof(dummy_file_name); + memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name)); + const size_t ievent_size = (sizeof(struct inotify_event) + + sizeof(dummy_file_name)); + g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size), + ==, ievent_size); + g_assert_cmpint(close(pipefds[1]), ==, 0); + + bool quit_now = false; + buffer password = {}; + bool mandos_client_exited = false; + bool password_is_read = false; + __attribute__((cleanup(cleanup_queue))) + task_queue *queue = create_queue(); + g_assert_nonnull(queue); + + task_context task = { + .func=read_inotify_event, + .epoll_fd=epoll_fd, + .fd=pipefds[0], + .quit_now=&quit_now, + .password=&password, + .filename=strdup("/nonexistent"), + .cancelled_filenames=&cancelled_filenames, + .current_time=¤t_time, + .mandos_client_exited=&mandos_client_exited, + .password_is_read=&password_is_read, + }; + task.func(task, queue); + g_assert_false(quit_now); + g_assert_true(queue->next_run == 0); + g_assert_cmpuint((unsigned int)queue->length, ==, 1); + + g_assert_nonnull(find_matching_task(queue, (task_context){ + .func=read_inotify_event, + .epoll_fd=epoll_fd, + .fd=pipefds[0], + .quit_now=&quit_now, + .password=&password, + .filename=task.filename, + .cancelled_filenames=&cancelled_filenames, + .current_time=¤t_time, + .mandos_client_exited=&mandos_client_exited, + .password_is_read=&password_is_read, + })); + + g_assert_true(epoll_set_contains(epoll_fd, pipefds[0], + EPOLLIN | EPOLLRDHUP)); + + __attribute__((cleanup(cleanup_string))) + char *filename = NULL; + g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename, + dummy_file_name), >, 0); + g_assert_nonnull(filename); + g_assert_true(string_set_contains(*task.cancelled_filenames, + filename)); +} + static void test_read_inotify_event_IN_DELETE(__attribute__((unused)) test_fixture *fixture, __attribute__((unused)) @@ -4342,6 +4499,91 @@ EPOLLIN | EPOLLRDHUP)); } +static void +test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused)) + test_fixture *fixture, + __attribute__((unused)) + gconstpointer + user_data){ + __attribute__((cleanup(cleanup_close))) + const int epoll_fd = epoll_create1(EPOLL_CLOEXEC); + g_assert_cmpint(epoll_fd, >=, 0); + __attribute__((cleanup(string_set_clear))) + string_set cancelled_filenames = {}; + const mono_microsecs current_time = 0; + + int pipefds[2]; + g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0); + + /* "sufficient to read at least one event." - inotify(7) */ + const size_t ievent_max_size = (sizeof(struct inotify_event) + + NAME_MAX + 1); + g_assert_cmpint(ievent_max_size, <=, PIPE_BUF); + struct { + struct inotify_event event; + char name_buffer[NAME_MAX + 1]; + } ievent_buffer; + struct inotify_event *const ievent = &ievent_buffer.event; + + const char dummy_file_name[] = "ignored.dummy_file_name"; + ievent->mask = IN_MOVED_FROM; + ievent->len = sizeof(dummy_file_name); + memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name)); + const size_t ievent_size = (sizeof(struct inotify_event) + + sizeof(dummy_file_name)); + g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size), + ==, ievent_size); + g_assert_cmpint(close(pipefds[1]), ==, 0); + + bool quit_now = false; + buffer password = {}; + bool mandos_client_exited = false; + bool password_is_read = false; + __attribute__((cleanup(cleanup_queue))) + task_queue *queue = create_queue(); + g_assert_nonnull(queue); + + task_context task = { + .func=read_inotify_event, + .epoll_fd=epoll_fd, + .fd=pipefds[0], + .quit_now=&quit_now, + .password=&password, + .filename=strdup("/nonexistent"), + .cancelled_filenames=&cancelled_filenames, + .current_time=¤t_time, + .mandos_client_exited=&mandos_client_exited, + .password_is_read=&password_is_read, + }; + task.func(task, queue); + g_assert_false(quit_now); + g_assert_true(queue->next_run == 0); + g_assert_cmpuint((unsigned int)queue->length, ==, 1); + + g_assert_nonnull(find_matching_task(queue, (task_context){ + .func=read_inotify_event, + .epoll_fd=epoll_fd, + .fd=pipefds[0], + .quit_now=&quit_now, + .password=&password, + .filename=task.filename, + .cancelled_filenames=&cancelled_filenames, + .current_time=¤t_time, + .mandos_client_exited=&mandos_client_exited, + .password_is_read=&password_is_read, + })); + + g_assert_true(epoll_set_contains(epoll_fd, pipefds[0], + EPOLLIN | EPOLLRDHUP)); + + __attribute__((cleanup(cleanup_string))) + char *filename = NULL; + g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename, + dummy_file_name), >, 0); + g_assert_nonnull(filename); + g_assert_false(string_set_contains(cancelled_filenames, filename)); +} + static void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused)) test_fixture *fixture, @@ -7593,6 +7835,8 @@ test_add_inotify_dir_watch_IN_CLOSE_WRITE); test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO", test_add_inotify_dir_watch_IN_MOVED_TO); + test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM", + test_add_inotify_dir_watch_IN_MOVED_FROM); test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE", test_add_inotify_dir_watch_IN_DELETE); test_add_st("/task/read_inotify_event/readerror", @@ -7607,12 +7851,16 @@ test_read_inotify_event_IN_CLOSE_WRITE); test_add_st("/task/read_inotify_event/IN_MOVED_TO", test_read_inotify_event_IN_MOVED_TO); + test_add_st("/task/read_inotify_event/IN_MOVED_FROM", + test_read_inotify_event_IN_MOVED_FROM); test_add_st("/task/read_inotify_event/IN_DELETE", test_read_inotify_event_IN_DELETE); test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname", test_read_inotify_event_IN_CLOSE_WRITE_badname); test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname", test_read_inotify_event_IN_MOVED_TO_badname); + test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname", + test_read_inotify_event_IN_MOVED_FROM_badname); test_add_st("/task/read_inotify_event/IN_DELETE/badname", test_read_inotify_event_IN_DELETE_badname); test_add_st("/task/open_and_parse_question/ENOENT",