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 *
qemu_file_monitor_test_event_loop(void * opaque G_GNUC_UNUSED)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
qemu_file_monitor_test_handler(int64_t id,QFileMonitorEvent event,const char * filename,void * opaque)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
qemu_file_monitor_test_record_free(QFileMonitorTestRecord * rec)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 *
qemu_file_monitor_test_next_record(QFileMonitorTestData * data,QFileMonitorTestRecord * pushback)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
qemu_file_monitor_test_expect(QFileMonitorTestData * data,int64_t id,QFileMonitorEvent event,const char * filename,bool swapnext)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
test_file_monitor_events(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
main(int argc,char ** argv)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