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