]> Git Repo - qemu.git/blame - chardev/char.c
Merge remote-tracking branch 'remotes/elmarco/tags/prop-ptr-pull-request' into staging
[qemu.git] / chardev / char.c
CommitLineData
6f97dba0
AL
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 */
e688df6b 24
d38ea87a 25#include "qemu/osdep.h"
f348b6d1 26#include "qemu/cutils.h"
83c9089e 27#include "monitor/monitor.h"
9c17d615 28#include "sysemu/sysemu.h"
213dcb06 29#include "qemu/config-file.h"
d49b6836 30#include "qemu/error-report.h"
ef2fd6f1 31#include "qemu/qemu-print.h"
8228e353 32#include "chardev/char.h"
e688df6b 33#include "qapi/error.h"
9af23989 34#include "qapi/qapi-commands-char.h"
0dd13589 35#include "qapi/qmp/qerror.h"
33577b47 36#include "sysemu/replay.h"
517b3d40 37#include "qemu/help_option.h"
0b8fa32f 38#include "qemu/module.h"
922a01a0 39#include "qemu/option.h"
1e419ee6 40#include "qemu/id.h"
6f97dba0 41
8228e353 42#include "chardev/char-mux.h"
df85a78b 43
6f97dba0
AL
44/***********************************************************/
45/* character device */
46
2f5d45a1
MAL
47static Object *get_chardevs_root(void)
48{
49 return container_get(object_get_root(), "/chardevs");
50}
2970a6c9 51
d09c4a47 52static void chr_be_event(Chardev *s, int event)
6f97dba0 53{
a4afa548
MAL
54 CharBackend *be = s->be;
55
d09c4a47
MAL
56 if (!be || !be->chr_event) {
57 return;
58 }
59
60 be->chr_event(be->opaque, event);
61}
62
63void qemu_chr_be_event(Chardev *s, int event)
64{
73cdf3f2
AG
65 /* Keep track if the char device is open */
66 switch (event) {
67 case CHR_EVENT_OPENED:
16665b94 68 s->be_open = 1;
73cdf3f2
AG
69 break;
70 case CHR_EVENT_CLOSED:
16665b94 71 s->be_open = 0;
73cdf3f2
AG
72 break;
73 }
74
d09c4a47 75 CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
6f97dba0
AL
76}
77
d0d7708b
DB
78/* Not reporting errors from writing to logfile, as logs are
79 * defined to be "best effort" only */
a9b1ca38 80static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
d0d7708b
DB
81{
82 size_t done = 0;
83 ssize_t ret;
84
85 if (s->logfd < 0) {
86 return;
87 }
88
89 while (done < len) {
53628efb
DB
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 }
d0d7708b
DB
96
97 if (ret <= 0) {
98 return;
99 }
100 done += ret;
101 }
102}
103
a9b1ca38
MAL
104static int qemu_chr_write_buffer(Chardev *s,
105 const uint8_t *buf, int len,
106 int *offset, bool write_all)
33577b47 107{
777357d7 108 ChardevClass *cc = CHARDEV_GET_CLASS(s);
33577b47
PD
109 int res = 0;
110 *offset = 0;
111
112 qemu_mutex_lock(&s->chr_write_lock);
113 while (*offset < len) {
53628efb 114 retry:
777357d7 115 res = cc->chr_write(s, buf + *offset, len - *offset);
c90e9392 116 if (res < 0 && errno == EAGAIN && write_all) {
53628efb
DB
117 g_usleep(100);
118 goto retry;
119 }
33577b47
PD
120
121 if (res <= 0) {
122 break;
123 }
124
125 *offset += res;
c90e9392
MAL
126 if (!write_all) {
127 break;
128 }
33577b47
PD
129 }
130 if (*offset > 0) {
a9b1ca38 131 qemu_chr_write_log(s, buf, *offset);
33577b47
PD
132 }
133 qemu_mutex_unlock(&s->chr_write_lock);
134
135 return res;
136}
137
4d43a603 138int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all)
cd18720a 139{
c90e9392 140 int offset = 0;
33577b47 141 int res;
cd18720a 142
5ebd6703 143 if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
33577b47
PD
144 replay_char_write_event_load(&res, &offset);
145 assert(offset <= len);
a9b1ca38 146 qemu_chr_write_buffer(s, buf, offset, &offset, true);
33577b47
PD
147 return res;
148 }
cd18720a 149
a9b1ca38 150 res = qemu_chr_write_buffer(s, buf, len, &offset, write_all);
cd18720a 151
5ebd6703 152 if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
33577b47 153 replay_char_write_event_save(res, offset);
cd18720a
AL
154 }
155
9005b2a7
PB
156 if (res < 0) {
157 return res;
158 }
cd18720a
AL
159 return offset;
160}
161
0ec7b3e7 162int qemu_chr_be_can_write(Chardev *s)
6f97dba0 163{
a4afa548
MAL
164 CharBackend *be = s->be;
165
166 if (!be || !be->chr_can_read) {
6f97dba0 167 return 0;
a4afa548
MAL
168 }
169
170 return be->chr_can_read(be->opaque);
6f97dba0
AL
171}
172
0ec7b3e7 173void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
6f97dba0 174{
a4afa548
MAL
175 CharBackend *be = s->be;
176
177 if (be && be->chr_read) {
178 be->chr_read(be->opaque, buf, len);
ac310734 179 }
6f97dba0
AL
180}
181
0ec7b3e7 182void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
33577b47 183{
5ebd6703 184 if (qemu_chr_replay(s)) {
33577b47
PD
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
07241c20
PX
194void qemu_chr_be_update_read_handlers(Chardev *s,
195 GMainContext *context)
196{
197 ChardevClass *cc = CHARDEV_GET_CLASS(s);
198
9ac3788b
MAL
199 assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT)
200 || !context);
95eeeba6 201 s->gcontext = context;
07241c20 202 if (cc->chr_update_read_handler) {
bb86d05f 203 cc->chr_update_read_handler(s);
07241c20
PX
204 }
205}
206
0ec7b3e7 207int qemu_chr_add_client(Chardev *s, int fd)
13661089 208{
777357d7
MAL
209 return CHARDEV_GET_CLASS(s)->chr_add_client ?
210 CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
13661089
DB
211}
212
777357d7
MAL
213static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
214 bool *be_opened, Error **errp)
6f97dba0 215{
777357d7
MAL
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 }
6f97dba0
AL
240}
241
777357d7 242static void char_init(Object *obj)
6f97dba0 243{
777357d7 244 Chardev *chr = CHARDEV(obj);
6f97dba0 245
777357d7
MAL
246 chr->logfd = -1;
247 qemu_mutex_init(&chr->chr_write_lock);
9ac3788b
MAL
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
777357d7
MAL
257}
258
eb314a94
MAL
259static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
260{
261 return len;
262}
263
264static void char_class_init(ObjectClass *oc, void *data)
265{
266 ChardevClass *cc = CHARDEV_CLASS(oc);
267
268 cc->chr_write = null_chr_write;
d09c4a47 269 cc->chr_be_event = chr_be_event;
eb314a94
MAL
270}
271
777357d7
MAL
272static 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);
d0d7708b 283 }
777357d7
MAL
284 qemu_mutex_destroy(&chr->chr_write_lock);
285}
286
287static 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),
eb314a94 295 .class_init = char_class_init,
777357d7
MAL
296};
297
c7278b43 298static int chardev_machine_done_notify_one(Object *child, void *opaque)
7b7ab18d 299{
c7278b43
PX
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);
6061162e 305 }
7b7ab18d 306
6061162e
MAL
307 return 0;
308}
7b7ab18d 309
c7278b43 310static void chardev_machine_done_hook(Notifier *notifier, void *unused)
6061162e 311{
c7278b43
PX
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 }
7b7ab18d
MR
319}
320
c7278b43
PX
321static Notifier chardev_machine_done_notify = {
322 .notify = chardev_machine_done_hook,
7b7ab18d
MR
323};
324
0ec7b3e7 325static bool qemu_chr_is_busy(Chardev *s)
a4afa548 326{
777357d7
MAL
327 if (CHARDEV_IS_MUX(s)) {
328 MuxChardev *d = MUX_CHARDEV(s);
a4afa548
MAL
329 return d->mux_cnt >= 0;
330 } else {
331 return s->be != NULL;
332 }
333}
334
d24ca4b8 335int qemu_chr_wait_connected(Chardev *chr, Error **errp)
6b6723c3 336{
777357d7
MAL
337 ChardevClass *cc = CHARDEV_GET_CLASS(chr);
338
339 if (cc->chr_wait_connected) {
340 return cc->chr_wait_connected(chr, errp);
6b6723c3
MAL
341 }
342
343 return 0;
344}
345
95e30b2a
MAL
346QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
347 bool permit_mux_mon)
191bc01b 348{
6ea314d9 349 char host[65], port[33], width[8], height[8];
aeb2c47a 350 int pos;
7d31544f 351 const char *p;
191bc01b 352 QemuOpts *opts;
8be7e7e4 353 Error *local_err = NULL;
191bc01b 354
8be7e7e4 355 opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err);
84d18f06 356 if (local_err) {
33394884 357 error_report_err(local_err);
191bc01b 358 return NULL;
8be7e7e4 359 }
191bc01b 360
7591c5c1 361 if (strstart(filename, "mon:", &p)) {
95e30b2a
MAL
362 if (!permit_mux_mon) {
363 error_report("mon: isn't supported in this context");
364 return NULL;
365 }
7591c5c1 366 filename = p;
f43e47db 367 qemu_opt_set(opts, "mux", "on", &error_abort);
02c4bdf1
PB
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. */
f43e47db 374 qemu_opt_set(opts, "signal", "off", &error_abort);
02c4bdf1 375 }
7591c5c1
GH
376 }
377
f0457e8d
GH
378 if (strcmp(filename, "null") == 0 ||
379 strcmp(filename, "pty") == 0 ||
380 strcmp(filename, "msmouse") == 0 ||
378af961 381 strcmp(filename, "wctablet") == 0 ||
dc1c21e6 382 strcmp(filename, "braille") == 0 ||
5692399f 383 strcmp(filename, "testdev") == 0 ||
f0457e8d 384 strcmp(filename, "stdio") == 0) {
f43e47db 385 qemu_opt_set(opts, "backend", filename, &error_abort);
191bc01b
GH
386 return opts;
387 }
6ea314d9 388 if (strstart(filename, "vc", &p)) {
f43e47db 389 qemu_opt_set(opts, "backend", "vc", &error_abort);
6ea314d9 390 if (*p == ':') {
49aa4058 391 if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) {
6ea314d9 392 /* pixels */
f43e47db
MA
393 qemu_opt_set(opts, "width", width, &error_abort);
394 qemu_opt_set(opts, "height", height, &error_abort);
49aa4058 395 } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) {
6ea314d9 396 /* chars */
f43e47db
MA
397 qemu_opt_set(opts, "cols", width, &error_abort);
398 qemu_opt_set(opts, "rows", height, &error_abort);
6ea314d9
GH
399 } else {
400 goto fail;
401 }
402 }
403 return opts;
404 }
d6c983cd 405 if (strcmp(filename, "con:") == 0) {
f43e47db 406 qemu_opt_set(opts, "backend", "console", &error_abort);
d6c983cd
GH
407 return opts;
408 }
48b76496 409 if (strstart(filename, "COM", NULL)) {
f43e47db
MA
410 qemu_opt_set(opts, "backend", "serial", &error_abort);
411 qemu_opt_set(opts, "path", filename, &error_abort);
48b76496
GH
412 return opts;
413 }
7d31544f 414 if (strstart(filename, "file:", &p)) {
f43e47db
MA
415 qemu_opt_set(opts, "backend", "file", &error_abort);
416 qemu_opt_set(opts, "path", p, &error_abort);
7d31544f
GH
417 return opts;
418 }
419 if (strstart(filename, "pipe:", &p)) {
f43e47db
MA
420 qemu_opt_set(opts, "backend", "pipe", &error_abort);
421 qemu_opt_set(opts, "path", p, &error_abort);
7d31544f
GH
422 return opts;
423 }
aeb2c47a 424 if (strstart(filename, "tcp:", &p) ||
ae92cbd5 425 strstart(filename, "telnet:", &p) ||
981b06e7
JS
426 strstart(filename, "tn3270:", &p) ||
427 strstart(filename, "websocket:", &p)) {
aeb2c47a
GH
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 }
f43e47db
MA
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);
aeb2c47a 436 if (p[pos] == ',') {
dc523cd3
MA
437 qemu_opts_do_parse(opts, p+pos+1, NULL, &local_err);
438 if (local_err) {
439 error_report_err(local_err);
aeb2c47a 440 goto fail;
dc523cd3 441 }
aeb2c47a 442 }
ae92cbd5 443 if (strstart(filename, "telnet:", &p)) {
f43e47db 444 qemu_opt_set(opts, "telnet", "on", &error_abort);
ae92cbd5
JL
445 } else if (strstart(filename, "tn3270:", &p)) {
446 qemu_opt_set(opts, "tn3270", "on", &error_abort);
981b06e7
JS
447 } else if (strstart(filename, "websocket:", &p)) {
448 qemu_opt_set(opts, "websocket", "on", &error_abort);
ae92cbd5 449 }
aeb2c47a
GH
450 return opts;
451 }
7e1b35b4 452 if (strstart(filename, "udp:", &p)) {
f43e47db 453 qemu_opt_set(opts, "backend", "udp", &error_abort);
7e1b35b4
GH
454 if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
455 host[0] = 0;
39324ca4 456 if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
7e1b35b4
GH
457 goto fail;
458 }
459 }
f43e47db
MA
460 qemu_opt_set(opts, "host", host, &error_abort);
461 qemu_opt_set(opts, "port", port, &error_abort);
7e1b35b4
GH
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) {
7e1b35b4
GH
467 goto fail;
468 }
469 }
f43e47db
MA
470 qemu_opt_set(opts, "localaddr", host, &error_abort);
471 qemu_opt_set(opts, "localport", port, &error_abort);
7e1b35b4
GH
472 }
473 return opts;
474 }
aeb2c47a 475 if (strstart(filename, "unix:", &p)) {
f43e47db 476 qemu_opt_set(opts, "backend", "socket", &error_abort);
dc523cd3
MA
477 qemu_opts_do_parse(opts, p, "path", &local_err);
478 if (local_err) {
479 error_report_err(local_err);
aeb2c47a 480 goto fail;
dc523cd3 481 }
aeb2c47a
GH
482 return opts;
483 }
48b76496
GH
484 if (strstart(filename, "/dev/parport", NULL) ||
485 strstart(filename, "/dev/ppi", NULL)) {
73119c28 486 qemu_opt_set(opts, "backend", "parallel", &error_abort);
f43e47db 487 qemu_opt_set(opts, "path", filename, &error_abort);
48b76496
GH
488 return opts;
489 }
490 if (strstart(filename, "/dev/", NULL)) {
73119c28 491 qemu_opt_set(opts, "backend", "serial", &error_abort);
f43e47db 492 qemu_opt_set(opts, "path", filename, &error_abort);
48b76496
GH
493 return opts;
494 }
191bc01b 495
0bf62dc8
DB
496 error_report("'%s' is not a valid char driver", filename);
497
aeb2c47a 498fail:
191bc01b
GH
499 qemu_opts_del(opts);
500 return NULL;
501}
502
21a933ea 503void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
d0d7708b
DB
504{
505 const char *logfile = qemu_opt_get(opts, "logfile");
506
507 backend->has_logfile = logfile != NULL;
e1f98fe4 508 backend->logfile = g_strdup(logfile);
d0d7708b
DB
509
510 backend->has_logappend = true;
511 backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
512}
513
88cace9f
MAL
514static 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 }
d654f34e 527
88cace9f
MAL
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
543static 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
555typedef struct ChadevClassFE {
556 void (*fn)(const char *name, void *opaque);
557 void *opaque;
558} ChadevClassFE;
559
560static void
561chardev_class_foreach(ObjectClass *klass, void *opaque)
2c5f4882 562{
88cace9f
MAL
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
573static void
574chardev_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
c7e47c63 581 for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
88cace9f
MAL
582 fn(chardev_alias_table[i].alias, opaque);
583 }
584}
585
586static void
587help_string_append(const char *name, void *opaque)
588{
589 GString *str = opaque;
590
8513ec28 591 g_string_append_printf(str, "\n %s", name);
2c5f4882
GH
592}
593
313e45b5
AN
594static 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
75b60160 605ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
191bc01b 606{
0aff637e 607 Error *local_err = NULL;
88cace9f 608 const ChardevClass *cc;
0b663b7d 609 ChardevBackend *backend = NULL;
313e45b5 610 const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
191bc01b 611
0b812f31 612 if (name == NULL) {
312fd5f2 613 error_setg(errp, "chardev: \"%s\" missing backend",
bd2d80b2 614 qemu_opts_id(opts));
0b663b7d 615 return NULL;
1bbd185f 616 }
517b3d40 617
313e45b5
AN
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
4ad6f6cb
PB
642Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
643 Error **errp)
313e45b5
AN
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)) {
776a32a0 653 GString *str = g_string_new("");
88cace9f
MAL
654
655 chardev_name_foreach(help_string_append, str);
776a32a0 656
ef2fd6f1 657 qemu_printf("Available chardev backend types: %s\n", str->str);
776a32a0 658 g_string_free(str, true);
0ec846bf 659 return NULL;
517b3d40
LM
660 }
661
662 if (id == NULL) {
663 error_setg(errp, "chardev: no id specified");
0b663b7d 664 return NULL;
517b3d40
LM
665 }
666
313e45b5
AN
667 backend = qemu_chr_parse_opts(opts, errp);
668 if (backend == NULL) {
669 return NULL;
191bc01b 670 }
88cace9f
MAL
671
672 cc = char_get_class(name, errp);
673 if (cc == NULL) {
313e45b5 674 goto out;
191bc01b
GH
675 }
676
a61ae7f8
PM
677 if (qemu_opt_get_bool(opts, "mux", 0)) {
678 bid = g_strdup_printf("%s-base", id);
679 }
2c5f4882 680
c5749f7c 681 chr = qemu_chardev_new(bid ? bid : id,
0b663b7d 682 object_class_get_name(OBJECT_CLASS(cc)),
4ad6f6cb 683 backend, context, errp);
c5749f7c 684
0b663b7d
MAL
685 if (chr == NULL) {
686 goto out;
191bc01b
GH
687 }
688
a61ae7f8 689 if (bid) {
0b663b7d 690 Chardev *mux;
a61ae7f8 691 qapi_free_ChardevBackend(backend);
a61ae7f8 692 backend = g_new0(ChardevBackend, 1);
130257dc 693 backend->type = CHARDEV_BACKEND_KIND_MUX;
0b663b7d 694 backend->u.mux.data = g_new0(ChardevMux, 1);
32bafa8f 695 backend->u.mux.data->chardev = g_strdup(bid);
4ad6f6cb 696 mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, context, errp);
0b663b7d 697 if (mux == NULL) {
2f5d45a1 698 object_unparent(OBJECT(chr));
a61ae7f8 699 chr = NULL;
0b663b7d 700 goto out;
a61ae7f8 701 }
0b663b7d 702 chr = mux;
bd5c51ee 703 }
7591c5c1 704
0b663b7d 705out:
a61ae7f8 706 qapi_free_ChardevBackend(backend);
a61ae7f8 707 g_free(bid);
191bc01b
GH
708 return chr;
709}
710
95e30b2a 711Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
4ad6f6cb 712 bool permit_mux_mon, GMainContext *context)
6f97dba0
AL
713{
714 const char *p;
0ec7b3e7 715 Chardev *chr;
191bc01b 716 QemuOpts *opts;
bd2d80b2 717 Error *err = NULL;
191bc01b 718
c845f401
GH
719 if (strstart(filename, "chardev:", &p)) {
720 return qemu_chr_find(p);
721 }
722
95e30b2a 723 opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
7e1b35b4
GH
724 if (!opts)
725 return NULL;
6f97dba0 726
4ad6f6cb 727 chr = qemu_chr_new_from_opts(opts, context, &err);
95e30b2a 728 if (!chr) {
565f65d2 729 error_report_err(err);
95e30b2a 730 goto out;
bd2d80b2 731 }
95e30b2a
MAL
732
733 if (qemu_opt_get_bool(opts, "mux", 0)) {
734 assert(permit_mux_mon);
fbfc29e3 735 monitor_init_hmp(chr, true);
6f97dba0 736 }
95e30b2a
MAL
737
738out:
0a73336d 739 qemu_opts_del(opts);
6f97dba0
AL
740 return chr;
741}
742
95e30b2a
MAL
743static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
744 const char *filename,
4ad6f6cb
PB
745 bool permit_mux_mon,
746 GMainContext *context)
33577b47 747{
0ec7b3e7 748 Chardev *chr;
4ad6f6cb 749 chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
33577b47 750 if (chr) {
5ebd6703
MAL
751 if (replay_mode != REPLAY_MODE_NONE) {
752 qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
753 }
777357d7 754 if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
776a32a0
MAL
755 error_report("Replay: ioctl is not supported "
756 "for serial devices yet");
33577b47
PD
757 }
758 replay_register_char_driver(chr);
759 }
760 return chr;
761}
762
4ad6f6cb
PB
763Chardev *qemu_chr_new(const char *label, const char *filename,
764 GMainContext *context)
95e30b2a 765{
4ad6f6cb 766 return qemu_chr_new_permit_mux_mon(label, filename, false, context);
95e30b2a
MAL
767}
768
4ad6f6cb
PB
769Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename,
770 GMainContext *context)
95e30b2a 771{
4ad6f6cb 772 return qemu_chr_new_permit_mux_mon(label, filename, true, context);
95e30b2a
MAL
773}
774
6061162e 775static int qmp_query_chardev_foreach(Object *obj, void *data)
1ad78ea5 776{
6061162e
MAL
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;
1ad78ea5
MAL
790}
791
c5a415a0 792ChardevInfoList *qmp_query_chardev(Error **errp)
6f97dba0 793{
c5a415a0 794 ChardevInfoList *chr_list = NULL;
6f97dba0 795
6061162e
MAL
796 object_child_foreach(get_chardevs_root(),
797 qmp_query_chardev_foreach, &chr_list);
588b3832 798
c5a415a0 799 return chr_list;
6f97dba0 800}
c845f401 801
88cace9f
MAL
802static void
803qmp_prepend_backend(const char *name, void *opaque)
0b812f31 804{
88cace9f 805 ChardevBackendInfoList **list = opaque;
0b812f31 806 ChardevBackendInfoList *info = g_malloc0(sizeof(*info));
88cace9f 807
0b812f31
MAL
808 info->value = g_malloc0(sizeof(*info->value));
809 info->value->name = g_strdup(name);
88cace9f
MAL
810 info->next = *list;
811 *list = info;
0b812f31
MAL
812}
813
77d1c3c6
MK
814ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
815{
816 ChardevBackendInfoList *backend_list = NULL;
a1698bf1 817
88cace9f 818 chardev_name_foreach(qmp_prepend_backend, &backend_list);
77d1c3c6
MK
819
820 return backend_list;
821}
822
0ec7b3e7 823Chardev *qemu_chr_find(const char *name)
c845f401 824{
6061162e 825 Object *obj = object_resolve_path_component(get_chardevs_root(), name);
c845f401 826
6061162e 827 return obj ? CHARDEV(obj) : NULL;
c845f401 828}
0beb4942 829
4d454574
PB
830QemuOptsList 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,
0935700f
DB
847 },{
848 .name = "fd",
849 .type = QEMU_OPT_STRING,
4d454574
PB
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,
5dd1f02b
CM
874 },{
875 .name = "reconnect",
876 .type = QEMU_OPT_NUMBER,
4d454574
PB
877 },{
878 .name = "telnet",
879 .type = QEMU_OPT_BOOL,
ae92cbd5
JL
880 },{
881 .name = "tn3270",
882 .type = QEMU_OPT_BOOL,
a8fb5427
DB
883 },{
884 .name = "tls-creds",
885 .type = QEMU_OPT_STRING,
fd4a5fd4
DB
886 },{
887 .name = "tls-authz",
888 .type = QEMU_OPT_STRING,
981b06e7
JS
889 },{
890 .name = "websocket",
891 .type = QEMU_OPT_BOOL,
4d454574
PB
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,
51767e7c 916 },{
3949e594 917 .name = "size",
de1cc36e 918 .type = QEMU_OPT_SIZE,
bb6fb7c0
GH
919 },{
920 .name = "chardev",
921 .type = QEMU_OPT_STRING,
31e38a22
OK
922 },{
923 .name = "append",
924 .type = QEMU_OPT_BOOL,
d0d7708b
DB
925 },{
926 .name = "logfile",
927 .type = QEMU_OPT_STRING,
928 },{
929 .name = "logappend",
930 .type = QEMU_OPT_BOOL,
4d454574
PB
931 },
932 { /* end of list */ }
933 },
934};
f1a1a356 935
0ec7b3e7 936bool qemu_chr_has_feature(Chardev *chr,
279b066e 937 ChardevFeature feature)
0a73336d
DB
938{
939 return test_bit(feature, chr->features);
940}
941
0ec7b3e7 942void qemu_chr_set_feature(Chardev *chr,
279b066e 943 ChardevFeature feature)
0a73336d
DB
944{
945 return set_bit(feature, chr->features);
946}
947
1e419ee6
MAL
948static Chardev *chardev_new(const char *id, const char *typename,
949 ChardevBackend *backend,
950 GMainContext *gcontext,
951 Error **errp)
f1a1a356 952{
2f5d45a1 953 Object *obj;
0ec7b3e7 954 Chardev *chr = NULL;
eaeba653 955 Error *local_err = NULL;
82878dac 956 bool be_opened = true;
f1a1a356 957
777357d7 958 assert(g_str_has_prefix(typename, "chardev-"));
f1a1a356 959
2f5d45a1
MAL
960 obj = object_new(typename);
961 chr = CHARDEV(obj);
777357d7 962 chr->label = g_strdup(id);
4ad6f6cb 963 chr->gcontext = gcontext;
4ca17281 964
777357d7 965 qemu_char_open(chr, backend, &be_opened, &local_err);
a1698bf1 966 if (local_err) {
2f5d45a1 967 goto end;
eaeba653
PB
968 }
969
eaeba653 970 if (!chr->filename) {
777357d7 971 chr->filename = g_strdup(typename + 8);
f1a1a356 972 }
82878dac 973 if (be_opened) {
eaeba653
PB
974 qemu_chr_be_event(chr, CHR_EVENT_OPENED);
975 }
777357d7 976
2f5d45a1
MAL
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
985end:
986 if (local_err) {
987 error_propagate(errp, local_err);
988 object_unref(obj);
989 return NULL;
990 }
991
777357d7
MAL
992 return chr;
993}
994
1e419ee6
MAL
995Chardev *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
777357d7
MAL
1010ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
1011 Error **errp)
1012{
1013 const ChardevClass *cc;
1014 ChardevReturn *ret;
1015 Chardev *chr;
1016
977c736f 1017 cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
777357d7
MAL
1018 if (!cc) {
1019 return NULL;
1020 }
1021
1e419ee6
MAL
1022 chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
1023 backend, NULL, errp);
777357d7
MAL
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
eaeba653 1034 return ret;
f1a1a356
GH
1035}
1036
7bb86085
AN
1037ChardevReturn *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
977c736f 1075 cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
7bb86085
AN
1076 if (!cc) {
1077 return NULL;
1078 }
1079
1e419ee6
MAL
1080 chr_new = chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
1081 backend, chr->gcontext, errp);
7bb86085
AN
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
f1a1a356
GH
1120void qmp_chardev_remove(const char *id, Error **errp)
1121{
0ec7b3e7 1122 Chardev *chr;
f1a1a356
GH
1123
1124 chr = qemu_chr_find(id);
8108fd3e 1125 if (chr == NULL) {
f1a1a356
GH
1126 error_setg(errp, "Chardev '%s' not found", id);
1127 return;
1128 }
a4afa548 1129 if (qemu_chr_is_busy(chr)) {
f1a1a356
GH
1130 error_setg(errp, "Chardev '%s' is busy", id);
1131 return;
1132 }
5ebd6703 1133 if (qemu_chr_replay(chr)) {
33577b47
PD
1134 error_setg(errp,
1135 "Chardev '%s' cannot be unplugged in record/replay mode", id);
1136 return;
1137 }
2f5d45a1 1138 object_unparent(OBJECT(chr));
f1a1a356 1139}
d654f34e 1140
bd1d5ad9
SF
1141void 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
2c716ba1
PX
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 */
1159GSource *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
aa5cb7f5 1171void qemu_chr_cleanup(void)
c1111a24 1172{
2f5d45a1 1173 object_unparent(get_chardevs_root());
c1111a24
MAL
1174}
1175
d654f34e
AL
1176static void register_types(void)
1177{
88cace9f 1178 type_register_static(&char_type_info);
0b812f31 1179
7b7ab18d
MR
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 */
c7278b43 1184 qemu_add_machine_init_done_notifier(&chardev_machine_done_notify);
d654f34e
AL
1185}
1186
1187type_init(register_types);
This page took 1.215367 seconds and 4 git commands to generate.