xref: /qemu/chardev/char.c (revision ab9056ff)
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