/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:
2
2
/*
3
3
 * Mandos password agent - Simple password agent to run Mandos client
4
4
 *
5
 
 * Copyright © 2019-2020 Teddy Hogeborn
6
 
 * Copyright © 2019-2020 Björn Påhlsson
 
5
 * Copyright © 2019 Teddy Hogeborn
 
6
 * Copyright © 2019 Björn Påhlsson
7
7
 * 
8
8
 * This file is part of Mandos.
9
9
 * 
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,
868
857
  }
869
858
  close(pipefds[1]);
870
859
 
871
 
  if(pid == -1){
872
 
    error(0, errno, "Failed to fork()");
873
 
    close(pipefds[0]);
874
 
    return false;
875
 
  }
876
 
 
877
860
  if(not add_to_queue(queue, (task_context){
878
861
        .func=wait_for_mandos_client_exit,
879
862
        .pid=pid,
1034
1017
    return false;
1035
1018
  }
1036
1019
 
1037
 
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
1038
 
                       | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK
1039
 
                       | IN_ONLYDIR)
 
1020
  if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE
 
1021
                       | IN_MOVED_TO | IN_DELETE)
1040
1022
     == -1){
1041
1023
    error(0, errno, "Failed to create inotify watch on %s", dir);
1042
1024
    return false;
1089
1071
  /* "sufficient to read at least one event." - inotify(7) */
1090
1072
  const size_t ievent_size = (sizeof(struct inotify_event)
1091
1073
                              + NAME_MAX + 1);
1092
 
  struct {
1093
 
    struct inotify_event event;
1094
 
    char name_buffer[NAME_MAX + 1];
1095
 
  } ievent_buffer;
1096
 
  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);
1097
1077
 
1098
1078
  const ssize_t read_length = read(fd, ievent, ievent_size);
1099
1079
  if(read_length == 0){ /* EOF */
1137
1117
             immediately */
1138
1118
          queue->next_run = 1;
1139
1119
        }
1140
 
      } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
 
1120
      } else if(ievent->mask & IN_DELETE){
1141
1121
        if(not string_set_add(cancelled_filenames,
1142
1122
                              question_filename)){
1143
1123
          error(0, errno, "Could not add question %s to"
1193
1173
  bool *const password_is_read = task.password_is_read;
1194
1174
 
1195
1175
  /* We use the GLib "Key-value file parser" functions to parse the
1196
 
     question file.  See <https://systemd.io/PASSWORD_AGENTS/> for
1197
 
     specification of contents */
 
1176
     question file.  See <https://www.freedesktop.org/wiki/Software
 
1177
     /systemd/PasswordAgents/> for specification of contents */
1198
1178
  __attribute__((nonnull))
1199
1179
    void cleanup_g_key_file(GKeyFile **key_file){
1200
1180
    if(*key_file != NULL){
1490
1470
         not. You may but don't have to include a final NUL byte in
1491
1471
         your message.
1492
1472
 
1493
 
         — <https://systemd.io/PASSWORD_AGENTS/> (Tue, 15 Sep 2020
1494
 
         14:24:20 GMT)
 
1473
         — <https://www.freedesktop.org/wiki/Software/systemd/
 
1474
         PasswordAgents/> (Wed 08 Oct 2014 02:14:28 AM UTC)
1495
1475
      */
1496
1476
      send_buffer[0] = '+';     /* Prefix with "+" */
1497
1477
      /* Always add an extra NUL */
1502
1482
      errno = 0;
1503
1483
      ssize_t ssret = send(fd, send_buffer, send_buffer_length,
1504
1484
                           MSG_NOSIGNAL);
1505
 
      const error_t saved_errno = (ssret < 0) ? errno : 0;
 
1485
      const error_t saved_errno = errno;
1506
1486
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
1507
1487
      explicit_bzero(send_buffer, send_buffer_length);
1508
1488
#else
1526
1506
          /* Retry, below */
1527
1507
          break;
1528
1508
        case EMSGSIZE:
1529
 
          error(0, saved_errno, "Password of size %" PRIuMAX
1530
 
                " is too big", (uintmax_t)password->length);
 
1509
          error(0, 0, "Password of size %" PRIuMAX " is too big",
 
1510
                (uintmax_t)password->length);
1531
1511
#if __GNUC__ < 7
1532
1512
          /* FALLTHROUGH */
1533
1513
#else
1535
1515
#endif
1536
1516
        case 0:
1537
1517
          if(ssret >= 0 and ssret < (ssize_t)send_buffer_length){
1538
 
            error(0, 0, "Password only partially sent to socket %s: %"
1539
 
                  PRIuMAX " out of %" PRIuMAX " bytes sent", filename,
1540
 
                  (uintmax_t)ssret, (uintmax_t)send_buffer_length);
 
1518
            error(0, 0, "Password only partially sent to socket");
1541
1519
          }
1542
1520
#if __GNUC__ < 7
1543
1521
          /* FALLTHROUGH */
1899
1877
  g_assert_true(queue->tasks[0].func == dummy_func);
1900
1878
}
1901
1879
 
1902
 
static void test_add_to_queue_overflow(__attribute__((unused))
1903
 
                                       test_fixture *fixture,
1904
 
                                       __attribute__((unused))
1905
 
                                       gconstpointer user_data){
1906
 
  __attribute__((cleanup(cleanup_queue)))
1907
 
    task_queue *queue = create_queue();
1908
 
  g_assert_nonnull(queue);
1909
 
  g_assert_true(queue->length == 0);
1910
 
  queue->length = SIZE_MAX / sizeof(task_context); /* fake max size */
1911
 
 
1912
 
  FILE *real_stderr = stderr;
1913
 
  FILE *devnull = fopen("/dev/null", "we");
1914
 
  g_assert_nonnull(devnull);
1915
 
  stderr = devnull;
1916
 
  const bool ret = add_to_queue(queue,
1917
 
                                (task_context){ .func=dummy_func });
1918
 
  g_assert_true(errno == ENOMEM);
1919
 
  g_assert_false(ret);
1920
 
  stderr = real_stderr;
1921
 
  g_assert_cmpint(fclose(devnull), ==, 0);
1922
 
  queue->length = 0;            /* Restore real size */
1923
 
}
1924
 
 
1925
1880
static void dummy_func(__attribute__((unused))
1926
1881
                       const task_context task,
1927
1882
                       __attribute__((unused))
2198
2153
    }
2199
2154
    exit(EXIT_SUCCESS);
2200
2155
  }
2201
 
  if(pid == -1){
2202
 
    error(EXIT_FAILURE, errno, "Failed to fork()");
2203
 
  }
2204
 
 
2205
2156
  int status;
2206
2157
  waitpid(pid, &status, 0);
2207
2158
  if(WIFEXITED(status) and (WEXITSTATUS(status) == EXIT_SUCCESS)){
2269
2220
 
2270
2221
  {
2271
2222
    __attribute__((cleanup(cleanup_close)))
2272
 
      const int devnull_fd = open("/dev/null",
2273
 
                                  O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2223
      const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
2274
2224
    g_assert_cmpint(devnull_fd, >=, 0);
2275
2225
    __attribute__((cleanup(cleanup_close)))
2276
2226
      const int real_stderr_fd = dup(STDERR_FILENO);
2300
2250
    {
2301
2251
      __attribute__((cleanup(cleanup_close)))
2302
2252
        const int devnull_fd = open("/dev/null",
2303
 
                                    O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2253
                                    O_WRONLY | O_CLOEXEC);
2304
2254
      g_assert_cmpint(devnull_fd, >=, 0);
2305
2255
      __attribute__((cleanup(cleanup_close)))
2306
2256
        const int real_stderr_fd = dup(STDERR_FILENO);
2951
2901
 
2952
2902
  __attribute__((cleanup(cleanup_close)))
2953
2903
    const int devnull_fd = open("/dev/null",
2954
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
2904
                                O_WRONLY | O_CLOEXEC);
2955
2905
  g_assert_cmpint(devnull_fd, >=, 0);
2956
2906
  __attribute__((cleanup(cleanup_close)))
2957
2907
    const int real_stderr_fd = dup(STDERR_FILENO);
3022
2972
 
3023
2973
  __attribute__((cleanup(cleanup_close)))
3024
2974
    const int devnull_fd = open("/dev/null",
3025
 
                                O_WRONLY | O_CLOEXEC, O_NOCTTY);
 
2975
                                O_WRONLY | O_CLOEXEC);
3026
2976
  g_assert_cmpint(devnull_fd, >=, 0);
3027
2977
  __attribute__((cleanup(cleanup_close)))
3028
2978
    const int real_stderr_fd = dup(STDERR_FILENO);
3066
3016
    buffer password = {};
3067
3017
 
3068
3018
  /* Reading /proc/self/mem from offset 0 will always give EIO */
3069
 
  const int fd = open("/proc/self/mem",
3070
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3019
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3071
3020
 
3072
3021
  bool password_is_read = false;
3073
3022
  bool quit_now = false;
3501
3450
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3502
3451
}
3503
3452
 
3504
 
static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
3505
 
                                              test_fixture *fixture,
3506
 
                                            __attribute__((unused))
3507
 
                                              gconstpointer
3508
 
                                              user_data){
3509
 
  __attribute__((cleanup(cleanup_close)))
3510
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3511
 
  g_assert_cmpint(epoll_fd, >=, 0);
3512
 
  __attribute__((cleanup(cleanup_queue)))
3513
 
    task_queue *queue = create_queue();
3514
 
  g_assert_nonnull(queue);
3515
 
  __attribute__((cleanup(string_set_clear)))
3516
 
    string_set cancelled_filenames = {};
3517
 
  const mono_microsecs current_time = 0;
3518
 
 
3519
 
  bool quit_now = false;
3520
 
  buffer password = {};
3521
 
  bool mandos_client_exited = false;
3522
 
  bool password_is_read = false;
3523
 
 
3524
 
  const char not_a_directory[] = "/dev/tty";
3525
 
 
3526
 
  FILE *real_stderr = stderr;
3527
 
  FILE *devnull = fopen("/dev/null", "we");
3528
 
  g_assert_nonnull(devnull);
3529
 
  stderr = devnull;
3530
 
  g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3531
 
                                       &password, not_a_directory,
3532
 
                                       &cancelled_filenames,
3533
 
                                       &current_time,
3534
 
                                       &mandos_client_exited,
3535
 
                                       &password_is_read));
3536
 
  stderr = real_stderr;
3537
 
  g_assert_cmpint(fclose(devnull), ==, 0);
3538
 
 
3539
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 0);
3540
 
}
3541
 
 
3542
3453
static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
3543
3454
                                              test_fixture *fixture,
3544
3455
                                              __attribute__((unused))
3759
3670
}
3760
3671
 
3761
3672
static
3762
 
void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
3763
 
                                              test_fixture *fixture,
3764
 
                                              __attribute__((unused))
3765
 
                                              gconstpointer
3766
 
                                              user_data){
3767
 
  __attribute__((cleanup(cleanup_close)))
3768
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3769
 
  g_assert_cmpint(epoll_fd, >=, 0);
3770
 
  __attribute__((cleanup(cleanup_queue)))
3771
 
    task_queue *queue = create_queue();
3772
 
  g_assert_nonnull(queue);
3773
 
  __attribute__((cleanup(string_set_clear)))
3774
 
    string_set cancelled_filenames = {};
3775
 
  const mono_microsecs current_time = 0;
3776
 
 
3777
 
  bool quit_now = false;
3778
 
  buffer password = {};
3779
 
  bool mandos_client_exited = false;
3780
 
  bool password_is_read = false;
3781
 
 
3782
 
  __attribute__((cleanup(cleanup_string)))
3783
 
    char *tempdir = make_temporary_directory();
3784
 
  g_assert_nonnull(tempdir);
3785
 
 
3786
 
  __attribute__((cleanup(cleanup_string)))
3787
 
    char *tempfilename = make_temporary_file_in_directory(tempdir);
3788
 
  g_assert_nonnull(tempfilename);
3789
 
 
3790
 
  __attribute__((cleanup(cleanup_string)))
3791
 
    char *targetdir = make_temporary_directory();
3792
 
  g_assert_nonnull(targetdir);
3793
 
 
3794
 
  __attribute__((cleanup(cleanup_string)))
3795
 
    char *targetfilename = NULL;
3796
 
  g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
3797
 
                           basename(tempfilename)), >, 0);
3798
 
  g_assert_nonnull(targetfilename);
3799
 
 
3800
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3801
 
                                      &password, tempdir,
3802
 
                                      &cancelled_filenames,
3803
 
                                      &current_time,
3804
 
                                      &mandos_client_exited,
3805
 
                                      &password_is_read));
3806
 
 
3807
 
  g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
3808
 
 
3809
 
  const task_context *const added_read_task
3810
 
    = find_matching_task(queue,
3811
 
                         (task_context){ .func=read_inotify_event });
3812
 
  g_assert_nonnull(added_read_task);
3813
 
 
3814
 
  /* "sufficient to read at least one event." - inotify(7) */
3815
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3816
 
                              + NAME_MAX + 1);
3817
 
  struct inotify_event *ievent = malloc(ievent_size);
3818
 
  g_assert_nonnull(ievent);
3819
 
 
3820
 
  ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
3821
 
 
3822
 
  g_assert_cmpint((int)read_size, >, 0);
3823
 
  g_assert_true(ievent->mask & IN_MOVED_FROM);
3824
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
3825
 
 
3826
 
  free(ievent);
3827
 
 
3828
 
  g_assert_cmpint(unlink(targetfilename), ==, 0);
3829
 
  g_assert_cmpint(rmdir(targetdir), ==, 0);
3830
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3831
 
}
3832
 
 
3833
 
static
3834
3673
void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
3835
3674
                                          test_fixture *fixture,
3836
3675
                                          __attribute__((unused))
3894
3733
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3895
3734
}
3896
3735
 
3897
 
static
3898
 
void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
3899
 
                                               test_fixture *fixture,
3900
 
                                               __attribute__((unused))
3901
 
                                               gconstpointer
3902
 
                                               user_data){
3903
 
  __attribute__((cleanup(cleanup_close)))
3904
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
3905
 
  g_assert_cmpint(epoll_fd, >=, 0);
3906
 
  __attribute__((cleanup(cleanup_queue)))
3907
 
    task_queue *queue = create_queue();
3908
 
  g_assert_nonnull(queue);
3909
 
  __attribute__((cleanup(string_set_clear)))
3910
 
    string_set cancelled_filenames = {};
3911
 
  const mono_microsecs current_time = 0;
3912
 
 
3913
 
  bool quit_now = false;
3914
 
  buffer password = {};
3915
 
  bool mandos_client_exited = false;
3916
 
  bool password_is_read = false;
3917
 
 
3918
 
  __attribute__((cleanup(cleanup_string)))
3919
 
    char *tempdir = make_temporary_directory();
3920
 
  g_assert_nonnull(tempdir);
3921
 
 
3922
 
  __attribute__((cleanup(cleanup_string)))
3923
 
    char *tempfile = make_temporary_file_in_directory(tempdir);
3924
 
  g_assert_nonnull(tempfile);
3925
 
  int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
3926
 
                         | O_NOFOLLOW);
3927
 
  g_assert_cmpint(tempfile_fd, >, 2);
3928
 
 
3929
 
  g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
3930
 
                                      &password, tempdir,
3931
 
                                      &cancelled_filenames,
3932
 
                                      &current_time,
3933
 
                                      &mandos_client_exited,
3934
 
                                      &password_is_read));
3935
 
  g_assert_cmpint(unlink(tempfile), ==, 0);
3936
 
 
3937
 
  g_assert_cmpuint((unsigned int)queue->length, >, 0);
3938
 
 
3939
 
  const task_context *const added_read_task
3940
 
    = find_matching_task(queue,
3941
 
                         (task_context){ .func=read_inotify_event });
3942
 
  g_assert_nonnull(added_read_task);
3943
 
 
3944
 
  g_assert_cmpint(added_read_task->fd, >, 2);
3945
 
  g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
3946
 
 
3947
 
  /* "sufficient to read at least one event." - inotify(7) */
3948
 
  const size_t ievent_size = (sizeof(struct inotify_event)
3949
 
                              + NAME_MAX + 1);
3950
 
  struct inotify_event *ievent = malloc(ievent_size);
3951
 
  g_assert_nonnull(ievent);
3952
 
 
3953
 
  ssize_t read_size = 0;
3954
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3955
 
 
3956
 
  g_assert_cmpint((int)read_size, >, 0);
3957
 
  g_assert_true(ievent->mask & IN_DELETE);
3958
 
  g_assert_cmpstr(ievent->name, ==, basename(tempfile));
3959
 
 
3960
 
  g_assert_cmpint(close(tempfile_fd), ==, 0);
3961
 
 
3962
 
  /* IN_EXCL_UNLINK should make the closing of the previously unlinked
3963
 
     file not appear as an ievent, so we should not see it now. */
3964
 
  read_size = read(added_read_task->fd, ievent, ievent_size);
3965
 
  g_assert_cmpint((int)read_size, ==, -1);
3966
 
  g_assert_true(errno == EAGAIN);
3967
 
 
3968
 
  free(ievent);
3969
 
 
3970
 
  g_assert_cmpint(rmdir(tempdir), ==, 0);
3971
 
}
3972
 
 
3973
3736
static void test_read_inotify_event_readerror(__attribute__((unused))
3974
3737
                                              test_fixture *fixture,
3975
3738
                                              __attribute__((unused))
3981
3744
  const mono_microsecs current_time = 0;
3982
3745
 
3983
3746
  /* Reading /proc/self/mem from offset 0 will always result in EIO */
3984
 
  const int fd = open("/proc/self/mem",
3985
 
                      O_RDONLY | O_CLOEXEC | O_NOCTTY);
 
3747
  const int fd = open("/proc/self/mem", O_RDONLY | O_CLOEXEC);
3986
3748
 
3987
3749
  bool quit_now = false;
3988
3750
  __attribute__((cleanup(cleanup_queue)))
4167
3929
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4168
3930
                                  + NAME_MAX + 1);
4169
3931
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4170
 
  struct {
4171
 
    struct inotify_event event;
4172
 
    char name_buffer[NAME_MAX + 1];
4173
 
  } ievent_buffer;
4174
 
  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);
4175
3935
 
4176
3936
  const char dummy_file_name[] = "ask.dummy_file_name";
4177
3937
  ievent->mask = IN_CLOSE_WRITE;
4179
3939
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4180
3940
  const size_t ievent_size = (sizeof(struct inotify_event)
4181
3941
                              + sizeof(dummy_file_name));
4182
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
3942
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4183
3943
                  ==, ievent_size);
4184
3944
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4185
3945
 
4262
4022
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4263
4023
                                  + NAME_MAX + 1);
4264
4024
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4265
 
  struct {
4266
 
    struct inotify_event event;
4267
 
    char name_buffer[NAME_MAX + 1];
4268
 
  } ievent_buffer;
4269
 
  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);
4270
4028
 
4271
4029
  const char dummy_file_name[] = "ask.dummy_file_name";
4272
4030
  ievent->mask = IN_MOVED_TO;
4274
4032
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4275
4033
  const size_t ievent_size = (sizeof(struct inotify_event)
4276
4034
                              + sizeof(dummy_file_name));
4277
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4035
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4278
4036
                  ==, ievent_size);
4279
4037
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4280
4038
 
4340
4098
      }));
4341
4099
}
4342
4100
 
4343
 
static
4344
 
void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
4345
 
                                           test_fixture *fixture,
4346
 
                                           __attribute__((unused))
4347
 
                                           gconstpointer user_data){
4348
 
  __attribute__((cleanup(cleanup_close)))
4349
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4350
 
  g_assert_cmpint(epoll_fd, >=, 0);
4351
 
  __attribute__((cleanup(string_set_clear)))
4352
 
    string_set cancelled_filenames = {};
4353
 
  const mono_microsecs current_time = 0;
4354
 
 
4355
 
  int pipefds[2];
4356
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4357
 
 
4358
 
  /* "sufficient to read at least one event." - inotify(7) */
4359
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4360
 
                                  + NAME_MAX + 1);
4361
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4362
 
  struct {
4363
 
    struct inotify_event event;
4364
 
    char name_buffer[NAME_MAX + 1];
4365
 
  } ievent_buffer;
4366
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4367
 
 
4368
 
  const char dummy_file_name[] = "ask.dummy_file_name";
4369
 
  ievent->mask = IN_MOVED_FROM;
4370
 
  ievent->len = sizeof(dummy_file_name);
4371
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4372
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4373
 
                              + sizeof(dummy_file_name));
4374
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4375
 
                  ==, ievent_size);
4376
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4377
 
 
4378
 
  bool quit_now = false;
4379
 
  buffer password = {};
4380
 
  bool mandos_client_exited = false;
4381
 
  bool password_is_read = false;
4382
 
  __attribute__((cleanup(cleanup_queue)))
4383
 
    task_queue *queue = create_queue();
4384
 
  g_assert_nonnull(queue);
4385
 
 
4386
 
  task_context task = {
4387
 
    .func=read_inotify_event,
4388
 
    .epoll_fd=epoll_fd,
4389
 
    .fd=pipefds[0],
4390
 
    .quit_now=&quit_now,
4391
 
    .password=&password,
4392
 
    .filename=strdup("/nonexistent"),
4393
 
    .cancelled_filenames=&cancelled_filenames,
4394
 
    .current_time=&current_time,
4395
 
    .mandos_client_exited=&mandos_client_exited,
4396
 
    .password_is_read=&password_is_read,
4397
 
  };
4398
 
  task.func(task, queue);
4399
 
  g_assert_false(quit_now);
4400
 
  g_assert_true(queue->next_run == 0);
4401
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4402
 
 
4403
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4404
 
        .func=read_inotify_event,
4405
 
        .epoll_fd=epoll_fd,
4406
 
        .fd=pipefds[0],
4407
 
        .quit_now=&quit_now,
4408
 
        .password=&password,
4409
 
        .filename=task.filename,
4410
 
        .cancelled_filenames=&cancelled_filenames,
4411
 
        .current_time=&current_time,
4412
 
        .mandos_client_exited=&mandos_client_exited,
4413
 
        .password_is_read=&password_is_read,
4414
 
      }));
4415
 
 
4416
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4417
 
                                   EPOLLIN | EPOLLRDHUP));
4418
 
 
4419
 
  __attribute__((cleanup(cleanup_string)))
4420
 
    char *filename = NULL;
4421
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4422
 
                           dummy_file_name), >, 0);
4423
 
  g_assert_nonnull(filename);
4424
 
  g_assert_true(string_set_contains(*task.cancelled_filenames,
4425
 
                                    filename));
4426
 
}
4427
 
 
4428
4101
static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
4429
4102
                                              test_fixture *fixture,
4430
4103
                                              __attribute__((unused))
4444
4117
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4445
4118
                                  + NAME_MAX + 1);
4446
4119
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4447
 
  struct {
4448
 
    struct inotify_event event;
4449
 
    char name_buffer[NAME_MAX + 1];
4450
 
  } ievent_buffer;
4451
 
  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);
4452
4123
 
4453
4124
  const char dummy_file_name[] = "ask.dummy_file_name";
4454
4125
  ievent->mask = IN_DELETE;
4456
4127
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4457
4128
  const size_t ievent_size = (sizeof(struct inotify_event)
4458
4129
                              + sizeof(dummy_file_name));
4459
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4130
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4460
4131
                  ==, ievent_size);
4461
4132
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4462
4133
 
4528
4199
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4529
4200
                                  + NAME_MAX + 1);
4530
4201
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4531
 
  struct {
4532
 
    struct inotify_event event;
4533
 
    char name_buffer[NAME_MAX + 1];
4534
 
  } ievent_buffer;
4535
 
  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);
4536
4205
 
4537
4206
  const char dummy_file_name[] = "ignored.dummy_file_name";
4538
4207
  ievent->mask = IN_CLOSE_WRITE;
4540
4209
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4541
4210
  const size_t ievent_size = (sizeof(struct inotify_event)
4542
4211
                              + sizeof(dummy_file_name));
4543
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4212
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4544
4213
                  ==, ievent_size);
4545
4214
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4546
4215
 
4604
4273
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4605
4274
                                  + NAME_MAX + 1);
4606
4275
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4607
 
  struct {
4608
 
    struct inotify_event event;
4609
 
    char name_buffer[NAME_MAX + 1];
4610
 
  } ievent_buffer;
4611
 
  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);
4612
4279
 
4613
4280
  const char dummy_file_name[] = "ignored.dummy_file_name";
4614
4281
  ievent->mask = IN_MOVED_TO;
4616
4283
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4617
4284
  const size_t ievent_size = (sizeof(struct inotify_event)
4618
4285
                              + sizeof(dummy_file_name));
4619
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4286
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4620
4287
                  ==, ievent_size);
4621
4288
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4622
4289
 
4663
4330
                                   EPOLLIN | EPOLLRDHUP));
4664
4331
}
4665
4332
 
4666
 
static void
4667
 
test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
4668
 
                                              test_fixture *fixture,
4669
 
                                              __attribute__((unused))
4670
 
                                              gconstpointer
4671
 
                                              user_data){
4672
 
  __attribute__((cleanup(cleanup_close)))
4673
 
    const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
4674
 
  g_assert_cmpint(epoll_fd, >=, 0);
4675
 
  __attribute__((cleanup(string_set_clear)))
4676
 
    string_set cancelled_filenames = {};
4677
 
  const mono_microsecs current_time = 0;
4678
 
 
4679
 
  int pipefds[2];
4680
 
  g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
4681
 
 
4682
 
  /* "sufficient to read at least one event." - inotify(7) */
4683
 
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4684
 
                                  + NAME_MAX + 1);
4685
 
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4686
 
  struct {
4687
 
    struct inotify_event event;
4688
 
    char name_buffer[NAME_MAX + 1];
4689
 
  } ievent_buffer;
4690
 
  struct inotify_event *const ievent = &ievent_buffer.event;
4691
 
 
4692
 
  const char dummy_file_name[] = "ignored.dummy_file_name";
4693
 
  ievent->mask = IN_MOVED_FROM;
4694
 
  ievent->len = sizeof(dummy_file_name);
4695
 
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4696
 
  const size_t ievent_size = (sizeof(struct inotify_event)
4697
 
                              + sizeof(dummy_file_name));
4698
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
4699
 
                  ==, ievent_size);
4700
 
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4701
 
 
4702
 
  bool quit_now = false;
4703
 
  buffer password = {};
4704
 
  bool mandos_client_exited = false;
4705
 
  bool password_is_read = false;
4706
 
  __attribute__((cleanup(cleanup_queue)))
4707
 
    task_queue *queue = create_queue();
4708
 
  g_assert_nonnull(queue);
4709
 
 
4710
 
  task_context task = {
4711
 
    .func=read_inotify_event,
4712
 
    .epoll_fd=epoll_fd,
4713
 
    .fd=pipefds[0],
4714
 
    .quit_now=&quit_now,
4715
 
    .password=&password,
4716
 
    .filename=strdup("/nonexistent"),
4717
 
    .cancelled_filenames=&cancelled_filenames,
4718
 
    .current_time=&current_time,
4719
 
    .mandos_client_exited=&mandos_client_exited,
4720
 
    .password_is_read=&password_is_read,
4721
 
  };
4722
 
  task.func(task, queue);
4723
 
  g_assert_false(quit_now);
4724
 
  g_assert_true(queue->next_run == 0);
4725
 
  g_assert_cmpuint((unsigned int)queue->length, ==, 1);
4726
 
 
4727
 
  g_assert_nonnull(find_matching_task(queue, (task_context){
4728
 
        .func=read_inotify_event,
4729
 
        .epoll_fd=epoll_fd,
4730
 
        .fd=pipefds[0],
4731
 
        .quit_now=&quit_now,
4732
 
        .password=&password,
4733
 
        .filename=task.filename,
4734
 
        .cancelled_filenames=&cancelled_filenames,
4735
 
        .current_time=&current_time,
4736
 
        .mandos_client_exited=&mandos_client_exited,
4737
 
        .password_is_read=&password_is_read,
4738
 
      }));
4739
 
 
4740
 
  g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
4741
 
                                   EPOLLIN | EPOLLRDHUP));
4742
 
 
4743
 
  __attribute__((cleanup(cleanup_string)))
4744
 
    char *filename = NULL;
4745
 
  g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
4746
 
                           dummy_file_name), >, 0);
4747
 
  g_assert_nonnull(filename);
4748
 
  g_assert_false(string_set_contains(cancelled_filenames, filename));
4749
 
}
4750
 
 
4751
4333
static
4752
4334
void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
4753
4335
                                               test_fixture *fixture,
4768
4350
  const size_t ievent_max_size = (sizeof(struct inotify_event)
4769
4351
                                  + NAME_MAX + 1);
4770
4352
  g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
4771
 
  struct {
4772
 
    struct inotify_event event;
4773
 
    char name_buffer[NAME_MAX + 1];
4774
 
  } ievent_buffer;
4775
 
  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);
4776
4356
 
4777
4357
  const char dummy_file_name[] = "ignored.dummy_file_name";
4778
4358
  ievent->mask = IN_DELETE;
4780
4360
  memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
4781
4361
  const size_t ievent_size = (sizeof(struct inotify_event)
4782
4362
                              + sizeof(dummy_file_name));
4783
 
  g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
 
4363
  g_assert_cmpint(write(pipefds[1], ievent_buffer, ievent_size),
4784
4364
                  ==, ievent_size);
4785
4365
  g_assert_cmpint(close(pipefds[1]), ==, 0);
4786
4366
 
5673
5253
                                            __attribute__((unused))
5674
5254
                                            gconstpointer user_data){
5675
5255
  __attribute__((cleanup(cleanup_close)))
5676
 
    const int epoll_fd = open("/dev/null",
5677
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5256
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
5678
5257
  __attribute__((cleanup(cleanup_string)))
5679
5258
    char *const question_filename = strdup("/nonexistent/question");
5680
5259
  g_assert_nonnull(question_filename);
5809
5388
  char write_data[PIPE_BUF];
5810
5389
  {
5811
5390
    /* Construct test password buffer */
5812
 
    /* Start with + since that is what the real protocol uses */
 
5391
    /* Start with + since that is what the real procotol uses */
5813
5392
    write_data[0] = '+';
5814
5393
    /* Set a special character at string end just to mark the end */
5815
5394
    write_data[sizeof(write_data)-2] = 'y';
5967
5546
  char *const filename = strdup("/nonexistent/socket");
5968
5547
  __attribute__((cleanup(string_set_clear)))
5969
5548
    string_set cancelled_filenames = {};
5970
 
  int socketfds[2];
5971
 
 
5972
 
  /* Find a message size which triggers EMSGSIZE */
5973
 
  __attribute__((cleanup(cleanup_string)))
5974
 
    char *message_buffer = NULL;
5975
 
  size_t message_size = PIPE_BUF + 1;
5976
 
  for(ssize_t ssret = 0; ssret >= 0; message_size += 1024){
5977
 
    if(message_size >= 1024*1024*1024){ /* 1 GiB */
5978
 
      g_test_skip("Skipping EMSGSIZE test: Will not try 1GiB");
5979
 
      return;
5980
 
    }
5981
 
    free(message_buffer);
5982
 
    message_buffer = malloc(message_size);
5983
 
    if(message_buffer == NULL){
5984
 
      g_test_skip("Skipping EMSGSIZE test");
5985
 
      g_test_message("Failed to malloc() %" PRIuMAX " bytes",
5986
 
                     (uintmax_t)message_size);
5987
 
      return;
5988
 
    }
5989
 
    /* Fill buffer with 'x' */
5990
 
    memset(message_buffer, 'x', message_size);
5991
 
    /* Create a new socketpair for each message size to avoid having
5992
 
       to empty the pipe by reading the message to a separate buffer
5993
 
    */
5994
 
    g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
5995
 
                               | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
5996
 
                               socketfds), ==, 0);
5997
 
    ssret = send(socketfds[1], message_buffer, message_size,
5998
 
                 MSG_NOSIGNAL);
5999
 
    error_t saved_errno = errno;
6000
 
    g_assert_cmpint(close(socketfds[0]), ==, 0);
6001
 
    g_assert_cmpint(close(socketfds[1]), ==, 0);
6002
 
 
6003
 
    if(ssret < 0){
6004
 
      if(saved_errno != EMSGSIZE) {
6005
 
        g_test_skip("Skipping EMSGSIZE test");
6006
 
        g_test_message("Error on send(): %s", strerror(saved_errno));
6007
 
        return;
6008
 
      }
6009
 
    } else if(ssret != (ssize_t)message_size){
6010
 
      g_test_skip("Skipping EMSGSIZE test");
6011
 
      g_test_message("Partial send(): %" PRIuMAX " of %" PRIdMAX
6012
 
                     " bytes", (uintmax_t)ssret,
6013
 
                     (intmax_t)message_size);
6014
 
      return;
6015
 
    }
6016
 
  }
6017
 
  g_test_message("EMSGSIZE triggered by %" PRIdMAX " bytes",
6018
 
                 (intmax_t)message_size);
6019
 
 
6020
 
  buffer password = {
6021
 
    .data=message_buffer,
6022
 
    .length=message_size - 2,   /* Compensate for added '+' and NUL */
6023
 
    .allocated=message_size,
 
5549
  const size_t oversized = 1024*1024; /* Limit seems to be 212960 */
 
5550
  __attribute__((cleanup(cleanup_buffer)))
 
5551
    buffer password = {
 
5552
    .data=malloc(oversized),
 
5553
    .length=oversized,
 
5554
    .allocated=oversized,
6024
5555
  };
 
5556
  g_assert_nonnull(password.data);
6025
5557
  if(mlock(password.data, password.allocated) != 0){
6026
5558
    g_assert_true(errno == EPERM or errno == ENOMEM);
6027
5559
  }
 
5560
  /* Construct test password buffer */
 
5561
  /* Start with + since that is what the real procotol uses */
 
5562
  password.data[0] = '+';
 
5563
  /* Set a special character at string end just to mark the end */
 
5564
  password.data[oversized-3] = 'y';
 
5565
  /* Set NUL at buffer end, as suggested by the protocol */
 
5566
  password.data[oversized-2] = '\0';
 
5567
  /* Fill rest of password with 'x' */
 
5568
  memset(password.data+1, 'x', oversized-3);
6028
5569
 
6029
5570
  __attribute__((cleanup(cleanup_queue)))
6030
5571
    task_queue *queue = create_queue();
6031
5572
  g_assert_nonnull(queue);
 
5573
  int socketfds[2];
6032
5574
  g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
6033
5575
                             | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
6034
5576
                             socketfds), ==, 0);
6121
5663
                                            __attribute__((unused))
6122
5664
                                            gconstpointer user_data){
6123
5665
  __attribute__((cleanup(cleanup_close)))
6124
 
    const int epoll_fd = open("/dev/null",
6125
 
                              O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5666
    const int epoll_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6126
5667
  __attribute__((cleanup(cleanup_string)))
6127
5668
    char *const question_filename = strdup("/nonexistent/question");
6128
5669
  g_assert_nonnull(question_filename);
6391
5932
                                              const char *const
6392
5933
                                              dirname){
6393
5934
  __attribute__((cleanup(cleanup_close)))
6394
 
    const int devnull_fd = open("/dev/null",
6395
 
                                O_WRONLY | O_CLOEXEC | O_NOCTTY);
 
5935
    const int devnull_fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
6396
5936
  g_assert_cmpint(devnull_fd, >=, 0);
6397
5937
  __attribute__((cleanup(cleanup_close)))
6398
5938
    const int real_stderr_fd = dup(STDERR_FILENO);
7941
7481
  test_add("/parse_arguments/mixed", test_parse_arguments_mixed);
7942
7482
  test_add("/queue/create", test_create_queue);
7943
7483
  test_add("/queue/add", test_add_to_queue);
7944
 
  test_add("/queue/add/overflow", test_add_to_queue_overflow);
7945
7484
  test_add("/queue/has_question/empty",
7946
7485
           test_queue_has_question_empty);
7947
7486
  test_add("/queue/has_question/false",
8034
7573
              test_add_inotify_dir_watch);
8035
7574
  test_add_st("/task-creators/add_inotify_dir_watch/fail",
8036
7575
              test_add_inotify_dir_watch_fail);
8037
 
  test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
8038
 
              test_add_inotify_dir_watch_nondir);
8039
7576
  test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
8040
7577
              test_add_inotify_dir_watch_EAGAIN);
8041
7578
  test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
8042
7579
              test_add_inotify_dir_watch_IN_CLOSE_WRITE);
8043
7580
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
8044
7581
              test_add_inotify_dir_watch_IN_MOVED_TO);
8045
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
8046
 
              test_add_inotify_dir_watch_IN_MOVED_FROM);
8047
 
  test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
8048
 
              test_add_inotify_dir_watch_IN_EXCL_UNLINK);
8049
7582
  test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
8050
7583
              test_add_inotify_dir_watch_IN_DELETE);
8051
7584
  test_add_st("/task/read_inotify_event/readerror",
8060
7593
              test_read_inotify_event_IN_CLOSE_WRITE);
8061
7594
  test_add_st("/task/read_inotify_event/IN_MOVED_TO",
8062
7595
              test_read_inotify_event_IN_MOVED_TO);
8063
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
8064
 
              test_read_inotify_event_IN_MOVED_FROM);
8065
7596
  test_add_st("/task/read_inotify_event/IN_DELETE",
8066
7597
              test_read_inotify_event_IN_DELETE);
8067
7598
  test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
8068
7599
              test_read_inotify_event_IN_CLOSE_WRITE_badname);
8069
7600
  test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
8070
7601
              test_read_inotify_event_IN_MOVED_TO_badname);
8071
 
  test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
8072
 
              test_read_inotify_event_IN_MOVED_FROM_badname);
8073
7602
  test_add_st("/task/read_inotify_event/IN_DELETE/badname",
8074
7603
              test_read_inotify_event_IN_DELETE_badname);
8075
7604
  test_add_st("/task/open_and_parse_question/ENOENT",
8172
7701
  g_option_context_set_help_enabled(context, FALSE);
8173
7702
  g_option_context_set_ignore_unknown_options(context, TRUE);
8174
7703
 
8175
 
  gboolean should_run_tests = FALSE;
 
7704
  gboolean run_tests = FALSE;
8176
7705
  GOptionEntry entries[] = {
8177
7706
    { "test", 0, 0, G_OPTION_ARG_NONE,
8178
 
      &should_run_tests, "Run tests", NULL },
 
7707
      &run_tests, "Run tests", NULL },
8179
7708
    { NULL }
8180
7709
  };
8181
7710
  g_option_context_add_main_entries(context, entries, NULL);
8188
7717
  }
8189
7718
 
8190
7719
  g_option_context_free(context);
8191
 
  return should_run_tests != FALSE;
 
7720
  return run_tests != FALSE;
8192
7721
}