qemu/tests/test-char.c
<<
>>
Prefs
   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
  15static bool quit;
  16
  17typedef struct FeHandler {
  18    int read_count;
  19    int last_event;
  20    char read_buf[128];
  21} FeHandler;
  22
  23static void main_loop(void)
  24{
  25    quit = false;
  26    do {
  27        main_loop_wait(false);
  28    } while (!quit);
  29}
  30
  31static int fe_can_read(void *opaque)
  32{
  33    FeHandler *h = opaque;
  34
  35    return sizeof(h->read_buf) - h->read_count;
  36}
  37
  38static 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
  49static 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
  61static 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
  79static 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
  86static 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
 103static 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
 111static 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
 161static 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 *)"\1b", 2);
 218    g_assert_cmpint(h1.last_event, ==, 42);
 219    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
 220
 221    qemu_chr_be_write(base, (void *)"\1c", 2);
 222    g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
 223    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 224    qemu_chr_be_event(chr, -1);
 225    g_assert_cmpint(h1.last_event, ==, -1);
 226    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 227
 228    qemu_chr_be_write(base, (void *)"hello", 6);
 229    g_assert_cmpint(h2.read_count, ==, 0);
 230    g_assert_cmpint(h1.read_count, ==, 6);
 231    g_assert_cmpstr(h1.read_buf, ==, "hello");
 232    h1.read_count = 0;
 233
 234    qemu_chr_be_write(base, (void *)"\1b", 2);
 235    g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
 236    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 237
 238    /* remove first handler */
 239    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
 240                             NULL, NULL, true);
 241    qemu_chr_be_write(base, (void *)"hello", 6);
 242    g_assert_cmpint(h1.read_count, ==, 0);
 243    g_assert_cmpint(h2.read_count, ==, 0);
 244
 245    qemu_chr_be_write(base, (void *)"\1c", 2);
 246    qemu_chr_be_write(base, (void *)"hello", 6);
 247    g_assert_cmpint(h1.read_count, ==, 0);
 248    g_assert_cmpint(h2.read_count, ==, 6);
 249    g_assert_cmpstr(h2.read_buf, ==, "hello");
 250    h2.read_count = 0;
 251
 252    /* print help */
 253    qemu_chr_be_write(base, (void *)"\1?", 2);
 254    data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
 255    g_assert_cmpint(strlen(data), !=, 0);
 256    g_free(data);
 257
 258    qemu_chr_fe_deinit(&chr_be1, false);
 259    qemu_chr_fe_deinit(&chr_be2, true);
 260}
 261
 262typedef struct SocketIdleData {
 263    GMainLoop *loop;
 264    Chardev *chr;
 265    bool conn_expected;
 266    CharBackend *be;
 267    CharBackend *client_be;
 268} SocketIdleData;
 269
 270static gboolean char_socket_test_idle(gpointer user_data)
 271{
 272    SocketIdleData *data = user_data;
 273
 274    if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
 275        == data->conn_expected) {
 276        quit = true;
 277        return FALSE;
 278    }
 279
 280    return TRUE;
 281}
 282
 283static void socket_read(void *opaque, const uint8_t *buf, int size)
 284{
 285    SocketIdleData *data = opaque;
 286
 287    g_assert_cmpint(size, ==, 1);
 288    g_assert_cmpint(*buf, ==, 'Z');
 289
 290    size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
 291    g_assert_cmpint(size, ==, 5);
 292}
 293
 294static int socket_can_read(void *opaque)
 295{
 296    return 10;
 297}
 298
 299static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
 300{
 301    g_assert_cmpint(size, ==, 5);
 302    g_assert(strncmp((char *)buf, "hello", 5) == 0);
 303
 304    quit = true;
 305}
 306
 307static int socket_can_read_hello(void *opaque)
 308{
 309    return 10;
 310}
 311
 312static void char_socket_test_common(Chardev *chr)
 313{
 314    Chardev *chr_client;
 315    QObject *addr;
 316    QDict *qdict;
 317    const char *port;
 318    SocketIdleData d = { .chr = chr };
 319    CharBackend be;
 320    CharBackend client_be;
 321    char *tmp;
 322
 323    d.be = &be;
 324    d.client_be = &be;
 325
 326    g_assert_nonnull(chr);
 327    g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
 328
 329    addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
 330    qdict = qobject_to(QDict, addr);
 331    port = qdict_get_str(qdict, "port");
 332    tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
 333    qobject_unref(qdict);
 334
 335    qemu_chr_fe_init(&be, chr, &error_abort);
 336    qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
 337                             NULL, NULL, &d, NULL, true);
 338
 339    chr_client = qemu_chr_new("client", tmp);
 340    qemu_chr_fe_init(&client_be, chr_client, &error_abort);
 341    qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
 342                             socket_read_hello,
 343                             NULL, NULL, &d, NULL, true);
 344    g_free(tmp);
 345
 346    d.conn_expected = true;
 347    guint id = g_idle_add(char_socket_test_idle, &d);
 348    g_source_set_name_by_id(id, "test-idle");
 349    g_assert_cmpint(id, >, 0);
 350    main_loop();
 351
 352    g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
 353    g_assert(object_property_get_bool(OBJECT(chr_client),
 354                                      "connected", &error_abort));
 355
 356    qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
 357    main_loop();
 358
 359    object_unparent(OBJECT(chr_client));
 360
 361    d.conn_expected = false;
 362    g_idle_add(char_socket_test_idle, &d);
 363    main_loop();
 364
 365    object_unparent(OBJECT(chr));
 366}
 367
 368
 369static void char_socket_basic_test(void)
 370{
 371    Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
 372
 373    char_socket_test_common(chr);
 374}
 375
 376
 377static void char_socket_fdpass_test(void)
 378{
 379    Chardev *chr;
 380    char *optstr;
 381    QemuOpts *opts;
 382    int fd;
 383    SocketAddress *addr = g_new0(SocketAddress, 1);
 384
 385    addr->type = SOCKET_ADDRESS_TYPE_INET;
 386    addr->u.inet.host = g_strdup("127.0.0.1");
 387    addr->u.inet.port = g_strdup("0");
 388
 389    fd = socket_listen(addr, &error_abort);
 390    g_assert(fd >= 0);
 391
 392    qapi_free_SocketAddress(addr);
 393
 394    optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
 395
 396    opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
 397                                   optstr, true);
 398    g_free(optstr);
 399    g_assert_nonnull(opts);
 400
 401    chr = qemu_chr_new_from_opts(opts, &error_abort);
 402
 403    qemu_opts_del(opts);
 404
 405    char_socket_test_common(chr);
 406}
 407
 408
 409#ifndef _WIN32
 410static void char_pipe_test(void)
 411{
 412    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 413    gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
 414    Chardev *chr;
 415    CharBackend be;
 416    int ret, fd;
 417    char buf[10];
 418    FeHandler fe = { 0, };
 419
 420    in = g_strdup_printf("%s.in", pipe);
 421    if (mkfifo(in, 0600) < 0) {
 422        abort();
 423    }
 424    out = g_strdup_printf("%s.out", pipe);
 425    if (mkfifo(out, 0600) < 0) {
 426        abort();
 427    }
 428
 429    tmp = g_strdup_printf("pipe:%s", pipe);
 430    chr = qemu_chr_new("pipe", tmp);
 431    g_assert_nonnull(chr);
 432    g_free(tmp);
 433
 434    qemu_chr_fe_init(&be, chr, &error_abort);
 435
 436    ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
 437    g_assert_cmpint(ret, ==, 9);
 438
 439    fd = open(out, O_RDWR);
 440    ret = read(fd, buf, sizeof(buf));
 441    g_assert_cmpint(ret, ==, 9);
 442    g_assert_cmpstr(buf, ==, "pipe-out");
 443    close(fd);
 444
 445    fd = open(in, O_WRONLY);
 446    ret = write(fd, "pipe-in", 8);
 447    g_assert_cmpint(ret, ==, 8);
 448    close(fd);
 449
 450    qemu_chr_fe_set_handlers(&be,
 451                             fe_can_read,
 452                             fe_read,
 453                             fe_event,
 454                             NULL,
 455                             &fe,
 456                             NULL, true);
 457
 458    main_loop();
 459
 460    g_assert_cmpint(fe.read_count, ==, 8);
 461    g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
 462
 463    qemu_chr_fe_deinit(&be, true);
 464
 465    g_assert(g_unlink(in) == 0);
 466    g_assert(g_unlink(out) == 0);
 467    g_assert(g_rmdir(tmp_path) == 0);
 468    g_free(in);
 469    g_free(out);
 470    g_free(tmp_path);
 471    g_free(pipe);
 472}
 473#endif
 474
 475static int make_udp_socket(int *port)
 476{
 477    struct sockaddr_in addr = { 0, };
 478    socklen_t alen = sizeof(addr);
 479    int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
 480
 481    g_assert_cmpint(sock, >, 0);
 482    addr.sin_family = AF_INET ;
 483    addr.sin_addr.s_addr = htonl(INADDR_ANY);
 484    addr.sin_port = 0;
 485    ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
 486    g_assert_cmpint(ret, ==, 0);
 487    ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
 488    g_assert_cmpint(ret, ==, 0);
 489
 490    *port = ntohs(addr.sin_port);
 491    return sock;
 492}
 493
 494static void char_udp_test_internal(Chardev *reuse_chr, int sock)
 495{
 496    struct sockaddr_in other;
 497    SocketIdleData d = { 0, };
 498    Chardev *chr;
 499    CharBackend *be;
 500    socklen_t alen = sizeof(other);
 501    int ret;
 502    char buf[10];
 503    char *tmp = NULL;
 504
 505    if (reuse_chr) {
 506        chr = reuse_chr;
 507        be = chr->be;
 508    } else {
 509        int port;
 510        sock = make_udp_socket(&port);
 511        tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
 512        chr = qemu_chr_new("client", tmp);
 513        g_assert_nonnull(chr);
 514
 515        be = g_alloca(sizeof(CharBackend));
 516        qemu_chr_fe_init(be, chr, &error_abort);
 517    }
 518
 519    d.chr = chr;
 520    qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
 521                             NULL, NULL, &d, NULL, true);
 522    ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
 523    g_assert_cmpint(ret, ==, 5);
 524
 525    ret = recvfrom(sock, buf, sizeof(buf), 0,
 526                   (struct sockaddr *)&other, &alen);
 527    g_assert_cmpint(ret, ==, 5);
 528    ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
 529    g_assert_cmpint(ret, ==, 5);
 530
 531    main_loop();
 532
 533    if (!reuse_chr) {
 534        close(sock);
 535        qemu_chr_fe_deinit(be, true);
 536    }
 537    g_free(tmp);
 538}
 539
 540static void char_udp_test(void)
 541{
 542    char_udp_test_internal(NULL, 0);
 543}
 544
 545#ifdef HAVE_CHARDEV_SERIAL
 546static void char_serial_test(void)
 547{
 548    QemuOpts *opts;
 549    Chardev *chr;
 550
 551    opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
 552                            1, &error_abort);
 553    qemu_opt_set(opts, "backend", "serial", &error_abort);
 554    qemu_opt_set(opts, "path", "/dev/null", &error_abort);
 555
 556    chr = qemu_chr_new_from_opts(opts, NULL);
 557    g_assert_nonnull(chr);
 558    /* TODO: add more tests with a pty */
 559    object_unparent(OBJECT(chr));
 560
 561    /* test tty alias */
 562    qemu_opt_set(opts, "backend", "tty", &error_abort);
 563    chr = qemu_chr_new_from_opts(opts, NULL);
 564    g_assert_nonnull(chr);
 565    object_unparent(OBJECT(chr));
 566
 567    qemu_opts_del(opts);
 568}
 569#endif
 570
 571#ifndef _WIN32
 572static void char_file_fifo_test(void)
 573{
 574    Chardev *chr;
 575    CharBackend be;
 576    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 577    char *fifo = g_build_filename(tmp_path, "fifo", NULL);
 578    char *out = g_build_filename(tmp_path, "out", NULL);
 579    ChardevFile file = { .in = fifo,
 580                         .has_in = true,
 581                         .out = out };
 582    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 583                               .u.file.data = &file };
 584    FeHandler fe = { 0, };
 585    int fd, ret;
 586
 587    if (mkfifo(fifo, 0600) < 0) {
 588        abort();
 589    }
 590
 591    fd = open(fifo, O_RDWR);
 592    ret = write(fd, "fifo-in", 8);
 593    g_assert_cmpint(ret, ==, 8);
 594
 595    chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
 596                           &error_abort);
 597
 598    qemu_chr_fe_init(&be, chr, &error_abort);
 599    qemu_chr_fe_set_handlers(&be,
 600                             fe_can_read,
 601                             fe_read,
 602                             fe_event,
 603                             NULL,
 604                             &fe, NULL, true);
 605
 606    g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
 607    qmp_chardev_send_break("label-foo", NULL);
 608    g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
 609    qmp_chardev_send_break("label-file", NULL);
 610    g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
 611
 612    main_loop();
 613
 614    close(fd);
 615
 616    g_assert_cmpint(fe.read_count, ==, 8);
 617    g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
 618
 619    qemu_chr_fe_deinit(&be, true);
 620
 621    g_unlink(fifo);
 622    g_free(fifo);
 623    g_unlink(out);
 624    g_free(out);
 625    g_rmdir(tmp_path);
 626    g_free(tmp_path);
 627}
 628#endif
 629
 630static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
 631{
 632    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 633    char *out;
 634    Chardev *chr;
 635    char *contents = NULL;
 636    ChardevFile file = {};
 637    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 638                               .u.file.data = &file };
 639    gsize length;
 640    int ret;
 641
 642    if (ext_chr) {
 643        chr = ext_chr;
 644        out = g_strdup(filepath);
 645        file.out = out;
 646    } else {
 647        out = g_build_filename(tmp_path, "out", NULL);
 648        file.out = out;
 649        chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
 650                               &error_abort);
 651    }
 652    ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
 653    g_assert_cmpint(ret, ==, 6);
 654
 655    ret = g_file_get_contents(out, &contents, &length, NULL);
 656    g_assert(ret == TRUE);
 657    g_assert_cmpint(length, ==, 6);
 658    g_assert(strncmp(contents, "hello!", 6) == 0);
 659
 660    if (!ext_chr) {
 661        object_unref(OBJECT(chr));
 662        g_unlink(out);
 663    }
 664    g_free(contents);
 665    g_rmdir(tmp_path);
 666    g_free(tmp_path);
 667    g_free(out);
 668}
 669
 670static void char_file_test(void)
 671{
 672    char_file_test_internal(NULL, NULL);
 673}
 674
 675static void char_null_test(void)
 676{
 677    Error *err = NULL;
 678    Chardev *chr;
 679    CharBackend be;
 680    int ret;
 681
 682    chr = qemu_chr_find("label-null");
 683    g_assert_null(chr);
 684
 685    chr = qemu_chr_new("label-null", "null");
 686    chr = qemu_chr_find("label-null");
 687    g_assert_nonnull(chr);
 688
 689    g_assert(qemu_chr_has_feature(chr,
 690                 QEMU_CHAR_FEATURE_FD_PASS) == false);
 691    g_assert(qemu_chr_has_feature(chr,
 692                 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
 693
 694    /* check max avail */
 695    qemu_chr_fe_init(&be, chr, &error_abort);
 696    qemu_chr_fe_init(&be, chr, &err);
 697    error_free_or_abort(&err);
 698
 699    /* deinit & reinit */
 700    qemu_chr_fe_deinit(&be, false);
 701    qemu_chr_fe_init(&be, chr, &error_abort);
 702
 703    qemu_chr_fe_set_open(&be, true);
 704
 705    qemu_chr_fe_set_handlers(&be,
 706                             fe_can_read,
 707                             fe_read,
 708                             fe_event,
 709                             NULL,
 710                             NULL, NULL, true);
 711
 712    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
 713    g_assert_cmpint(ret, ==, 4);
 714
 715    qemu_chr_fe_deinit(&be, true);
 716}
 717
 718static void char_invalid_test(void)
 719{
 720    Chardev *chr;
 721
 722    chr = qemu_chr_new("label-invalid", "invalid");
 723    g_assert_null(chr);
 724}
 725
 726static int chardev_change(void *opaque)
 727{
 728    return 0;
 729}
 730
 731static int chardev_change_denied(void *opaque)
 732{
 733    return -1;
 734}
 735
 736static void char_hotswap_test(void)
 737{
 738    char *chr_args;
 739    Chardev *chr;
 740    CharBackend be;
 741
 742    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 743    char *filename = g_build_filename(tmp_path, "file", NULL);
 744    ChardevFile file = { .out = filename };
 745    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 746                               .u.file.data = &file };
 747    ChardevReturn *ret;
 748
 749    int port;
 750    int sock = make_udp_socket(&port);
 751    g_assert_cmpint(sock, >, 0);
 752
 753    chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
 754
 755    chr = qemu_chr_new("chardev", chr_args);
 756    qemu_chr_fe_init(&be, chr, &error_abort);
 757
 758    /* check that chardev operates correctly */
 759    char_udp_test_internal(chr, sock);
 760
 761    /* set the handler that denies the hotswap */
 762    qemu_chr_fe_set_handlers(&be, NULL, NULL,
 763                             NULL, chardev_change_denied, NULL, NULL, true);
 764
 765    /* now, change is denied and has to keep the old backend operating */
 766    ret = qmp_chardev_change("chardev", &backend, NULL);
 767    g_assert(!ret);
 768    g_assert(be.chr == chr);
 769
 770    char_udp_test_internal(chr, sock);
 771
 772    /* now allow the change */
 773    qemu_chr_fe_set_handlers(&be, NULL, NULL,
 774                             NULL, chardev_change, NULL, NULL, true);
 775
 776    /* has to succeed now */
 777    ret = qmp_chardev_change("chardev", &backend, &error_abort);
 778    g_assert(be.chr != chr);
 779
 780    close(sock);
 781    chr = be.chr;
 782
 783    /* run the file chardev test */
 784    char_file_test_internal(chr, filename);
 785
 786    object_unparent(OBJECT(chr));
 787
 788    qapi_free_ChardevReturn(ret);
 789    g_unlink(filename);
 790    g_free(filename);
 791    g_rmdir(tmp_path);
 792    g_free(tmp_path);
 793    g_free(chr_args);
 794}
 795
 796int main(int argc, char **argv)
 797{
 798    qemu_init_main_loop(&error_abort);
 799    socket_init();
 800
 801    g_test_init(&argc, &argv, NULL);
 802
 803    module_call_init(MODULE_INIT_QOM);
 804    qemu_add_opts(&qemu_chardev_opts);
 805
 806    g_test_add_func("/char/null", char_null_test);
 807    g_test_add_func("/char/invalid", char_invalid_test);
 808    g_test_add_func("/char/ringbuf", char_ringbuf_test);
 809    g_test_add_func("/char/mux", char_mux_test);
 810#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
 811#ifdef _WIN32
 812    g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
 813    g_test_add_func("/char/console", char_console_test);
 814#endif
 815    g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
 816    g_test_add_func("/char/stdio", char_stdio_test);
 817#endif
 818#ifndef _WIN32
 819    g_test_add_func("/char/pipe", char_pipe_test);
 820#endif
 821    g_test_add_func("/char/file", char_file_test);
 822#ifndef _WIN32
 823    g_test_add_func("/char/file-fifo", char_file_fifo_test);
 824#endif
 825    g_test_add_func("/char/socket/basic", char_socket_basic_test);
 826    g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
 827    g_test_add_func("/char/udp", char_udp_test);
 828#ifdef HAVE_CHARDEV_SERIAL
 829    g_test_add_func("/char/serial", char_serial_test);
 830#endif
 831    g_test_add_func("/char/hotswap", char_hotswap_test);
 832
 833    return g_test_run();
 834}
 835