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