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 { .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 } 721