hw/display/xlnx_dp: Free FIFOs adding xlnx_dp_finalize()
[qemu/ar7.git] / chardev / char.c
blob140d6d9d369a6e17668ca2c4e3be4e14af6f9674
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  */
25 #include "qemu/osdep.h"
26 #include "qemu/cutils.h"
27 #include "monitor/monitor.h"
28 #include "sysemu/sysemu.h"
29 #include "qemu/config-file.h"
30 #include "qemu/error-report.h"
31 #include "qemu/qemu-print.h"
32 #include "chardev/char.h"
33 #include "qapi/error.h"
34 #include "qapi/qapi-commands-char.h"
35 #include "qapi/qmp/qerror.h"
36 #include "sysemu/replay.h"
37 #include "qemu/help_option.h"
38 #include "qemu/module.h"
39 #include "qemu/option.h"
40 #include "qemu/id.h"
41 #include "qemu/coroutine.h"
43 #include "chardev-internal.h"
45 /***********************************************************/
46 /* character device */
48 Object *get_chardevs_root(void)
50     return container_get(object_get_root(), "/chardevs");
53 static void chr_be_event(Chardev *s, QEMUChrEvent event)
55     CharBackend *be = s->be;
57     if (!be || !be->chr_event) {
58         return;
59     }
61     be->chr_event(be->opaque, event);
64 void qemu_chr_be_event(Chardev *s, QEMUChrEvent event)
66     /* Keep track if the char device is open */
67     switch (event) {
68         case CHR_EVENT_OPENED:
69             s->be_open = 1;
70             break;
71         case CHR_EVENT_CLOSED:
72             s->be_open = 0;
73             break;
74     case CHR_EVENT_BREAK:
75     case CHR_EVENT_MUX_IN:
76     case CHR_EVENT_MUX_OUT:
77         /* Ignore */
78         break;
79     }
81     CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
84 /* Not reporting errors from writing to logfile, as logs are
85  * defined to be "best effort" only */
86 static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
88     size_t done = 0;
89     ssize_t ret;
91     if (s->logfd < 0) {
92         return;
93     }
95     while (done < len) {
96     retry:
97         ret = write(s->logfd, buf + done, len - done);
98         if (ret == -1 && errno == EAGAIN) {
99             g_usleep(100);
100             goto retry;
101         }
103         if (ret <= 0) {
104             return;
105         }
106         done += ret;
107     }
110 static int qemu_chr_write_buffer(Chardev *s,
111                                  const uint8_t *buf, int len,
112                                  int *offset, bool write_all)
114     ChardevClass *cc = CHARDEV_GET_CLASS(s);
115     int res = 0;
116     *offset = 0;
118     qemu_mutex_lock(&s->chr_write_lock);
119     while (*offset < len) {
120     retry:
121         res = cc->chr_write(s, buf + *offset, len - *offset);
122         if (res < 0 && errno == EAGAIN && write_all) {
123             if (qemu_in_coroutine()) {
124                 qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
125             } else {
126                 g_usleep(100);
127             }
128             goto retry;
129         }
131         if (res <= 0) {
132             break;
133         }
135         *offset += res;
136         if (!write_all) {
137             break;
138         }
139     }
140     if (*offset > 0) {
141         /*
142          * If some data was written by backend, we should
143          * only log what was actually written. This method
144          * may be invoked again to write the remaining
145          * method, thus we'll log the remainder at that time.
146          */
147         qemu_chr_write_log(s, buf, *offset);
148     } else if (res < 0) {
149         /*
150          * If a fatal error was reported by the backend,
151          * assume this method won't be invoked again with
152          * this buffer, so log it all right away.
153          */
154         qemu_chr_write_log(s, buf, len);
155     }
156     qemu_mutex_unlock(&s->chr_write_lock);
158     return res;
161 int qemu_chr_write(Chardev *s, const uint8_t *buf, int len, bool write_all)
163     int offset = 0;
164     int res;
166     if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
167         replay_char_write_event_load(&res, &offset);
168         assert(offset <= len);
169         qemu_chr_write_buffer(s, buf, offset, &offset, true);
170         return res;
171     }
173     res = qemu_chr_write_buffer(s, buf, len, &offset, write_all);
175     if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
176         replay_char_write_event_save(res, offset);
177     }
179     if (res < 0) {
180         return res;
181     }
182     return offset;
185 int qemu_chr_be_can_write(Chardev *s)
187     CharBackend *be = s->be;
189     if (!be || !be->chr_can_read) {
190         return 0;
191     }
193     return be->chr_can_read(be->opaque);
196 void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len)
198     CharBackend *be = s->be;
200     if (be && be->chr_read) {
201         be->chr_read(be->opaque, buf, len);
202     }
205 void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len)
207     if (qemu_chr_replay(s)) {
208         if (replay_mode == REPLAY_MODE_PLAY) {
209             return;
210         }
211         replay_chr_be_write(s, buf, len);
212     } else {
213         qemu_chr_be_write_impl(s, buf, len);
214     }
217 void qemu_chr_be_update_read_handlers(Chardev *s,
218                                       GMainContext *context)
220     ChardevClass *cc = CHARDEV_GET_CLASS(s);
222     assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT)
223            || !context);
224     s->gcontext = context;
225     if (cc->chr_update_read_handler) {
226         cc->chr_update_read_handler(s);
227     }
230 int qemu_chr_add_client(Chardev *s, int fd)
232     return CHARDEV_GET_CLASS(s)->chr_add_client ?
233         CHARDEV_GET_CLASS(s)->chr_add_client(s, fd) : -1;
236 static void qemu_char_open(Chardev *chr, ChardevBackend *backend,
237                            bool *be_opened, Error **errp)
239     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
240     /* Any ChardevCommon member would work */
241     ChardevCommon *common = backend ? backend->u.null.data : NULL;
243     if (common && common->has_logfile) {
244         int flags = O_WRONLY | O_CREAT;
245         if (common->has_logappend &&
246             common->logappend) {
247             flags |= O_APPEND;
248         } else {
249             flags |= O_TRUNC;
250         }
251         chr->logfd = qemu_open_old(common->logfile, flags, 0666);
252         if (chr->logfd < 0) {
253             error_setg_errno(errp, errno,
254                              "Unable to open logfile %s",
255                              common->logfile);
256             return;
257         }
258     }
260     if (cc->open) {
261         cc->open(chr, backend, be_opened, errp);
262     }
265 static void char_init(Object *obj)
267     Chardev *chr = CHARDEV(obj);
269     chr->logfd = -1;
270     qemu_mutex_init(&chr->chr_write_lock);
272     /*
273      * Assume if chr_update_read_handler is implemented it will
274      * take the updated gcontext into account.
275      */
276     if (CHARDEV_GET_CLASS(chr)->chr_update_read_handler) {
277         qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT);
278     }
282 static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
284     return len;
287 static void char_class_init(ObjectClass *oc, void *data)
289     ChardevClass *cc = CHARDEV_CLASS(oc);
291     cc->chr_write = null_chr_write;
292     cc->chr_be_event = chr_be_event;
295 static void char_finalize(Object *obj)
297     Chardev *chr = CHARDEV(obj);
299     if (chr->be) {
300         chr->be->chr = NULL;
301     }
302     g_free(chr->filename);
303     g_free(chr->label);
304     if (chr->logfd != -1) {
305         close(chr->logfd);
306     }
307     qemu_mutex_destroy(&chr->chr_write_lock);
310 static const TypeInfo char_type_info = {
311     .name = TYPE_CHARDEV,
312     .parent = TYPE_OBJECT,
313     .instance_size = sizeof(Chardev),
314     .instance_init = char_init,
315     .instance_finalize = char_finalize,
316     .abstract = true,
317     .class_size = sizeof(ChardevClass),
318     .class_init = char_class_init,
321 static bool qemu_chr_is_busy(Chardev *s)
323     if (CHARDEV_IS_MUX(s)) {
324         MuxChardev *d = MUX_CHARDEV(s);
325         return d->mux_cnt >= 0;
326     } else {
327         return s->be != NULL;
328     }
331 int qemu_chr_wait_connected(Chardev *chr, Error **errp)
333     ChardevClass *cc = CHARDEV_GET_CLASS(chr);
335     if (cc->chr_wait_connected) {
336         return cc->chr_wait_connected(chr, errp);
337     }
339     return 0;
342 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
343                                 bool permit_mux_mon)
345     char host[65], port[33], width[8], height[8];
346     int pos;
347     const char *p;
348     QemuOpts *opts;
349     Error *local_err = NULL;
351     opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1, &local_err);
352     if (local_err) {
353         error_report_err(local_err);
354         return NULL;
355     }
357     if (strstart(filename, "mon:", &p)) {
358         if (!permit_mux_mon) {
359             error_report("mon: isn't supported in this context");
360             return NULL;
361         }
362         filename = p;
363         qemu_opt_set(opts, "mux", "on", &error_abort);
364         if (strcmp(filename, "stdio") == 0) {
365             /* Monitor is muxed to stdio: do not exit on Ctrl+C by default
366              * but pass it to the guest.  Handle this only for compat syntax,
367              * for -chardev syntax we have special option for this.
368              * This is what -nographic did, redirecting+muxing serial+monitor
369              * to stdio causing Ctrl+C to be passed to guest. */
370             qemu_opt_set(opts, "signal", "off", &error_abort);
371         }
372     }
374     if (strcmp(filename, "null")    == 0 ||
375         strcmp(filename, "pty")     == 0 ||
376         strcmp(filename, "msmouse") == 0 ||
377         strcmp(filename, "wctablet") == 0 ||
378         strcmp(filename, "braille") == 0 ||
379         strcmp(filename, "testdev") == 0 ||
380         strcmp(filename, "stdio")   == 0) {
381         qemu_opt_set(opts, "backend", filename, &error_abort);
382         return opts;
383     }
384     if (strstart(filename, "vc", &p)) {
385         qemu_opt_set(opts, "backend", "vc", &error_abort);
386         if (*p == ':') {
387             if (sscanf(p+1, "%7[0-9]x%7[0-9]", width, height) == 2) {
388                 /* pixels */
389                 qemu_opt_set(opts, "width", width, &error_abort);
390                 qemu_opt_set(opts, "height", height, &error_abort);
391             } else if (sscanf(p+1, "%7[0-9]Cx%7[0-9]C", width, height) == 2) {
392                 /* chars */
393                 qemu_opt_set(opts, "cols", width, &error_abort);
394                 qemu_opt_set(opts, "rows", height, &error_abort);
395             } else {
396                 goto fail;
397             }
398         }
399         return opts;
400     }
401     if (strcmp(filename, "con:") == 0) {
402         qemu_opt_set(opts, "backend", "console", &error_abort);
403         return opts;
404     }
405     if (strstart(filename, "COM", NULL)) {
406         qemu_opt_set(opts, "backend", "serial", &error_abort);
407         qemu_opt_set(opts, "path", filename, &error_abort);
408         return opts;
409     }
410     if (strstart(filename, "file:", &p)) {
411         qemu_opt_set(opts, "backend", "file", &error_abort);
412         qemu_opt_set(opts, "path", p, &error_abort);
413         return opts;
414     }
415     if (strstart(filename, "pipe:", &p)) {
416         qemu_opt_set(opts, "backend", "pipe", &error_abort);
417         qemu_opt_set(opts, "path", p, &error_abort);
418         return opts;
419     }
420     if (strstart(filename, "tcp:", &p) ||
421         strstart(filename, "telnet:", &p) ||
422         strstart(filename, "tn3270:", &p) ||
423         strstart(filename, "websocket:", &p)) {
424         if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
425             host[0] = 0;
426             if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
427                 goto fail;
428         }
429         qemu_opt_set(opts, "backend", "socket", &error_abort);
430         qemu_opt_set(opts, "host", host, &error_abort);
431         qemu_opt_set(opts, "port", port, &error_abort);
432         if (p[pos] == ',') {
433             if (!qemu_opts_do_parse(opts, p + pos + 1, NULL, &local_err)) {
434                 error_report_err(local_err);
435                 goto fail;
436             }
437         }
438         if (strstart(filename, "telnet:", &p)) {
439             qemu_opt_set(opts, "telnet", "on", &error_abort);
440         } else if (strstart(filename, "tn3270:", &p)) {
441             qemu_opt_set(opts, "tn3270", "on", &error_abort);
442         } else if (strstart(filename, "websocket:", &p)) {
443             qemu_opt_set(opts, "websocket", "on", &error_abort);
444         }
445         return opts;
446     }
447     if (strstart(filename, "udp:", &p)) {
448         qemu_opt_set(opts, "backend", "udp", &error_abort);
449         if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
450             host[0] = 0;
451             if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
452                 goto fail;
453             }
454         }
455         qemu_opt_set(opts, "host", host, &error_abort);
456         qemu_opt_set(opts, "port", port, &error_abort);
457         if (p[pos] == '@') {
458             p += pos + 1;
459             if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
460                 host[0] = 0;
461                 if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
462                     goto fail;
463                 }
464             }
465             qemu_opt_set(opts, "localaddr", host, &error_abort);
466             qemu_opt_set(opts, "localport", port, &error_abort);
467         }
468         return opts;
469     }
470     if (strstart(filename, "unix:", &p)) {
471         qemu_opt_set(opts, "backend", "socket", &error_abort);
472         if (!qemu_opts_do_parse(opts, p, "path", &local_err)) {
473             error_report_err(local_err);
474             goto fail;
475         }
476         return opts;
477     }
478     if (strstart(filename, "/dev/parport", NULL) ||
479         strstart(filename, "/dev/ppi", NULL)) {
480         qemu_opt_set(opts, "backend", "parallel", &error_abort);
481         qemu_opt_set(opts, "path", filename, &error_abort);
482         return opts;
483     }
484     if (strstart(filename, "/dev/", NULL)) {
485         qemu_opt_set(opts, "backend", "serial", &error_abort);
486         qemu_opt_set(opts, "path", filename, &error_abort);
487         return opts;
488     }
490     error_report("'%s' is not a valid char driver", filename);
492 fail:
493     qemu_opts_del(opts);
494     return NULL;
497 void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
499     const char *logfile = qemu_opt_get(opts, "logfile");
501     backend->has_logfile = logfile != NULL;
502     backend->logfile = g_strdup(logfile);
504     backend->has_logappend = true;
505     backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
508 static const ChardevClass *char_get_class(const char *driver, Error **errp)
510     ObjectClass *oc;
511     const ChardevClass *cc;
512     char *typename = g_strdup_printf("chardev-%s", driver);
514     oc = module_object_class_by_name(typename);
515     g_free(typename);
517     if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {
518         error_setg(errp, "'%s' is not a valid char driver name", driver);
519         return NULL;
520     }
522     if (object_class_is_abstract(oc)) {
523         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
524                    "an abstract device type");
525         return NULL;
526     }
528     cc = CHARDEV_CLASS(oc);
529     if (cc->internal) {
530         error_setg(errp, "'%s' is not a valid char driver name", driver);
531         return NULL;
532     }
534     return cc;
537 static struct ChardevAlias {
538     const char *typename;
539     const char *alias;
540     bool deprecation_warning_printed;
541 } chardev_alias_table[] = {
542 #ifdef HAVE_CHARDEV_PARPORT
543     { "parallel", "parport" },
544 #endif
545 #ifdef HAVE_CHARDEV_SERIAL
546     { "serial", "tty" },
547 #endif
550 typedef struct ChadevClassFE {
551     void (*fn)(const char *name, void *opaque);
552     void *opaque;
553 } ChadevClassFE;
555 static void
556 chardev_class_foreach(ObjectClass *klass, void *opaque)
558     ChadevClassFE *fe = opaque;
560     assert(g_str_has_prefix(object_class_get_name(klass), "chardev-"));
561     if (CHARDEV_CLASS(klass)->internal) {
562         return;
563     }
565     fe->fn(object_class_get_name(klass) + 8, fe->opaque);
568 static void
569 chardev_name_foreach(void (*fn)(const char *name, void *opaque),
570                      void *opaque)
572     ChadevClassFE fe = { .fn = fn, .opaque = opaque };
574     object_class_foreach(chardev_class_foreach, TYPE_CHARDEV, false, &fe);
577 static void
578 help_string_append(const char *name, void *opaque)
580     GString *str = opaque;
582     g_string_append_printf(str, "\n  %s", name);
585 static const char *chardev_alias_translate(const char *name)
587     int i;
588     for (i = 0; i < (int)ARRAY_SIZE(chardev_alias_table); i++) {
589         if (g_strcmp0(chardev_alias_table[i].alias, name) == 0) {
590             if (!chardev_alias_table[i].deprecation_warning_printed) {
591                 warn_report("The alias '%s' is deprecated, use '%s' instead",
592                             name, chardev_alias_table[i].typename);
593                 chardev_alias_table[i].deprecation_warning_printed = true;
594             }
595             return chardev_alias_table[i].typename;
596         }
597     }
598     return name;
601 ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
603     Error *local_err = NULL;
604     const ChardevClass *cc;
605     ChardevBackend *backend = NULL;
606     const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
608     if (name == NULL) {
609         error_setg(errp, "chardev: \"%s\" missing backend",
610                    qemu_opts_id(opts));
611         return NULL;
612     }
614     cc = char_get_class(name, errp);
615     if (cc == NULL) {
616         return NULL;
617     }
619     backend = g_new0(ChardevBackend, 1);
620     backend->type = CHARDEV_BACKEND_KIND_NULL;
622     if (cc->parse) {
623         cc->parse(opts, backend, &local_err);
624         if (local_err) {
625             error_propagate(errp, local_err);
626             qapi_free_ChardevBackend(backend);
627             return NULL;
628         }
629     } else {
630         ChardevCommon *ccom = g_new0(ChardevCommon, 1);
631         qemu_chr_parse_common(opts, ccom);
632         backend->u.null.data = ccom; /* Any ChardevCommon member would work */
633     }
635     return backend;
638 Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
639                                 Error **errp)
641     const ChardevClass *cc;
642     Chardev *chr = NULL;
643     ChardevBackend *backend = NULL;
644     const char *name = chardev_alias_translate(qemu_opt_get(opts, "backend"));
645     const char *id = qemu_opts_id(opts);
646     char *bid = NULL;
648     if (name && is_help_option(name)) {
649         GString *str = g_string_new("");
651         chardev_name_foreach(help_string_append, str);
653         qemu_printf("Available chardev backend types: %s\n", str->str);
654         g_string_free(str, true);
655         return NULL;
656     }
658     if (id == NULL) {
659         error_setg(errp, "chardev: no id specified");
660         return NULL;
661     }
663     backend = qemu_chr_parse_opts(opts, errp);
664     if (backend == NULL) {
665         return NULL;
666     }
668     cc = char_get_class(name, errp);
669     if (cc == NULL) {
670         goto out;
671     }
673     if (qemu_opt_get_bool(opts, "mux", 0)) {
674         bid = g_strdup_printf("%s-base", id);
675     }
677     chr = qemu_chardev_new(bid ? bid : id,
678                            object_class_get_name(OBJECT_CLASS(cc)),
679                            backend, context, errp);
681     if (chr == NULL) {
682         goto out;
683     }
685     if (bid) {
686         Chardev *mux;
687         qapi_free_ChardevBackend(backend);
688         backend = g_new0(ChardevBackend, 1);
689         backend->type = CHARDEV_BACKEND_KIND_MUX;
690         backend->u.mux.data = g_new0(ChardevMux, 1);
691         backend->u.mux.data->chardev = g_strdup(bid);
692         mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, context, errp);
693         if (mux == NULL) {
694             object_unparent(OBJECT(chr));
695             chr = NULL;
696             goto out;
697         }
698         chr = mux;
699     }
701 out:
702     qapi_free_ChardevBackend(backend);
703     g_free(bid);
704     return chr;
707 Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
708                                bool permit_mux_mon, GMainContext *context)
710     const char *p;
711     Chardev *chr;
712     QemuOpts *opts;
713     Error *err = NULL;
715     if (strstart(filename, "chardev:", &p)) {
716         return qemu_chr_find(p);
717     }
719     opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
720     if (!opts)
721         return NULL;
723     chr = qemu_chr_new_from_opts(opts, context, &err);
724     if (!chr) {
725         error_report_err(err);
726         goto out;
727     }
729     if (qemu_opt_get_bool(opts, "mux", 0)) {
730         assert(permit_mux_mon);
731         monitor_init_hmp(chr, true, &err);
732         if (err) {
733             error_report_err(err);
734             object_unparent(OBJECT(chr));
735             chr = NULL;
736             goto out;
737         }
738     }
740 out:
741     qemu_opts_del(opts);
742     return chr;
745 static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
746                                           const char *filename,
747                                           bool permit_mux_mon,
748                                           GMainContext *context)
750     Chardev *chr;
751     chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
752     if (chr) {
753         if (replay_mode != REPLAY_MODE_NONE) {
754             qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
755         }
756         if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
757             error_report("Replay: ioctl is not supported "
758                          "for serial devices yet");
759         }
760         replay_register_char_driver(chr);
761     }
762     return chr;
765 Chardev *qemu_chr_new(const char *label, const char *filename,
766                       GMainContext *context)
768     return qemu_chr_new_permit_mux_mon(label, filename, false, context);
771 Chardev *qemu_chr_new_mux_mon(const char *label, const char *filename,
772                               GMainContext *context)
774     return qemu_chr_new_permit_mux_mon(label, filename, true, context);
777 static int qmp_query_chardev_foreach(Object *obj, void *data)
779     Chardev *chr = CHARDEV(obj);
780     ChardevInfoList **list = data;
781     ChardevInfo *value = g_malloc0(sizeof(*value));
783     value->label = g_strdup(chr->label);
784     value->filename = g_strdup(chr->filename);
785     value->frontend_open = chr->be && chr->be->fe_open;
787     QAPI_LIST_PREPEND(*list, value);
789     return 0;
792 ChardevInfoList *qmp_query_chardev(Error **errp)
794     ChardevInfoList *chr_list = NULL;
796     object_child_foreach(get_chardevs_root(),
797                          qmp_query_chardev_foreach, &chr_list);
799     return chr_list;
802 static void
803 qmp_prepend_backend(const char *name, void *opaque)
805     ChardevBackendInfoList **list = opaque;
806     ChardevBackendInfo *value;
808     value = g_new0(ChardevBackendInfo, 1);
809     value->name = g_strdup(name);
810     QAPI_LIST_PREPEND(*list, value);
813 ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
815     ChardevBackendInfoList *backend_list = NULL;
817     chardev_name_foreach(qmp_prepend_backend, &backend_list);
819     return backend_list;
822 Chardev *qemu_chr_find(const char *name)
824     Object *obj = object_resolve_path_component(get_chardevs_root(), name);
826     return obj ? CHARDEV(obj) : NULL;
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 = "nodelay",
875             .type = QEMU_OPT_BOOL,
876         },{
877             .name = "reconnect",
878             .type = QEMU_OPT_NUMBER,
879         },{
880             .name = "telnet",
881             .type = QEMU_OPT_BOOL,
882         },{
883             .name = "tn3270",
884             .type = QEMU_OPT_BOOL,
885         },{
886             .name = "tls-creds",
887             .type = QEMU_OPT_STRING,
888         },{
889             .name = "tls-authz",
890             .type = QEMU_OPT_STRING,
891         },{
892             .name = "websocket",
893             .type = QEMU_OPT_BOOL,
894         },{
895             .name = "width",
896             .type = QEMU_OPT_NUMBER,
897         },{
898             .name = "height",
899             .type = QEMU_OPT_NUMBER,
900         },{
901             .name = "cols",
902             .type = QEMU_OPT_NUMBER,
903         },{
904             .name = "rows",
905             .type = QEMU_OPT_NUMBER,
906         },{
907             .name = "mux",
908             .type = QEMU_OPT_BOOL,
909         },{
910             .name = "signal",
911             .type = QEMU_OPT_BOOL,
912         },{
913             .name = "name",
914             .type = QEMU_OPT_STRING,
915         },{
916             .name = "debug",
917             .type = QEMU_OPT_NUMBER,
918         },{
919             .name = "size",
920             .type = QEMU_OPT_SIZE,
921         },{
922             .name = "chardev",
923             .type = QEMU_OPT_STRING,
924         },{
925             .name = "append",
926             .type = QEMU_OPT_BOOL,
927         },{
928             .name = "logfile",
929             .type = QEMU_OPT_STRING,
930         },{
931             .name = "logappend",
932             .type = QEMU_OPT_BOOL,
933 #ifdef CONFIG_LINUX
934         },{
935             .name = "tight",
936             .type = QEMU_OPT_BOOL,
937             .def_value_str = "on",
938         },{
939             .name = "abstract",
940             .type = QEMU_OPT_BOOL,
941 #endif
942         },
943         { /* end of list */ }
944     },
947 bool qemu_chr_has_feature(Chardev *chr,
948                           ChardevFeature feature)
950     return test_bit(feature, chr->features);
953 void qemu_chr_set_feature(Chardev *chr,
954                            ChardevFeature feature)
956     return set_bit(feature, chr->features);
959 static Chardev *chardev_new(const char *id, const char *typename,
960                             ChardevBackend *backend,
961                             GMainContext *gcontext,
962                             Error **errp)
964     Object *obj;
965     Chardev *chr = NULL;
966     Error *local_err = NULL;
967     bool be_opened = true;
969     assert(g_str_has_prefix(typename, "chardev-"));
971     obj = object_new(typename);
972     chr = CHARDEV(obj);
973     chr->label = g_strdup(id);
974     chr->gcontext = gcontext;
976     qemu_char_open(chr, backend, &be_opened, &local_err);
977     if (local_err) {
978         goto end;
979     }
981     if (!chr->filename) {
982         chr->filename = g_strdup(typename + 8);
983     }
984     if (be_opened) {
985         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
986     }
988     if (id) {
989         object_property_try_add_child(get_chardevs_root(), id, obj,
990                                       &local_err);
991         if (local_err) {
992             goto end;
993         }
994         object_unref(obj);
995     }
997 end:
998     if (local_err) {
999         error_propagate(errp, local_err);
1000         object_unref(obj);
1001         return NULL;
1002     }
1004     return chr;
1007 Chardev *qemu_chardev_new(const char *id, const char *typename,
1008                           ChardevBackend *backend,
1009                           GMainContext *gcontext,
1010                           Error **errp)
1012     g_autofree char *genid = NULL;
1014     if (!id) {
1015         genid = id_generate(ID_CHR);
1016         id = genid;
1017     }
1019     return chardev_new(id, typename, backend, gcontext, errp);
1022 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
1023                                Error **errp)
1025     const ChardevClass *cc;
1026     ChardevReturn *ret;
1027     Chardev *chr;
1029     cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
1030     if (!cc) {
1031         return NULL;
1032     }
1034     chr = chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
1035                       backend, NULL, errp);
1036     if (!chr) {
1037         return NULL;
1038     }
1040     ret = g_new0(ChardevReturn, 1);
1041     if (CHARDEV_IS_PTY(chr)) {
1042         ret->pty = g_strdup(chr->filename + 4);
1043         ret->has_pty = true;
1044     }
1046     return ret;
1049 ChardevReturn *qmp_chardev_change(const char *id, ChardevBackend *backend,
1050                                   Error **errp)
1052     CharBackend *be;
1053     const ChardevClass *cc;
1054     Chardev *chr, *chr_new;
1055     bool closed_sent = false;
1056     ChardevReturn *ret;
1058     chr = qemu_chr_find(id);
1059     if (!chr) {
1060         error_setg(errp, "Chardev '%s' does not exist", id);
1061         return NULL;
1062     }
1064     if (CHARDEV_IS_MUX(chr)) {
1065         error_setg(errp, "Mux device hotswap not supported yet");
1066         return NULL;
1067     }
1069     if (qemu_chr_replay(chr)) {
1070         error_setg(errp,
1071             "Chardev '%s' cannot be changed in record/replay mode", id);
1072         return NULL;
1073     }
1075     be = chr->be;
1076     if (!be) {
1077         /* easy case */
1078         object_unparent(OBJECT(chr));
1079         return qmp_chardev_add(id, backend, errp);
1080     }
1082     if (!be->chr_be_change) {
1083         error_setg(errp, "Chardev user does not support chardev hotswap");
1084         return NULL;
1085     }
1087     cc = char_get_class(ChardevBackendKind_str(backend->type), errp);
1088     if (!cc) {
1089         return NULL;
1090     }
1092     chr_new = chardev_new(NULL, object_class_get_name(OBJECT_CLASS(cc)),
1093                           backend, chr->gcontext, errp);
1094     if (!chr_new) {
1095         return NULL;
1096     }
1097     chr_new->label = g_strdup(id);
1099     if (chr->be_open && !chr_new->be_open) {
1100         qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
1101         closed_sent = true;
1102     }
1104     chr->be = NULL;
1105     qemu_chr_fe_init(be, chr_new, &error_abort);
1107     if (be->chr_be_change(be->opaque) < 0) {
1108         error_setg(errp, "Chardev '%s' change failed", chr_new->label);
1109         chr_new->be = NULL;
1110         qemu_chr_fe_init(be, chr, &error_abort);
1111         if (closed_sent) {
1112             qemu_chr_be_event(chr, CHR_EVENT_OPENED);
1113         }
1114         object_unref(OBJECT(chr_new));
1115         return NULL;
1116     }
1118     object_unparent(OBJECT(chr));
1119     object_property_add_child(get_chardevs_root(), chr_new->label,
1120                               OBJECT(chr_new));
1121     object_unref(OBJECT(chr_new));
1123     ret = g_new0(ChardevReturn, 1);
1124     if (CHARDEV_IS_PTY(chr_new)) {
1125         ret->pty = g_strdup(chr_new->filename + 4);
1126         ret->has_pty = true;
1127     }
1129     return ret;
1132 void qmp_chardev_remove(const char *id, Error **errp)
1134     Chardev *chr;
1136     chr = qemu_chr_find(id);
1137     if (chr == NULL) {
1138         error_setg(errp, "Chardev '%s' not found", id);
1139         return;
1140     }
1141     if (qemu_chr_is_busy(chr)) {
1142         error_setg(errp, "Chardev '%s' is busy", id);
1143         return;
1144     }
1145     if (qemu_chr_replay(chr)) {
1146         error_setg(errp,
1147             "Chardev '%s' cannot be unplugged in record/replay mode", id);
1148         return;
1149     }
1150     object_unparent(OBJECT(chr));
1153 void qmp_chardev_send_break(const char *id, Error **errp)
1155     Chardev *chr;
1157     chr = qemu_chr_find(id);
1158     if (chr == NULL) {
1159         error_setg(errp, "Chardev '%s' not found", id);
1160         return;
1161     }
1162     qemu_chr_be_event(chr, CHR_EVENT_BREAK);
1166  * Add a timeout callback for the chardev (in milliseconds), return
1167  * the GSource object created. Please use this to add timeout hook for
1168  * chardev instead of g_timeout_add() and g_timeout_add_seconds(), to
1169  * make sure the gcontext that the task bound to is correct.
1170  */
1171 GSource *qemu_chr_timeout_add_ms(Chardev *chr, guint ms,
1172                                  GSourceFunc func, void *private)
1174     GSource *source = g_timeout_source_new(ms);
1176     assert(func);
1177     g_source_set_callback(source, func, private, NULL);
1178     g_source_attach(source, chr->gcontext);
1180     return source;
1183 void qemu_chr_cleanup(void)
1185     object_unparent(get_chardevs_root());
1188 static void register_types(void)
1190     type_register_static(&char_type_info);
1193 type_init(register_types);