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