]> Git Repo - qemu.git/blob - tests/test-char.c
hw/intc/arm_gicv3: Fix secure-GIC NS ICC_PMR and ICC_RPR accesses
[qemu.git] / tests / test-char.c
1 #include "qemu/osdep.h"
2 #include <glib/gstdio.h>
3
4 #include "qemu/config-file.h"
5 #include "qemu/option.h"
6 #include "qemu/sockets.h"
7 #include "chardev/char-fe.h"
8 #include "chardev/char-mux.h"
9 #include "sysemu/sysemu.h"
10 #include "qapi/error.h"
11 #include "qapi/qapi-commands-char.h"
12 #include "qapi/qmp/qdict.h"
13 #include "qom/qom-qobject.h"
14
15 static bool quit;
16
17 typedef struct FeHandler {
18     int read_count;
19     int last_event;
20     char read_buf[128];
21 } FeHandler;
22
23 static void main_loop(void)
24 {
25     quit = false;
26     do {
27         main_loop_wait(false);
28     } while (!quit);
29 }
30
31 static int fe_can_read(void *opaque)
32 {
33     FeHandler *h = opaque;
34
35     return sizeof(h->read_buf) - h->read_count;
36 }
37
38 static void fe_read(void *opaque, const uint8_t *buf, int size)
39 {
40     FeHandler *h = opaque;
41
42     g_assert_cmpint(size, <=, fe_can_read(opaque));
43
44     memcpy(h->read_buf + h->read_count, buf, size);
45     h->read_count += size;
46     quit = true;
47 }
48
49 static void fe_event(void *opaque, int event)
50 {
51     FeHandler *h = opaque;
52
53     h->last_event = event;
54     if (event != CHR_EVENT_BREAK) {
55         quit = true;
56     }
57 }
58
59 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
60 #ifdef _WIN32
61 static void char_console_test_subprocess(void)
62 {
63     QemuOpts *opts;
64     Chardev *chr;
65
66     opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
67                             1, &error_abort);
68     qemu_opt_set(opts, "backend", "console", &error_abort);
69
70     chr = qemu_chr_new_from_opts(opts, NULL);
71     g_assert_nonnull(chr);
72
73     qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
74
75     qemu_opts_del(opts);
76     object_unparent(OBJECT(chr));
77 }
78
79 static void char_console_test(void)
80 {
81     g_test_trap_subprocess("/char/console/subprocess", 0, 0);
82     g_test_trap_assert_passed();
83     g_test_trap_assert_stdout("CONSOLE");
84 }
85 #endif
86 static void char_stdio_test_subprocess(void)
87 {
88     Chardev *chr;
89     CharBackend be;
90     int ret;
91
92     chr = qemu_chr_new("label", "stdio");
93     g_assert_nonnull(chr);
94
95     qemu_chr_fe_init(&be, chr, &error_abort);
96     qemu_chr_fe_set_open(&be, true);
97     ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
98     g_assert_cmpint(ret, ==, 4);
99
100     qemu_chr_fe_deinit(&be, true);
101 }
102
103 static void char_stdio_test(void)
104 {
105     g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
106     g_test_trap_assert_passed();
107     g_test_trap_assert_stdout("buf");
108 }
109 #endif
110
111 static void char_ringbuf_test(void)
112 {
113     QemuOpts *opts;
114     Chardev *chr;
115     CharBackend be;
116     char *data;
117     int ret;
118
119     opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
120                             1, &error_abort);
121     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
122
123     qemu_opt_set(opts, "size", "5", &error_abort);
124     chr = qemu_chr_new_from_opts(opts, NULL);
125     g_assert_null(chr);
126     qemu_opts_del(opts);
127
128     opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
129                             1, &error_abort);
130     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
131     qemu_opt_set(opts, "size", "2", &error_abort);
132     chr = qemu_chr_new_from_opts(opts, &error_abort);
133     g_assert_nonnull(chr);
134     qemu_opts_del(opts);
135
136     qemu_chr_fe_init(&be, chr, &error_abort);
137     ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
138     g_assert_cmpint(ret, ==, 4);
139
140     data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
141     g_assert_cmpstr(data, ==, "ff");
142     g_free(data);
143
144     data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
145     g_assert_cmpstr(data, ==, "");
146     g_free(data);
147
148     qemu_chr_fe_deinit(&be, true);
149
150     /* check alias */
151     opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
152                             1, &error_abort);
153     qemu_opt_set(opts, "backend", "memory", &error_abort);
154     qemu_opt_set(opts, "size", "2", &error_abort);
155     chr = qemu_chr_new_from_opts(opts, NULL);
156     g_assert_nonnull(chr);
157     object_unparent(OBJECT(chr));
158     qemu_opts_del(opts);
159 }
160
161 static void char_mux_test(void)
162 {
163     QemuOpts *opts;
164     Chardev *chr, *base;
165     char *data;
166     FeHandler h1 = { 0, }, h2 = { 0, };
167     CharBackend chr_be1, chr_be2;
168
169     opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
170                             1, &error_abort);
171     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
172     qemu_opt_set(opts, "size", "128", &error_abort);
173     qemu_opt_set(opts, "mux", "on", &error_abort);
174     chr = qemu_chr_new_from_opts(opts, &error_abort);
175     g_assert_nonnull(chr);
176     qemu_opts_del(opts);
177
178     qemu_chr_fe_init(&chr_be1, chr, &error_abort);
179     qemu_chr_fe_set_handlers(&chr_be1,
180                              fe_can_read,
181                              fe_read,
182                              fe_event,
183                              NULL,
184                              &h1,
185                              NULL, true);
186
187     qemu_chr_fe_init(&chr_be2, chr, &error_abort);
188     qemu_chr_fe_set_handlers(&chr_be2,
189                              fe_can_read,
190                              fe_read,
191                              fe_event,
192                              NULL,
193                              &h2,
194                              NULL, true);
195     qemu_chr_fe_take_focus(&chr_be2);
196
197     base = qemu_chr_find("mux-label-base");
198     g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
199
200     qemu_chr_be_write(base, (void *)"hello", 6);
201     g_assert_cmpint(h1.read_count, ==, 0);
202     g_assert_cmpint(h2.read_count, ==, 6);
203     g_assert_cmpstr(h2.read_buf, ==, "hello");
204     h2.read_count = 0;
205
206     g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
207     g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
208     /* sending event on the base broadcast to all fe, historical reasons? */
209     qemu_chr_be_event(base, 42);
210     g_assert_cmpint(h1.last_event, ==, 42);
211     g_assert_cmpint(h2.last_event, ==, 42);
212     qemu_chr_be_event(chr, -1);
213     g_assert_cmpint(h1.last_event, ==, 42);
214     g_assert_cmpint(h2.last_event, ==, -1);
215
216     /* switch focus */
217     qemu_chr_be_write(base, (void *)"\1c", 2);
218     g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
219     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
220     qemu_chr_be_event(chr, -1);
221     g_assert_cmpint(h1.last_event, ==, -1);
222     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
223
224     qemu_chr_be_write(base, (void *)"hello", 6);
225     g_assert_cmpint(h2.read_count, ==, 0);
226     g_assert_cmpint(h1.read_count, ==, 6);
227     g_assert_cmpstr(h1.read_buf, ==, "hello");
228     h1.read_count = 0;
229
230     /* remove first handler */
231     qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
232                              NULL, NULL, true);
233     qemu_chr_be_write(base, (void *)"hello", 6);
234     g_assert_cmpint(h1.read_count, ==, 0);
235     g_assert_cmpint(h2.read_count, ==, 0);
236
237     qemu_chr_be_write(base, (void *)"\1c", 2);
238     qemu_chr_be_write(base, (void *)"hello", 6);
239     g_assert_cmpint(h1.read_count, ==, 0);
240     g_assert_cmpint(h2.read_count, ==, 6);
241     g_assert_cmpstr(h2.read_buf, ==, "hello");
242     h2.read_count = 0;
243
244     /* print help */
245     qemu_chr_be_write(base, (void *)"\1?", 2);
246     data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
247     g_assert_cmpint(strlen(data), !=, 0);
248     g_free(data);
249
250     qemu_chr_fe_deinit(&chr_be1, false);
251     qemu_chr_fe_deinit(&chr_be2, true);
252 }
253
254 typedef struct SocketIdleData {
255     GMainLoop *loop;
256     Chardev *chr;
257     bool conn_expected;
258     CharBackend *be;
259     CharBackend *client_be;
260 } SocketIdleData;
261
262 static gboolean char_socket_test_idle(gpointer user_data)
263 {
264     SocketIdleData *data = user_data;
265
266     if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
267         == data->conn_expected) {
268         quit = true;
269         return FALSE;
270     }
271
272     return TRUE;
273 }
274
275 static void socket_read(void *opaque, const uint8_t *buf, int size)
276 {
277     SocketIdleData *data = opaque;
278
279     g_assert_cmpint(size, ==, 1);
280     g_assert_cmpint(*buf, ==, 'Z');
281
282     size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
283     g_assert_cmpint(size, ==, 5);
284 }
285
286 static int socket_can_read(void *opaque)
287 {
288     return 10;
289 }
290
291 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
292 {
293     g_assert_cmpint(size, ==, 5);
294     g_assert(strncmp((char *)buf, "hello", 5) == 0);
295
296     quit = true;
297 }
298
299 static int socket_can_read_hello(void *opaque)
300 {
301     return 10;
302 }
303
304 static void char_socket_test_common(Chardev *chr)
305 {
306     Chardev *chr_client;
307     QObject *addr;
308     QDict *qdict;
309     const char *port;
310     SocketIdleData d = { .chr = chr };
311     CharBackend be;
312     CharBackend client_be;
313     char *tmp;
314
315     d.be = &be;
316     d.client_be = &be;
317
318     g_assert_nonnull(chr);
319     g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
320
321     addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
322     qdict = qobject_to(QDict, addr);
323     port = qdict_get_str(qdict, "port");
324     tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
325     QDECREF(qdict);
326
327     qemu_chr_fe_init(&be, chr, &error_abort);
328     qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
329                              NULL, NULL, &d, NULL, true);
330
331     chr_client = qemu_chr_new("client", tmp);
332     qemu_chr_fe_init(&client_be, chr_client, &error_abort);
333     qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
334                              socket_read_hello,
335                              NULL, NULL, &d, NULL, true);
336     g_free(tmp);
337
338     d.conn_expected = true;
339     guint id = g_idle_add(char_socket_test_idle, &d);
340     g_source_set_name_by_id(id, "test-idle");
341     g_assert_cmpint(id, >, 0);
342     main_loop();
343
344     g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
345     g_assert(object_property_get_bool(OBJECT(chr_client),
346                                       "connected", &error_abort));
347
348     qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
349     main_loop();
350
351     object_unparent(OBJECT(chr_client));
352
353     d.conn_expected = false;
354     g_idle_add(char_socket_test_idle, &d);
355     main_loop();
356
357     object_unparent(OBJECT(chr));
358 }
359
360
361 static void char_socket_basic_test(void)
362 {
363     Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
364
365     char_socket_test_common(chr);
366 }
367
368
369 static void char_socket_fdpass_test(void)
370 {
371     Chardev *chr;
372     char *optstr;
373     QemuOpts *opts;
374     int fd;
375     SocketAddress *addr = g_new0(SocketAddress, 1);
376
377     addr->type = SOCKET_ADDRESS_TYPE_INET;
378     addr->u.inet.host = g_strdup("127.0.0.1");
379     addr->u.inet.port = g_strdup("0");
380
381     fd = socket_listen(addr, &error_abort);
382     g_assert(fd >= 0);
383
384     qapi_free_SocketAddress(addr);
385
386     optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
387
388     opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
389                                    optstr, true);
390     g_free(optstr);
391     g_assert_nonnull(opts);
392
393     chr = qemu_chr_new_from_opts(opts, &error_abort);
394
395     qemu_opts_del(opts);
396
397     char_socket_test_common(chr);
398 }
399
400
401 #ifndef _WIN32
402 static void char_pipe_test(void)
403 {
404     gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
405     gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
406     Chardev *chr;
407     CharBackend be;
408     int ret, fd;
409     char buf[10];
410     FeHandler fe = { 0, };
411
412     in = g_strdup_printf("%s.in", pipe);
413     if (mkfifo(in, 0600) < 0) {
414         abort();
415     }
416     out = g_strdup_printf("%s.out", pipe);
417     if (mkfifo(out, 0600) < 0) {
418         abort();
419     }
420
421     tmp = g_strdup_printf("pipe:%s", pipe);
422     chr = qemu_chr_new("pipe", tmp);
423     g_assert_nonnull(chr);
424     g_free(tmp);
425
426     qemu_chr_fe_init(&be, chr, &error_abort);
427
428     ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
429     g_assert_cmpint(ret, ==, 9);
430
431     fd = open(out, O_RDWR);
432     ret = read(fd, buf, sizeof(buf));
433     g_assert_cmpint(ret, ==, 9);
434     g_assert_cmpstr(buf, ==, "pipe-out");
435     close(fd);
436
437     fd = open(in, O_WRONLY);
438     ret = write(fd, "pipe-in", 8);
439     g_assert_cmpint(ret, ==, 8);
440     close(fd);
441
442     qemu_chr_fe_set_handlers(&be,
443                              fe_can_read,
444                              fe_read,
445                              fe_event,
446                              NULL,
447                              &fe,
448                              NULL, true);
449
450     main_loop();
451
452     g_assert_cmpint(fe.read_count, ==, 8);
453     g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
454
455     qemu_chr_fe_deinit(&be, true);
456
457     g_assert(g_unlink(in) == 0);
458     g_assert(g_unlink(out) == 0);
459     g_assert(g_rmdir(tmp_path) == 0);
460     g_free(in);
461     g_free(out);
462     g_free(tmp_path);
463     g_free(pipe);
464 }
465 #endif
466
467 static int make_udp_socket(int *port)
468 {
469     struct sockaddr_in addr = { 0, };
470     socklen_t alen = sizeof(addr);
471     int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
472
473     g_assert_cmpint(sock, >, 0);
474     addr.sin_family = AF_INET ;
475     addr.sin_addr.s_addr = htonl(INADDR_ANY);
476     addr.sin_port = 0;
477     ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
478     g_assert_cmpint(ret, ==, 0);
479     ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
480     g_assert_cmpint(ret, ==, 0);
481
482     *port = ntohs(addr.sin_port);
483     return sock;
484 }
485
486 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
487 {
488     struct sockaddr_in other;
489     SocketIdleData d = { 0, };
490     Chardev *chr;
491     CharBackend *be;
492     socklen_t alen = sizeof(other);
493     int ret;
494     char buf[10];
495     char *tmp = NULL;
496
497     if (reuse_chr) {
498         chr = reuse_chr;
499         be = chr->be;
500     } else {
501         int port;
502         sock = make_udp_socket(&port);
503         tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
504         chr = qemu_chr_new("client", tmp);
505         g_assert_nonnull(chr);
506
507         be = g_alloca(sizeof(CharBackend));
508         qemu_chr_fe_init(be, chr, &error_abort);
509     }
510
511     d.chr = chr;
512     qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
513                              NULL, NULL, &d, NULL, true);
514     ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
515     g_assert_cmpint(ret, ==, 5);
516
517     ret = recvfrom(sock, buf, sizeof(buf), 0,
518                    (struct sockaddr *)&other, &alen);
519     g_assert_cmpint(ret, ==, 5);
520     ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
521     g_assert_cmpint(ret, ==, 5);
522
523     main_loop();
524
525     if (!reuse_chr) {
526         close(sock);
527         qemu_chr_fe_deinit(be, true);
528     }
529     g_free(tmp);
530 }
531
532 static void char_udp_test(void)
533 {
534     char_udp_test_internal(NULL, 0);
535 }
536
537 #ifdef HAVE_CHARDEV_SERIAL
538 static void char_serial_test(void)
539 {
540     QemuOpts *opts;
541     Chardev *chr;
542
543     opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
544                             1, &error_abort);
545     qemu_opt_set(opts, "backend", "serial", &error_abort);
546     qemu_opt_set(opts, "path", "/dev/null", &error_abort);
547
548     chr = qemu_chr_new_from_opts(opts, NULL);
549     g_assert_nonnull(chr);
550     /* TODO: add more tests with a pty */
551     object_unparent(OBJECT(chr));
552
553     /* test tty alias */
554     qemu_opt_set(opts, "backend", "tty", &error_abort);
555     chr = qemu_chr_new_from_opts(opts, NULL);
556     g_assert_nonnull(chr);
557     object_unparent(OBJECT(chr));
558
559     qemu_opts_del(opts);
560 }
561 #endif
562
563 #ifndef _WIN32
564 static void char_file_fifo_test(void)
565 {
566     Chardev *chr;
567     CharBackend be;
568     char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
569     char *fifo = g_build_filename(tmp_path, "fifo", NULL);
570     char *out = g_build_filename(tmp_path, "out", NULL);
571     ChardevFile file = { .in = fifo,
572                          .has_in = true,
573                          .out = out };
574     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
575                                .u.file.data = &file };
576     FeHandler fe = { 0, };
577     int fd, ret;
578
579     if (mkfifo(fifo, 0600) < 0) {
580         abort();
581     }
582
583     fd = open(fifo, O_RDWR);
584     ret = write(fd, "fifo-in", 8);
585     g_assert_cmpint(ret, ==, 8);
586
587     chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
588                            &error_abort);
589
590     qemu_chr_fe_init(&be, chr, &error_abort);
591     qemu_chr_fe_set_handlers(&be,
592                              fe_can_read,
593                              fe_read,
594                              fe_event,
595                              NULL,
596                              &fe, NULL, true);
597
598     g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
599     qmp_chardev_send_break("label-foo", NULL);
600     g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
601     qmp_chardev_send_break("label-file", NULL);
602     g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
603
604     main_loop();
605
606     close(fd);
607
608     g_assert_cmpint(fe.read_count, ==, 8);
609     g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
610
611     qemu_chr_fe_deinit(&be, true);
612
613     g_unlink(fifo);
614     g_free(fifo);
615     g_unlink(out);
616     g_free(out);
617     g_rmdir(tmp_path);
618     g_free(tmp_path);
619 }
620 #endif
621
622 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
623 {
624     char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
625     char *out;
626     Chardev *chr;
627     char *contents = NULL;
628     ChardevFile file = {};
629     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
630                                .u.file.data = &file };
631     gsize length;
632     int ret;
633
634     if (ext_chr) {
635         chr = ext_chr;
636         out = g_strdup(filepath);
637         file.out = out;
638     } else {
639         out = g_build_filename(tmp_path, "out", NULL);
640         file.out = out;
641         chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
642                                &error_abort);
643     }
644     ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
645     g_assert_cmpint(ret, ==, 6);
646
647     ret = g_file_get_contents(out, &contents, &length, NULL);
648     g_assert(ret == TRUE);
649     g_assert_cmpint(length, ==, 6);
650     g_assert(strncmp(contents, "hello!", 6) == 0);
651
652     if (!ext_chr) {
653         object_unref(OBJECT(chr));
654         g_unlink(out);
655     }
656     g_free(contents);
657     g_rmdir(tmp_path);
658     g_free(tmp_path);
659     g_free(out);
660 }
661
662 static void char_file_test(void)
663 {
664     char_file_test_internal(NULL, NULL);
665 }
666
667 static void char_null_test(void)
668 {
669     Error *err = NULL;
670     Chardev *chr;
671     CharBackend be;
672     int ret;
673
674     chr = qemu_chr_find("label-null");
675     g_assert_null(chr);
676
677     chr = qemu_chr_new("label-null", "null");
678     chr = qemu_chr_find("label-null");
679     g_assert_nonnull(chr);
680
681     g_assert(qemu_chr_has_feature(chr,
682                  QEMU_CHAR_FEATURE_FD_PASS) == false);
683     g_assert(qemu_chr_has_feature(chr,
684                  QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
685
686     /* check max avail */
687     qemu_chr_fe_init(&be, chr, &error_abort);
688     qemu_chr_fe_init(&be, chr, &err);
689     error_free_or_abort(&err);
690
691     /* deinit & reinit */
692     qemu_chr_fe_deinit(&be, false);
693     qemu_chr_fe_init(&be, chr, &error_abort);
694
695     qemu_chr_fe_set_open(&be, true);
696
697     qemu_chr_fe_set_handlers(&be,
698                              fe_can_read,
699                              fe_read,
700                              fe_event,
701                              NULL,
702                              NULL, NULL, true);
703
704     ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
705     g_assert_cmpint(ret, ==, 4);
706
707     qemu_chr_fe_deinit(&be, true);
708 }
709
710 static void char_invalid_test(void)
711 {
712     Chardev *chr;
713
714     chr = qemu_chr_new("label-invalid", "invalid");
715     g_assert_null(chr);
716 }
717
718 static int chardev_change(void *opaque)
719 {
720     return 0;
721 }
722
723 static int chardev_change_denied(void *opaque)
724 {
725     return -1;
726 }
727
728 static void char_hotswap_test(void)
729 {
730     char *chr_args;
731     Chardev *chr;
732     CharBackend be;
733
734     gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
735     char *filename = g_build_filename(tmp_path, "file", NULL);
736     ChardevFile file = { .out = filename };
737     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
738                                .u.file.data = &file };
739     ChardevReturn *ret;
740
741     int port;
742     int sock = make_udp_socket(&port);
743     g_assert_cmpint(sock, >, 0);
744
745     chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
746
747     chr = qemu_chr_new("chardev", chr_args);
748     qemu_chr_fe_init(&be, chr, &error_abort);
749
750     /* check that chardev operates correctly */
751     char_udp_test_internal(chr, sock);
752
753     /* set the handler that denies the hotswap */
754     qemu_chr_fe_set_handlers(&be, NULL, NULL,
755                              NULL, chardev_change_denied, NULL, NULL, true);
756
757     /* now, change is denied and has to keep the old backend operating */
758     ret = qmp_chardev_change("chardev", &backend, NULL);
759     g_assert(!ret);
760     g_assert(be.chr == chr);
761
762     char_udp_test_internal(chr, sock);
763
764     /* now allow the change */
765     qemu_chr_fe_set_handlers(&be, NULL, NULL,
766                              NULL, chardev_change, NULL, NULL, true);
767
768     /* has to succeed now */
769     ret = qmp_chardev_change("chardev", &backend, &error_abort);
770     g_assert(be.chr != chr);
771
772     close(sock);
773     chr = be.chr;
774
775     /* run the file chardev test */
776     char_file_test_internal(chr, filename);
777
778     object_unparent(OBJECT(chr));
779
780     qapi_free_ChardevReturn(ret);
781     g_unlink(filename);
782     g_free(filename);
783     g_rmdir(tmp_path);
784     g_free(tmp_path);
785     g_free(chr_args);
786 }
787
788 int main(int argc, char **argv)
789 {
790     qemu_init_main_loop(&error_abort);
791     socket_init();
792
793     g_test_init(&argc, &argv, NULL);
794
795     module_call_init(MODULE_INIT_QOM);
796     qemu_add_opts(&qemu_chardev_opts);
797
798     g_test_add_func("/char/null", char_null_test);
799     g_test_add_func("/char/invalid", char_invalid_test);
800     g_test_add_func("/char/ringbuf", char_ringbuf_test);
801     g_test_add_func("/char/mux", char_mux_test);
802 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
803 #ifdef _WIN32
804     g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
805     g_test_add_func("/char/console", char_console_test);
806 #endif
807     g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
808     g_test_add_func("/char/stdio", char_stdio_test);
809 #endif
810 #ifndef _WIN32
811     g_test_add_func("/char/pipe", char_pipe_test);
812 #endif
813     g_test_add_func("/char/file", char_file_test);
814 #ifndef _WIN32
815     g_test_add_func("/char/file-fifo", char_file_fifo_test);
816 #endif
817     g_test_add_func("/char/socket/basic", char_socket_basic_test);
818     g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
819     g_test_add_func("/char/udp", char_udp_test);
820 #ifdef HAVE_CHARDEV_SERIAL
821     g_test_add_func("/char/serial", char_serial_test);
822 #endif
823     g_test_add_func("/char/hotswap", char_hotswap_test);
824
825     return g_test_run();
826 }
This page took 0.118225 seconds and 4 git commands to generate.