3452
3454
g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3457
static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
3458
test_fixture *fixture,
3459
__attribute__((unused))
3462
__attribute__((cleanup(cleanup_close)))
3463
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3464
g_assert_cmpint(epoll_fd, >=, 0);
3465
__attribute__((cleanup(cleanup_queue)))
3466
task_queue *queue = create_queue();
3467
g_assert_nonnull(queue);
3468
__attribute__((cleanup(string_set_clear)))
3469
string_set cancelled_filenames = {};
3470
const mono_microsecs current_time = 0;
3472
bool quit_now = false;
3473
buffer password = {};
3474
bool mandos_client_exited = false;
3475
bool password_is_read = false;
3477
const char not_a_directory[] = "/dev/tty";
3479
FILE *real_stderr = stderr;
3480
FILE *devnull = fopen("/dev/null", "we");
3481
g_assert_nonnull(devnull);
3483
g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3484
&password, not_a_directory,
3485
&cancelled_filenames,
3487
&mandos_client_exited,
3488
&password_is_read));
3489
stderr = real_stderr;
3490
g_assert_cmpint(fclose(devnull), ==, 0);
3492
g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3455
3495
static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
3456
3496
test_fixture *fixture,
3457
3497
__attribute__((unused))
3715
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3716
test_fixture *fixture,
3717
__attribute__((unused))
3720
__attribute__((cleanup(cleanup_close)))
3721
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3722
g_assert_cmpint(epoll_fd, >=, 0);
3723
__attribute__((cleanup(cleanup_queue)))
3724
task_queue *queue = create_queue();
3725
g_assert_nonnull(queue);
3726
__attribute__((cleanup(string_set_clear)))
3727
string_set cancelled_filenames = {};
3728
const mono_microsecs current_time = 0;
3730
bool quit_now = false;
3731
buffer password = {};
3732
bool mandos_client_exited = false;
3733
bool password_is_read = false;
3735
__attribute__((cleanup(cleanup_string)))
3736
char *tempdir = make_temporary_directory();
3737
g_assert_nonnull(tempdir);
3739
__attribute__((cleanup(cleanup_string)))
3740
char *tempfilename = make_temporary_file_in_directory(tempdir);
3741
g_assert_nonnull(tempfilename);
3743
__attribute__((cleanup(cleanup_string)))
3744
char *targetdir = make_temporary_directory();
3745
g_assert_nonnull(targetdir);
3747
__attribute__((cleanup(cleanup_string)))
3748
char *targetfilename = NULL;
3749
g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3750
basename(tempfilename)), >, 0);
3751
g_assert_nonnull(targetfilename);
3753
g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3755
&cancelled_filenames,
3757
&mandos_client_exited,
3758
&password_is_read));
3760
g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3762
const task_context *const added_read_task
3763
= find_matching_task(queue,
3764
(task_context){ .func=read_inotify_event });
3765
g_assert_nonnull(added_read_task);
3767
/* "sufficient to read at least one event." - inotify(7) */
3768
const size_t ievent_size = (sizeof(struct inotify_event)
3770
struct inotify_event *ievent = malloc(ievent_size);
3771
g_assert_nonnull(ievent);
3773
ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3775
g_assert_cmpint((int)read_size, >, 0);
3776
g_assert_true(ievent->mask & IN_MOVED_FROM);
3777
g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3781
g_assert_cmpint(unlink(targetfilename), ==, 0);
3782
g_assert_cmpint(rmdir(targetdir), ==, 0);
3783
g_assert_cmpint(rmdir(tempdir), ==, 0);
3675
3787
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3676
3788
test_fixture *fixture,
3677
3789
__attribute__((unused))
3735
3847
g_assert_cmpint(rmdir(tempdir), ==, 0);
3851
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3852
test_fixture *fixture,
3853
__attribute__((unused))
3856
__attribute__((cleanup(cleanup_close)))
3857
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3858
g_assert_cmpint(epoll_fd, >=, 0);
3859
__attribute__((cleanup(cleanup_queue)))
3860
task_queue *queue = create_queue();
3861
g_assert_nonnull(queue);
3862
__attribute__((cleanup(string_set_clear)))
3863
string_set cancelled_filenames = {};
3864
const mono_microsecs current_time = 0;
3866
bool quit_now = false;
3867
buffer password = {};
3868
bool mandos_client_exited = false;
3869
bool password_is_read = false;
3871
__attribute__((cleanup(cleanup_string)))
3872
char *tempdir = make_temporary_directory();
3873
g_assert_nonnull(tempdir);
3875
__attribute__((cleanup(cleanup_string)))
3876
char *tempfile = make_temporary_file_in_directory(tempdir);
3877
g_assert_nonnull(tempfile);
3878
int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3880
g_assert_cmpint(tempfile_fd, >, 2);
3882
g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3884
&cancelled_filenames,
3886
&mandos_client_exited,
3887
&password_is_read));
3888
g_assert_cmpint(unlink(tempfile), ==, 0);
3890
g_assert_cmpuint((unsigned int)queue->length, >, 0);
3892
const task_context *const added_read_task
3893
= find_matching_task(queue,
3894
(task_context){ .func=read_inotify_event });
3895
g_assert_nonnull(added_read_task);
3897
g_assert_cmpint(added_read_task->fd, >, 2);
3898
g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3900
/* "sufficient to read at least one event." - inotify(7) */
3901
const size_t ievent_size = (sizeof(struct inotify_event)
3903
struct inotify_event *ievent = malloc(ievent_size);
3904
g_assert_nonnull(ievent);
3906
ssize_t read_size = 0;
3907
read_size = read(added_read_task->fd, ievent, ievent_size);
3909
g_assert_cmpint((int)read_size, >, 0);
3910
g_assert_true(ievent->mask & IN_DELETE);
3911
g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3913
g_assert_cmpint(close(tempfile_fd), ==, 0);
3915
/* IN_EXCL_UNLINK should make the closing of the previously unlinked
3916
file not appear as an ievent, so we should not see it now. */
3917
read_size = read(added_read_task->fd, ievent, ievent_size);
3918
g_assert_cmpint((int)read_size, ==, -1);
3919
g_assert_true(errno == EAGAIN);
3923
g_assert_cmpint(rmdir(tempdir), ==, 0);
3738
3926
static void test_read_inotify_event_readerror(__attribute__((unused))
3739
3927
test_fixture *fixture,
3740
3928
__attribute__((unused))
4296
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4297
test_fixture *fixture,
4298
__attribute__((unused))
4299
gconstpointer user_data){
4300
__attribute__((cleanup(cleanup_close)))
4301
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4302
g_assert_cmpint(epoll_fd, >=, 0);
4303
__attribute__((cleanup(string_set_clear)))
4304
string_set cancelled_filenames = {};
4305
const mono_microsecs current_time = 0;
4308
g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4310
/* "sufficient to read at least one event." - inotify(7) */
4311
const size_t ievent_max_size = (sizeof(struct inotify_event)
4313
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4315
struct inotify_event event;
4316
char name_buffer[NAME_MAX + 1];
4318
struct inotify_event *const ievent = &ievent_buffer.event;
4320
const char dummy_file_name[] = "ask.dummy_file_name";
4321
ievent->mask = IN_MOVED_FROM;
4322
ievent->len = sizeof(dummy_file_name);
4323
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4324
const size_t ievent_size = (sizeof(struct inotify_event)
4325
+ sizeof(dummy_file_name));
4326
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4328
g_assert_cmpint(close(pipefds[1]), ==, 0);
4330
bool quit_now = false;
4331
buffer password = {};
4332
bool mandos_client_exited = false;
4333
bool password_is_read = false;
4334
__attribute__((cleanup(cleanup_queue)))
4335
task_queue *queue = create_queue();
4336
g_assert_nonnull(queue);
4338
task_context task = {
4339
.func=read_inotify_event,
4342
.quit_now=&quit_now,
4343
.password=&password,
4344
.filename=strdup("/nonexistent"),
4345
.cancelled_filenames=&cancelled_filenames,
4346
.current_time=¤t_time,
4347
.mandos_client_exited=&mandos_client_exited,
4348
.password_is_read=&password_is_read,
4350
task.func(task, queue);
4351
g_assert_false(quit_now);
4352
g_assert_true(queue->next_run == 0);
4353
g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4355
g_assert_nonnull(find_matching_task(queue, (task_context){
4356
.func=read_inotify_event,
4359
.quit_now=&quit_now,
4360
.password=&password,
4361
.filename=task.filename,
4362
.cancelled_filenames=&cancelled_filenames,
4363
.current_time=¤t_time,
4364
.mandos_client_exited=&mandos_client_exited,
4365
.password_is_read=&password_is_read,
4368
g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4369
EPOLLIN | EPOLLRDHUP));
4371
__attribute__((cleanup(cleanup_string)))
4372
char *filename = NULL;
4373
g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4374
dummy_file_name), >, 0);
4375
g_assert_nonnull(filename);
4376
g_assert_true(string_set_contains(*task.cancelled_filenames,
4107
4380
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4108
4381
test_fixture *fixture,
4109
4382
__attribute__((unused))
4342
4615
EPOLLIN | EPOLLRDHUP));
4619
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4620
test_fixture *fixture,
4621
__attribute__((unused))
4624
__attribute__((cleanup(cleanup_close)))
4625
const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4626
g_assert_cmpint(epoll_fd, >=, 0);
4627
__attribute__((cleanup(string_set_clear)))
4628
string_set cancelled_filenames = {};
4629
const mono_microsecs current_time = 0;
4632
g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4634
/* "sufficient to read at least one event." - inotify(7) */
4635
const size_t ievent_max_size = (sizeof(struct inotify_event)
4637
g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4639
struct inotify_event event;
4640
char name_buffer[NAME_MAX + 1];
4642
struct inotify_event *const ievent = &ievent_buffer.event;
4644
const char dummy_file_name[] = "ignored.dummy_file_name";
4645
ievent->mask = IN_MOVED_FROM;
4646
ievent->len = sizeof(dummy_file_name);
4647
memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4648
const size_t ievent_size = (sizeof(struct inotify_event)
4649
+ sizeof(dummy_file_name));
4650
g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4652
g_assert_cmpint(close(pipefds[1]), ==, 0);
4654
bool quit_now = false;
4655
buffer password = {};
4656
bool mandos_client_exited = false;
4657
bool password_is_read = false;
4658
__attribute__((cleanup(cleanup_queue)))
4659
task_queue *queue = create_queue();
4660
g_assert_nonnull(queue);
4662
task_context task = {
4663
.func=read_inotify_event,
4666
.quit_now=&quit_now,
4667
.password=&password,
4668
.filename=strdup("/nonexistent"),
4669
.cancelled_filenames=&cancelled_filenames,
4670
.current_time=¤t_time,
4671
.mandos_client_exited=&mandos_client_exited,
4672
.password_is_read=&password_is_read,
4674
task.func(task, queue);
4675
g_assert_false(quit_now);
4676
g_assert_true(queue->next_run == 0);
4677
g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4679
g_assert_nonnull(find_matching_task(queue, (task_context){
4680
.func=read_inotify_event,
4683
.quit_now=&quit_now,
4684
.password=&password,
4685
.filename=task.filename,
4686
.cancelled_filenames=&cancelled_filenames,
4687
.current_time=¤t_time,
4688
.mandos_client_exited=&mandos_client_exited,
4689
.password_is_read=&password_is_read,
4692
g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4693
EPOLLIN | EPOLLRDHUP));
4695
__attribute__((cleanup(cleanup_string)))
4696
char *filename = NULL;
4697
g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4698
dummy_file_name), >, 0);
4699
g_assert_nonnull(filename);
4700
g_assert_false(string_set_contains(cancelled_filenames, filename));
4346
4704
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4347
4705
test_fixture *fixture,
7587
7945
test_add_inotify_dir_watch);
7588
7946
test_add_st("/task-creators/add_inotify_dir_watch/fail",
7589
7947
test_add_inotify_dir_watch_fail);
7948
test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
7949
test_add_inotify_dir_watch_nondir);
7590
7950
test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
7591
7951
test_add_inotify_dir_watch_EAGAIN);
7592
7952
test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
7593
7953
test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7594
7954
test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7595
7955
test_add_inotify_dir_watch_IN_MOVED_TO);
7956
test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
7957
test_add_inotify_dir_watch_IN_MOVED_FROM);
7958
test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
7959
test_add_inotify_dir_watch_IN_EXCL_UNLINK);
7596
7960
test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7597
7961
test_add_inotify_dir_watch_IN_DELETE);
7598
7962
test_add_st("/task/read_inotify_event/readerror",
7607
7971
test_read_inotify_event_IN_CLOSE_WRITE);
7608
7972
test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7609
7973
test_read_inotify_event_IN_MOVED_TO);
7974
test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
7975
test_read_inotify_event_IN_MOVED_FROM);
7610
7976
test_add_st("/task/read_inotify_event/IN_DELETE",
7611
7977
test_read_inotify_event_IN_DELETE);
7612
7978
test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7613
7979
test_read_inotify_event_IN_CLOSE_WRITE_badname);
7614
7980
test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7615
7981
test_read_inotify_event_IN_MOVED_TO_badname);
7982
test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
7983
test_read_inotify_event_IN_MOVED_FROM_badname);
7616
7984
test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7617
7985
test_read_inotify_event_IN_DELETE_badname);
7618
7986
test_add_st("/task/open_and_parse_question/ENOENT",