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