/* swiss-army knife: takes an strv of pkgspecs destined for * install, and splits it into repo pkgs, and for local * pkgs, an fd list & idx variant. */ gboolean rpmostree_sort_pkgs_strv (const char *const* pkgs, GUnixFDList *fd_list, GPtrArray **out_repo_pkgs, GVariant **out_fd_idxs, GError **error) { g_autoptr(GPtrArray) repo_pkgs = g_ptr_array_new_with_free_func (g_free); g_auto(GVariantBuilder) builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("ah")); for (const char *const* pkg = pkgs; pkg && *pkg; pkg++) { if (!g_str_has_suffix (*pkg, ".rpm")) g_ptr_array_add (repo_pkgs, g_strdup (*pkg)); else { glnx_fd_close int fd = -1; if (!glnx_openat_rdonly (AT_FDCWD, *pkg, TRUE, &fd, error)) return FALSE; int idx = g_unix_fd_list_append (fd_list, fd, error); if (idx < 0) return FALSE; g_variant_builder_add (&builder, "h", idx); } } *out_fd_idxs = g_variant_ref_sink (g_variant_new ("ah", &builder)); *out_repo_pkgs = g_steal_pointer (&repo_pkgs); return TRUE; }
static VALUE unixfdlist_append(VALUE self, VALUE fd) { GError *error = NULL; int index; index = g_unix_fd_list_append(_SELF(self), RVAL2FD(fd), &error); if (index == -1) rbgio_raise_error(error); return self; }
static void portal_job_complete (GtkPrintJob *job, gpointer data, const GError *error) { GtkPrintOperation *op = data; GtkPrintOperationPortal *op_portal = op->priv->platform_data; GtkPrintSettings *settings; const char *uri; char *filename; int fd, idx; GVariantBuilder opt_builder; GUnixFDList *fd_list; if (error != NULL && op->priv->error == NULL) { g_warning ("Print job failed: %s", error->message); op->priv->error = g_error_copy (error); return; } op_portal->file_written = TRUE; settings = gtk_print_job_get_settings (job); uri = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI); filename = g_filename_from_uri (uri, NULL, NULL); fd = open (filename, O_RDONLY|O_CLOEXEC); fd_list = g_unix_fd_list_new (); idx = g_unix_fd_list_append (fd_list, fd, NULL); close (fd); g_free (filename); g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&opt_builder, "{sv}", "token", g_variant_new_uint32 (op_portal->token)); g_dbus_proxy_call_with_unix_fd_list (op_portal->proxy, "Print", g_variant_new ("(ssh@a{sv})", "", /* window */ _("Print"), /* title */ idx, g_variant_builder_end (&opt_builder)), G_DBUS_CALL_FLAGS_NONE, -1, fd_list, NULL, print_file_done, op); g_object_unref (fd_list); }
gboolean builder_host_spawnv (GFile *dir, char **output, GError **error, const gchar * const *argv) { guint32 client_pid; GVariantBuilder *fd_builder = g_variant_builder_new (G_VARIANT_TYPE("a{uh}")); GVariantBuilder *env_builder = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new (); gint stdout_handle, stdin_handle, stderr_handle; g_autoptr(GDBusConnection) connection = NULL; g_autoptr(GVariant) ret = NULL; g_autoptr(GMainLoop) loop = NULL; g_auto(GStrv) env_vars = NULL; guint subscription; HostCommandCallData data = { NULL }; guint sigterm_id = 0, sigint_id = 0; g_autofree gchar *commandline = NULL; g_autoptr(GOutputStream) out = NULL; int pipefd[2]; int i; commandline = flatpak_quote_argv ((const char **) argv); g_debug ("Running '%s' on host", commandline); connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error); if (connection == NULL) return FALSE; loop = g_main_loop_new (NULL, FALSE); data.connection = connection; data.loop = loop; data.refs = 1; subscription = g_dbus_connection_signal_subscribe (connection, NULL, "org.freedesktop.Flatpak.Development", "HostCommandExited", "/org/freedesktop/Flatpak/Development", NULL, G_DBUS_SIGNAL_FLAGS_NONE, host_command_exited_cb, &data, NULL); stdin_handle = g_unix_fd_list_append (fd_list, 0, error); if (stdin_handle == -1) return FALSE; if (output) { g_autoptr(GInputStream) in = NULL; if (pipe2 (pipefd, O_CLOEXEC) != 0) { glnx_set_error_from_errno (error); return FALSE; } data.refs++; in = g_unix_input_stream_new (pipefd[0], TRUE); out = g_memory_output_stream_new_resizable (); g_output_stream_splice_async (out, in, G_OUTPUT_STREAM_SPLICE_NONE, 0, NULL, output_spliced_cb, &data); stdout_handle = g_unix_fd_list_append (fd_list, pipefd[1], error); close (pipefd[1]); if (stdout_handle == -1) return FALSE; } else { stdout_handle = g_unix_fd_list_append (fd_list, 1, error); if (stdout_handle == -1) return FALSE; } stderr_handle = g_unix_fd_list_append (fd_list, 2, error); if (stderr_handle == -1) return FALSE; g_variant_builder_add (fd_builder, "{uh}", 0, stdin_handle); g_variant_builder_add (fd_builder, "{uh}", 1, stdout_handle); g_variant_builder_add (fd_builder, "{uh}", 2, stderr_handle); env_vars = g_listenv (); for (i = 0; env_vars[i] != NULL; i++) { const char *env_var = env_vars[i]; g_variant_builder_add (env_builder, "{ss}", env_var, g_getenv (env_var)); } sigterm_id = g_unix_signal_add (SIGTERM, sigterm_handler, &data); sigint_id = g_unix_signal_add (SIGINT, sigint_handler, &data); ret = g_dbus_connection_call_with_unix_fd_list_sync (connection, "org.freedesktop.Flatpak", "/org/freedesktop/Flatpak/Development", "org.freedesktop.Flatpak.Development", "HostCommand", g_variant_new ("(^ay^aay@a{uh}@a{ss}u)", dir ? flatpak_file_get_path_cached (dir) : "", argv, g_variant_builder_end (fd_builder), g_variant_builder_end (env_builder), FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV), G_VARIANT_TYPE ("(u)"), G_DBUS_CALL_FLAGS_NONE, -1, fd_list, NULL, NULL, error); if (ret == NULL) return FALSE; g_variant_get (ret, "(u)", &client_pid); data.client_pid = client_pid; g_main_loop_run (loop); g_source_remove (sigterm_id); g_source_remove (sigint_id); g_dbus_connection_signal_unsubscribe (connection, subscription); if (!g_spawn_check_exit_status (data.exit_status, error)) return FALSE; if (out) { if (data.splice_error) { g_propagate_error (error, data.splice_error); return FALSE; } /* Null terminate */ g_output_stream_write (out, "\0", 1, NULL, NULL); g_output_stream_close (out, NULL, NULL); *output = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out)); } return TRUE; }
/** * fu_util_refresh_internal: **/ static gboolean fu_util_refresh_internal (FuUtilPrivate *priv, const gchar *data_fn, const gchar *sig_fn, GError **error) { GVariant *body; gint fd; gint fd_sig; _cleanup_object_unref_ GDBusMessage *request = NULL; _cleanup_object_unref_ GUnixFDList *fd_list = NULL; /* open file */ fd = open (data_fn, O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", data_fn); return FALSE; } fd_sig = open (sig_fn, O_RDONLY); if (fd_sig < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", sig_fn); return FALSE; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); g_unix_fd_list_append (fd_list, fd, NULL); g_unix_fd_list_append (fd_list, fd_sig, NULL); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "UpdateMetadata"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); close (fd_sig); /* send message */ body = g_variant_new ("(hh)", fd, fd_sig); g_dbus_message_set_body (request, body); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, fu_util_update_cb, priv); g_main_loop_run (priv->loop); if (priv->message == NULL) { g_dbus_error_strip_remote_error (priv->error); g_propagate_error (error, priv->error); return FALSE; } if (g_dbus_message_to_gerror (priv->message, error)) { g_dbus_error_strip_remote_error (*error); return FALSE; } return TRUE; }
/** * fu_util_get_details: **/ static gboolean fu_util_get_details (FuUtilPrivate *priv, gchar **values, GError **error) { GVariant *body; GVariant *val; gint fd; gint retval; _cleanup_object_unref_ GDBusMessage *message = NULL; _cleanup_object_unref_ GDBusMessage *request = NULL; _cleanup_object_unref_ GUnixFDList *fd_list = NULL; /* check args */ if (g_strv_length (values) != 1) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Invalid arguments: expected 'filename'"); return FALSE; } /* open file */ fd = open (values[0], O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", values[0]); return FALSE; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); retval = g_unix_fd_list_append (fd_list, fd, NULL); g_assert (retval != -1); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "GetDetails"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); /* send message */ body = g_variant_new ("(h)", fd > -1 ? 0 : -1); g_dbus_message_set_body (request, body); message = g_dbus_connection_send_message_with_reply_sync (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, error); if (message == NULL) { g_dbus_error_strip_remote_error (*error); return FALSE; } if (g_dbus_message_to_gerror (message, error)) { g_dbus_error_strip_remote_error (*error); return FALSE; } /* print results */ val = g_dbus_message_get_body (message); fu_util_print_metadata (val); return TRUE; }
/** * fu_util_install_internal: **/ static gboolean fu_util_install_internal (FuUtilPrivate *priv, const gchar *id, const gchar *filename, GError **error) { GVariant *body; GVariantBuilder builder; gint retval; gint fd; _cleanup_object_unref_ GDBusMessage *request = NULL; _cleanup_object_unref_ GUnixFDList *fd_list = NULL; /* set options */ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", "reason", g_variant_new_string ("user-action")); g_variant_builder_add (&builder, "{sv}", "filename", g_variant_new_string (filename)); if (priv->flags & FU_PROVIDER_UPDATE_FLAG_OFFLINE) { g_variant_builder_add (&builder, "{sv}", "offline", g_variant_new_boolean (TRUE)); } if (priv->flags & FU_PROVIDER_UPDATE_FLAG_ALLOW_OLDER) { g_variant_builder_add (&builder, "{sv}", "allow-older", g_variant_new_boolean (TRUE)); } if (priv->flags & FU_PROVIDER_UPDATE_FLAG_ALLOW_REINSTALL) { g_variant_builder_add (&builder, "{sv}", "allow-reinstall", g_variant_new_boolean (TRUE)); } /* open file */ fd = open (filename, O_RDONLY); if (fd < 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "failed to open %s", filename); return FALSE; } /* set out of band file descriptor */ fd_list = g_unix_fd_list_new (); retval = g_unix_fd_list_append (fd_list, fd, NULL); g_assert (retval != -1); request = g_dbus_message_new_method_call (FWUPD_DBUS_SERVICE, FWUPD_DBUS_PATH, FWUPD_DBUS_INTERFACE, "Install"); g_dbus_message_set_unix_fd_list (request, fd_list); /* g_unix_fd_list_append did a dup() already */ close (fd); /* send message */ body = g_variant_new ("(sha{sv})", id, fd > -1 ? 0 : -1, &builder); g_dbus_message_set_body (request, body); g_dbus_connection_send_message_with_reply (priv->conn, request, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, fu_util_update_cb, priv); g_main_loop_run (priv->loop); if (priv->message == NULL) { g_dbus_error_strip_remote_error (priv->error); g_propagate_error (error, priv->error); return FALSE; } if (g_dbus_message_to_gerror (priv->message, error)) { g_dbus_error_strip_remote_error (*error); return FALSE; } /* TRANSLATORS: update completed, no errors */ g_print ("%s\n", _("Done!")); return TRUE; }
static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { if (g_strcmp0 (method_name, "HelloWorld") == 0) { const gchar *greeting; g_variant_get (parameters, "(&s)", &greeting); if (g_strcmp0 (greeting, "Return Unregistered") == 0) { g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED, "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)"); } else if (g_strcmp0 (greeting, "Return Registered") == 0) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)"); } else if (g_strcmp0 (greeting, "Return Raw") == 0) { g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.SomeErrorName", "As requested, here's a raw D-Bus error"); } else { gchar *response; response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", response)); g_free (response); } } else if (g_strcmp0 (method_name, "EmitSignal") == 0) { GError *local_error; gdouble speed_in_mph; gchar *speed_as_string; g_variant_get (parameters, "(d)", &speed_in_mph); speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph); local_error = NULL; g_dbus_connection_emit_signal (connection, NULL, object_path, interface_name, "VelocityChanged", g_variant_new ("(ds)", speed_in_mph, speed_as_string), &local_error); g_assert_no_error (local_error); g_free (speed_as_string); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "GimmeStdout") == 0) { #ifdef G_OS_UNIX if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING) { GDBusMessage *reply; GUnixFDList *fd_list; GError *error; fd_list = g_unix_fd_list_new (); error = NULL; g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error); g_assert_no_error (error); reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation)); g_dbus_message_set_unix_fd_list (reply, fd_list); error = NULL; g_dbus_connection_send_message (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, /* out_serial */ &error); g_assert_no_error (error); g_object_unref (invocation); g_object_unref (fd_list); g_object_unref (reply); } else { g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.Failed", "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)"); } #else g_dbus_method_invocation_return_dbus_error (invocation, "org.gtk.GDBus.NotOnUnix", "Your OS does not support file descriptor passing"); #endif } }