qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-util-filemonitor.c (22932B)


      1 /*
      2  * Tests for util/filemonitor-*.c
      3  *
      4  * Copyright 2018 Red Hat, Inc.
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  *
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/main-loop.h"
     23 #include "qapi/error.h"
     24 #include "qemu/filemonitor.h"
     25 
     26 #include <glib/gstdio.h>
     27 
     28 #include <utime.h>
     29 
     30 enum {
     31     QFILE_MONITOR_TEST_OP_ADD_WATCH,
     32     QFILE_MONITOR_TEST_OP_DEL_WATCH,
     33     QFILE_MONITOR_TEST_OP_EVENT,
     34     QFILE_MONITOR_TEST_OP_CREATE,
     35     QFILE_MONITOR_TEST_OP_APPEND,
     36     QFILE_MONITOR_TEST_OP_TRUNC,
     37     QFILE_MONITOR_TEST_OP_RENAME,
     38     QFILE_MONITOR_TEST_OP_TOUCH,
     39     QFILE_MONITOR_TEST_OP_UNLINK,
     40     QFILE_MONITOR_TEST_OP_MKDIR,
     41     QFILE_MONITOR_TEST_OP_RMDIR,
     42 };
     43 
     44 typedef struct {
     45     int type;
     46     const char *filesrc;
     47     const char *filedst;
     48     int64_t *watchid;
     49     int eventid;
     50     /*
     51      * Only valid with OP_EVENT - this event might be
     52      * swapped with the next OP_EVENT
     53      */
     54     bool swapnext;
     55 } QFileMonitorTestOp;
     56 
     57 typedef struct {
     58     int64_t id;
     59     QFileMonitorEvent event;
     60     char *filename;
     61 } QFileMonitorTestRecord;
     62 
     63 
     64 typedef struct {
     65     QemuMutex lock;
     66     GList *records;
     67 } QFileMonitorTestData;
     68 
     69 static QemuMutex evlock;
     70 static bool evstopping;
     71 static bool evrunning;
     72 static bool debug;
     73 
     74 /*
     75  * Main function for a background thread that is
     76  * running the event loop during the test
     77  */
     78 static void *
     79 qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED)
     80 {
     81     qemu_mutex_lock(&evlock);
     82 
     83     while (!evstopping) {
     84         qemu_mutex_unlock(&evlock);
     85         main_loop_wait(true);
     86         qemu_mutex_lock(&evlock);
     87     }
     88 
     89     evrunning = false;
     90     qemu_mutex_unlock(&evlock);
     91     return NULL;
     92 }
     93 
     94 
     95 /*
     96  * File monitor event handler which simply maintains
     97  * an ordered list of all events that it receives
     98  */
     99 static void
    100 qemu_file_monitor_test_handler(int64_t id,
    101                                QFileMonitorEvent event,
    102                                const char *filename,
    103                                void *opaque)
    104 {
    105     QFileMonitorTestData *data = opaque;
    106     QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
    107 
    108     if (debug) {
    109         g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
    110                    id, event, filename);
    111     }
    112     rec->id = id;
    113     rec->event = event;
    114     rec->filename = g_strdup(filename);
    115 
    116     qemu_mutex_lock(&data->lock);
    117     data->records = g_list_append(data->records, rec);
    118     qemu_mutex_unlock(&data->lock);
    119 }
    120 
    121 
    122 static void
    123 qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec)
    124 {
    125     g_free(rec->filename);
    126     g_free(rec);
    127 }
    128 
    129 
    130 /*
    131  * Get the next event record that has been received by
    132  * the file monitor event handler. Since events are
    133  * emitted in the background thread running the event
    134  * loop, we can't assume there is a record available
    135  * immediately. Thus we will sleep for upto 5 seconds
    136  * to wait for the event to be queued for us.
    137  */
    138 static QFileMonitorTestRecord *
    139 qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
    140                                    QFileMonitorTestRecord *pushback)
    141 {
    142     GTimer *timer = g_timer_new();
    143     QFileMonitorTestRecord *record = NULL;
    144     GList *tmp;
    145 
    146     qemu_mutex_lock(&data->lock);
    147     while (!data->records && g_timer_elapsed(timer, NULL) < 5) {
    148         qemu_mutex_unlock(&data->lock);
    149         usleep(10 * 1000);
    150         qemu_mutex_lock(&data->lock);
    151     }
    152     if (data->records) {
    153         record = data->records->data;
    154         if (pushback) {
    155             data->records->data = pushback;
    156         } else {
    157             tmp = data->records;
    158             data->records = g_list_remove_link(data->records, tmp);
    159             g_list_free(tmp);
    160         }
    161     } else if (pushback) {
    162         qemu_file_monitor_test_record_free(pushback);
    163     }
    164     qemu_mutex_unlock(&data->lock);
    165 
    166     g_timer_destroy(timer);
    167     return record;
    168 }
    169 
    170 
    171 /*
    172  * Check whether the event record we retrieved matches
    173  * data we were expecting to see for the event
    174  */
    175 static bool
    176 qemu_file_monitor_test_expect(QFileMonitorTestData *data,
    177                               int64_t id,
    178                               QFileMonitorEvent event,
    179                               const char *filename,
    180                               bool swapnext)
    181 {
    182     QFileMonitorTestRecord *rec;
    183     bool ret = false;
    184 
    185     rec = qemu_file_monitor_test_next_record(data, NULL);
    186 
    187  retry:
    188     if (!rec) {
    189         g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
    190                    id, event, filename);
    191         return false;
    192     }
    193 
    194     if (id != rec->id) {
    195         if (swapnext) {
    196             rec = qemu_file_monitor_test_next_record(data, rec);
    197             swapnext = false;
    198             goto retry;
    199         }
    200         g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
    201                    id, rec->id);
    202         goto cleanup;
    203     }
    204 
    205     if (event != rec->event) {
    206         g_printerr("Expected event %d but got %d\n", event, rec->event);
    207         goto cleanup;
    208     }
    209 
    210     if (!g_str_equal(filename, rec->filename)) {
    211         g_printerr("Expected filename %s but got %s\n",
    212                    filename, rec->filename);
    213         goto cleanup;
    214     }
    215 
    216     ret = true;
    217 
    218  cleanup:
    219     qemu_file_monitor_test_record_free(rec);
    220     return ret;
    221 }
    222 
    223 
    224 static void
    225 test_file_monitor_events(void)
    226 {
    227     int64_t watch0 = 0;
    228     int64_t watch1 = 0;
    229     int64_t watch2 = 0;
    230     int64_t watch3 = 0;
    231     int64_t watch4 = 0;
    232     int64_t watch5 = 0;
    233     QFileMonitorTestOp ops[] = {
    234         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    235           .filesrc = NULL, .watchid = &watch0 },
    236         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    237           .filesrc = "one.txt", .watchid = &watch1 },
    238         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    239           .filesrc = "two.txt", .watchid = &watch2 },
    240 
    241 
    242         { .type = QFILE_MONITOR_TEST_OP_CREATE,
    243           .filesrc = "one.txt", },
    244         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    245           .filesrc = "one.txt", .watchid = &watch0,
    246           .eventid = QFILE_MONITOR_EVENT_CREATED },
    247         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    248           .filesrc = "one.txt", .watchid = &watch1,
    249           .eventid = QFILE_MONITOR_EVENT_CREATED },
    250 
    251 
    252         { .type = QFILE_MONITOR_TEST_OP_CREATE,
    253           .filesrc = "two.txt", },
    254         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    255           .filesrc = "two.txt", .watchid = &watch0,
    256           .eventid = QFILE_MONITOR_EVENT_CREATED },
    257         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    258           .filesrc = "two.txt", .watchid = &watch2,
    259           .eventid = QFILE_MONITOR_EVENT_CREATED },
    260 
    261 
    262         { .type = QFILE_MONITOR_TEST_OP_CREATE,
    263           .filesrc = "three.txt", },
    264         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    265           .filesrc = "three.txt", .watchid = &watch0,
    266           .eventid = QFILE_MONITOR_EVENT_CREATED },
    267 
    268 
    269         { .type = QFILE_MONITOR_TEST_OP_UNLINK,
    270           .filesrc = "three.txt", },
    271         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    272           .filesrc = "three.txt", .watchid = &watch0,
    273           .eventid = QFILE_MONITOR_EVENT_DELETED },
    274 
    275 
    276         { .type = QFILE_MONITOR_TEST_OP_RENAME,
    277           .filesrc = "one.txt", .filedst = "two.txt" },
    278         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    279           .filesrc = "one.txt", .watchid = &watch0,
    280           .eventid = QFILE_MONITOR_EVENT_DELETED },
    281         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    282           .filesrc = "one.txt", .watchid = &watch1,
    283           .eventid = QFILE_MONITOR_EVENT_DELETED },
    284         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    285           .filesrc = "two.txt", .watchid = &watch0,
    286           .eventid = QFILE_MONITOR_EVENT_CREATED },
    287         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    288           .filesrc = "two.txt", .watchid = &watch2,
    289           .eventid = QFILE_MONITOR_EVENT_CREATED },
    290 
    291 
    292         { .type = QFILE_MONITOR_TEST_OP_APPEND,
    293           .filesrc = "two.txt", },
    294         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    295           .filesrc = "two.txt", .watchid = &watch0,
    296           .eventid = QFILE_MONITOR_EVENT_MODIFIED },
    297         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    298           .filesrc = "two.txt", .watchid = &watch2,
    299           .eventid = QFILE_MONITOR_EVENT_MODIFIED },
    300 
    301 
    302         { .type = QFILE_MONITOR_TEST_OP_TOUCH,
    303           .filesrc = "two.txt", },
    304         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    305           .filesrc = "two.txt", .watchid = &watch0,
    306           .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
    307         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    308           .filesrc = "two.txt", .watchid = &watch2,
    309           .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
    310 
    311 
    312         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    313           .filesrc = "one.txt", .watchid = &watch1 },
    314         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    315           .filesrc = "one.txt", .watchid = &watch3 },
    316         { .type = QFILE_MONITOR_TEST_OP_CREATE,
    317           .filesrc = "one.txt", },
    318         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    319           .filesrc = "one.txt", .watchid = &watch0,
    320           .eventid = QFILE_MONITOR_EVENT_CREATED },
    321         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    322           .filesrc = "one.txt", .watchid = &watch3,
    323           .eventid = QFILE_MONITOR_EVENT_CREATED },
    324 
    325 
    326         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    327           .filesrc = "one.txt", .watchid = &watch3 },
    328         { .type = QFILE_MONITOR_TEST_OP_UNLINK,
    329           .filesrc = "one.txt", },
    330         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    331           .filesrc = "one.txt", .watchid = &watch0,
    332           .eventid = QFILE_MONITOR_EVENT_DELETED },
    333 
    334 
    335         { .type = QFILE_MONITOR_TEST_OP_MKDIR,
    336           .filesrc = "fish", },
    337         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    338           .filesrc = "fish", .watchid = &watch0,
    339           .eventid = QFILE_MONITOR_EVENT_CREATED },
    340 
    341 
    342         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    343           .filesrc = "fish/", .watchid = &watch4 },
    344         { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
    345           .filesrc = "fish/one.txt", .watchid = &watch5 },
    346         { .type = QFILE_MONITOR_TEST_OP_CREATE,
    347           .filesrc = "fish/one.txt", },
    348         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    349           .filesrc = "one.txt", .watchid = &watch4,
    350           .eventid = QFILE_MONITOR_EVENT_CREATED },
    351         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    352           .filesrc = "one.txt", .watchid = &watch5,
    353           .eventid = QFILE_MONITOR_EVENT_CREATED },
    354 
    355 
    356         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    357           .filesrc = "fish/one.txt", .watchid = &watch5 },
    358         { .type = QFILE_MONITOR_TEST_OP_RENAME,
    359           .filesrc = "fish/one.txt", .filedst = "two.txt", },
    360         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    361           .filesrc = "one.txt", .watchid = &watch4,
    362           .eventid = QFILE_MONITOR_EVENT_DELETED },
    363         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    364           .filesrc = "two.txt", .watchid = &watch0,
    365           .eventid = QFILE_MONITOR_EVENT_CREATED },
    366         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    367           .filesrc = "two.txt", .watchid = &watch2,
    368           .eventid = QFILE_MONITOR_EVENT_CREATED },
    369 
    370 
    371         { .type = QFILE_MONITOR_TEST_OP_RMDIR,
    372           .filesrc = "fish", },
    373         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    374           .filesrc = "", .watchid = &watch4,
    375           .eventid = QFILE_MONITOR_EVENT_IGNORED,
    376           .swapnext = true },
    377         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    378           .filesrc = "fish", .watchid = &watch0,
    379           .eventid = QFILE_MONITOR_EVENT_DELETED },
    380         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    381           .filesrc = "fish", .watchid = &watch4 },
    382 
    383 
    384         { .type = QFILE_MONITOR_TEST_OP_UNLINK,
    385           .filesrc = "two.txt", },
    386         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    387           .filesrc = "two.txt", .watchid = &watch0,
    388           .eventid = QFILE_MONITOR_EVENT_DELETED },
    389         { .type = QFILE_MONITOR_TEST_OP_EVENT,
    390           .filesrc = "two.txt", .watchid = &watch2,
    391           .eventid = QFILE_MONITOR_EVENT_DELETED },
    392 
    393 
    394         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    395           .filesrc = "two.txt", .watchid = &watch2 },
    396         { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
    397           .filesrc = NULL, .watchid = &watch0 },
    398     };
    399     Error *local_err = NULL;
    400     GError *gerr = NULL;
    401     QFileMonitor *mon = qemu_file_monitor_new(&local_err);
    402     QemuThread th;
    403     GTimer *timer;
    404     gchar *dir = NULL;
    405     int err = -1;
    406     gsize i;
    407     char *pathsrc = NULL;
    408     char *pathdst = NULL;
    409     QFileMonitorTestData data;
    410     GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal);
    411     char *travis_arch;
    412 
    413     qemu_mutex_init(&data.lock);
    414     data.records = NULL;
    415 
    416     /*
    417      * This test does not work on Travis LXD containers since some
    418      * syscalls are blocked in that environment.
    419      */
    420     travis_arch = getenv("TRAVIS_ARCH");
    421     if (travis_arch && !g_str_equal(travis_arch, "x86_64")) {
    422         g_test_skip("Test does not work on non-x86 Travis containers.");
    423         return;
    424     }
    425 
    426     /*
    427      * The file monitor needs the main loop running in
    428      * order to receive events from inotify. We must
    429      * thus spawn a background thread to run an event
    430      * loop impl, while this thread triggers the
    431      * actual file operations we're testing
    432      */
    433     evrunning = 1;
    434     evstopping = 0;
    435     qemu_thread_create(&th, "event-loop",
    436                        qemu_file_monitor_test_event_loop, NULL,
    437                        QEMU_THREAD_JOINABLE);
    438 
    439     if (local_err) {
    440         g_printerr("File monitoring not available: %s",
    441                    error_get_pretty(local_err));
    442         error_free(local_err);
    443         return;
    444     }
    445 
    446     dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX",
    447                          &gerr);
    448     if (!dir) {
    449         g_printerr("Unable to create tmp dir %s",
    450                    gerr->message);
    451         g_error_free(gerr);
    452         abort();
    453     }
    454 
    455     /*
    456      * Run through the operation sequence validating events
    457      * as we go
    458      */
    459     for (i = 0; i < G_N_ELEMENTS(ops); i++) {
    460         const QFileMonitorTestOp *op = &(ops[i]);
    461         int fd;
    462         struct utimbuf ubuf;
    463         char *watchdir;
    464         const char *watchfile;
    465 
    466         pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
    467         if (op->filedst) {
    468             pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
    469         }
    470 
    471         switch (op->type) {
    472         case QFILE_MONITOR_TEST_OP_ADD_WATCH:
    473             if (debug) {
    474                 g_printerr("Add watch %s %s\n",
    475                            dir, op->filesrc);
    476             }
    477             if (op->filesrc && strchr(op->filesrc, '/')) {
    478                 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
    479                 watchfile = strrchr(watchdir, '/');
    480                 *(char *)watchfile = '\0';
    481                 watchfile++;
    482                 if (*watchfile == '\0') {
    483                     watchfile = NULL;
    484                 }
    485             } else {
    486                 watchdir = g_strdup(dir);
    487                 watchfile = op->filesrc;
    488             }
    489             *op->watchid =
    490                 qemu_file_monitor_add_watch(mon,
    491                                             watchdir,
    492                                             watchfile,
    493                                             qemu_file_monitor_test_handler,
    494                                             &data,
    495                                             &local_err);
    496             g_free(watchdir);
    497             if (*op->watchid < 0) {
    498                 g_printerr("Unable to add watch %s",
    499                            error_get_pretty(local_err));
    500                 error_free(local_err);
    501                 goto cleanup;
    502             }
    503             if (debug) {
    504                 g_printerr("Watch ID %" PRIx64 "\n", *op->watchid);
    505             }
    506             if (g_hash_table_contains(ids, op->watchid)) {
    507                 g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid);
    508                 goto cleanup;
    509             }
    510             g_hash_table_add(ids, op->watchid);
    511             break;
    512         case QFILE_MONITOR_TEST_OP_DEL_WATCH:
    513             if (debug) {
    514                 g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid);
    515             }
    516             if (op->filesrc && strchr(op->filesrc, '/')) {
    517                 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
    518                 watchfile = strrchr(watchdir, '/');
    519                 *(char *)watchfile = '\0';
    520             } else {
    521                 watchdir = g_strdup(dir);
    522             }
    523             g_hash_table_remove(ids, op->watchid);
    524             qemu_file_monitor_remove_watch(mon,
    525                                            watchdir,
    526                                            *op->watchid);
    527             g_free(watchdir);
    528             break;
    529         case QFILE_MONITOR_TEST_OP_EVENT:
    530             if (debug) {
    531                 g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
    532                            *op->watchid, op->eventid, op->filesrc);
    533             }
    534             if (!qemu_file_monitor_test_expect(&data, *op->watchid,
    535                                                op->eventid, op->filesrc,
    536                                                op->swapnext))
    537                 goto cleanup;
    538             break;
    539         case QFILE_MONITOR_TEST_OP_CREATE:
    540             if (debug) {
    541                 g_printerr("Create %s\n", pathsrc);
    542             }
    543             fd = open(pathsrc, O_WRONLY | O_CREAT, 0700);
    544             if (fd < 0) {
    545                 g_printerr("Unable to create %s: %s",
    546                            pathsrc, strerror(errno));
    547                 goto cleanup;
    548             }
    549             close(fd);
    550             break;
    551 
    552         case QFILE_MONITOR_TEST_OP_APPEND:
    553             if (debug) {
    554                 g_printerr("Append %s\n", pathsrc);
    555             }
    556             fd = open(pathsrc, O_WRONLY | O_APPEND, 0700);
    557             if (fd < 0) {
    558                 g_printerr("Unable to open %s: %s",
    559                            pathsrc, strerror(errno));
    560                 goto cleanup;
    561             }
    562 
    563             if (write(fd, "Hello World", 10) != 10) {
    564                 g_printerr("Unable to write %s: %s",
    565                            pathsrc, strerror(errno));
    566                 close(fd);
    567                 goto cleanup;
    568             }
    569             close(fd);
    570             break;
    571 
    572         case QFILE_MONITOR_TEST_OP_TRUNC:
    573             if (debug) {
    574                 g_printerr("Truncate %s\n", pathsrc);
    575             }
    576             if (truncate(pathsrc, 4) < 0) {
    577                 g_printerr("Unable to truncate %s: %s",
    578                            pathsrc, strerror(errno));
    579                 goto cleanup;
    580             }
    581             break;
    582 
    583         case QFILE_MONITOR_TEST_OP_RENAME:
    584             if (debug) {
    585                 g_printerr("Rename %s -> %s\n", pathsrc, pathdst);
    586             }
    587             if (rename(pathsrc, pathdst) < 0) {
    588                 g_printerr("Unable to rename %s to %s: %s",
    589                            pathsrc, pathdst, strerror(errno));
    590                 goto cleanup;
    591             }
    592             break;
    593 
    594         case QFILE_MONITOR_TEST_OP_UNLINK:
    595             if (debug) {
    596                 g_printerr("Unlink %s\n", pathsrc);
    597             }
    598             if (unlink(pathsrc) < 0) {
    599                 g_printerr("Unable to unlink %s: %s",
    600                            pathsrc, strerror(errno));
    601                 goto cleanup;
    602             }
    603             break;
    604 
    605         case QFILE_MONITOR_TEST_OP_TOUCH:
    606             if (debug) {
    607                 g_printerr("Touch %s\n", pathsrc);
    608             }
    609             ubuf.actime = 1024;
    610             ubuf.modtime = 1025;
    611             if (utime(pathsrc, &ubuf) < 0) {
    612                 g_printerr("Unable to touch %s: %s",
    613                            pathsrc, strerror(errno));
    614                 goto cleanup;
    615             }
    616             break;
    617 
    618         case QFILE_MONITOR_TEST_OP_MKDIR:
    619             if (debug) {
    620                 g_printerr("Mkdir %s\n", pathsrc);
    621             }
    622             if (g_mkdir_with_parents(pathsrc, 0700) < 0) {
    623                 g_printerr("Unable to mkdir %s: %s",
    624                            pathsrc, strerror(errno));
    625                 goto cleanup;
    626             }
    627             break;
    628 
    629         case QFILE_MONITOR_TEST_OP_RMDIR:
    630             if (debug) {
    631                 g_printerr("Rmdir %s\n", pathsrc);
    632             }
    633             if (rmdir(pathsrc) < 0) {
    634                 g_printerr("Unable to rmdir %s: %s",
    635                            pathsrc, strerror(errno));
    636                 goto cleanup;
    637             }
    638             break;
    639 
    640         default:
    641             g_assert_not_reached();
    642         }
    643 
    644         g_free(pathsrc);
    645         g_free(pathdst);
    646         pathsrc = pathdst = NULL;
    647     }
    648 
    649     g_assert_cmpint(g_hash_table_size(ids), ==, 0);
    650 
    651     err = 0;
    652 
    653  cleanup:
    654     g_free(pathsrc);
    655     g_free(pathdst);
    656 
    657     qemu_mutex_lock(&evlock);
    658     evstopping = 1;
    659     timer = g_timer_new();
    660     while (evrunning && g_timer_elapsed(timer, NULL) < 5) {
    661         qemu_mutex_unlock(&evlock);
    662         usleep(10 * 1000);
    663         qemu_mutex_lock(&evlock);
    664     }
    665     qemu_mutex_unlock(&evlock);
    666 
    667     if (g_timer_elapsed(timer, NULL) >= 5) {
    668         g_printerr("Event loop failed to quit after 5 seconds\n");
    669     }
    670     g_timer_destroy(timer);
    671 
    672     qemu_file_monitor_free(mon);
    673     g_list_foreach(data.records,
    674                    (GFunc)qemu_file_monitor_test_record_free, NULL);
    675     g_list_free(data.records);
    676     qemu_mutex_destroy(&data.lock);
    677     if (dir) {
    678         for (i = 0; i < G_N_ELEMENTS(ops); i++) {
    679             const QFileMonitorTestOp *op = &(ops[i]);
    680             char *path = g_strdup_printf("%s/%s",
    681                                          dir, op->filesrc);
    682             if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) {
    683                 rmdir(path);
    684                 g_free(path);
    685             } else {
    686                 unlink(path);
    687                 g_free(path);
    688                 if (op->filedst) {
    689                     path = g_strdup_printf("%s/%s",
    690                                            dir, op->filedst);
    691                     unlink(path);
    692                     g_free(path);
    693                 }
    694             }
    695         }
    696         if (rmdir(dir) < 0) {
    697             g_printerr("Failed to remove %s: %s\n",
    698                        dir, strerror(errno));
    699             abort();
    700         }
    701     }
    702     g_hash_table_unref(ids);
    703     g_free(dir);
    704     g_assert(err == 0);
    705 }
    706 
    707 
    708 int main(int argc, char **argv)
    709 {
    710     g_test_init(&argc, &argv, NULL);
    711 
    712     qemu_init_main_loop(&error_abort);
    713 
    714     qemu_mutex_init(&evlock);
    715 
    716     debug = getenv("FILEMONITOR_DEBUG") != NULL;
    717     g_test_add_func("/util/filemonitor", test_file_monitor_events);
    718 
    719     return g_test_run();
    720 }