cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     30enum {
     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
     44typedef 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
     57typedef struct {
     58    int64_t id;
     59    QFileMonitorEvent event;
     60    char *filename;
     61} QFileMonitorTestRecord;
     62
     63
     64typedef struct {
     65    QemuMutex lock;
     66    GList *records;
     67} QFileMonitorTestData;
     68
     69static QemuMutex evlock;
     70static bool evstopping;
     71static bool evrunning;
     72static bool debug;
     73
     74/*
     75 * Main function for a background thread that is
     76 * running the event loop during the test
     77 */
     78static void *
     79qemu_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 */
     99static void
    100qemu_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
    122static void
    123qemu_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 */
    138static QFileMonitorTestRecord *
    139qemu_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 */
    175static bool
    176qemu_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
    224static void
    225test_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
    708int 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}