]> git.proxmox.com Git - mirror_qemu.git/blame - tests/unit/test-util-filemonitor.c
tests/qtest/libqos/e1000e: Remove "other" interrupts
[mirror_qemu.git] / tests / unit / test-util-filemonitor.c
CommitLineData
90e33dfe
DB
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
0fdc1f2f
YL
26#include <glib/gstdio.h>
27
90e33dfe
DB
28#include <utime.h>
29
30enum {
b26c3f9c
DB
31 QFILE_MONITOR_TEST_OP_ADD_WATCH,
32 QFILE_MONITOR_TEST_OP_DEL_WATCH,
33 QFILE_MONITOR_TEST_OP_EVENT,
90e33dfe
DB
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,
ff3dc8fe
DB
40 QFILE_MONITOR_TEST_OP_MKDIR,
41 QFILE_MONITOR_TEST_OP_RMDIR,
90e33dfe
DB
42};
43
44typedef struct {
45 int type;
46 const char *filesrc;
47 const char *filedst;
b4682a63 48 int64_t *watchid;
b26c3f9c 49 int eventid;
bf9e0313
DB
50 /*
51 * Only valid with OP_EVENT - this event might be
52 * swapped with the next OP_EVENT
53 */
54 bool swapnext;
90e33dfe
DB
55} QFileMonitorTestOp;
56
90e33dfe 57typedef struct {
b4682a63 58 int64_t id;
90e33dfe
DB
59 QFileMonitorEvent event;
60 char *filename;
61} QFileMonitorTestRecord;
62
63
64typedef struct {
65 QemuMutex lock;
66 GList *records;
67} QFileMonitorTestData;
68
69static QemuMutex evlock;
70static bool evstopping;
71static bool evrunning;
b26c3f9c 72static bool debug;
90e33dfe
DB
73
74/*
75 * Main function for a background thread that is
76 * running the event loop during the test
77 */
78static void *
79qemu_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 */
99static void
b4682a63 100qemu_file_monitor_test_handler(int64_t id,
90e33dfe
DB
101 QFileMonitorEvent event,
102 const char *filename,
103 void *opaque)
104{
105 QFileMonitorTestData *data = opaque;
106 QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1);
107
bf9e0313
DB
108 if (debug) {
109 g_printerr("Queue event id %" PRIx64 " event %d file %s\n",
110 id, event, filename);
111 }
90e33dfe
DB
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
122static void
123qemu_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 upto 5 seconds
136 * to wait for the event to be queued for us.
137 */
138static QFileMonitorTestRecord *
bf9e0313
DB
139qemu_file_monitor_test_next_record(QFileMonitorTestData *data,
140 QFileMonitorTestRecord *pushback)
90e33dfe
DB
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;
bf9e0313
DB
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);
90e33dfe
DB
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 */
175static bool
176qemu_file_monitor_test_expect(QFileMonitorTestData *data,
b4682a63 177 int64_t id,
90e33dfe 178 QFileMonitorEvent event,
bf9e0313
DB
179 const char *filename,
180 bool swapnext)
90e33dfe
DB
181{
182 QFileMonitorTestRecord *rec;
183 bool ret = false;
184
bf9e0313 185 rec = qemu_file_monitor_test_next_record(data, NULL);
90e33dfe 186
bf9e0313 187 retry:
90e33dfe 188 if (!rec) {
b4682a63 189 g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n",
90e33dfe
DB
190 id, event, filename);
191 return false;
192 }
193
194 if (id != rec->id) {
bf9e0313
DB
195 if (swapnext) {
196 rec = qemu_file_monitor_test_next_record(data, rec);
197 swapnext = false;
198 goto retry;
199 }
b4682a63
DB
200 g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n",
201 id, rec->id);
90e33dfe
DB
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
224static void
b26c3f9c 225test_file_monitor_events(void)
90e33dfe 226{
b4682a63
DB
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;
b26c3f9c
DB
233 QFileMonitorTestOp ops[] = {
234 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 235 .filesrc = NULL, .watchid = &watch0 },
b26c3f9c 236 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 237 .filesrc = "one.txt", .watchid = &watch1 },
b26c3f9c 238 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 239 .filesrc = "two.txt", .watchid = &watch2 },
b26c3f9c
DB
240
241
242 { .type = QFILE_MONITOR_TEST_OP_CREATE,
243 .filesrc = "one.txt", },
244 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 245 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
246 .eventid = QFILE_MONITOR_EVENT_CREATED },
247 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 248 .filesrc = "one.txt", .watchid = &watch1,
b26c3f9c
DB
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,
b4682a63 255 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
256 .eventid = QFILE_MONITOR_EVENT_CREATED },
257 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 258 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
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,
b4682a63 265 .filesrc = "three.txt", .watchid = &watch0,
b26c3f9c
DB
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,
b4682a63 272 .filesrc = "three.txt", .watchid = &watch0,
b26c3f9c
DB
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,
b4682a63 279 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
280 .eventid = QFILE_MONITOR_EVENT_DELETED },
281 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 282 .filesrc = "one.txt", .watchid = &watch1,
b26c3f9c
DB
283 .eventid = QFILE_MONITOR_EVENT_DELETED },
284 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 285 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
286 .eventid = QFILE_MONITOR_EVENT_CREATED },
287 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 288 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
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,
b4682a63 295 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
296 .eventid = QFILE_MONITOR_EVENT_MODIFIED },
297 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 298 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
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,
b4682a63 305 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
306 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
307 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 308 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
309 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES },
310
311
312 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 313 .filesrc = "one.txt", .watchid = &watch1 },
b26c3f9c 314 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 315 .filesrc = "one.txt", .watchid = &watch3 },
b26c3f9c
DB
316 { .type = QFILE_MONITOR_TEST_OP_CREATE,
317 .filesrc = "one.txt", },
318 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 319 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
320 .eventid = QFILE_MONITOR_EVENT_CREATED },
321 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 322 .filesrc = "one.txt", .watchid = &watch3,
b26c3f9c
DB
323 .eventid = QFILE_MONITOR_EVENT_CREATED },
324
325
326 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 327 .filesrc = "one.txt", .watchid = &watch3 },
b26c3f9c
DB
328 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
329 .filesrc = "one.txt", },
330 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 331 .filesrc = "one.txt", .watchid = &watch0,
b26c3f9c
DB
332 .eventid = QFILE_MONITOR_EVENT_DELETED },
333
334
ff3dc8fe
DB
335 { .type = QFILE_MONITOR_TEST_OP_MKDIR,
336 .filesrc = "fish", },
337 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 338 .filesrc = "fish", .watchid = &watch0,
ff3dc8fe
DB
339 .eventid = QFILE_MONITOR_EVENT_CREATED },
340
341
342 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 343 .filesrc = "fish/", .watchid = &watch4 },
ff3dc8fe 344 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH,
b4682a63 345 .filesrc = "fish/one.txt", .watchid = &watch5 },
ff3dc8fe
DB
346 { .type = QFILE_MONITOR_TEST_OP_CREATE,
347 .filesrc = "fish/one.txt", },
348 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 349 .filesrc = "one.txt", .watchid = &watch4,
ff3dc8fe
DB
350 .eventid = QFILE_MONITOR_EVENT_CREATED },
351 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 352 .filesrc = "one.txt", .watchid = &watch5,
ff3dc8fe
DB
353 .eventid = QFILE_MONITOR_EVENT_CREATED },
354
355
356 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 357 .filesrc = "fish/one.txt", .watchid = &watch5 },
ff3dc8fe
DB
358 { .type = QFILE_MONITOR_TEST_OP_RENAME,
359 .filesrc = "fish/one.txt", .filedst = "two.txt", },
360 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 361 .filesrc = "one.txt", .watchid = &watch4,
ff3dc8fe
DB
362 .eventid = QFILE_MONITOR_EVENT_DELETED },
363 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 364 .filesrc = "two.txt", .watchid = &watch0,
ff3dc8fe
DB
365 .eventid = QFILE_MONITOR_EVENT_CREATED },
366 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 367 .filesrc = "two.txt", .watchid = &watch2,
ff3dc8fe
DB
368 .eventid = QFILE_MONITOR_EVENT_CREATED },
369
370
371 { .type = QFILE_MONITOR_TEST_OP_RMDIR,
372 .filesrc = "fish", },
373 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 374 .filesrc = "", .watchid = &watch4,
bf9e0313
DB
375 .eventid = QFILE_MONITOR_EVENT_IGNORED,
376 .swapnext = true },
ff3dc8fe 377 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 378 .filesrc = "fish", .watchid = &watch0,
ff3dc8fe
DB
379 .eventid = QFILE_MONITOR_EVENT_DELETED },
380 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 381 .filesrc = "fish", .watchid = &watch4 },
ff3dc8fe
DB
382
383
b26c3f9c
DB
384 { .type = QFILE_MONITOR_TEST_OP_UNLINK,
385 .filesrc = "two.txt", },
386 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 387 .filesrc = "two.txt", .watchid = &watch0,
b26c3f9c
DB
388 .eventid = QFILE_MONITOR_EVENT_DELETED },
389 { .type = QFILE_MONITOR_TEST_OP_EVENT,
b4682a63 390 .filesrc = "two.txt", .watchid = &watch2,
b26c3f9c
DB
391 .eventid = QFILE_MONITOR_EVENT_DELETED },
392
393
394 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 395 .filesrc = "two.txt", .watchid = &watch2 },
b26c3f9c 396 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH,
b4682a63 397 .filesrc = NULL, .watchid = &watch0 },
b26c3f9c 398 };
90e33dfe
DB
399 Error *local_err = NULL;
400 GError *gerr = NULL;
401 QFileMonitor *mon = qemu_file_monitor_new(&local_err);
402 QemuThread th;
403 GTimer *timer;
404 gchar *dir = NULL;
405 int err = -1;
b26c3f9c 406 gsize i;
90e33dfe
DB
407 char *pathsrc = NULL;
408 char *pathdst = NULL;
409 QFileMonitorTestData data;
b4682a63 410 GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal);
4f370b10 411 char *travis_arch;
90e33dfe
DB
412
413 qemu_mutex_init(&data.lock);
414 data.records = NULL;
415
4f370b10
TH
416 /*
417 * This test does not work on Travis LXD containers since some
418 * syscalls are blocked in that environment.
419 */
420 travis_arch = getenv("TRAVIS_ARCH");
421 if (travis_arch && !g_str_equal(travis_arch, "x86_64")) {
422 g_test_skip("Test does not work on non-x86 Travis containers.");
423 return;
424 }
425
90e33dfe
DB
426 /*
427 * The file monitor needs the main loop running in
428 * order to receive events from inotify. We must
429 * thus spawn a background thread to run an event
430 * loop impl, while this thread triggers the
431 * actual file operations we're testing
432 */
433 evrunning = 1;
434 evstopping = 0;
435 qemu_thread_create(&th, "event-loop",
436 qemu_file_monitor_test_event_loop, NULL,
437 QEMU_THREAD_JOINABLE);
438
439 if (local_err) {
440 g_printerr("File monitoring not available: %s",
441 error_get_pretty(local_err));
442 error_free(local_err);
443 return;
444 }
445
446 dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX",
447 &gerr);
448 if (!dir) {
449 g_printerr("Unable to create tmp dir %s",
450 gerr->message);
451 g_error_free(gerr);
452 abort();
453 }
454
455 /*
b26c3f9c
DB
456 * Run through the operation sequence validating events
457 * as we go
90e33dfe 458 */
b26c3f9c
DB
459 for (i = 0; i < G_N_ELEMENTS(ops); i++) {
460 const QFileMonitorTestOp *op = &(ops[i]);
90e33dfe
DB
461 int fd;
462 struct utimbuf ubuf;
ff3dc8fe
DB
463 char *watchdir;
464 const char *watchfile;
90e33dfe
DB
465
466 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc);
467 if (op->filedst) {
468 pathdst = g_strdup_printf("%s/%s", dir, op->filedst);
469 }
470
471 switch (op->type) {
b26c3f9c
DB
472 case QFILE_MONITOR_TEST_OP_ADD_WATCH:
473 if (debug) {
b4682a63
DB
474 g_printerr("Add watch %s %s\n",
475 dir, op->filesrc);
b26c3f9c 476 }
ff3dc8fe
DB
477 if (op->filesrc && strchr(op->filesrc, '/')) {
478 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
479 watchfile = strrchr(watchdir, '/');
480 *(char *)watchfile = '\0';
481 watchfile++;
482 if (*watchfile == '\0') {
483 watchfile = NULL;
484 }
485 } else {
486 watchdir = g_strdup(dir);
487 watchfile = op->filesrc;
488 }
b4682a63 489 *op->watchid =
b26c3f9c 490 qemu_file_monitor_add_watch(mon,
ff3dc8fe
DB
491 watchdir,
492 watchfile,
b26c3f9c
DB
493 qemu_file_monitor_test_handler,
494 &data,
495 &local_err);
ff3dc8fe 496 g_free(watchdir);
b4682a63 497 if (*op->watchid < 0) {
b26c3f9c
DB
498 g_printerr("Unable to add watch %s",
499 error_get_pretty(local_err));
05584d12 500 error_free(local_err);
b26c3f9c
DB
501 goto cleanup;
502 }
b4682a63
DB
503 if (debug) {
504 g_printerr("Watch ID %" PRIx64 "\n", *op->watchid);
505 }
506 if (g_hash_table_contains(ids, op->watchid)) {
507 g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid);
b26c3f9c
DB
508 goto cleanup;
509 }
b4682a63 510 g_hash_table_add(ids, op->watchid);
b26c3f9c
DB
511 break;
512 case QFILE_MONITOR_TEST_OP_DEL_WATCH:
513 if (debug) {
b4682a63 514 g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid);
b26c3f9c 515 }
ff3dc8fe
DB
516 if (op->filesrc && strchr(op->filesrc, '/')) {
517 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc);
518 watchfile = strrchr(watchdir, '/');
519 *(char *)watchfile = '\0';
520 } else {
521 watchdir = g_strdup(dir);
522 }
b4682a63 523 g_hash_table_remove(ids, op->watchid);
b26c3f9c 524 qemu_file_monitor_remove_watch(mon,
ff3dc8fe 525 watchdir,
b4682a63 526 *op->watchid);
ff3dc8fe 527 g_free(watchdir);
b26c3f9c
DB
528 break;
529 case QFILE_MONITOR_TEST_OP_EVENT:
530 if (debug) {
b4682a63
DB
531 g_printerr("Event id=%" PRIx64 " event=%d file=%s\n",
532 *op->watchid, op->eventid, op->filesrc);
b26c3f9c 533 }
bf9e0313
DB
534 if (!qemu_file_monitor_test_expect(&data, *op->watchid,
535 op->eventid, op->filesrc,
536 op->swapnext))
b26c3f9c
DB
537 goto cleanup;
538 break;
90e33dfe 539 case QFILE_MONITOR_TEST_OP_CREATE:
b26c3f9c
DB
540 if (debug) {
541 g_printerr("Create %s\n", pathsrc);
542 }
90e33dfe
DB
543 fd = open(pathsrc, O_WRONLY | O_CREAT, 0700);
544 if (fd < 0) {
545 g_printerr("Unable to create %s: %s",
546 pathsrc, strerror(errno));
547 goto cleanup;
548 }
549 close(fd);
550 break;
551
552 case QFILE_MONITOR_TEST_OP_APPEND:
b26c3f9c
DB
553 if (debug) {
554 g_printerr("Append %s\n", pathsrc);
555 }
90e33dfe
DB
556 fd = open(pathsrc, O_WRONLY | O_APPEND, 0700);
557 if (fd < 0) {
558 g_printerr("Unable to open %s: %s",
559 pathsrc, strerror(errno));
560 goto cleanup;
561 }
562
563 if (write(fd, "Hello World", 10) != 10) {
564 g_printerr("Unable to write %s: %s",
565 pathsrc, strerror(errno));
566 close(fd);
567 goto cleanup;
568 }
569 close(fd);
570 break;
571
572 case QFILE_MONITOR_TEST_OP_TRUNC:
b26c3f9c
DB
573 if (debug) {
574 g_printerr("Truncate %s\n", pathsrc);
575 }
90e33dfe
DB
576 if (truncate(pathsrc, 4) < 0) {
577 g_printerr("Unable to truncate %s: %s",
578 pathsrc, strerror(errno));
579 goto cleanup;
580 }
581 break;
582
583 case QFILE_MONITOR_TEST_OP_RENAME:
b26c3f9c
DB
584 if (debug) {
585 g_printerr("Rename %s -> %s\n", pathsrc, pathdst);
586 }
90e33dfe
DB
587 if (rename(pathsrc, pathdst) < 0) {
588 g_printerr("Unable to rename %s to %s: %s",
589 pathsrc, pathdst, strerror(errno));
590 goto cleanup;
591 }
592 break;
593
594 case QFILE_MONITOR_TEST_OP_UNLINK:
b26c3f9c
DB
595 if (debug) {
596 g_printerr("Unlink %s\n", pathsrc);
597 }
90e33dfe
DB
598 if (unlink(pathsrc) < 0) {
599 g_printerr("Unable to unlink %s: %s",
600 pathsrc, strerror(errno));
601 goto cleanup;
602 }
603 break;
604
605 case QFILE_MONITOR_TEST_OP_TOUCH:
b26c3f9c
DB
606 if (debug) {
607 g_printerr("Touch %s\n", pathsrc);
608 }
90e33dfe
DB
609 ubuf.actime = 1024;
610 ubuf.modtime = 1025;
611 if (utime(pathsrc, &ubuf) < 0) {
612 g_printerr("Unable to touch %s: %s",
613 pathsrc, strerror(errno));
614 goto cleanup;
615 }
616 break;
617
ff3dc8fe
DB
618 case QFILE_MONITOR_TEST_OP_MKDIR:
619 if (debug) {
620 g_printerr("Mkdir %s\n", pathsrc);
621 }
0fdc1f2f 622 if (g_mkdir_with_parents(pathsrc, 0700) < 0) {
ff3dc8fe
DB
623 g_printerr("Unable to mkdir %s: %s",
624 pathsrc, strerror(errno));
625 goto cleanup;
626 }
627 break;
628
629 case QFILE_MONITOR_TEST_OP_RMDIR:
630 if (debug) {
631 g_printerr("Rmdir %s\n", pathsrc);
632 }
633 if (rmdir(pathsrc) < 0) {
634 g_printerr("Unable to rmdir %s: %s",
635 pathsrc, strerror(errno));
636 goto cleanup;
637 }
638 break;
639
90e33dfe
DB
640 default:
641 g_assert_not_reached();
642 }
643
644 g_free(pathsrc);
645 g_free(pathdst);
646 pathsrc = pathdst = NULL;
647 }
648
b4682a63
DB
649 g_assert_cmpint(g_hash_table_size(ids), ==, 0);
650
90e33dfe
DB
651 err = 0;
652
653 cleanup:
654 g_free(pathsrc);
655 g_free(pathdst);
656
657 qemu_mutex_lock(&evlock);
658 evstopping = 1;
659 timer = g_timer_new();
660 while (evrunning && g_timer_elapsed(timer, NULL) < 5) {
661 qemu_mutex_unlock(&evlock);
662 usleep(10 * 1000);
663 qemu_mutex_lock(&evlock);
664 }
665 qemu_mutex_unlock(&evlock);
666
667 if (g_timer_elapsed(timer, NULL) >= 5) {
668 g_printerr("Event loop failed to quit after 5 seconds\n");
669 }
670 g_timer_destroy(timer);
671
90e33dfe
DB
672 qemu_file_monitor_free(mon);
673 g_list_foreach(data.records,
674 (GFunc)qemu_file_monitor_test_record_free, NULL);
675 g_list_free(data.records);
676 qemu_mutex_destroy(&data.lock);
677 if (dir) {
b26c3f9c
DB
678 for (i = 0; i < G_N_ELEMENTS(ops); i++) {
679 const QFileMonitorTestOp *op = &(ops[i]);
680 char *path = g_strdup_printf("%s/%s",
681 dir, op->filesrc);
ff3dc8fe
DB
682 if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) {
683 rmdir(path);
684 g_free(path);
685 } else {
b26c3f9c
DB
686 unlink(path);
687 g_free(path);
ff3dc8fe
DB
688 if (op->filedst) {
689 path = g_strdup_printf("%s/%s",
690 dir, op->filedst);
691 unlink(path);
692 g_free(path);
693 }
b26c3f9c
DB
694 }
695 }
696 if (rmdir(dir) < 0) {
697 g_printerr("Failed to remove %s: %s\n",
698 dir, strerror(errno));
699 abort();
700 }
90e33dfe 701 }
b4682a63 702 g_hash_table_unref(ids);
90e33dfe
DB
703 g_free(dir);
704 g_assert(err == 0);
705}
706
707
90e33dfe
DB
708int main(int argc, char **argv)
709{
710 g_test_init(&argc, &argv, NULL);
711
712 qemu_init_main_loop(&error_abort);
713
714 qemu_mutex_init(&evlock);
715
b26c3f9c
DB
716 debug = getenv("FILEMONITOR_DEBUG") != NULL;
717 g_test_add_func("/util/filemonitor", test_file_monitor_events);
90e33dfe
DB
718
719 return g_test_run();
720}