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