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