qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

dbus-chardev.c (8343B)


      1 /*
      2  * QEMU DBus display
      3  *
      4  * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
      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 #include "qemu/osdep.h"
     25 #include "trace.h"
     26 #include "qapi/error.h"
     27 #include "qemu/config-file.h"
     28 #include "qemu/option.h"
     29 
     30 #include <gio/gunixfdlist.h>
     31 
     32 #include "dbus.h"
     33 
     34 static char *
     35 dbus_display_chardev_path(DBusChardev *chr)
     36 {
     37     return g_strdup_printf(DBUS_DISPLAY1_ROOT "/Chardev_%s",
     38                            CHARDEV(chr)->label);
     39 }
     40 
     41 static void
     42 dbus_display_chardev_export(DBusDisplay *dpy, DBusChardev *chr)
     43 {
     44     g_autoptr(GDBusObjectSkeleton) sk = NULL;
     45     g_autofree char *path = dbus_display_chardev_path(chr);
     46 
     47     if (chr->exported) {
     48         return;
     49     }
     50 
     51     sk = g_dbus_object_skeleton_new(path);
     52     g_dbus_object_skeleton_add_interface(
     53         sk, G_DBUS_INTERFACE_SKELETON(chr->iface));
     54     g_dbus_object_manager_server_export(dpy->server, sk);
     55     chr->exported = true;
     56 }
     57 
     58 static void
     59 dbus_display_chardev_unexport(DBusDisplay *dpy, DBusChardev *chr)
     60 {
     61     g_autofree char *path = dbus_display_chardev_path(chr);
     62 
     63     if (!chr->exported) {
     64         return;
     65     }
     66 
     67     g_dbus_object_manager_server_unexport(dpy->server, path);
     68     chr->exported = false;
     69 }
     70 
     71 static int
     72 dbus_display_chardev_foreach(Object *obj, void *data)
     73 {
     74     DBusDisplay *dpy = DBUS_DISPLAY(data);
     75 
     76     if (!CHARDEV_IS_DBUS(obj)) {
     77         return 0;
     78     }
     79 
     80     dbus_display_chardev_export(dpy, DBUS_CHARDEV(obj));
     81 
     82     return 0;
     83 }
     84 
     85 static void
     86 dbus_display_on_notify(Notifier *notifier, void *data)
     87 {
     88     DBusDisplay *dpy = container_of(notifier, DBusDisplay, notifier);
     89     DBusDisplayEvent *event = data;
     90 
     91     switch (event->type) {
     92     case DBUS_DISPLAY_CHARDEV_OPEN:
     93         dbus_display_chardev_export(dpy, event->chardev);
     94         break;
     95     case DBUS_DISPLAY_CHARDEV_CLOSE:
     96         dbus_display_chardev_unexport(dpy, event->chardev);
     97         break;
     98     }
     99 }
    100 
    101 void
    102 dbus_chardev_init(DBusDisplay *dpy)
    103 {
    104     dpy->notifier.notify = dbus_display_on_notify;
    105     dbus_display_notifier_add(&dpy->notifier);
    106 
    107     object_child_foreach(container_get(object_get_root(), "/chardevs"),
    108                          dbus_display_chardev_foreach, dpy);
    109 }
    110 
    111 static gboolean
    112 dbus_chr_register(
    113     DBusChardev *dc,
    114     GDBusMethodInvocation *invocation,
    115     GUnixFDList *fd_list,
    116     GVariant *arg_stream,
    117     QemuDBusDisplay1Chardev *object)
    118 {
    119     g_autoptr(GError) err = NULL;
    120     int fd;
    121 
    122     fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
    123     if (err) {
    124         g_dbus_method_invocation_return_error(
    125             invocation,
    126             DBUS_DISPLAY_ERROR,
    127             DBUS_DISPLAY_ERROR_FAILED,
    128             "Couldn't get peer FD: %s", err->message);
    129         return DBUS_METHOD_INVOCATION_HANDLED;
    130     }
    131 
    132     if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
    133         g_dbus_method_invocation_return_error(invocation,
    134                                               DBUS_DISPLAY_ERROR,
    135                                               DBUS_DISPLAY_ERROR_FAILED,
    136                                               "Couldn't register FD!");
    137         close(fd);
    138         return DBUS_METHOD_INVOCATION_HANDLED;
    139     }
    140 
    141     g_object_set(dc->iface,
    142                  "owner", g_dbus_method_invocation_get_sender(invocation),
    143                  NULL);
    144 
    145     qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
    146     return DBUS_METHOD_INVOCATION_HANDLED;
    147 }
    148 
    149 static gboolean
    150 dbus_chr_send_break(
    151     DBusChardev *dc,
    152     GDBusMethodInvocation *invocation,
    153     QemuDBusDisplay1Chardev *object)
    154 {
    155     qemu_chr_be_event(CHARDEV(dc), CHR_EVENT_BREAK);
    156 
    157     qemu_dbus_display1_chardev_complete_send_break(object, invocation);
    158     return DBUS_METHOD_INVOCATION_HANDLED;
    159 }
    160 
    161 static void
    162 dbus_chr_open(Chardev *chr, ChardevBackend *backend,
    163               bool *be_opened, Error **errp)
    164 {
    165     ERRP_GUARD();
    166 
    167     DBusChardev *dc = DBUS_CHARDEV(chr);
    168     DBusDisplayEvent event = {
    169         .type = DBUS_DISPLAY_CHARDEV_OPEN,
    170         .chardev = dc,
    171     };
    172     g_autoptr(ChardevBackend) be = NULL;
    173     g_autoptr(QemuOpts) opts = NULL;
    174 
    175     dc->iface = qemu_dbus_display1_chardev_skeleton_new();
    176     g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
    177     g_object_connect(dc->iface,
    178                      "swapped-signal::handle-register",
    179                      dbus_chr_register, dc,
    180                      "swapped-signal::handle-send-break",
    181                      dbus_chr_send_break, dc,
    182                      NULL);
    183 
    184     dbus_display_notify(&event);
    185 
    186     be = g_new0(ChardevBackend, 1);
    187     opts = qemu_opts_create(qemu_find_opts("chardev"), NULL, 0, &error_abort);
    188     qemu_opt_set(opts, "server", "on", &error_abort);
    189     qemu_opt_set(opts, "wait", "off", &error_abort);
    190     CHARDEV_CLASS(object_class_by_name(TYPE_CHARDEV_SOCKET))->parse(
    191         opts, be, errp);
    192     if (*errp) {
    193         return;
    194     }
    195     CHARDEV_CLASS(object_class_by_name(TYPE_CHARDEV_SOCKET))->open(
    196         chr, be, be_opened, errp);
    197 }
    198 
    199 static void
    200 dbus_chr_set_fe_open(Chardev *chr, int fe_open)
    201 {
    202     DBusChardev *dc = DBUS_CHARDEV(chr);
    203 
    204     g_object_set(dc->iface, "feopened", fe_open, NULL);
    205 }
    206 
    207 static void
    208 dbus_chr_set_echo(Chardev *chr, bool echo)
    209 {
    210     DBusChardev *dc = DBUS_CHARDEV(chr);
    211 
    212     g_object_set(dc->iface, "echo", echo, NULL);
    213 }
    214 
    215 static void
    216 dbus_chr_be_event(Chardev *chr, QEMUChrEvent event)
    217 {
    218     DBusChardev *dc = DBUS_CHARDEV(chr);
    219     DBusChardevClass *klass = DBUS_CHARDEV_GET_CLASS(chr);
    220 
    221     switch (event) {
    222     case CHR_EVENT_CLOSED:
    223         if (dc->iface) {
    224             /* on finalize, iface is set to NULL */
    225             g_object_set(dc->iface, "owner", "", NULL);
    226         }
    227         break;
    228     default:
    229         break;
    230     };
    231 
    232     klass->parent_chr_be_event(chr, event);
    233 }
    234 
    235 static void
    236 dbus_chr_parse(QemuOpts *opts, ChardevBackend *backend,
    237                Error **errp)
    238 {
    239     const char *name = qemu_opt_get(opts, "name");
    240     ChardevDBus *dbus;
    241 
    242     if (name == NULL) {
    243         error_setg(errp, "chardev: dbus: no name given");
    244         return;
    245     }
    246 
    247     backend->type = CHARDEV_BACKEND_KIND_DBUS;
    248     dbus = backend->u.dbus.data = g_new0(ChardevDBus, 1);
    249     qemu_chr_parse_common(opts, qapi_ChardevDBus_base(dbus));
    250     dbus->name = g_strdup(name);
    251 }
    252 
    253 static void
    254 char_dbus_class_init(ObjectClass *oc, void *data)
    255 {
    256     DBusChardevClass *klass = DBUS_CHARDEV_CLASS(oc);
    257     ChardevClass *cc = CHARDEV_CLASS(oc);
    258 
    259     cc->parse = dbus_chr_parse;
    260     cc->open = dbus_chr_open;
    261     cc->chr_set_fe_open = dbus_chr_set_fe_open;
    262     cc->chr_set_echo = dbus_chr_set_echo;
    263     klass->parent_chr_be_event = cc->chr_be_event;
    264     cc->chr_be_event = dbus_chr_be_event;
    265 }
    266 
    267 static void
    268 char_dbus_finalize(Object *obj)
    269 {
    270     DBusChardev *dc = DBUS_CHARDEV(obj);
    271     DBusDisplayEvent event = {
    272         .type = DBUS_DISPLAY_CHARDEV_CLOSE,
    273         .chardev = dc,
    274     };
    275 
    276     dbus_display_notify(&event);
    277     g_clear_object(&dc->iface);
    278 }
    279 
    280 static const TypeInfo char_dbus_type_info = {
    281     .name = TYPE_CHARDEV_DBUS,
    282     .parent = TYPE_CHARDEV_SOCKET,
    283     .class_size = sizeof(DBusChardevClass),
    284     .instance_size = sizeof(DBusChardev),
    285     .instance_finalize = char_dbus_finalize,
    286     .class_init = char_dbus_class_init,
    287 };
    288 module_obj(TYPE_CHARDEV_DBUS);
    289 
    290 static void
    291 register_types(void)
    292 {
    293     type_register_static(&char_dbus_type_info);
    294 }
    295 
    296 type_init(register_types);