2
0

dbus-chardev.c 8.1 KB

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