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