From dab1d99c469b5c01990be27f07af85589b610c83 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 24 Jun 2016 21:07:57 +0100 Subject: [PATCH] document portal: don't reply to GetMountPoint() until ready As soon as we get our D-Bus name, we can start receiving method calls. If we reply immediately, callers will think our mount point is ready. In particular, if FUSE is unavailable, we want "flatpak run" to proceed with no document portal; it currently tries and fails to bind-mount the nonexistent document portal mount-point into the container. Signed-off-by: Simon McVittie --- document-portal/xdp-main.c | 63 +++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/document-portal/xdp-main.c b/document-portal/xdp-main.c index 4efb4492..91347f39 100644 --- a/document-portal/xdp-main.c +++ b/document-portal/xdp-main.c @@ -41,7 +41,10 @@ static FlatpakDb *db = NULL; static XdgPermissionStore *permission_store; static int daemon_event_fd = -1; static int final_exit_status = 0; +static GError *exit_error = NULL; static dev_t fuse_dev = 0; +static GQueue get_mount_point_invocations = G_QUEUE_INIT; +static XdpDbusDocuments *dbus_api; G_LOCK_DEFINE (db); @@ -626,6 +629,14 @@ handle_method (GCallback method_callback, static gboolean handle_get_mount_point (XdpDbusDocuments *object, GDBusMethodInvocation *invocation) { + if (fuse_dev == 0) + { + /* We mustn't reply to this until the FUSE mount point is open for + * business. */ + g_queue_push_tail (&get_mount_point_invocations, g_object_ref (invocation)); + return TRUE; + } + xdp_dbus_documents_complete_get_mount_point (object, invocation, xdp_fuse_get_mountpoint ()); return TRUE; } @@ -811,24 +822,23 @@ on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { - XdpDbusDocuments *helper; GError *error = NULL; - helper = xdp_dbus_documents_skeleton_new (); + dbus_api = xdp_dbus_documents_skeleton_new (); - g_signal_connect_swapped (helper, "handle-get-mount-point", G_CALLBACK (handle_get_mount_point), NULL); - g_signal_connect_swapped (helper, "handle-add", G_CALLBACK (handle_method), portal_add); - g_signal_connect_swapped (helper, "handle-add-named", G_CALLBACK (handle_method), portal_add_named); - g_signal_connect_swapped (helper, "handle-grant-permissions", G_CALLBACK (handle_method), portal_grant_permissions); - g_signal_connect_swapped (helper, "handle-revoke-permissions", G_CALLBACK (handle_method), portal_revoke_permissions); - g_signal_connect_swapped (helper, "handle-delete", G_CALLBACK (handle_method), portal_delete); - g_signal_connect_swapped (helper, "handle-lookup", G_CALLBACK (handle_method), portal_lookup); - g_signal_connect_swapped (helper, "handle-info", G_CALLBACK (handle_method), portal_info); - g_signal_connect_swapped (helper, "handle-list", G_CALLBACK (handle_method), portal_list); + g_signal_connect_swapped (dbus_api, "handle-get-mount-point", G_CALLBACK (handle_get_mount_point), NULL); + g_signal_connect_swapped (dbus_api, "handle-add", G_CALLBACK (handle_method), portal_add); + g_signal_connect_swapped (dbus_api, "handle-add-named", G_CALLBACK (handle_method), portal_add_named); + g_signal_connect_swapped (dbus_api, "handle-grant-permissions", G_CALLBACK (handle_method), portal_grant_permissions); + g_signal_connect_swapped (dbus_api, "handle-revoke-permissions", G_CALLBACK (handle_method), portal_revoke_permissions); + g_signal_connect_swapped (dbus_api, "handle-delete", G_CALLBACK (handle_method), portal_delete); + g_signal_connect_swapped (dbus_api, "handle-lookup", G_CALLBACK (handle_method), portal_lookup); + g_signal_connect_swapped (dbus_api, "handle-info", G_CALLBACK (handle_method), portal_info); + g_signal_connect_swapped (dbus_api, "handle-list", G_CALLBACK (handle_method), portal_list); flatpak_connection_track_name_owners (connection); - if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (helper), + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (dbus_api), connection, "/org/freedesktop/portal/documents", &error)) @@ -865,21 +875,22 @@ on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { - g_autoptr(GError) error = NULL; struct stat stbuf; + gpointer invocation; g_debug ("%s acquired", name); - if (!xdp_fuse_init (&error)) + if (!xdp_fuse_init (&exit_error)) { final_exit_status = 6; - g_printerr ("fuse init failed: %s", error->message); + g_printerr ("fuse init failed: %s", exit_error->message); g_main_loop_quit (loop); return; } if (stat (xdp_fuse_get_mountpoint (), &stbuf) != 0) { + g_set_error (&exit_error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "fuse stat failed: %s", strerror (errno)); final_exit_status = 7; g_printerr ("fuse stat failed: %s", strerror (errno)); g_main_loop_quit (loop); @@ -888,6 +899,12 @@ on_name_acquired (GDBusConnection *connection, fuse_dev = stbuf.st_dev; + while ((invocation = g_queue_pop_head (&get_mount_point_invocations)) != NULL) + { + xdp_dbus_documents_complete_get_mount_point (dbus_api, invocation, xdp_fuse_get_mountpoint ()); + g_object_unref (invocation); + } + daemon_report_done (0); } @@ -898,12 +915,16 @@ on_name_lost (GDBusConnection *connection, { g_debug ("%s lost", name); final_exit_status = 20; + g_set_error (&exit_error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "D-Bus name \"%s\" lost", name); g_main_loop_quit (loop); } static void exit_handler (int sig) { + /* We cannot set exit_error here, because malloc() in a signal handler + * is undefined behaviour. Rely on main() coping gracefully with + * that. */ g_main_loop_quit (loop); } @@ -912,6 +933,7 @@ session_bus_closed (GDBusConnection *connection, gboolean remote_peer_vanished, GError *bus_error) { + g_set_error (&exit_error, G_IO_ERROR, G_IO_ERROR_NOT_CONNECTED, "Disconnected from session bus"); g_main_loop_quit (loop); } @@ -992,6 +1014,7 @@ main (int argc, g_autofree char *path = NULL; GDBusConnection *session_bus; GOptionContext *context; + GDBusMethodInvocation *invocation; setlocale (LC_ALL, ""); @@ -1082,6 +1105,16 @@ main (int argc, g_main_loop_run (loop); + while ((invocation = g_queue_pop_head (&get_mount_point_invocations)) != NULL) + { + if (exit_error != NULL) + g_dbus_method_invocation_return_gerror (invocation, exit_error); + else + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Terminated"); + + g_object_unref (invocation); + } + xdp_fuse_exit (); g_bus_unown_name (owner_id);