/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to dracut-module/password-agent.c

  • Committer: Teddy Hogeborn
  • Date: 2019-07-29 16:35:53 UTC
  • Revision ID: teddy@recompile.se-20190729163553-1i442i2cbx64c537
Make tests and man page examples match

Make the tests test_manual_page_example[1-5] match exactly what is
written in the manual page, and add comments to manual page as
reminders to keep tests and manual page examples in sync.

* mandos-ctl (Test_commands_from_options.test_manual_page_example_1):
  Remove "--verbose" option, since the manual does not have it as the
  first example, and change assertion to match.
* mandos-ctl.xml (EXAMPLE): Add comments to all examples documenting
  which test function they correspond to.  Also remove unnecessary
  quotes from option arguments in fourth example, and clarify language
  slightly in fifth example.

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
#include <error.h>              /* error() */
49
49
#include <sysexits.h>           /* EX_USAGE, EX_OSERR, EX_OSFILE */
50
50
#include <errno.h>              /* errno, error_t, EACCES,
51
 
                                   ENAMETOOLONG, ENOENT, ENOTDIR,
52
 
                                   EEXIST, ECHILD, EPERM, ENOMEM,
53
 
                                   EAGAIN, EINTR, ENOBUFS, EADDRINUSE,
 
51
                                   ENAMETOOLONG, ENOENT, EEXIST,
 
52
                                   ECHILD, EPERM, ENOMEM, EAGAIN,
 
53
                                   EINTR, ENOBUFS, EADDRINUSE,
54
54
                                   ECONNREFUSED, ECONNRESET,
55
55
                                   ETOOMANYREFS, EMSGSIZE, EBADF,
56
56
                                   EINVAL */
83
83
#include <sys/mman.h>           /* munlock(), mlock() */
84
84
#include <fcntl.h>              /* O_CLOEXEC, O_NONBLOCK, fcntl(),
85
85
                                   F_GETFD, F_GETFL, FD_CLOEXEC,
86
 
                                   open(), O_WRONLY, O_NOCTTY,
87
 
                                   O_RDONLY, O_NOFOLLOW */
 
86
                                   open(), O_WRONLY, O_RDONLY */
88
87
#include <sys/wait.h>           /* waitpid(), WNOHANG, WIFEXITED(),
89
88
                                   WEXITSTATUS() */
90
89
#include <limits.h>             /* PIPE_BUF, NAME_MAX, INT_MAX */
91
90
#include <sys/inotify.h>        /* inotify_init1(), IN_NONBLOCK,
92
91
                                   IN_CLOEXEC, inotify_add_watch(),
93
92
                                   IN_CLOSE_WRITE, IN_MOVED_TO,
94
 
                                   IN_MOVED_FROM, IN_DELETE,
95
 
                                   IN_EXCL_UNLINK, IN_ONLYDIR,
96
 
                                   struct inotify_event */
 
93
                                   IN_DELETE, struct inotify_event */
97
94
#include <fnmatch.h>            /* fnmatch(), FNM_FILE_NAME */
98
95
#include <stdio.h>              /* asprintf(), FILE, fopen(),
99
96
                                   getline(), sscanf(), feof(),
148
145
  mono_microsecs next_run;
149
146
} __attribute__((designated_init)) task_queue;
150
147
 
151
 
/* "task_func" - A function type for task functions
 
148
/* "func_type" - A function type for task functions
152
149
 
153
150
   I.e. functions for the code which runs when a task is run, all have
154
151
   this type */
434
431
    case EACCES:
435
432
    case ENAMETOOLONG:
436
433
    case ENOENT:
437
 
    case ENOTDIR:
438
434
      return EX_OSFILE;
439
435
    default:
440
436
      return EX_OSERR;
1021
1017
    return false;
1022
1018
  }
1023
1019
 
1024
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
1025
 
                       | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK
1026
 
                       | IN_ONLYDIR)
 
1020
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
 
1021
                       | IN_MOVED_TO | IN_DELETE)
1027
1022
     == -1){
1028
1023
    error(0, errno, "Failed to create inotify watch on %s", dir);
1029
1024
    return false;
1076
1071
  /* "sufficient to read at least one event." - inotify(7) */
1077
1072
  const size_t ievent_size = (sizeof(struct inotify_event)
1078
1073
                              + NAME_MAX + 1);
1079
 
  struct {
1080
 
    struct inotify_event event;
1081
 
    char name_buffer[NAME_MAX + 1];
1082
 
  } ievent_buffer;
1083
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
1074
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
1075
  struct inotify_event *ievent = ((struct inotify_event *)
 
1076
                                  ievent_buffer);
1084
1077
 
1085
1078
  const ssize_t read_length = read(fd, ievent, ievent_size);
1086
1079
  if(read_length == 0){ /* EOF */
1124
1117
             immediately */
1125
1118
          queue->next_run = 1;
1126
1119
        }
1127
 
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
 
1120
      } else if(ievent->mask & IN_DELETE){
1128
1121
        if(not string_set_add(cancelled_filenames,
1129
1122
                              question_filename)){
1130
1123
          error(0, errno, "Could not add question %s to"
2227
2220
 
2228
2221
  {
2229
2222
    __attribute__((cleanup(cleanup_close)))
2230
 
      const int devnull_fd = open("/dev/null",
2231
 
                                  O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2223
      const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
2232
2224
    g_assert_cmpint(devnull_fd, >=, 0);
2233
2225
    __attribute__((cleanup(cleanup_close)))
2234
2226
      const int real_stderr_fd = dup(STDERR_FILENO);
2258
2250
    {
2259
2251
      __attribute__((cleanup(cleanup_close)))
2260
2252
        const int devnull_fd = open("/dev/null",
2261
 
                                    O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2253
                                    O_WRONLY | O_CLOEXEC);
2262
2254
      g_assert_cmpint(devnull_fd, >=, 0);
2263
2255
      __attribute__((cleanup(cleanup_close)))
2264
2256
        const int real_stderr_fd = dup(STDERR_FILENO);
2909
2901
 
2910
2902
  __attribute__((cleanup(cleanup_close)))
2911
2903
    const int devnull_fd = open("/dev/null",
2912
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2904
                                O_WRONLY | O_CLOEXEC);
2913
2905
  g_assert_cmpint(devnull_fd, >=, 0);
2914
2906
  __attribute__((cleanup(cleanup_close)))
2915
2907
    const int real_stderr_fd = dup(STDERR_FILENO);
2980
2972
 
2981
2973
  __attribute__((cleanup(cleanup_close)))
2982
2974
    const int devnull_fd = open("/dev/null",
2983
 
                                O_WRONLY | O_CLOEXEC, O_NOCTTY);
 
2975
                                O_WRONLY | O_CLOEXEC);
2984
2976
  g_assert_cmpint(devnull_fd, >=, 0);
2985
2977
  __attribute__((cleanup(cleanup_close)))
2986
2978
    const int real_stderr_fd = dup(STDERR_FILENO);
3024
3016
    buffer password = {};
3025
3017
 
3026
3018
  /* Reading /proc/self/mem from offset 0 will always give EIO */
3027
 
  const int fd = open("/proc/self/mem",
3028
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3019
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3029
3020
 
3030
3021
  bool password_is_read = false;
3031
3022
  bool quit_now = false;
3459
3450
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3460
3451
}
3461
3452
 
3462
 
static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
3463
 
                                              test_fixture *fixture,
3464
 
                                            __attribute__((unused))
3465
 
                                              gconstpointer
3466
 
                                              user_data){
3467
 
  __attribute__((cleanup(cleanup_close)))
3468
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3469
 
  g_assert_cmpint(epoll_fd, >=, 0);
3470
 
  __attribute__((cleanup(cleanup_queue)))
3471
 
    task_queue *queue = create_queue();
3472
 
  g_assert_nonnull(queue);
3473
 
  __attribute__((cleanup(string_set_clear)))
3474
 
    string_set cancelled_filenames = {};
3475
 
  const mono_microsecs current_time = 0;
3476
 
 
3477
 
  bool quit_now = false;
3478
 
  buffer password = {};
3479
 
  bool mandos_client_exited = false;
3480
 
  bool password_is_read = false;
3481
 
 
3482
 
  const char not_a_directory[] = "/dev/tty";
3483
 
 
3484
 
  FILE *real_stderr = stderr;
3485
 
  FILE *devnull = fopen("/dev/null", "we");
3486
 
  g_assert_nonnull(devnull);
3487
 
  stderr = devnull;
3488
 
  g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3489
 
                                       &password, not_a_directory,
3490
 
                                       &cancelled_filenames,
3491
 
                                       &current_time,
3492
 
                                       &mandos_client_exited,
3493
 
                                       &password_is_read));
3494
 
  stderr = real_stderr;
3495
 
  g_assert_cmpint(fclose(devnull), ==, 0);
3496
 
 
3497
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3498
 
}
3499
 
 
3500
3453
static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
3501
3454
                                              test_fixture *fixture,
3502
3455
                                              __attribute__((unused))
3717
3670
}
3718
3671
 
3719
3672
static
3720
 
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3721
 
                                              test_fixture *fixture,
3722
 
                                              __attribute__((unused))
3723
 
                                              gconstpointer
3724
 
                                              user_data){
3725
 
  __attribute__((cleanup(cleanup_close)))
3726
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3727
 
  g_assert_cmpint(epoll_fd, >=, 0);
3728
 
  __attribute__((cleanup(cleanup_queue)))
3729
 
    task_queue *queue = create_queue();
3730
 
  g_assert_nonnull(queue);
3731
 
  __attribute__((cleanup(string_set_clear)))
3732
 
    string_set cancelled_filenames = {};
3733
 
  const mono_microsecs current_time = 0;
3734
 
 
3735
 
  bool quit_now = false;
3736
 
  buffer password = {};
3737
 
  bool mandos_client_exited = false;
3738
 
  bool password_is_read = false;
3739
 
 
3740
 
  __attribute__((cleanup(cleanup_string)))
3741
 
    char *tempdir = make_temporary_directory();
3742
 
  g_assert_nonnull(tempdir);
3743
 
 
3744
 
  __attribute__((cleanup(cleanup_string)))
3745
 
    char *tempfilename = make_temporary_file_in_directory(tempdir);
3746
 
  g_assert_nonnull(tempfilename);
3747
 
 
3748
 
  __attribute__((cleanup(cleanup_string)))
3749
 
    char *targetdir = make_temporary_directory();
3750
 
  g_assert_nonnull(targetdir);
3751
 
 
3752
 
  __attribute__((cleanup(cleanup_string)))
3753
 
    char *targetfilename = NULL;
3754
 
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3755
 
                           basename(tempfilename)), >, 0);
3756
 
  g_assert_nonnull(targetfilename);
3757
 
 
3758
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3759
 
                                      &password, tempdir,
3760
 
                                      &cancelled_filenames,
3761
 
                                      &current_time,
3762
 
                                      &mandos_client_exited,
3763
 
                                      &password_is_read));
3764
 
 
3765
 
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3766
 
 
3767
 
  const task_context *const added_read_task
3768
 
    = find_matching_task(queue,
3769
 
                         (task_context){ .func=read_inotify_event });
3770
 
  g_assert_nonnull(added_read_task);
3771
 
 
3772
 
  /* "sufficient to read at least one event." - inotify(7) */
3773
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3774
 
                              + NAME_MAX + 1);
3775
 
  struct inotify_event *ievent = malloc(ievent_size);
3776
 
  g_assert_nonnull(ievent);
3777
 
 
3778
 
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3779
 
 
3780
 
  g_assert_cmpint((int)read_size, >, 0);
3781
 
  g_assert_true(ievent->mask & IN_MOVED_FROM);
3782
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3783
 
 
3784
 
  free(ievent);
3785
 
 
3786
 
  g_assert_cmpint(unlink(targetfilename), ==, 0);
3787
 
  g_assert_cmpint(rmdir(targetdir), ==, 0);
3788
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3789
 
}
3790
 
 
3791
 
static
3792
3673
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3793
3674
                                          test_fixture *fixture,
3794
3675
                                          __attribute__((unused))
3852
3733
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3853
3734
}
3854
3735
 
3855
 
static
3856
 
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3857
 
                                               test_fixture *fixture,
3858
 
                                               __attribute__((unused))
3859
 
                                               gconstpointer
3860
 
                                               user_data){
3861
 
  __attribute__((cleanup(cleanup_close)))
3862
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3863
 
  g_assert_cmpint(epoll_fd, >=, 0);
3864
 
  __attribute__((cleanup(cleanup_queue)))
3865
 
    task_queue *queue = create_queue();
3866
 
  g_assert_nonnull(queue);
3867
 
  __attribute__((cleanup(string_set_clear)))
3868
 
    string_set cancelled_filenames = {};
3869
 
  const mono_microsecs current_time = 0;
3870
 
 
3871
 
  bool quit_now = false;
3872
 
  buffer password = {};
3873
 
  bool mandos_client_exited = false;
3874
 
  bool password_is_read = false;
3875
 
 
3876
 
  __attribute__((cleanup(cleanup_string)))
3877
 
    char *tempdir = make_temporary_directory();
3878
 
  g_assert_nonnull(tempdir);
3879
 
 
3880
 
  __attribute__((cleanup(cleanup_string)))
3881
 
    char *tempfile = make_temporary_file_in_directory(tempdir);
3882
 
  g_assert_nonnull(tempfile);
3883
 
  int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3884
 
                         | O_NOFOLLOW);
3885
 
  g_assert_cmpint(tempfile_fd, >, 2);
3886
 
 
3887
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3888
 
                                      &password, tempdir,
3889
 
                                      &cancelled_filenames,
3890
 
                                      &current_time,
3891
 
                                      &mandos_client_exited,
3892
 
                                      &password_is_read));
3893
 
  g_assert_cmpint(unlink(tempfile), ==, 0);
3894
 
 
3895
 
  g_assert_cmpuint((unsigned int)queue->length, >, 0);
3896
 
 
3897
 
  const task_context *const added_read_task
3898
 
    = find_matching_task(queue,
3899
 
                         (task_context){ .func=read_inotify_event });
3900
 
  g_assert_nonnull(added_read_task);
3901
 
 
3902
 
  g_assert_cmpint(added_read_task->fd, >, 2);
3903
 
  g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3904
 
 
3905
 
  /* "sufficient to read at least one event." - inotify(7) */
3906
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3907
 
                              + NAME_MAX + 1);
3908
 
  struct inotify_event *ievent = malloc(ievent_size);
3909
 
  g_assert_nonnull(ievent);
3910
 
 
3911
 
  ssize_t read_size = 0;
3912
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3913
 
 
3914
 
  g_assert_cmpint((int)read_size, >, 0);
3915
 
  g_assert_true(ievent->mask & IN_DELETE);
3916
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3917
 
 
3918
 
  g_assert_cmpint(close(tempfile_fd), ==, 0);
3919
 
 
3920
 
  /* IN_EXCL_UNLINK should make the closing of the previously unlinked
3921
 
     file not appear as an ievent, so we should not see it now. */
3922
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3923
 
  g_assert_cmpint((int)read_size, ==, -1);
3924
 
  g_assert_true(errno == EAGAIN);
3925
 
 
3926
 
  free(ievent);
3927
 
 
3928
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3929
 
}
3930
 
 
3931
3736
static void test_read_inotify_event_readerror(__attribute__((unused))
3932
3737
                                              test_fixture *fixture,
3933
3738
                                              __attribute__((unused))
3939
3744
  const mono_microsecs current_time = 0;
3940
3745
 
3941
3746
  /* Reading /proc/self/mem from offset 0 will always result in EIO */
3942
 
  const int fd = open("/proc/self/mem",
3943
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3747
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3944
3748
 
3945
3749
  bool quit_now = false;
3946
3750
  __attribute__((cleanup(cleanup_queue)))
4125
3929
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4126
3930
                                  + NAME_MAX + 1);
4127
3931
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4128
 
  struct {
4129
 
    struct inotify_event event;
4130
 
    char name_buffer[NAME_MAX + 1];
4131
 
  } ievent_buffer;
4132
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
3932
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
3933
  struct inotify_event *ievent = ((struct inotify_event *)
 
3934
                                  ievent_buffer);
4133
3935
 
4134
3936
  const char dummy_file_name[] = "ask.dummy_file_name";
4135
3937
  ievent->mask = IN_CLOSE_WRITE;
4137
3939
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4138
3940
  const size_t ievent_size = (sizeof(struct inotify_event)
4139
3941
                              + sizeof(dummy_file_name));
4140
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
3942
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4141
3943
                  ==, ievent_size);
4142
3944
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4143
3945
 
4220
4022
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4221
4023
                                  + NAME_MAX + 1);
4222
4024
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4223
 
  struct {
4224
 
    struct inotify_event event;
4225
 
    char name_buffer[NAME_MAX + 1];
4226
 
  } ievent_buffer;
4227
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4025
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4026
  struct inotify_event *ievent = ((struct inotify_event *)
 
4027
                                  ievent_buffer);
4228
4028
 
4229
4029
  const char dummy_file_name[] = "ask.dummy_file_name";
4230
4030
  ievent->mask = IN_MOVED_TO;
4232
4032
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4233
4033
  const size_t ievent_size = (sizeof(struct inotify_event)
4234
4034
                              + sizeof(dummy_file_name));
4235
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4035
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4236
4036
                  ==, ievent_size);
4237
4037
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4238
4038
 
4298
4098
      }));
4299
4099
}
4300
4100
 
4301
 
static
4302
 
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4303
 
                                           test_fixture *fixture,
4304
 
                                           __attribute__((unused))
4305
 
                                           gconstpointer user_data){
4306
 
  __attribute__((cleanup(cleanup_close)))
4307
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4308
 
  g_assert_cmpint(epoll_fd, >=, 0);
4309
 
  __attribute__((cleanup(string_set_clear)))
4310
 
    string_set cancelled_filenames = {};
4311
 
  const mono_microsecs current_time = 0;
4312
 
 
4313
 
  int pipefds[2];
4314
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4315
 
 
4316
 
  /* "sufficient to read at least one event." - inotify(7) */
4317
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4318
 
                                  + NAME_MAX + 1);
4319
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4320
 
  struct {
4321
 
    struct inotify_event event;
4322
 
    char name_buffer[NAME_MAX + 1];
4323
 
  } ievent_buffer;
4324
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4325
 
 
4326
 
  const char dummy_file_name[] = "ask.dummy_file_name";
4327
 
  ievent->mask = IN_MOVED_FROM;
4328
 
  ievent->len = sizeof(dummy_file_name);
4329
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4330
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4331
 
                              + sizeof(dummy_file_name));
4332
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4333
 
                  ==, ievent_size);
4334
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4335
 
 
4336
 
  bool quit_now = false;
4337
 
  buffer password = {};
4338
 
  bool mandos_client_exited = false;
4339
 
  bool password_is_read = false;
4340
 
  __attribute__((cleanup(cleanup_queue)))
4341
 
    task_queue *queue = create_queue();
4342
 
  g_assert_nonnull(queue);
4343
 
 
4344
 
  task_context task = {
4345
 
    .func=read_inotify_event,
4346
 
    .epoll_fd=epoll_fd,
4347
 
    .fd=pipefds[0],
4348
 
    .quit_now=&quit_now,
4349
 
    .password=&password,
4350
 
    .filename=strdup("/nonexistent"),
4351
 
    .cancelled_filenames=&cancelled_filenames,
4352
 
    .current_time=&current_time,
4353
 
    .mandos_client_exited=&mandos_client_exited,
4354
 
    .password_is_read=&password_is_read,
4355
 
  };
4356
 
  task.func(task, queue);
4357
 
  g_assert_false(quit_now);
4358
 
  g_assert_true(queue->next_run == 0);
4359
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4360
 
 
4361
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4362
 
        .func=read_inotify_event,
4363
 
        .epoll_fd=epoll_fd,
4364
 
        .fd=pipefds[0],
4365
 
        .quit_now=&quit_now,
4366
 
        .password=&password,
4367
 
        .filename=task.filename,
4368
 
        .cancelled_filenames=&cancelled_filenames,
4369
 
        .current_time=&current_time,
4370
 
        .mandos_client_exited=&mandos_client_exited,
4371
 
        .password_is_read=&password_is_read,
4372
 
      }));
4373
 
 
4374
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4375
 
                                   EPOLLIN | EPOLLRDHUP));
4376
 
 
4377
 
  __attribute__((cleanup(cleanup_string)))
4378
 
    char *filename = NULL;
4379
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4380
 
                           dummy_file_name), >, 0);
4381
 
  g_assert_nonnull(filename);
4382
 
  g_assert_true(string_set_contains(*task.cancelled_filenames,
4383
 
                                    filename));
4384
 
}
4385
 
 
4386
4101
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4387
4102
                                              test_fixture *fixture,
4388
4103
                                              __attribute__((unused))
4402
4117
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4403
4118
                                  + NAME_MAX + 1);
4404
4119
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4405
 
  struct {
4406
 
    struct inotify_event event;
4407
 
    char name_buffer[NAME_MAX + 1];
4408
 
  } ievent_buffer;
4409
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4120
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4121
  struct inotify_event *ievent = ((struct inotify_event *)
 
4122
                                  ievent_buffer);
4410
4123
 
4411
4124
  const char dummy_file_name[] = "ask.dummy_file_name";
4412
4125
  ievent->mask = IN_DELETE;
4414
4127
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4415
4128
  const size_t ievent_size = (sizeof(struct inotify_event)
4416
4129
                              + sizeof(dummy_file_name));
4417
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4130
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4418
4131
                  ==, ievent_size);
4419
4132
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4420
4133
 
4486
4199
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4487
4200
                                  + NAME_MAX + 1);
4488
4201
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4489
 
  struct {
4490
 
    struct inotify_event event;
4491
 
    char name_buffer[NAME_MAX + 1];
4492
 
  } ievent_buffer;
4493
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4202
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4203
  struct inotify_event *ievent = ((struct inotify_event *)
 
4204
                                  ievent_buffer);
4494
4205
 
4495
4206
  const char dummy_file_name[] = "ignored.dummy_file_name";
4496
4207
  ievent->mask = IN_CLOSE_WRITE;
4498
4209
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4499
4210
  const size_t ievent_size = (sizeof(struct inotify_event)
4500
4211
                              + sizeof(dummy_file_name));
4501
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4212
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4502
4213
                  ==, ievent_size);
4503
4214
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4504
4215
 
4562
4273
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4563
4274
                                  + NAME_MAX + 1);
4564
4275
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4565
 
  struct {
4566
 
    struct inotify_event event;
4567
 
    char name_buffer[NAME_MAX + 1];
4568
 
  } ievent_buffer;
4569
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4276
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4277
  struct inotify_event *ievent = ((struct inotify_event *)
 
4278
                                  ievent_buffer);
4570
4279
 
4571
4280
  const char dummy_file_name[] = "ignored.dummy_file_name";
4572
4281
  ievent->mask = IN_MOVED_TO;
4574
4283
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4575
4284
  const size_t ievent_size = (sizeof(struct inotify_event)
4576
4285
                              + sizeof(dummy_file_name));
4577
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4286
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4578
4287
                  ==, ievent_size);
4579
4288
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4580
4289
 
4621
4330
                                   EPOLLIN | EPOLLRDHUP));
4622
4331
}
4623
4332
 
4624
 
static void
4625
 
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4626
 
                                              test_fixture *fixture,
4627
 
                                              __attribute__((unused))
4628
 
                                              gconstpointer
4629
 
                                              user_data){
4630
 
  __attribute__((cleanup(cleanup_close)))
4631
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4632
 
  g_assert_cmpint(epoll_fd, >=, 0);
4633
 
  __attribute__((cleanup(string_set_clear)))
4634
 
    string_set cancelled_filenames = {};
4635
 
  const mono_microsecs current_time = 0;
4636
 
 
4637
 
  int pipefds[2];
4638
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4639
 
 
4640
 
  /* "sufficient to read at least one event." - inotify(7) */
4641
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4642
 
                                  + NAME_MAX + 1);
4643
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4644
 
  struct {
4645
 
    struct inotify_event event;
4646
 
    char name_buffer[NAME_MAX + 1];
4647
 
  } ievent_buffer;
4648
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4649
 
 
4650
 
  const char dummy_file_name[] = "ignored.dummy_file_name";
4651
 
  ievent->mask = IN_MOVED_FROM;
4652
 
  ievent->len = sizeof(dummy_file_name);
4653
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4654
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4655
 
                              + sizeof(dummy_file_name));
4656
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4657
 
                  ==, ievent_size);
4658
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4659
 
 
4660
 
  bool quit_now = false;
4661
 
  buffer password = {};
4662
 
  bool mandos_client_exited = false;
4663
 
  bool password_is_read = false;
4664
 
  __attribute__((cleanup(cleanup_queue)))
4665
 
    task_queue *queue = create_queue();
4666
 
  g_assert_nonnull(queue);
4667
 
 
4668
 
  task_context task = {
4669
 
    .func=read_inotify_event,
4670
 
    .epoll_fd=epoll_fd,
4671
 
    .fd=pipefds[0],
4672
 
    .quit_now=&quit_now,
4673
 
    .password=&password,
4674
 
    .filename=strdup("/nonexistent"),
4675
 
    .cancelled_filenames=&cancelled_filenames,
4676
 
    .current_time=&current_time,
4677
 
    .mandos_client_exited=&mandos_client_exited,
4678
 
    .password_is_read=&password_is_read,
4679
 
  };
4680
 
  task.func(task, queue);
4681
 
  g_assert_false(quit_now);
4682
 
  g_assert_true(queue->next_run == 0);
4683
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4684
 
 
4685
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4686
 
        .func=read_inotify_event,
4687
 
        .epoll_fd=epoll_fd,
4688
 
        .fd=pipefds[0],
4689
 
        .quit_now=&quit_now,
4690
 
        .password=&password,
4691
 
        .filename=task.filename,
4692
 
        .cancelled_filenames=&cancelled_filenames,
4693
 
        .current_time=&current_time,
4694
 
        .mandos_client_exited=&mandos_client_exited,
4695
 
        .password_is_read=&password_is_read,
4696
 
      }));
4697
 
 
4698
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4699
 
                                   EPOLLIN | EPOLLRDHUP));
4700
 
 
4701
 
  __attribute__((cleanup(cleanup_string)))
4702
 
    char *filename = NULL;
4703
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4704
 
                           dummy_file_name), >, 0);
4705
 
  g_assert_nonnull(filename);
4706
 
  g_assert_false(string_set_contains(cancelled_filenames, filename));
4707
 
}
4708
 
 
4709
4333
static
4710
4334
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4711
4335
                                               test_fixture *fixture,
4726
4350
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4727
4351
                                  + NAME_MAX + 1);
4728
4352
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4729
 
  struct {
4730
 
    struct inotify_event event;
4731
 
    char name_buffer[NAME_MAX + 1];
4732
 
  } ievent_buffer;
4733
 
  struct inotify_event *const ievent = &ievent_buffer.event;
 
4353
  char ievent_buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
 
4354
  struct inotify_event *ievent = ((struct inotify_event *)
 
4355
                                  ievent_buffer);
4734
4356
 
4735
4357
  const char dummy_file_name[] = "ignored.dummy_file_name";
4736
4358
  ievent->mask = IN_DELETE;
4738
4360
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4739
4361
  const size_t ievent_size = (sizeof(struct inotify_event)
4740
4362
                              + sizeof(dummy_file_name));
4741
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4363
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4742
4364
                  ==, ievent_size);
4743
4365
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4744
4366
 
5631
5253
                                            __attribute__((unused))
5632
5254
                                            gconstpointer user_data){
5633
5255
  __attribute__((cleanup(cleanup_close)))
5634
 
    const int epoll_fd = open("/dev/null",
5635
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5256
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
5636
5257
  __attribute__((cleanup(cleanup_string)))
5637
5258
    char *const question_filename = strdup("/nonexistent/question");
5638
5259
  g_assert_nonnull(question_filename);
6042
5663
                                            __attribute__((unused))
6043
5664
                                            gconstpointer user_data){
6044
5665
  __attribute__((cleanup(cleanup_close)))
6045
 
    const int epoll_fd = open("/dev/null",
6046
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5666
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6047
5667
  __attribute__((cleanup(cleanup_string)))
6048
5668
    char *const question_filename = strdup("/nonexistent/question");
6049
5669
  g_assert_nonnull(question_filename);
6312
5932
                                              const char *const
6313
5933
                                              dirname){
6314
5934
  __attribute__((cleanup(cleanup_close)))
6315
 
    const int devnull_fd = open("/dev/null",
6316
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5935
    const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6317
5936
  g_assert_cmpint(devnull_fd, >=, 0);
6318
5937
  __attribute__((cleanup(cleanup_close)))
6319
5938
    const int real_stderr_fd = dup(STDERR_FILENO);
7954
7573
              test_add_inotify_dir_watch);
7955
7574
  test_add_st("/task-creators/add_inotify_dir_watch/fail",
7956
7575
              test_add_inotify_dir_watch_fail);
7957
 
  test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
7958
 
              test_add_inotify_dir_watch_nondir);
7959
7576
  test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
7960
7577
              test_add_inotify_dir_watch_EAGAIN);
7961
7578
  test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
7962
7579
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7963
7580
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7964
7581
              test_add_inotify_dir_watch_IN_MOVED_TO);
7965
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
7966
 
              test_add_inotify_dir_watch_IN_MOVED_FROM);
7967
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
7968
 
              test_add_inotify_dir_watch_IN_EXCL_UNLINK);
7969
7582
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
7970
7583
              test_add_inotify_dir_watch_IN_DELETE);
7971
7584
  test_add_st("/task/read_inotify_event/readerror",
7980
7593
              test_read_inotify_event_IN_CLOSE_WRITE);
7981
7594
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
7982
7595
              test_read_inotify_event_IN_MOVED_TO);
7983
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
7984
 
              test_read_inotify_event_IN_MOVED_FROM);
7985
7596
  test_add_st("/task/read_inotify_event/IN_DELETE",
7986
7597
              test_read_inotify_event_IN_DELETE);
7987
7598
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
7988
7599
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
7989
7600
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
7990
7601
              test_read_inotify_event_IN_MOVED_TO_badname);
7991
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
7992
 
              test_read_inotify_event_IN_MOVED_FROM_badname);
7993
7602
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
7994
7603
              test_read_inotify_event_IN_DELETE_badname);
7995
7604
  test_add_st("/task/open_and_parse_question/ENOENT",