/mandos/release

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

« 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
  • mto: This revision was merged to the branch mainline in revision 384.
  • 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
 
                                   ENOMEM, EEXIST, ECHILD, EPERM,
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 */
73
73
                                   ARGP_ERR_UNKNOWN, ARGP_KEY_ARGS,
74
74
                                   struct argp, argp_parse(),
75
75
                                   ARGP_NO_EXIT */
76
 
#include <stdint.h>             /* SIZE_MAX */
77
76
#include <unistd.h>             /* uid_t, gid_t, close(), pipe2(),
78
77
                                   fork(), _exit(), dup2(),
79
78
                                   STDOUT_FILENO, setresgid(),
84
83
#include <sys/mman.h>           /* munlock(), mlock() */
85
84
#include <fcntl.h>              /* O_CLOEXEC, O_NONBLOCK, fcntl(),
86
85
                                   F_GETFD, F_GETFL, FD_CLOEXEC,
87
 
                                   open(), O_WRONLY, O_NOCTTY,
88
 
                                   O_RDONLY, O_NOFOLLOW */
 
86
                                   open(), O_WRONLY, O_RDONLY */
89
87
#include <sys/wait.h>           /* waitpid(), WNOHANG, WIFEXITED(),
90
88
                                   WEXITSTATUS() */
91
89
#include <limits.h>             /* PIPE_BUF, NAME_MAX, INT_MAX */
92
90
#include <sys/inotify.h>        /* inotify_init1(), IN_NONBLOCK,
93
91
                                   IN_CLOEXEC, inotify_add_watch(),
94
92
                                   IN_CLOSE_WRITE, IN_MOVED_TO,
95
 
                                   IN_MOVED_FROM, IN_DELETE,
96
 
                                   IN_EXCL_UNLINK, IN_ONLYDIR,
97
 
                                   struct inotify_event */
 
93
                                   IN_DELETE, struct inotify_event */
98
94
#include <fnmatch.h>            /* fnmatch(), FNM_FILE_NAME */
99
 
#include <stdio.h>              /* asprintf(), FILE, stderr, fopen(),
100
 
                                   fclose(), getline(), sscanf(),
101
 
                                   feof(), ferror(), rename(),
102
 
                                   fdopen(), fprintf(), fscanf() */
 
95
#include <stdio.h>              /* asprintf(), FILE, fopen(),
 
96
                                   getline(), sscanf(), feof(),
 
97
                                   ferror(), fclose(), stderr,
 
98
                                   rename(), fdopen(), fprintf(),
 
99
                                   fscanf() */
103
100
#include <glib.h>    /* GKeyFile, g_key_file_free(), g_key_file_new(),
104
101
                        GError, g_key_file_load_from_file(),
105
102
                        G_KEY_FILE_NONE, TRUE, G_FILE_ERROR_NOENT,
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;
651
647
 
652
648
__attribute__((nonnull, warn_unused_result))
653
649
bool add_to_queue(task_queue *const queue, const task_context task){
654
 
  if((queue->length + 1) > (SIZE_MAX / sizeof(task_context))){
655
 
    /* overflow */
656
 
    error(0, ENOMEM, "Failed to allocate %" PRIuMAX
657
 
          " tasks for queue->tasks", (uintmax_t)(queue->length + 1));
658
 
    errno = ENOMEM;
659
 
    return false;
660
 
  }
661
650
  const size_t needed_size = sizeof(task_context)*(queue->length + 1);
662
651
  if(needed_size > (queue->allocated)){
663
652
    task_context *const new_tasks = realloc(queue->tasks,
1028
1017
    return false;
1029
1018
  }
1030
1019
 
1031
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
1032
 
                       | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK
1033
 
                       | IN_ONLYDIR)
 
1020
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
 
1021
                       | IN_MOVED_TO | IN_DELETE)
1034
1022
     == -1){
1035
1023
    error(0, errno, "Failed to create inotify watch on %s", dir);
1036
1024
    return false;
1083
1071
  /* "sufficient to read at least one event." - inotify(7) */
1084
1072
  const size_t ievent_size = (sizeof(struct inotify_event)
1085
1073
                              + NAME_MAX + 1);
1086
 
  struct {
1087
 
    struct inotify_event event;
1088
 
    char name_buffer[NAME_MAX + 1];
1089
 
  } ievent_buffer;
1090
 
  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);
1091
1077
 
1092
1078
  const ssize_t read_length = read(fd, ievent, ievent_size);
1093
1079
  if(read_length == 0){ /* EOF */
1131
1117
             immediately */
1132
1118
          queue->next_run = 1;
1133
1119
        }
1134
 
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
 
1120
      } else if(ievent->mask & IN_DELETE){
1135
1121
        if(not string_set_add(cancelled_filenames,
1136
1122
                              question_filename)){
1137
1123
          error(0, errno, "Could not add question %s to"
1891
1877
  g_assert_true(queue->tasks[0].func == dummy_func);
1892
1878
}
1893
1879
 
1894
 
static void test_add_to_queue_overflow(__attribute__((unused))
1895
 
                                       test_fixture *fixture,
1896
 
                                       __attribute__((unused))
1897
 
                                       gconstpointer user_data){
1898
 
  __attribute__((cleanup(cleanup_queue)))
1899
 
    task_queue *queue = create_queue();
1900
 
  g_assert_nonnull(queue);
1901
 
  g_assert_true(queue->length == 0);
1902
 
  queue->length = SIZE_MAX / sizeof(task_context); /* fake max size */
1903
 
 
1904
 
  FILE *real_stderr = stderr;
1905
 
  FILE *devnull = fopen("/dev/null", "we");
1906
 
  g_assert_nonnull(devnull);
1907
 
  stderr = devnull;
1908
 
  const bool ret = add_to_queue(queue,
1909
 
                                (task_context){ .func=dummy_func });
1910
 
  g_assert_true(errno == ENOMEM);
1911
 
  g_assert_false(ret);
1912
 
  stderr = real_stderr;
1913
 
  g_assert_cmpint(fclose(devnull), ==, 0);
1914
 
  queue->length = 0;            /* Restore real size */
1915
 
}
1916
 
 
1917
1880
static void dummy_func(__attribute__((unused))
1918
1881
                       const task_context task,
1919
1882
                       __attribute__((unused))
2257
2220
 
2258
2221
  {
2259
2222
    __attribute__((cleanup(cleanup_close)))
2260
 
      const int devnull_fd = open("/dev/null",
2261
 
                                  O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2223
      const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
2262
2224
    g_assert_cmpint(devnull_fd, >=, 0);
2263
2225
    __attribute__((cleanup(cleanup_close)))
2264
2226
      const int real_stderr_fd = dup(STDERR_FILENO);
2288
2250
    {
2289
2251
      __attribute__((cleanup(cleanup_close)))
2290
2252
        const int devnull_fd = open("/dev/null",
2291
 
                                    O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2253
                                    O_WRONLY | O_CLOEXEC);
2292
2254
      g_assert_cmpint(devnull_fd, >=, 0);
2293
2255
      __attribute__((cleanup(cleanup_close)))
2294
2256
        const int real_stderr_fd = dup(STDERR_FILENO);
2939
2901
 
2940
2902
  __attribute__((cleanup(cleanup_close)))
2941
2903
    const int devnull_fd = open("/dev/null",
2942
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2904
                                O_WRONLY | O_CLOEXEC);
2943
2905
  g_assert_cmpint(devnull_fd, >=, 0);
2944
2906
  __attribute__((cleanup(cleanup_close)))
2945
2907
    const int real_stderr_fd = dup(STDERR_FILENO);
3010
2972
 
3011
2973
  __attribute__((cleanup(cleanup_close)))
3012
2974
    const int devnull_fd = open("/dev/null",
3013
 
                                O_WRONLY | O_CLOEXEC, O_NOCTTY);
 
2975
                                O_WRONLY | O_CLOEXEC);
3014
2976
  g_assert_cmpint(devnull_fd, >=, 0);
3015
2977
  __attribute__((cleanup(cleanup_close)))
3016
2978
    const int real_stderr_fd = dup(STDERR_FILENO);
3054
3016
    buffer password = {};
3055
3017
 
3056
3018
  /* Reading /proc/self/mem from offset 0 will always give EIO */
3057
 
  const int fd = open("/proc/self/mem",
3058
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3019
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3059
3020
 
3060
3021
  bool password_is_read = false;
3061
3022
  bool quit_now = false;
3489
3450
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3490
3451
}
3491
3452
 
3492
 
static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
3493
 
                                              test_fixture *fixture,
3494
 
                                            __attribute__((unused))
3495
 
                                              gconstpointer
3496
 
                                              user_data){
3497
 
  __attribute__((cleanup(cleanup_close)))
3498
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3499
 
  g_assert_cmpint(epoll_fd, >=, 0);
3500
 
  __attribute__((cleanup(cleanup_queue)))
3501
 
    task_queue *queue = create_queue();
3502
 
  g_assert_nonnull(queue);
3503
 
  __attribute__((cleanup(string_set_clear)))
3504
 
    string_set cancelled_filenames = {};
3505
 
  const mono_microsecs current_time = 0;
3506
 
 
3507
 
  bool quit_now = false;
3508
 
  buffer password = {};
3509
 
  bool mandos_client_exited = false;
3510
 
  bool password_is_read = false;
3511
 
 
3512
 
  const char not_a_directory[] = "/dev/tty";
3513
 
 
3514
 
  FILE *real_stderr = stderr;
3515
 
  FILE *devnull = fopen("/dev/null", "we");
3516
 
  g_assert_nonnull(devnull);
3517
 
  stderr = devnull;
3518
 
  g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3519
 
                                       &password, not_a_directory,
3520
 
                                       &cancelled_filenames,
3521
 
                                       &current_time,
3522
 
                                       &mandos_client_exited,
3523
 
                                       &password_is_read));
3524
 
  stderr = real_stderr;
3525
 
  g_assert_cmpint(fclose(devnull), ==, 0);
3526
 
 
3527
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3528
 
}
3529
 
 
3530
3453
static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
3531
3454
                                              test_fixture *fixture,
3532
3455
                                              __attribute__((unused))
3747
3670
}
3748
3671
 
3749
3672
static
3750
 
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3751
 
                                              test_fixture *fixture,
3752
 
                                              __attribute__((unused))
3753
 
                                              gconstpointer
3754
 
                                              user_data){
3755
 
  __attribute__((cleanup(cleanup_close)))
3756
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3757
 
  g_assert_cmpint(epoll_fd, >=, 0);
3758
 
  __attribute__((cleanup(cleanup_queue)))
3759
 
    task_queue *queue = create_queue();
3760
 
  g_assert_nonnull(queue);
3761
 
  __attribute__((cleanup(string_set_clear)))
3762
 
    string_set cancelled_filenames = {};
3763
 
  const mono_microsecs current_time = 0;
3764
 
 
3765
 
  bool quit_now = false;
3766
 
  buffer password = {};
3767
 
  bool mandos_client_exited = false;
3768
 
  bool password_is_read = false;
3769
 
 
3770
 
  __attribute__((cleanup(cleanup_string)))
3771
 
    char *tempdir = make_temporary_directory();
3772
 
  g_assert_nonnull(tempdir);
3773
 
 
3774
 
  __attribute__((cleanup(cleanup_string)))
3775
 
    char *tempfilename = make_temporary_file_in_directory(tempdir);
3776
 
  g_assert_nonnull(tempfilename);
3777
 
 
3778
 
  __attribute__((cleanup(cleanup_string)))
3779
 
    char *targetdir = make_temporary_directory();
3780
 
  g_assert_nonnull(targetdir);
3781
 
 
3782
 
  __attribute__((cleanup(cleanup_string)))
3783
 
    char *targetfilename = NULL;
3784
 
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3785
 
                           basename(tempfilename)), >, 0);
3786
 
  g_assert_nonnull(targetfilename);
3787
 
 
3788
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3789
 
                                      &password, tempdir,
3790
 
                                      &cancelled_filenames,
3791
 
                                      &current_time,
3792
 
                                      &mandos_client_exited,
3793
 
                                      &password_is_read));
3794
 
 
3795
 
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3796
 
 
3797
 
  const task_context *const added_read_task
3798
 
    = find_matching_task(queue,
3799
 
                         (task_context){ .func=read_inotify_event });
3800
 
  g_assert_nonnull(added_read_task);
3801
 
 
3802
 
  /* "sufficient to read at least one event." - inotify(7) */
3803
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3804
 
                              + NAME_MAX + 1);
3805
 
  struct inotify_event *ievent = malloc(ievent_size);
3806
 
  g_assert_nonnull(ievent);
3807
 
 
3808
 
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3809
 
 
3810
 
  g_assert_cmpint((int)read_size, >, 0);
3811
 
  g_assert_true(ievent->mask & IN_MOVED_FROM);
3812
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3813
 
 
3814
 
  free(ievent);
3815
 
 
3816
 
  g_assert_cmpint(unlink(targetfilename), ==, 0);
3817
 
  g_assert_cmpint(rmdir(targetdir), ==, 0);
3818
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3819
 
}
3820
 
 
3821
 
static
3822
3673
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3823
3674
                                          test_fixture *fixture,
3824
3675
                                          __attribute__((unused))
3882
3733
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3883
3734
}
3884
3735
 
3885
 
static
3886
 
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3887
 
                                               test_fixture *fixture,
3888
 
                                               __attribute__((unused))
3889
 
                                               gconstpointer
3890
 
                                               user_data){
3891
 
  __attribute__((cleanup(cleanup_close)))
3892
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3893
 
  g_assert_cmpint(epoll_fd, >=, 0);
3894
 
  __attribute__((cleanup(cleanup_queue)))
3895
 
    task_queue *queue = create_queue();
3896
 
  g_assert_nonnull(queue);
3897
 
  __attribute__((cleanup(string_set_clear)))
3898
 
    string_set cancelled_filenames = {};
3899
 
  const mono_microsecs current_time = 0;
3900
 
 
3901
 
  bool quit_now = false;
3902
 
  buffer password = {};
3903
 
  bool mandos_client_exited = false;
3904
 
  bool password_is_read = false;
3905
 
 
3906
 
  __attribute__((cleanup(cleanup_string)))
3907
 
    char *tempdir = make_temporary_directory();
3908
 
  g_assert_nonnull(tempdir);
3909
 
 
3910
 
  __attribute__((cleanup(cleanup_string)))
3911
 
    char *tempfile = make_temporary_file_in_directory(tempdir);
3912
 
  g_assert_nonnull(tempfile);
3913
 
  int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3914
 
                         | O_NOFOLLOW);
3915
 
  g_assert_cmpint(tempfile_fd, >, 2);
3916
 
 
3917
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3918
 
                                      &password, tempdir,
3919
 
                                      &cancelled_filenames,
3920
 
                                      &current_time,
3921
 
                                      &mandos_client_exited,
3922
 
                                      &password_is_read));
3923
 
  g_assert_cmpint(unlink(tempfile), ==, 0);
3924
 
 
3925
 
  g_assert_cmpuint((unsigned int)queue->length, >, 0);
3926
 
 
3927
 
  const task_context *const added_read_task
3928
 
    = find_matching_task(queue,
3929
 
                         (task_context){ .func=read_inotify_event });
3930
 
  g_assert_nonnull(added_read_task);
3931
 
 
3932
 
  g_assert_cmpint(added_read_task->fd, >, 2);
3933
 
  g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3934
 
 
3935
 
  /* "sufficient to read at least one event." - inotify(7) */
3936
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3937
 
                              + NAME_MAX + 1);
3938
 
  struct inotify_event *ievent = malloc(ievent_size);
3939
 
  g_assert_nonnull(ievent);
3940
 
 
3941
 
  ssize_t read_size = 0;
3942
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3943
 
 
3944
 
  g_assert_cmpint((int)read_size, >, 0);
3945
 
  g_assert_true(ievent->mask & IN_DELETE);
3946
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3947
 
 
3948
 
  g_assert_cmpint(close(tempfile_fd), ==, 0);
3949
 
 
3950
 
  /* IN_EXCL_UNLINK should make the closing of the previously unlinked
3951
 
     file not appear as an ievent, so we should not see it now. */
3952
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3953
 
  g_assert_cmpint((int)read_size, ==, -1);
3954
 
  g_assert_true(errno == EAGAIN);
3955
 
 
3956
 
  free(ievent);
3957
 
 
3958
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3959
 
}
3960
 
 
3961
3736
static void test_read_inotify_event_readerror(__attribute__((unused))
3962
3737
                                              test_fixture *fixture,
3963
3738
                                              __attribute__((unused))
3969
3744
  const mono_microsecs current_time = 0;
3970
3745
 
3971
3746
  /* Reading /proc/self/mem from offset 0 will always result in EIO */
3972
 
  const int fd = open("/proc/self/mem",
3973
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3747
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3974
3748
 
3975
3749
  bool quit_now = false;
3976
3750
  __attribute__((cleanup(cleanup_queue)))
4155
3929
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4156
3930
                                  + NAME_MAX + 1);
4157
3931
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4158
 
  struct {
4159
 
    struct inotify_event event;
4160
 
    char name_buffer[NAME_MAX + 1];
4161
 
  } ievent_buffer;
4162
 
  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);
4163
3935
 
4164
3936
  const char dummy_file_name[] = "ask.dummy_file_name";
4165
3937
  ievent->mask = IN_CLOSE_WRITE;
4167
3939
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4168
3940
  const size_t ievent_size = (sizeof(struct inotify_event)
4169
3941
                              + sizeof(dummy_file_name));
4170
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
3942
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4171
3943
                  ==, ievent_size);
4172
3944
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4173
3945
 
4250
4022
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4251
4023
                                  + NAME_MAX + 1);
4252
4024
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4253
 
  struct {
4254
 
    struct inotify_event event;
4255
 
    char name_buffer[NAME_MAX + 1];
4256
 
  } ievent_buffer;
4257
 
  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);
4258
4028
 
4259
4029
  const char dummy_file_name[] = "ask.dummy_file_name";
4260
4030
  ievent->mask = IN_MOVED_TO;
4262
4032
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4263
4033
  const size_t ievent_size = (sizeof(struct inotify_event)
4264
4034
                              + sizeof(dummy_file_name));
4265
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4035
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4266
4036
                  ==, ievent_size);
4267
4037
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4268
4038
 
4328
4098
      }));
4329
4099
}
4330
4100
 
4331
 
static
4332
 
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4333
 
                                           test_fixture *fixture,
4334
 
                                           __attribute__((unused))
4335
 
                                           gconstpointer user_data){
4336
 
  __attribute__((cleanup(cleanup_close)))
4337
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4338
 
  g_assert_cmpint(epoll_fd, >=, 0);
4339
 
  __attribute__((cleanup(string_set_clear)))
4340
 
    string_set cancelled_filenames = {};
4341
 
  const mono_microsecs current_time = 0;
4342
 
 
4343
 
  int pipefds[2];
4344
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4345
 
 
4346
 
  /* "sufficient to read at least one event." - inotify(7) */
4347
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4348
 
                                  + NAME_MAX + 1);
4349
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4350
 
  struct {
4351
 
    struct inotify_event event;
4352
 
    char name_buffer[NAME_MAX + 1];
4353
 
  } ievent_buffer;
4354
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4355
 
 
4356
 
  const char dummy_file_name[] = "ask.dummy_file_name";
4357
 
  ievent->mask = IN_MOVED_FROM;
4358
 
  ievent->len = sizeof(dummy_file_name);
4359
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4360
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4361
 
                              + sizeof(dummy_file_name));
4362
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4363
 
                  ==, ievent_size);
4364
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4365
 
 
4366
 
  bool quit_now = false;
4367
 
  buffer password = {};
4368
 
  bool mandos_client_exited = false;
4369
 
  bool password_is_read = false;
4370
 
  __attribute__((cleanup(cleanup_queue)))
4371
 
    task_queue *queue = create_queue();
4372
 
  g_assert_nonnull(queue);
4373
 
 
4374
 
  task_context task = {
4375
 
    .func=read_inotify_event,
4376
 
    .epoll_fd=epoll_fd,
4377
 
    .fd=pipefds[0],
4378
 
    .quit_now=&quit_now,
4379
 
    .password=&password,
4380
 
    .filename=strdup("/nonexistent"),
4381
 
    .cancelled_filenames=&cancelled_filenames,
4382
 
    .current_time=&current_time,
4383
 
    .mandos_client_exited=&mandos_client_exited,
4384
 
    .password_is_read=&password_is_read,
4385
 
  };
4386
 
  task.func(task, queue);
4387
 
  g_assert_false(quit_now);
4388
 
  g_assert_true(queue->next_run == 0);
4389
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4390
 
 
4391
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4392
 
        .func=read_inotify_event,
4393
 
        .epoll_fd=epoll_fd,
4394
 
        .fd=pipefds[0],
4395
 
        .quit_now=&quit_now,
4396
 
        .password=&password,
4397
 
        .filename=task.filename,
4398
 
        .cancelled_filenames=&cancelled_filenames,
4399
 
        .current_time=&current_time,
4400
 
        .mandos_client_exited=&mandos_client_exited,
4401
 
        .password_is_read=&password_is_read,
4402
 
      }));
4403
 
 
4404
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4405
 
                                   EPOLLIN | EPOLLRDHUP));
4406
 
 
4407
 
  __attribute__((cleanup(cleanup_string)))
4408
 
    char *filename = NULL;
4409
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4410
 
                           dummy_file_name), >, 0);
4411
 
  g_assert_nonnull(filename);
4412
 
  g_assert_true(string_set_contains(*task.cancelled_filenames,
4413
 
                                    filename));
4414
 
}
4415
 
 
4416
4101
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4417
4102
                                              test_fixture *fixture,
4418
4103
                                              __attribute__((unused))
4432
4117
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4433
4118
                                  + NAME_MAX + 1);
4434
4119
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4435
 
  struct {
4436
 
    struct inotify_event event;
4437
 
    char name_buffer[NAME_MAX + 1];
4438
 
  } ievent_buffer;
4439
 
  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);
4440
4123
 
4441
4124
  const char dummy_file_name[] = "ask.dummy_file_name";
4442
4125
  ievent->mask = IN_DELETE;
4444
4127
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4445
4128
  const size_t ievent_size = (sizeof(struct inotify_event)
4446
4129
                              + sizeof(dummy_file_name));
4447
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4130
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4448
4131
                  ==, ievent_size);
4449
4132
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4450
4133
 
4516
4199
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4517
4200
                                  + NAME_MAX + 1);
4518
4201
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4519
 
  struct {
4520
 
    struct inotify_event event;
4521
 
    char name_buffer[NAME_MAX + 1];
4522
 
  } ievent_buffer;
4523
 
  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);
4524
4205
 
4525
4206
  const char dummy_file_name[] = "ignored.dummy_file_name";
4526
4207
  ievent->mask = IN_CLOSE_WRITE;
4528
4209
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4529
4210
  const size_t ievent_size = (sizeof(struct inotify_event)
4530
4211
                              + sizeof(dummy_file_name));
4531
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4212
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4532
4213
                  ==, ievent_size);
4533
4214
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4534
4215
 
4592
4273
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4593
4274
                                  + NAME_MAX + 1);
4594
4275
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4595
 
  struct {
4596
 
    struct inotify_event event;
4597
 
    char name_buffer[NAME_MAX + 1];
4598
 
  } ievent_buffer;
4599
 
  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);
4600
4279
 
4601
4280
  const char dummy_file_name[] = "ignored.dummy_file_name";
4602
4281
  ievent->mask = IN_MOVED_TO;
4604
4283
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4605
4284
  const size_t ievent_size = (sizeof(struct inotify_event)
4606
4285
                              + sizeof(dummy_file_name));
4607
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4286
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4608
4287
                  ==, ievent_size);
4609
4288
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4610
4289
 
4651
4330
                                   EPOLLIN | EPOLLRDHUP));
4652
4331
}
4653
4332
 
4654
 
static void
4655
 
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4656
 
                                              test_fixture *fixture,
4657
 
                                              __attribute__((unused))
4658
 
                                              gconstpointer
4659
 
                                              user_data){
4660
 
  __attribute__((cleanup(cleanup_close)))
4661
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4662
 
  g_assert_cmpint(epoll_fd, >=, 0);
4663
 
  __attribute__((cleanup(string_set_clear)))
4664
 
    string_set cancelled_filenames = {};
4665
 
  const mono_microsecs current_time = 0;
4666
 
 
4667
 
  int pipefds[2];
4668
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4669
 
 
4670
 
  /* "sufficient to read at least one event." - inotify(7) */
4671
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4672
 
                                  + NAME_MAX + 1);
4673
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4674
 
  struct {
4675
 
    struct inotify_event event;
4676
 
    char name_buffer[NAME_MAX + 1];
4677
 
  } ievent_buffer;
4678
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4679
 
 
4680
 
  const char dummy_file_name[] = "ignored.dummy_file_name";
4681
 
  ievent->mask = IN_MOVED_FROM;
4682
 
  ievent->len = sizeof(dummy_file_name);
4683
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4684
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4685
 
                              + sizeof(dummy_file_name));
4686
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4687
 
                  ==, ievent_size);
4688
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4689
 
 
4690
 
  bool quit_now = false;
4691
 
  buffer password = {};
4692
 
  bool mandos_client_exited = false;
4693
 
  bool password_is_read = false;
4694
 
  __attribute__((cleanup(cleanup_queue)))
4695
 
    task_queue *queue = create_queue();
4696
 
  g_assert_nonnull(queue);
4697
 
 
4698
 
  task_context task = {
4699
 
    .func=read_inotify_event,
4700
 
    .epoll_fd=epoll_fd,
4701
 
    .fd=pipefds[0],
4702
 
    .quit_now=&quit_now,
4703
 
    .password=&password,
4704
 
    .filename=strdup("/nonexistent"),
4705
 
    .cancelled_filenames=&cancelled_filenames,
4706
 
    .current_time=&current_time,
4707
 
    .mandos_client_exited=&mandos_client_exited,
4708
 
    .password_is_read=&password_is_read,
4709
 
  };
4710
 
  task.func(task, queue);
4711
 
  g_assert_false(quit_now);
4712
 
  g_assert_true(queue->next_run == 0);
4713
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4714
 
 
4715
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4716
 
        .func=read_inotify_event,
4717
 
        .epoll_fd=epoll_fd,
4718
 
        .fd=pipefds[0],
4719
 
        .quit_now=&quit_now,
4720
 
        .password=&password,
4721
 
        .filename=task.filename,
4722
 
        .cancelled_filenames=&cancelled_filenames,
4723
 
        .current_time=&current_time,
4724
 
        .mandos_client_exited=&mandos_client_exited,
4725
 
        .password_is_read=&password_is_read,
4726
 
      }));
4727
 
 
4728
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4729
 
                                   EPOLLIN | EPOLLRDHUP));
4730
 
 
4731
 
  __attribute__((cleanup(cleanup_string)))
4732
 
    char *filename = NULL;
4733
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4734
 
                           dummy_file_name), >, 0);
4735
 
  g_assert_nonnull(filename);
4736
 
  g_assert_false(string_set_contains(cancelled_filenames, filename));
4737
 
}
4738
 
 
4739
4333
static
4740
4334
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4741
4335
                                               test_fixture *fixture,
4756
4350
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4757
4351
                                  + NAME_MAX + 1);
4758
4352
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4759
 
  struct {
4760
 
    struct inotify_event event;
4761
 
    char name_buffer[NAME_MAX + 1];
4762
 
  } ievent_buffer;
4763
 
  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);
4764
4356
 
4765
4357
  const char dummy_file_name[] = "ignored.dummy_file_name";
4766
4358
  ievent->mask = IN_DELETE;
4768
4360
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4769
4361
  const size_t ievent_size = (sizeof(struct inotify_event)
4770
4362
                              + sizeof(dummy_file_name));
4771
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4363
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4772
4364
                  ==, ievent_size);
4773
4365
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4774
4366
 
5661
5253
                                            __attribute__((unused))
5662
5254
                                            gconstpointer user_data){
5663
5255
  __attribute__((cleanup(cleanup_close)))
5664
 
    const int epoll_fd = open("/dev/null",
5665
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5256
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
5666
5257
  __attribute__((cleanup(cleanup_string)))
5667
5258
    char *const question_filename = strdup("/nonexistent/question");
5668
5259
  g_assert_nonnull(question_filename);
6072
5663
                                            __attribute__((unused))
6073
5664
                                            gconstpointer user_data){
6074
5665
  __attribute__((cleanup(cleanup_close)))
6075
 
    const int epoll_fd = open("/dev/null",
6076
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5666
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6077
5667
  __attribute__((cleanup(cleanup_string)))
6078
5668
    char *const question_filename = strdup("/nonexistent/question");
6079
5669
  g_assert_nonnull(question_filename);
6342
5932
                                              const char *const
6343
5933
                                              dirname){
6344
5934
  __attribute__((cleanup(cleanup_close)))
6345
 
    const int devnull_fd = open("/dev/null",
6346
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5935
    const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6347
5936
  g_assert_cmpint(devnull_fd, >=, 0);
6348
5937
  __attribute__((cleanup(cleanup_close)))
6349
5938
    const int real_stderr_fd = dup(STDERR_FILENO);
7892
7481
  test_add("/parse_arguments/mixed", test_parse_arguments_mixed);
7893
7482
  test_add("/queue/create", test_create_queue);
7894
7483
  test_add("/queue/add", test_add_to_queue);
7895
 
  test_add("/queue/add/overflow", test_add_to_queue_overflow);
7896
7484
  test_add("/queue/has_question/empty",
7897
7485
           test_queue_has_question_empty);
7898
7486
  test_add("/queue/has_question/false",
7985
7573
              test_add_inotify_dir_watch);
7986
7574
  test_add_st("/task-creators/add_inotify_dir_watch/fail",
7987
7575
              test_add_inotify_dir_watch_fail);
7988
 
  test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
7989
 
              test_add_inotify_dir_watch_nondir);
7990
7576
  test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
7991
7577
              test_add_inotify_dir_watch_EAGAIN);
7992
7578
  test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
7993
7579
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
7994
7580
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
7995
7581
              test_add_inotify_dir_watch_IN_MOVED_TO);
7996
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
7997
 
              test_add_inotify_dir_watch_IN_MOVED_FROM);
7998
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
7999
 
              test_add_inotify_dir_watch_IN_EXCL_UNLINK);
8000
7582
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
8001
7583
              test_add_inotify_dir_watch_IN_DELETE);
8002
7584
  test_add_st("/task/read_inotify_event/readerror",
8011
7593
              test_read_inotify_event_IN_CLOSE_WRITE);
8012
7594
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
8013
7595
              test_read_inotify_event_IN_MOVED_TO);
8014
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
8015
 
              test_read_inotify_event_IN_MOVED_FROM);
8016
7596
  test_add_st("/task/read_inotify_event/IN_DELETE",
8017
7597
              test_read_inotify_event_IN_DELETE);
8018
7598
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
8019
7599
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
8020
7600
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
8021
7601
              test_read_inotify_event_IN_MOVED_TO_badname);
8022
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
8023
 
              test_read_inotify_event_IN_MOVED_FROM_badname);
8024
7602
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
8025
7603
              test_read_inotify_event_IN_DELETE_badname);
8026
7604
  test_add_st("/task/open_and_parse_question/ENOENT",
8123
7701
  g_option_context_set_help_enabled(context, FALSE);
8124
7702
  g_option_context_set_ignore_unknown_options(context, TRUE);
8125
7703
 
8126
 
  gboolean should_run_tests = FALSE;
 
7704
  gboolean run_tests = FALSE;
8127
7705
  GOptionEntry entries[] = {
8128
7706
    { "test", 0, 0, G_OPTION_ARG_NONE,
8129
 
      &should_run_tests, "Run tests", NULL },
 
7707
      &run_tests, "Run tests", NULL },
8130
7708
    { NULL }
8131
7709
  };
8132
7710
  g_option_context_add_main_entries(context, entries, NULL);
8139
7717
  }
8140
7718
 
8141
7719
  g_option_context_free(context);
8142
 
  return should_run_tests != FALSE;
 
7720
  return run_tests != FALSE;
8143
7721
}