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 up to 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 #ifdef __FreeBSD__ 364 { .type = QFILE_MONITOR_TEST_OP_EVENT, 365 .filesrc = "two.txt", .watchid = &watch0, 366 .eventid = QFILE_MONITOR_EVENT_DELETED }, 367 { .type = QFILE_MONITOR_TEST_OP_EVENT, 368 .filesrc = "two.txt", .watchid = &watch2, 369 .eventid = QFILE_MONITOR_EVENT_DELETED }, 370 #endif 371 { .type = QFILE_MONITOR_TEST_OP_EVENT, 372 .filesrc = "two.txt", .watchid = &watch0, 373 .eventid = QFILE_MONITOR_EVENT_CREATED }, 374 { .type = QFILE_MONITOR_TEST_OP_EVENT, 375 .filesrc = "two.txt", .watchid = &watch2, 376 .eventid = QFILE_MONITOR_EVENT_CREATED }, 377 378 379 { .type = QFILE_MONITOR_TEST_OP_RMDIR, 380 .filesrc = "fish", }, 381 { .type = QFILE_MONITOR_TEST_OP_EVENT, 382 .filesrc = "", .watchid = &watch4, 383 .eventid = QFILE_MONITOR_EVENT_IGNORED, 384 .swapnext = true }, 385 { .type = QFILE_MONITOR_TEST_OP_EVENT, 386 .filesrc = "fish", .watchid = &watch0, 387 .eventid = QFILE_MONITOR_EVENT_DELETED }, 388 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 389 .filesrc = "fish", .watchid = &watch4 }, 390 391 392 { .type = QFILE_MONITOR_TEST_OP_UNLINK, 393 .filesrc = "two.txt", }, 394 { .type = QFILE_MONITOR_TEST_OP_EVENT, 395 .filesrc = "two.txt", .watchid = &watch0, 396 .eventid = QFILE_MONITOR_EVENT_DELETED }, 397 { .type = QFILE_MONITOR_TEST_OP_EVENT, 398 .filesrc = "two.txt", .watchid = &watch2, 399 .eventid = QFILE_MONITOR_EVENT_DELETED }, 400 401 402 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 403 .filesrc = "two.txt", .watchid = &watch2 }, 404 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 405 .filesrc = NULL, .watchid = &watch0 }, 406 }; 407 Error *local_err = NULL; 408 GError *gerr = NULL; 409 QFileMonitor *mon = qemu_file_monitor_new(&local_err); 410 QemuThread th; 411 GTimer *timer; 412 gchar *dir = NULL; 413 int err = -1; 414 gsize i; 415 char *pathsrc = NULL; 416 char *pathdst = NULL; 417 QFileMonitorTestData data; 418 GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal); 419 char *travis_arch; 420 421 qemu_mutex_init(&data.lock); 422 data.records = NULL; 423 424 /* 425 * This test does not work on Travis LXD containers since some 426 * syscalls are blocked in that environment. 427 */ 428 travis_arch = getenv("TRAVIS_ARCH"); 429 if (travis_arch && !g_str_equal(travis_arch, "x86_64")) { 430 g_test_skip("Test does not work on non-x86 Travis containers."); 431 return; 432 } 433 434 /* 435 * The file monitor needs the main loop running in 436 * order to receive events from inotify. We must 437 * thus spawn a background thread to run an event 438 * loop impl, while this thread triggers the 439 * actual file operations we're testing 440 */ 441 evrunning = 1; 442 evstopping = 0; 443 qemu_thread_create(&th, "event-loop", 444 qemu_file_monitor_test_event_loop, NULL, 445 QEMU_THREAD_JOINABLE); 446 447 if (local_err) { 448 g_printerr("File monitoring not available: %s", 449 error_get_pretty(local_err)); 450 error_free(local_err); 451 return; 452 } 453 454 dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX", 455 &gerr); 456 if (!dir) { 457 g_printerr("Unable to create tmp dir %s", 458 gerr->message); 459 g_error_free(gerr); 460 abort(); 461 } 462 463 /* 464 * Run through the operation sequence validating events 465 * as we go 466 */ 467 for (i = 0; i < G_N_ELEMENTS(ops); i++) { 468 const QFileMonitorTestOp *op = &(ops[i]); 469 int fd; 470 struct utimbuf ubuf; 471 char *watchdir; 472 const char *watchfile; 473 474 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); 475 if (op->filedst) { 476 pathdst = g_strdup_printf("%s/%s", dir, op->filedst); 477 } 478 479 switch (op->type) { 480 case QFILE_MONITOR_TEST_OP_ADD_WATCH: 481 if (debug) { 482 g_printerr("Add watch %s %s\n", 483 dir, op->filesrc); 484 } 485 if (op->filesrc && strchr(op->filesrc, '/')) { 486 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 487 watchfile = strrchr(watchdir, '/'); 488 *(char *)watchfile = '\0'; 489 watchfile++; 490 if (*watchfile == '\0') { 491 watchfile = NULL; 492 } 493 } else { 494 watchdir = g_strdup(dir); 495 watchfile = op->filesrc; 496 } 497 *op->watchid = 498 qemu_file_monitor_add_watch(mon, 499 watchdir, 500 watchfile, 501 qemu_file_monitor_test_handler, 502 &data, 503 &local_err); 504 g_free(watchdir); 505 if (*op->watchid < 0) { 506 g_printerr("Unable to add watch %s", 507 error_get_pretty(local_err)); 508 error_free(local_err); 509 goto cleanup; 510 } 511 if (debug) { 512 g_printerr("Watch ID %" PRIx64 "\n", *op->watchid); 513 } 514 if (g_hash_table_contains(ids, op->watchid)) { 515 g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid); 516 goto cleanup; 517 } 518 g_hash_table_add(ids, op->watchid); 519 break; 520 case QFILE_MONITOR_TEST_OP_DEL_WATCH: 521 if (debug) { 522 g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid); 523 } 524 if (op->filesrc && strchr(op->filesrc, '/')) { 525 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 526 watchfile = strrchr(watchdir, '/'); 527 *(char *)watchfile = '\0'; 528 } else { 529 watchdir = g_strdup(dir); 530 } 531 g_hash_table_remove(ids, op->watchid); 532 qemu_file_monitor_remove_watch(mon, 533 watchdir, 534 *op->watchid); 535 g_free(watchdir); 536 break; 537 case QFILE_MONITOR_TEST_OP_EVENT: 538 if (debug) { 539 g_printerr("Event id=%" PRIx64 " event=%d file=%s\n", 540 *op->watchid, op->eventid, op->filesrc); 541 } 542 if (!qemu_file_monitor_test_expect(&data, *op->watchid, 543 op->eventid, op->filesrc, 544 op->swapnext)) 545 goto cleanup; 546 break; 547 case QFILE_MONITOR_TEST_OP_CREATE: 548 if (debug) { 549 g_printerr("Create %s\n", pathsrc); 550 } 551 fd = open(pathsrc, O_WRONLY | O_CREAT, 0700); 552 if (fd < 0) { 553 g_printerr("Unable to create %s: %s", 554 pathsrc, strerror(errno)); 555 goto cleanup; 556 } 557 close(fd); 558 break; 559 560 case QFILE_MONITOR_TEST_OP_APPEND: 561 if (debug) { 562 g_printerr("Append %s\n", pathsrc); 563 } 564 fd = open(pathsrc, O_WRONLY | O_APPEND, 0700); 565 if (fd < 0) { 566 g_printerr("Unable to open %s: %s", 567 pathsrc, strerror(errno)); 568 goto cleanup; 569 } 570 571 if (write(fd, "Hello World", 10) != 10) { 572 g_printerr("Unable to write %s: %s", 573 pathsrc, strerror(errno)); 574 close(fd); 575 goto cleanup; 576 } 577 close(fd); 578 break; 579 580 case QFILE_MONITOR_TEST_OP_TRUNC: 581 if (debug) { 582 g_printerr("Truncate %s\n", pathsrc); 583 } 584 if (truncate(pathsrc, 4) < 0) { 585 g_printerr("Unable to truncate %s: %s", 586 pathsrc, strerror(errno)); 587 goto cleanup; 588 } 589 break; 590 591 case QFILE_MONITOR_TEST_OP_RENAME: 592 if (debug) { 593 g_printerr("Rename %s -> %s\n", pathsrc, pathdst); 594 } 595 if (rename(pathsrc, pathdst) < 0) { 596 g_printerr("Unable to rename %s to %s: %s", 597 pathsrc, pathdst, strerror(errno)); 598 goto cleanup; 599 } 600 break; 601 602 case QFILE_MONITOR_TEST_OP_UNLINK: 603 if (debug) { 604 g_printerr("Unlink %s\n", pathsrc); 605 } 606 if (unlink(pathsrc) < 0) { 607 g_printerr("Unable to unlink %s: %s", 608 pathsrc, strerror(errno)); 609 goto cleanup; 610 } 611 break; 612 613 case QFILE_MONITOR_TEST_OP_TOUCH: 614 if (debug) { 615 g_printerr("Touch %s\n", pathsrc); 616 } 617 ubuf.actime = 1024; 618 ubuf.modtime = 1025; 619 if (utime(pathsrc, &ubuf) < 0) { 620 g_printerr("Unable to touch %s: %s", 621 pathsrc, strerror(errno)); 622 goto cleanup; 623 } 624 break; 625 626 case QFILE_MONITOR_TEST_OP_MKDIR: 627 if (debug) { 628 g_printerr("Mkdir %s\n", pathsrc); 629 } 630 if (g_mkdir_with_parents(pathsrc, 0700) < 0) { 631 g_printerr("Unable to mkdir %s: %s", 632 pathsrc, strerror(errno)); 633 goto cleanup; 634 } 635 break; 636 637 case QFILE_MONITOR_TEST_OP_RMDIR: 638 if (debug) { 639 g_printerr("Rmdir %s\n", pathsrc); 640 } 641 if (rmdir(pathsrc) < 0) { 642 g_printerr("Unable to rmdir %s: %s", 643 pathsrc, strerror(errno)); 644 goto cleanup; 645 } 646 break; 647 648 default: 649 g_assert_not_reached(); 650 } 651 652 g_free(pathsrc); 653 g_free(pathdst); 654 pathsrc = pathdst = NULL; 655 } 656 657 g_assert_cmpint(g_hash_table_size(ids), ==, 0); 658 659 err = 0; 660 661 cleanup: 662 g_free(pathsrc); 663 g_free(pathdst); 664 665 qemu_mutex_lock(&evlock); 666 evstopping = 1; 667 timer = g_timer_new(); 668 while (evrunning && g_timer_elapsed(timer, NULL) < 5) { 669 qemu_mutex_unlock(&evlock); 670 usleep(10 * 1000); 671 qemu_mutex_lock(&evlock); 672 } 673 qemu_mutex_unlock(&evlock); 674 675 if (g_timer_elapsed(timer, NULL) >= 5) { 676 g_printerr("Event loop failed to quit after 5 seconds\n"); 677 } 678 g_timer_destroy(timer); 679 680 qemu_file_monitor_free(mon); 681 g_list_foreach(data.records, 682 (GFunc)qemu_file_monitor_test_record_free, NULL); 683 g_list_free(data.records); 684 qemu_mutex_destroy(&data.lock); 685 if (dir) { 686 for (i = 0; i < G_N_ELEMENTS(ops); i++) { 687 const QFileMonitorTestOp *op = &(ops[i]); 688 char *path = g_strdup_printf("%s/%s", 689 dir, op->filesrc); 690 if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) { 691 rmdir(path); 692 g_free(path); 693 } else { 694 unlink(path); 695 g_free(path); 696 if (op->filedst) { 697 path = g_strdup_printf("%s/%s", 698 dir, op->filedst); 699 unlink(path); 700 g_free(path); 701 } 702 } 703 } 704 if (rmdir(dir) < 0) { 705 g_printerr("Failed to remove %s: %s\n", 706 dir, strerror(errno)); 707 abort(); 708 } 709 } 710 g_hash_table_unref(ids); 711 g_free(dir); 712 g_assert(err == 0); 713 } 714 715 716 int main(int argc, char **argv) 717 { 718 g_test_init(&argc, &argv, NULL); 719 720 qemu_init_main_loop(&error_abort); 721 722 qemu_mutex_init(&evlock); 723 724 debug = getenv("FILEMONITOR_DEBUG") != NULL; 725 g_test_add_func("/util/filemonitor", test_file_monitor_events); 726 727 return g_test_run(); 728 } 729