1 /* 2 * QEMU System Emulator 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qemu/cutils.h" 27 #include "monitor/monitor.h" 28 #include "sysemu/sysemu.h" 29 #include "qemu/config-file.h" 30 #include "qemu/error-report.h" 31 #include "qemu/qemu-print.h" 32 #include "chardev/char.h" 33 #include "qapi/error.h" 34 #include "qapi/qapi-commands-char.h" 35 #include "qapi/qmp/qerror.h" 36 #include "sysemu/replay.h" 37 #include "qemu/help_option.h" 38 #include "qemu/module.h" 39 #include "qemu/option.h" 40 #include "qemu/id.h" 41 #include "qemu/coroutine.h" 42 43 #include "chardev-internal.h" 44 45 /***********************************************************/ 46 /* character device */ 47 48 Object *get_chardevs_root(void) 49 { 50 return container_get(object_get_root(), "/chardevs"); 51 } 52 53 static void chr_be_event(Chardev *s, QEMUChrEvent event) 54 { 55 CharBackend *be = s->be; 56 57 if (!be || !be->chr_event) { 58 return; 59 } 60 61 be->chr_event(be->opaque, event); 62 } 63 64 void qemu_chr_be_event(Chardev *s, QEMUChrEvent event) 65 { 66 /* Keep track if the char device is open */ 67 switch (event) { 68 case CHR_EVENT_OPENED: 69 s->be_open = 1; 70 break; 71 case CHR_EVENT_CLOSED: 72 s->be_open = 0; 73 break; 74 case CHR_EVENT_BREAK: 75 case CHR_EVENT_MUX_IN: 76 case CHR_EVENT_MUX_OUT: 77 /* Ignore */ 78 break; 79 } 80 81 CHARDEV_GET_CLASS(s)->chr_be_event(s, event); 82 } 83 84 /* Not reporting errors from writing to logfile, as logs are 85 * defined to be "best effort" only */ 86 static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len) 87 { 88 size_t done = 0; 89 ssize_t ret; 90 91 if (s->logfd < 0) { 92 return; 93 } 94 95 while (done < len) { 96 retry: 97 ret = write(s->logfd, buf + done, len - done); 98 if (ret == -1 && errno == EAGAIN) { 99 g_usleep(100); 100 goto retry; 101 } 102 103 if (ret <= 0) { 104 return; 105 } 106 done += ret; 107 } 108 } 109 110 static int qemu_chr_write_buffer(Chardev *s, 111 const uint8_t *buf, int len, 112 int *offset, bool write_all) 113 { 114 ChardevClass *cc = CHARDEV_GET_CLASS(s); 115 int res = 0; 116 *offset = 0; 117 118 qemu_mutex_lock(&s->chr_write_lock); 119 while (*offset < len) { 120 retry: 121 res = cc->chr_write(s, buf + *offset, len - *offset); 122 if (res < 0 && errno == EAGAIN && write_all) { 123 if (qemu_in_coroutine()) { 124 qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); 125 } else { 126 g_usleep(100); 127 } 128 goto retry; 129 } 130 131 if (res <= 0) { 132 break; 133 } 134 135 *offset += res; 136 if (!write_all) { 137 break; 138 } 139 } 140 if (*offset > 0) { 141 qemu_chr_write_log(s, buf, *offset); 142 } 143 qemu_mutex_unlock(&s->chr_write_lock); 144 145 return res; 146 } 147 148 int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all) 149 { 150 int offset = 0; 151 int res; 152 153 if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) { 154 replay_char_write_event_load(&res, &offset); 155 assert(offset <= len); 156 qemu_chr_write_buffer(s, buf, offset, &offset, true); 157 return res; 158 } 159 160 res = qemu_chr_write_buffer(s, buf, len, &offset, write_all); 161 162 if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) { 163 replay_char_write_event_save(res, offset); 164 } 165 166 if (res < 0) { 167 return res; 168 } 169 return offset; 170 } 171 172 int qemu_chr_be_can_write(Chardev *s) 173 { 174 CharBackend *be = s->be; 175 176 if (!be || !be->chr_can_read) { 177 return 0; 178 } 179 180 return be->chr_can_read(be->opaque); 181 } 182 183 void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len) 184 { 185 CharBackend *be = s->be; 186 187 if (be && be->chr_read) { 188 be->chr_read(be->opaque, buf, len); 189 } 190 } 191 192 void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len) 193 { 194 if (qemu_chr_replay(s)) { 195 if (replay_mode == REPLAY_MODE_PLAY) { 196 return; 197 } 198 replay_chr_be_write(s, buf, len); 199 } else { 200 qemu_chr_be_write_impl(s, buf, len); 201 } 202 } 203 204 void qemu_chr_be_update_read_handlers(Chardev *s, 205 GMainContext *context) 206 { 207 ChardevClass *cc = CHARDEV_GET_CLASS(s); 208 209 assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT) 210 || !context); 211 s->gcontext = context; 212 if (cc->chr_update_read_handler) { 213 cc->chr_update_read_handler(s); 214 } 215 } 216 217 int qemu_chr_add_client(Chardev *s, int fd) 218 { 219 return CHARDEV_GET_CLASS(s)->chr_add_client ? 220 CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1; 221 } 222 223 static void qemu_char_open(Chardev *chr, ChardevBackend *backend, 224 bool *be_opened, Error **errp) 225 { 226 ChardevClass *cc = CHARDEV_GET_CLASS(chr); 227 /* Any ChardevCommon member would work */ 228 ChardevCommon *common = backend ? backend->u.null.data : NULL; 229 230 if (common && common->has_logfile) { 231 int flags = O_WRONLY | O_CREAT; 232 if (common->has_logappend && 233 common->logappend) { 234 flags |= O_APPEND; 235 } else { 236 flags |= O_TRUNC; 237 } 238 chr->logfd = qemu_open_old(common->logfile, flags, 0666); 239 if (chr->logfd < 0) { 240 error_setg_errno(errp, errno, 241 "Unable to open logfile %s", 242 common->logfile); 243 return; 244 } 245 } 246 247 if (cc->open) { 248 cc->open(chr, backend, be_opened, errp); 249 } 250 } 251 252 static void char_init(Object *obj) 253 { 254 Chardev *chr = CHARDEV(obj); 255 256 chr->logfd = -1; 257 qemu_mutex_init(&chr->chr_write_lock); 258 259 /* 260 * Assume if chr_update_read_handler is implemented it will 261 * take the updated gcontext into account. 262 */ 263 if (CHARDEV_GET_CLASS(chr)->chr_update_read_handler) { 264 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT); 265 } 266 267 } 268 269 static int null_chr_write(Chardev *chr, const uint8_t *buf, int len) 270 { 271 return len; 272 } 273 274 static void char_class_init(ObjectClass *oc, void *data) 275 { 276 ChardevClass *cc = CHARDEV_CLASS(oc); 277 278 cc->chr_write = null_chr_write; 279 cc->chr_be_event = chr_be_event; 280 } 281 282 static void char_finalize(Object *obj) 283 { 284 Chardev *chr = CHARDEV(obj); 285 286 if (chr->be) { 287 chr->be->chr = NULL; 288 } 289 g_free(chr->filename); 290 g_free(chr->label); 291 if (chr->logfd != -1) { 292 close(chr->logfd); 293 } 294 qemu_mutex_destroy(&chr->chr_write_lock); 295 } 296 297 static const TypeInfo char_type_info = { 298 .name = TYPE_CHARDEV, 299 .parent = TYPE_OBJECT, 300 .instance_size = sizeof(Chardev), 301 .instance_init = char_init, 302 .instance_finalize = char_finalize, 303 .abstract = true, 304 .class_size = sizeof(ChardevClass), 305 .class_init = char_class_init, 306 }; 307 308 static bool qemu_chr_is_busy(Chardev *s) 309 { 310 if (CHARDEV_IS_MUX(s)) { 311 MuxChardev *d = MUX_CHARDEV(s); 312 return d->mux_cnt >= 0; 313 } else { 314 return s->be != NULL; 315 } 316 } 317 318 int qemu_chr_wait_connected(Chardev *chr, Error **errp) 319 { 320 ChardevClass *cc = CHARDEV_GET_CLASS(chr); 321 322 if (cc->chr_wait_connected) { 323 return cc->chr_wait_connected(chr, errp); 324 } 325 326 return 0; 327 } 328 329 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, 330 bool permit_mux_mon) 331 { 332 char host[65], port[33], width[8], height[8]; 333 int pos; 334 const char *p; 335 QemuOpts *opts; 336 Error *local_err = NULL; 337 338 opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err); 339 if (local_err) { 340 error_report_err(local_err); 341 return NULL; 342 } 343 344 if (strstart(filename, "mon:", &p)) { 345 if (!permit_mux_mon) { 346 error_report("mon: isn't supported in this context"); 347 return NULL; 348 } 349 filename = p; 350 qemu_opt_set(opts, "mux", "on", &error_abort); 351 if (strcmp(filename, "stdio") == 0) { 352 /* Monitor is muxed to stdio: do not exit on Ctrl+C by default 353 * but pass it to the guest. Handle this only for compat syntax, 354 * for -chardev syntax we have special option for this. 355 * This is what -nographic did, redirecting+muxing serial+monitor 356 * to stdio causing Ctrl+C to be passed to guest. */ 357 qemu_opt_set(opts, "signal", "off", &error_abort); 358 } 359 } 360 361 if (strcmp(filename, "null") == 0 || 362 strcmp(filename, "pty") == 0 || 363 strcmp(filename, "msmouse") == 0 || 364 strcmp(filename, "wctablet") == 0 || 365 strcmp(filename, "braille") == 0 || 366 strcmp(filename, "testdev") == 0 || 367 strcmp(filename, "stdio") == 0) { 368 qemu_opt_set(opts, "backend", filename, &error_abort); 369 return opts; 370 } 371 if (strstart(filename, "vc", &p)) { 372 qemu_opt_set(opts, "backend", "vc", &error_abort); 373 if (*p == ':') { 374 if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) { 375 /* pixels */ 376 qemu_opt_set(opts, "width", width, &error_abort); 377 qemu_opt_set(opts, "height", height, &error_abort); 378 } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) { 379 /* chars */ 380 qemu_opt_set(opts, "cols", width, &error_abort); 381 qemu_opt_set(opts, "rows", height, &error_abort); 382 } else { 383 goto fail; 384 } 385 } 386 return opts; 387 } 388 if (strcmp(filename, "con:") == 0) { 389 qemu_opt_set(opts, "backend", "console", &error_abort); 390 return opts; 391 } 392 if (strstart(filename, "COM", NULL)) { 393 qemu_opt_set(opts, "backend", "serial", &error_abort); 394 qemu_opt_set(opts, "path", filename, &error_abort); 395 return opts; 396 } 397 if (strstart(filename, "file:", &p)) { 398 qemu_opt_set(opts, "backend", "file", &error_abort); 399 qemu_opt_set(opts, "path", p, &error_abort); 400 return opts; 401 } 402 if (strstart(filename, "pipe:", &p)) { 403 qemu_opt_set(opts, "backend", "pipe", &error_abort); 404 qemu_opt_set(opts, "path", p, &error_abort); 405 return opts; 406 } 407 if (strstart(filename, "tcp:", &p) || 408 strstart(filename, "telnet:", &p) || 409 strstart(filename, "tn3270:", &p) || 410 strstart(filename, "websocket:", &p)) { 411 if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { 412 host[0] = 0; 413 if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) 414 goto fail; 415 } 416 qemu_opt_set(opts, "backend", "socket", &error_abort); 417 qemu_opt_set(opts, "host", host, &error_abort); 418 qemu_opt_set(opts, "port", port, &error_abort); 419 if (p[pos] == ',') { 420 if (!qemu_opts_do_parse(opts, p + pos + 1, NULL, &local_err)) { 421 error_report_err(local_err); 422 goto fail; 423 } 424 } 425 if (strstart(filename, "telnet:", &p)) { 426 qemu_opt_set(opts, "telnet", "on", &error_abort); 427 } else if (strstart(filename, "tn3270:", &p)) { 428 qemu_opt_set(opts, "tn3270", "on", &error_abort); 429 } else if (strstart(filename, "websocket:", &p)) { 430 qemu_opt_set(opts, "websocket", "on", &error_abort); 431 } 432 return opts; 433 } 434 if (strstart(filename, "udp:", &p)) { 435 qemu_opt_set(opts, "backend", "udp", &error_abort); 436 if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { 437 host[0] = 0; 438 if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) { 439 goto fail; 440 } 441 } 442 qemu_opt_set(opts, "host", host, &error_abort); 443 qemu_opt_set(opts, "port", port, &error_abort); 444 if (p[pos] == '@') { 445 p += pos + 1; 446 if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { 447 host[0] = 0; 448 if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { 449 goto fail; 450 } 451 } 452 qemu_opt_set(opts, "localaddr", host, &error_abort); 453 qemu_opt_set(opts, "localport", port, &error_abort); 454 } 455 return opts; 456 } 457 if (strstart(filename, "unix:", &p)) { 458 qemu_opt_set(opts, "backend", "socket", &error_abort); 459 if (!qemu_opts_do_parse(opts, p, "path", &local_err)) { 460 error_report_err(local_err); 461 goto fail; 462 } 463 return opts; 464 } 465 if (strstart(filename, "/dev/parport", NULL) || 466 strstart(filename, "/dev/ppi", NULL)) { 467 qemu_opt_set(opts, "backend", "parallel", &error_abort); 468 qemu_opt_set(opts, "path", filename, &error_abort); 469 return opts; 470 } 471 if (strstart(filename, "/dev/", NULL)) { 472 qemu_opt_set(opts, "backend", "serial", &error_abort); 473 qemu_opt_set(opts, "path", filename, &error_abort); 474 return opts; 475 } 476 477 error_report("'%s' is not a valid char driver", filename); 478 479 fail: 480 qemu_opts_del(opts); 481 return NULL; 482 } 483 484 void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend) 485 { 486 const char *logfile = qemu_opt_get(opts, "logfile"); 487 488 backend->has_logfile = logfile != NULL; 489 backend->logfile = g_strdup(logfile); 490 491 backend->has_logappend = true; 492 backend->logappend = qemu_opt_get_bool(opts, "logappend", false); 493 } 494 495 static const ChardevClass *char_get_class(const char *driver, Error **errp) 496 { 497 ObjectClass *oc; 498 const ChardevClass *cc; 499 char *typename = g_strdup_printf("chardev-%s", driver); 500 501 oc = module_object_class_by_name(typename); 502 g_free(typename); 503 504 if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) { 505 error_setg(errp, "'%s' is not a valid char driver name", driver); 506 return NULL; 507 } 508 509 if (object_class_is_abstract(oc)) { 510 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", 511 "abstract device type"); 512 return NULL; 513 } 514 515 cc = CHARDEV_CLASS(oc); 516 if (cc->internal) { 517 error_setg(errp, "'%s' is not a valid char driver name", driver); 518 return NULL; 519 } 520 521 return cc; 522 } 523 524 static const struct ChardevAlias { 525 const char *typename; 526 const char *alias; 527 } chardev_alias_table[] = { 528 #ifdef HAVE_CHARDEV_PARPORT 529 { "parallel", "parport" }, 530 #endif 531 #ifdef HAVE_CHARDEV_SERIAL 532 { "serial", "tty" }, 533 #endif 534 }; 535 536 typedef struct ChadevClassFE { 537 void (*fn)(const char *name, void *opaque); 538 void *opaque; 539 } ChadevClassFE; 540 541 static void 542 chardev_class_foreach(ObjectClass *klass, void *opaque) 543 { 544 ChadevClassFE *fe = opaque; 545 546 assert(g_str_has_prefix(object_class_get_name(klass), "chardev-")); 547 if (CHARDEV_CLASS(klass)->internal) { 548 return; 549 } 550 551 fe->fn(object_class_get_name(klass) + 8, fe->opaque); 552 } 553 554 static void 555 chardev_name_foreach(void (*fn)(const char *name, void *opaque), void *opaque) 556 { 557 ChadevClassFE fe = { .fn = fn, .opaque = opaque }; 558 int i; 559 560 object_class_foreach(chardev_class_foreach, TYPE_CHARDEV, false, &fe); 561 562 for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) { 563 fn(chardev_alias_table[i].alias, opaque); 564 } 565 } 566 567 static void 568 help_string_append(const char *name, void *opaque) 569 { 570 GString *str = opaque; 571 572 g_string_append_printf(str, "\n %s", name); 573 } 574 575 static const char *chardev_alias_translate(const char *name) 576 { 577 int i; 578 for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) { 579 if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) { 580 return chardev_alias_table[i].typename; 581 } 582 } 583 return name; 584 } 585 586 ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp) 587 { 588 Error *local_err = NULL; 589 const ChardevClass *cc; 590 ChardevBackend *backend = NULL; 591 const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); 592 593 if (name == NULL) { 594 error_setg(errp, "chardev: \"%s\" missing backend", 595 qemu_opts_id(opts)); 596 return NULL; 597 } 598 599 cc = char_get_class(name, errp); 600 if (cc == NULL) { 601 return NULL; 602 } 603 604 backend = g_new0(ChardevBackend, 1); 605 backend->type = CHARDEV_BACKEND_KIND_NULL; 606 607 if (cc->parse) { 608 cc->parse(opts, backend, &local_err); 609 if (local_err) { 610 error_propagate(errp, local_err); 611 qapi_free_ChardevBackend(backend); 612 return NULL; 613 } 614 } else { 615 ChardevCommon *ccom = g_new0(ChardevCommon, 1); 616 qemu_chr_parse_common(opts, ccom); 617 backend->u.null.data = ccom; /* Any ChardevCommon member would work */ 618 } 619 620 return backend; 621 } 622 623 Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context, 624 Error **errp) 625 { 626 const ChardevClass *cc; 627 Chardev *chr = NULL; 628 ChardevBackend *backend = NULL; 629 const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend")); 630 const char *id = qemu_opts_id(opts); 631 char *bid = NULL; 632 633 if (name && is_help_option(name)) { 634 GString *str = g_string_new(""); 635 636 chardev_name_foreach(help_string_append, str); 637 638 qemu_printf("Available chardev backend types: %s\n", str->str); 639 g_string_free(str, true); 640 return NULL; 641 } 642 643 if (id == NULL) { 644 error_setg(errp, "chardev: no id specified"); 645 return NULL; 646 } 647 648 backend = qemu_chr_parse_opts(opts, errp); 649 if (backend == NULL) { 650 return NULL; 651 } 652 653 cc = char_get_class(name, errp); 654 if (cc == NULL) { 655 goto out; 656 } 657 658 if (qemu_opt_get_bool(opts, "mux", 0)) { 659 bid = g_strdup_printf("%s-base", id); 660 } 661 662 chr = qemu_chardev_new(bid ? bid : id, 663 object_class_get_name(OBJECT_CLASS(cc)), 664 backend, context, errp); 665 666 if (chr == NULL) { 667 goto out; 668 } 669 670 if (bid) { 671 Chardev *mux; 672 qapi_free_ChardevBackend(backend); 673 backend = g_new0(ChardevBackend, 1); 674 backend->type = CHARDEV_BACKEND_KIND_MUX; 675 backend->u.mux.data = g_new0(ChardevMux, 1); 676 backend->u.mux.data->chardev = g_strdup(bid); 677 mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, context, errp); 678 if (mux == NULL) { 679 object_unparent(OBJECT(chr)); 680 chr = NULL; 681 goto out; 682 } 683 chr = mux; 684 } 685 686 out: 687 qapi_free_ChardevBackend(backend); 688 g_free(bid); 689 return chr; 690 } 691 692 Chardev *qemu_chr_new_noreplay(const char *label, const char *filename, 693 bool permit_mux_mon, GMainContext *context) 694 { 695 const char *p; 696 Chardev *chr; 697 QemuOpts *opts; 698 Error *err = NULL; 699 700 if (strstart(filename, "chardev:", &p)) { 701 return qemu_chr_find(p); 702 } 703 704 opts = qemu_chr_parse_compat(label, filename, permit_mux_mon); 705 if (!opts) 706 return NULL; 707 708 chr = qemu_chr_new_from_opts(opts, context, &err); 709 if (!chr) { 710 error_report_err(err); 711 goto out; 712 } 713 714 if (qemu_opt_get_bool(opts, "mux", 0)) { 715 assert(permit_mux_mon); 716 monitor_init_hmp(chr, true, &err); 717 if (err) { 718 error_report_err(err); 719 object_unparent(OBJECT(chr)); 720 chr = NULL; 721 goto out; 722 } 723 } 724 725 out: 726 qemu_opts_del(opts); 727 return chr; 728 } 729 730 static Chardev *qemu_chr_new_permit_mux_mon(const char *label, 731 const char *filename, 732 bool permit_mux_mon, 733 GMainContext *context) 734 { 735 Chardev *chr; 736 chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context); 737 if (chr) { 738 if (replay_mode != REPLAY_MODE_NONE) { 739 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY); 740 } 741 if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) { 742 error_report("Replay: ioctl is not supported " 743 "for serial devices yet"); 744 } 745 replay_register_char_driver(chr); 746 } 747 return chr; 748 } 749 750 Chardev *qemu_chr_new(const char *label, const char *filename, 751 GMainContext *context) 752 { 753 return qemu_chr_new_permit_mux_mon(label, filename, false, context); 754 } 755 756 Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename, 757 GMainContext *context) 758 { 759 return qemu_chr_new_permit_mux_mon(label, filename, true, context); 760 } 761 762 static int qmp_query_chardev_foreach(Object *obj, void *data) 763 { 764 Chardev *chr = CHARDEV(obj); 765 ChardevInfoList **list = data; 766 ChardevInfoList *info = g_malloc0(sizeof(*info)); 767 768 info->value = g_malloc0(sizeof(*info->value)); 769 info->value->label = g_strdup(chr->label); 770 info->value->filename = g_strdup(chr->filename); 771 info->value->frontend_open = chr->be && chr->be->fe_open; 772 773 info->next = *list; 774 *list = info; 775 776 return 0; 777 } 778 779 ChardevInfoList *qmp_query_chardev(Error **errp) 780 { 781 ChardevInfoList *chr_list = NULL; 782 783 object_child_foreach(get_chardevs_root(), 784 qmp_query_chardev_foreach, &chr_list); 785 786 return chr_list; 787 } 788 789 static void 790 qmp_prepend_backend(const char *name, void *opaque) 791 { 792 ChardevBackendInfoList **list = opaque; 793 ChardevBackendInfoList *info = g_malloc0(sizeof(*info)); 794 795 info->value = g_malloc0(sizeof(*info->value)); 796 info->value->name = g_strdup(name); 797 info->next = *list; 798 *list = info; 799 } 800 801 ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp) 802 { 803 ChardevBackendInfoList *backend_list = NULL; 804 805 chardev_name_foreach(qmp_prepend_backend, &backend_list); 806 807 return backend_list; 808 } 809 810 Chardev *qemu_chr_find(const char *name) 811 { 812 Object *obj = object_resolve_path_component(get_chardevs_root(), name); 813 814 return obj ? CHARDEV(obj) : NULL; 815 } 816 817 QemuOptsList qemu_chardev_opts = { 818 .name = "chardev", 819 .implied_opt_name = "backend", 820 .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), 821 .desc = { 822 { 823 .name = "backend", 824 .type = QEMU_OPT_STRING, 825 },{ 826 .name = "path", 827 .type = QEMU_OPT_STRING, 828 },{ 829 .name = "host", 830 .type = QEMU_OPT_STRING, 831 },{ 832 .name = "port", 833 .type = QEMU_OPT_STRING, 834 },{ 835 .name = "fd", 836 .type = QEMU_OPT_STRING, 837 },{ 838 .name = "localaddr", 839 .type = QEMU_OPT_STRING, 840 },{ 841 .name = "localport", 842 .type = QEMU_OPT_STRING, 843 },{ 844 .name = "to", 845 .type = QEMU_OPT_NUMBER, 846 },{ 847 .name = "ipv4", 848 .type = QEMU_OPT_BOOL, 849 },{ 850 .name = "ipv6", 851 .type = QEMU_OPT_BOOL, 852 },{ 853 .name = "wait", 854 .type = QEMU_OPT_BOOL, 855 },{ 856 .name = "server", 857 .type = QEMU_OPT_BOOL, 858 },{ 859 .name = "delay", 860 .type = QEMU_OPT_BOOL, 861 },{ 862 .name = "reconnect", 863 .type = QEMU_OPT_NUMBER, 864 },{ 865 .name = "telnet", 866 .type = QEMU_OPT_BOOL, 867 },{ 868 .name = "tn3270", 869 .type = QEMU_OPT_BOOL, 870 },{ 871 .name = "tls-creds", 872 .type = QEMU_OPT_STRING, 873 },{ 874 .name = "tls-authz", 875 .type = QEMU_OPT_STRING, 876 },{ 877 .name = "websocket", 878 .type = QEMU_OPT_BOOL, 879 },{ 880 .name = "width", 881 .type = QEMU_OPT_NUMBER, 882 },{ 883 .name = "height", 884 .type = QEMU_OPT_NUMBER, 885 },{ 886 .name = "cols", 887 .type = QEMU_OPT_NUMBER, 888 },{ 889 .name = "rows", 890 .type = QEMU_OPT_NUMBER, 891 },{ 892 .name = "mux", 893 .type = QEMU_OPT_BOOL, 894 },{ 895 .name = "signal", 896 .type = QEMU_OPT_BOOL, 897 },{ 898 .name = "name", 899 .type = QEMU_OPT_STRING, 900 },{ 901 .name = "debug", 902 .type = QEMU_OPT_NUMBER, 903 },{ 904 .name = "size", 905 .type = QEMU_OPT_SIZE, 906 },{ 907 .name = "chardev", 908 .type = QEMU_OPT_STRING, 909 },{ 910 .name = "append", 911 .type = QEMU_OPT_BOOL, 912 },{ 913 .name = "logfile", 914 .type = QEMU_OPT_STRING, 915 },{ 916 .name = "logappend", 917 .type = QEMU_OPT_BOOL, 918 },{ 919 .name = "tight", 920 .type = QEMU_OPT_BOOL, 921 .def_value_str = "on", 922 },{ 923 .name = "abstract", 924 .type = QEMU_OPT_BOOL, 925 }, 926 { /* end of list */ } 927 }, 928 }; 929 930 bool qemu_chr_has_feature(Chardev *chr, 931 ChardevFeature feature) 932 { 933 return test_bit(feature, chr->features); 934 } 935 936 void qemu_chr_set_feature(Chardev *chr, 937 ChardevFeature feature) 938 { 939 return set_bit(feature, chr->features); 940 } 941 942 static Chardev *chardev_new(const char *id, const char *typename, 943 ChardevBackend *backend, 944 GMainContext *gcontext, 945 Error **errp) 946 { 947 Object *obj; 948 Chardev *chr = NULL; 949 Error *local_err = NULL; 950 bool be_opened = true; 951 952 assert(g_str_has_prefix(typename, "chardev-")); 953 954 obj = object_new(typename); 955 chr = CHARDEV(obj); 956 chr->label = g_strdup(id); 957 chr->gcontext = gcontext; 958 959 qemu_char_open(chr, backend, &be_opened, &local_err); 960 if (local_err) { 961 goto end; 962 } 963 964 if (!chr->filename) { 965 chr->filename = g_strdup(typename + 8); 966 } 967 if (be_opened) { 968 qemu_chr_be_event(chr, CHR_EVENT_OPENED); 969 } 970 971 if (id) { 972 object_property_try_add_child(get_chardevs_root(), id, obj, 973 &local_err); 974 if (local_err) { 975 goto end; 976 } 977 object_unref(obj); 978 } 979 980 end: 981 if (local_err) { 982 error_propagate(errp, local_err); 983 object_unref(obj); 984 return NULL; 985 } 986 987 return chr; 988 } 989 990 Chardev *qemu_chardev_new(const char *id, const char *typename, 991 ChardevBackend *backend, 992 GMainContext *gcontext, 993 Error **errp) 994 { 995 g_autofree char *genid = NULL; 996 997 if (!id) { 998 genid = id_generate(ID_CHR); 999 id = genid; 1000 } 1001 1002 return chardev_new(id, typename, backend, gcontext, errp); 1003 } 1004 1005 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, 1006 Error **errp) 1007 { 1008 const ChardevClass *cc; 1009 ChardevReturn *ret; 1010 Chardev *chr; 1011 1012 cc = char_get_class(ChardevBackendKind_str(backend->type), errp); 1013 if (!cc) { 1014 return NULL; 1015 } 1016 1017 chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)), 1018 backend, NULL, errp); 1019 if (!chr) { 1020 return NULL; 1021 } 1022 1023 ret = g_new0(ChardevReturn, 1); 1024 if (CHARDEV_IS_PTY(chr)) { 1025 ret->pty = g_strdup(chr->filename + 4); 1026 ret->has_pty = true; 1027 } 1028 1029 return ret; 1030 } 1031 1032 ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend, 1033 Error **errp) 1034 { 1035 CharBackend *be; 1036 const ChardevClass *cc; 1037 Chardev *chr, *chr_new; 1038 bool closed_sent = false; 1039 ChardevReturn *ret; 1040 1041 chr = qemu_chr_find(id); 1042 if (!chr) { 1043 error_setg(errp, "Chardev '%s' does not exist", id); 1044 return NULL; 1045 } 1046 1047 if (CHARDEV_IS_MUX(chr)) { 1048 error_setg(errp, "Mux device hotswap not supported yet"); 1049 return NULL; 1050 } 1051 1052 if (qemu_chr_replay(chr)) { 1053 error_setg(errp, 1054 "Chardev '%s' cannot be changed in record/replay mode", id); 1055 return NULL; 1056 } 1057 1058 be = chr->be; 1059 if (!be) { 1060 /* easy case */ 1061 object_unparent(OBJECT(chr)); 1062 return qmp_chardev_add(id, backend, errp); 1063 } 1064 1065 if (!be->chr_be_change) { 1066 error_setg(errp, "Chardev user does not support chardev hotswap"); 1067 return NULL; 1068 } 1069 1070 cc = char_get_class(ChardevBackendKind_str(backend->type), errp); 1071 if (!cc) { 1072 return NULL; 1073 } 1074 1075 chr_new = chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)), 1076 backend, chr->gcontext, errp); 1077 if (!chr_new) { 1078 return NULL; 1079 } 1080 chr_new->label = g_strdup(id); 1081 1082 if (chr->be_open && !chr_new->be_open) { 1083 qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 1084 closed_sent = true; 1085 } 1086 1087 chr->be = NULL; 1088 qemu_chr_fe_init(be, chr_new, &error_abort); 1089 1090 if (be->chr_be_change(be->opaque) < 0) { 1091 error_setg(errp, "Chardev '%s' change failed", chr_new->label); 1092 chr_new->be = NULL; 1093 qemu_chr_fe_init(be, chr, &error_abort); 1094 if (closed_sent) { 1095 qemu_chr_be_event(chr, CHR_EVENT_OPENED); 1096 } 1097 object_unref(OBJECT(chr_new)); 1098 return NULL; 1099 } 1100 1101 object_unparent(OBJECT(chr)); 1102 object_property_add_child(get_chardevs_root(), chr_new->label, 1103 OBJECT(chr_new)); 1104 object_unref(OBJECT(chr_new)); 1105 1106 ret = g_new0(ChardevReturn, 1); 1107 if (CHARDEV_IS_PTY(chr_new)) { 1108 ret->pty = g_strdup(chr_new->filename + 4); 1109 ret->has_pty = true; 1110 } 1111 1112 return ret; 1113 } 1114 1115 void qmp_chardev_remove(const char *id, Error **errp) 1116 { 1117 Chardev *chr; 1118 1119 chr = qemu_chr_find(id); 1120 if (chr == NULL) { 1121 error_setg(errp, "Chardev '%s' not found", id); 1122 return; 1123 } 1124 if (qemu_chr_is_busy(chr)) { 1125 error_setg(errp, "Chardev '%s' is busy", id); 1126 return; 1127 } 1128 if (qemu_chr_replay(chr)) { 1129 error_setg(errp, 1130 "Chardev '%s' cannot be unplugged in record/replay mode", id); 1131 return; 1132 } 1133 object_unparent(OBJECT(chr)); 1134 } 1135 1136 void qmp_chardev_send_break(const char *id, Error **errp) 1137 { 1138 Chardev *chr; 1139 1140 chr = qemu_chr_find(id); 1141 if (chr == NULL) { 1142 error_setg(errp, "Chardev '%s' not found", id); 1143 return; 1144 } 1145 qemu_chr_be_event(chr, CHR_EVENT_BREAK); 1146 } 1147 1148 /* 1149 * Add a timeout callback for the chardev (in milliseconds), return 1150 * the GSource object created. Please use this to add timeout hook for 1151 * chardev instead of g_timeout_add() and g_timeout_add_seconds(), to 1152 * make sure the gcontext that the task bound to is correct. 1153 */ 1154 GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms, 1155 GSourceFunc func, void *private) 1156 { 1157 GSource *source = g_timeout_source_new(ms); 1158 1159 assert(func); 1160 g_source_set_callback(source, func, private, NULL); 1161 g_source_attach(source, chr->gcontext); 1162 1163 return source; 1164 } 1165 1166 void qemu_chr_cleanup(void) 1167 { 1168 object_unparent(get_chardevs_root()); 1169 } 1170 1171 static void register_types(void) 1172 { 1173 type_register_static(&char_type_info); 1174 } 1175 1176 type_init(register_types); 1177