/* * Copyright (C) 2016 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #ifdef HAVE_GIO_UNIX #include #endif #include "fwupd-client-private.h" #include "fwupd-client-sync.h" #include "fwupd-client.h" #include "fwupd-common-private.h" #include "fwupd-error.h" typedef struct { gboolean ret; gchar *str; GError *error; GPtrArray *array; GMainContext *context; GMainLoop *loop; GVariant *val; GHashTable *hash; GBytes *bytes; FwupdDevice *device; } FwupdClientHelper; static void fwupd_client_helper_free(FwupdClientHelper *helper) { if (helper->val != NULL) g_variant_unref(helper->val); if (helper->error != NULL) g_error_free(helper->error); if (helper->array != NULL) g_ptr_array_unref(helper->array); if (helper->hash != NULL) g_hash_table_unref(helper->hash); if (helper->bytes != NULL) g_bytes_unref(helper->bytes); if (helper->device != NULL) g_object_unref(helper->device); g_free(helper->str); g_main_loop_unref(helper->loop); g_main_context_unref(helper->context); g_main_context_pop_thread_default(helper->context); g_free(helper); } static FwupdClientHelper * fwupd_client_helper_new(FwupdClient *self) { FwupdClientHelper *helper; helper = g_new0(FwupdClientHelper, 1); helper->context = fwupd_client_get_main_context(self); helper->loop = g_main_loop_new(helper->context, FALSE); g_main_context_push_thread_default(helper->context); return helper; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" G_DEFINE_AUTOPTR_CLEANUP_FUNC(FwupdClientHelper, fwupd_client_helper_free) #pragma clang diagnostic pop static void fwupd_client_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_connect_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_connect: (skip) * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Sets up the client ready for use. Most other methods call this * for you, and do you only need to call this if you are just watching * the client. * * Returns: %TRUE for success * * Since: 0.7.1 **/ gboolean fwupd_client_connect(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_connect_async(self, cancellable, fwupd_client_connect_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_get_devices_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_devices_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_devices: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the devices registered with the daemon. * * Returns: (element-type FwupdDevice) (transfer container): results * * Since: 0.9.2 **/ GPtrArray * fwupd_client_get_devices(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_devices_async(self, cancellable, fwupd_client_get_devices_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_plugins_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_plugins_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_plugins: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the plugins being used the daemon. * * Returns: (element-type FwupdPlugin) (transfer container): results * * Since: 1.5.0 **/ GPtrArray * fwupd_client_get_plugins(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_plugins_async(self, cancellable, fwupd_client_get_plugins_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_history_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_history_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_history: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the history. * * Returns: (element-type FwupdDevice) (transfer container): results * * Since: 1.0.4 **/ GPtrArray * fwupd_client_get_history(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_history_async(self, cancellable, fwupd_client_get_history_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_releases_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_releases_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_releases: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the releases for a specific device * * Returns: (element-type FwupdRelease) (transfer container): results * * Since: 0.9.3 **/ GPtrArray * fwupd_client_get_releases(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(device_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_releases_async(self, device_id, cancellable, fwupd_client_get_releases_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_downgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_downgrades_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_downgrades: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the downgrades for a specific device. * * Returns: (element-type FwupdRelease) (transfer container): results * * Since: 0.9.8 **/ GPtrArray * fwupd_client_get_downgrades(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(device_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_downgrades_async(self, device_id, cancellable, fwupd_client_get_downgrades_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_upgrades_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_upgrades_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_upgrades: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the upgrades for a specific device. * * Returns: (element-type FwupdRelease) (transfer container): results * * Since: 0.9.8 **/ GPtrArray * fwupd_client_get_upgrades(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(device_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_upgrades_async(self, device_id, cancellable, fwupd_client_get_upgrades_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_details_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_details_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_details_bytes: * @self: a #FwupdClient * @bytes: the firmware archive * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets details about a specific firmware file. * * Returns: (transfer container) (element-type FwupdDevice): an array of results * * Since: 1.5.0 **/ GPtrArray * fwupd_client_get_details_bytes(FwupdClient *self, GBytes *bytes, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(bytes != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_details_bytes_async(self, bytes, cancellable, fwupd_client_get_details_bytes_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } #ifdef HAVE_GIO_UNIX static void fwupd_client_get_details_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_details_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } #endif /** * fwupd_client_get_details: * @self: a #FwupdClient * @filename: the firmware filename, e.g. `firmware.cab` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets details about a specific firmware file. * * Returns: (transfer container) (element-type FwupdDevice): an array of results * * Since: 1.0.0 **/ GPtrArray * fwupd_client_get_details(FwupdClient *self, const gchar *filename, GCancellable *cancellable, GError **error) { #ifdef HAVE_GIO_UNIX g_autoptr(GUnixInputStream) istr = NULL; g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(filename != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ istr = fwupd_unix_input_stream_from_fn(filename, error); if (istr == NULL) return NULL; helper = fwupd_client_helper_new(self); fwupd_client_get_details_stream_async(self, istr, cancellable, fwupd_client_get_details_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); #else g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Not supported as is unavailable"); return NULL; #endif } static void fwupd_client_verify_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_verify_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_verify: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Verify a specific device. * * Returns: %TRUE for verification success * * Since: 0.7.0 **/ gboolean fwupd_client_verify(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_verify_async(self, device_id, cancellable, fwupd_client_verify_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_verify_update_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_verify_update_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_verify_update: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Update the verification record for a specific device. * * Returns: %TRUE for verification success * * Since: 0.8.0 **/ gboolean fwupd_client_verify_update(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_verify_update_async(self, device_id, cancellable, fwupd_client_verify_update_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_unlock_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_unlock_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_unlock: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Unlocks a specific device so firmware can be read or wrote. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_unlock(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_unlock_async(self, device_id, cancellable, fwupd_client_unlock_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_modify_config_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_modify_config_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_modify_config * @self: a #FwupdClient * @key: config key, e.g. `DisabledPlugins` * @value: config value, e.g. `*` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Modifies a daemon config option. * The daemon will only respond to this request with proper permissions. * * Returns: %TRUE for success * * Since: 1.2.8 **/ gboolean fwupd_client_modify_config(FwupdClient *self, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(key != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_modify_config_async(self, key, value, cancellable, fwupd_client_modify_config_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_activate_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_activate_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_activate: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @device_id: a device * @error: (nullable): optional return location for an error * * Activates up a device, which normally means the device switches to a new * firmware version. This should only be called when data loss cannot occur. * * Returns: %TRUE for success * * Since: 1.2.6 **/ gboolean fwupd_client_activate(FwupdClient *self, GCancellable *cancellable, const gchar *device_id, /* yes, this is the wrong way around :/ */ GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_activate_async(self, device_id, cancellable, fwupd_client_activate_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_clear_results_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_clear_results_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_clear_results: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Clears the results for a specific device. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_clear_results(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_clear_results_async(self, device_id, cancellable, fwupd_client_clear_results_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_get_results_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->device = fwupd_client_get_results_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_results: * @self: a #FwupdClient * @device_id: the device ID * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets the results of a previous firmware update for a specific device. * * Returns: (transfer full): a device, or %NULL for failure * * Since: 0.7.0 **/ FwupdDevice * fwupd_client_get_results(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(device_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_results_async(self, device_id, cancellable, fwupd_client_get_results_cb, helper); g_main_loop_run(helper->loop); if (helper->device == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->device); } static void fwupd_client_get_host_security_attrs_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_host_security_attrs_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_host_security_attrs: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the host security attributes from the daemon. * * Returns: (element-type FwupdSecurityAttr) (transfer container): attributes * * Since: 1.5.0 **/ GPtrArray * fwupd_client_get_host_security_attrs(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_host_security_attrs_async(self, cancellable, fwupd_client_get_host_security_attrs_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static void fwupd_client_get_device_by_id_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->device = fwupd_client_get_device_by_id_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_device_by_id: * @self: a #FwupdClient * @device_id: the device ID, e.g. `usb:00:01:03:03` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets a device by its device ID. * * Returns: (transfer full): a device or %NULL * * Since: 0.9.3 **/ FwupdDevice * fwupd_client_get_device_by_id(FwupdClient *self, const gchar *device_id, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(device_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_device_by_id_async(self, device_id, cancellable, fwupd_client_get_device_by_id_cb, helper); g_main_loop_run(helper->loop); if (helper->device == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->device); } static void fwupd_client_get_devices_by_guid_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_devices_by_guid_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_devices_by_guid: * @self: a #FwupdClient * @guid: the GUID, e.g. `e22c4520-43dc-5bb3-8245-5787fead9b63` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets any devices that provide a specific GUID. An error is returned if no * devices contains this GUID. * * Returns: (element-type FwupdDevice) (transfer container): devices or %NULL * * Since: 1.4.1 **/ GPtrArray * fwupd_client_get_devices_by_guid(FwupdClient *self, const gchar *guid, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(guid != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_devices_by_guid_async(self, guid, cancellable, fwupd_client_get_devices_by_guid_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } #ifdef HAVE_GIO_UNIX static void fwupd_client_install_fd_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_install_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } #endif /** * fwupd_client_install: * @self: a #FwupdClient * @device_id: the device ID * @filename: the filename to install * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Install a file onto a specific device. * * Returns: %TRUE for success * * Since: 0.7.0 **/ gboolean fwupd_client_install(FwupdClient *self, const gchar *device_id, const gchar *filename, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error) { #ifdef HAVE_GIO_UNIX g_autoptr(GUnixInputStream) istr = NULL; g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(filename != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* move to a thread if this ever takes more than a few ms */ istr = fwupd_unix_input_stream_from_fn(filename, error); if (istr == NULL) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_install_stream_async(self, device_id, istr, filename, install_flags, cancellable, fwupd_client_install_fd_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; #else g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Not supported as is unavailable"); return FALSE; #endif } static void fwupd_client_install_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_install_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_install_bytes: * @self: a #FwupdClient * @device_id: the device ID * @bytes: cabinet archive * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Install firmware onto a specific device. * * Returns: %TRUE for success * * Since: 1.4.5 **/ gboolean fwupd_client_install_bytes(FwupdClient *self, const gchar *device_id, GBytes *bytes, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(bytes != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_install_bytes_async(self, device_id, bytes, install_flags, cancellable, fwupd_client_install_bytes_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_install_release_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_install_release_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_install_release2: * @self: a #FwupdClient * @device: a device * @release: a release * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @download_flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Installs a new release on a device, downloading the firmware if required. * * Returns: %TRUE for success * * Since: 1.5.6 **/ gboolean fwupd_client_install_release2(FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, FwupdClientDownloadFlags download_flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(FWUPD_IS_DEVICE(device), FALSE); g_return_val_if_fail(FWUPD_IS_RELEASE(release), FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_install_release2_async(self, device, release, install_flags, download_flags, cancellable, fwupd_client_install_release_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } /** * fwupd_client_install_release: * @self: a #FwupdClient * @device: a device * @release: a release * @install_flags: install flags, e.g. %FWUPD_INSTALL_FLAG_ALLOW_REINSTALL * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Installs a new release on a device, downloading the firmware if required. * * Returns: %TRUE for success * * Since: 1.4.5 * Deprecated: 1.5.6 **/ gboolean fwupd_client_install_release(FwupdClient *self, FwupdDevice *device, FwupdRelease *release, FwupdInstallFlags install_flags, GCancellable *cancellable, GError **error) { return fwupd_client_install_release2(self, device, release, install_flags, FWUPD_CLIENT_DOWNLOAD_FLAG_NONE, cancellable, error); } #ifdef HAVE_GIO_UNIX static void fwupd_client_update_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_update_metadata_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } #endif /** * fwupd_client_update_metadata: * @self: a #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @metadata_fn: the XML metadata filename * @signature_fn: the GPG signature file * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Updates the metadata. This allows a session process to download the metadata * and metadata signing file to be passed into the daemon to be checked and * parsed. * * The @remote_id allows the firmware to be tagged so that the remote can be * matched when the firmware is downloaded. * * Returns: %TRUE for success * * Since: 1.0.0 **/ gboolean fwupd_client_update_metadata(FwupdClient *self, const gchar *remote_id, const gchar *metadata_fn, const gchar *signature_fn, GCancellable *cancellable, GError **error) { #ifdef HAVE_GIO_UNIX g_autoptr(GUnixInputStream) istr = NULL; g_autoptr(GUnixInputStream) istr_sig = NULL; g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(remote_id != NULL, FALSE); g_return_val_if_fail(metadata_fn != NULL, FALSE); g_return_val_if_fail(signature_fn != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; istr = fwupd_unix_input_stream_from_fn(metadata_fn, error); if (istr == NULL) return FALSE; istr_sig = fwupd_unix_input_stream_from_fn(signature_fn, error); if (istr_sig == NULL) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_update_metadata_stream_async(self, remote_id, istr, istr_sig, cancellable, fwupd_client_update_metadata_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; #else g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Not supported as is unavailable"); return FALSE; #endif } static void fwupd_client_update_metadata_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_update_metadata_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_update_metadata_bytes: * @self: a #FwupdClient * @remote_id: remote ID, e.g. `lvfs-testing` * @metadata: XML metadata data * @signature: signature data * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Updates the metadata. This allows a session process to download the metadata * and metadata signing file to be passed into the daemon to be checked and * parsed. * * The @remote_id allows the firmware to be tagged so that the remote can be * matched when the firmware is downloaded. * * Returns: %TRUE for success * * Since: 1.4.5 **/ gboolean fwupd_client_update_metadata_bytes(FwupdClient *self, const gchar *remote_id, GBytes *metadata, GBytes *signature, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(remote_id != NULL, FALSE); g_return_val_if_fail(metadata != NULL, FALSE); g_return_val_if_fail(signature != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_update_metadata_bytes_async(self, remote_id, metadata, signature, cancellable, fwupd_client_update_metadata_bytes_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_refresh_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_refresh_remote_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_refresh_remote: * @self: a #FwupdClient * @remote: a #FwupdRemote * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Refreshes a remote by downloading new metadata. * * Returns: %TRUE for success * * Since: 1.4.5 **/ gboolean fwupd_client_refresh_remote(FwupdClient *self, FwupdRemote *remote, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(FWUPD_IS_REMOTE(remote), FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_refresh_remote_async(self, remote, cancellable, fwupd_client_refresh_remote_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_modify_remote_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_modify_remote_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_modify_remote: * @self: a #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @key: the key, e.g. `Enabled` * @value: the key, e.g. `true` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Modifies a system remote in a specific way. * * NOTE: User authentication may be required to complete this action. * * Returns: %TRUE for success * * Since: 0.9.8 **/ gboolean fwupd_client_modify_remote(FwupdClient *self, const gchar *remote_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(remote_id != NULL, FALSE); g_return_val_if_fail(key != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_modify_remote_async(self, remote_id, key, value, cancellable, fwupd_client_modify_remote_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_get_report_metadata_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->hash = fwupd_client_get_report_metadata_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_report_metadata: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets all the report metadata from the daemon. * * Returns: (transfer container): attributes * * Since: 1.5.0 **/ GHashTable * fwupd_client_get_report_metadata(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_report_metadata_async(self, cancellable, fwupd_client_get_report_metadata_cb, helper); g_main_loop_run(helper->loop); if (helper->hash == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->hash); } static void fwupd_client_modify_device_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_modify_device_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_modify_device: * @self: a #FwupdClient * @device_id: the device ID * @key: the key, e.g. `Flags` * @value: the key, e.g. `reported` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Modifies a device in a specific way. Not all properties on the #FwupdDevice * are settable by the client, and some may have other restrictions on @value. * * NOTE: User authentication may be required to complete this action. * * Returns: %TRUE for success * * Since: 1.0.4 **/ gboolean fwupd_client_modify_device(FwupdClient *self, const gchar *device_id, const gchar *key, const gchar *value, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(device_id != NULL, FALSE); g_return_val_if_fail(key != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_modify_device_async(self, device_id, key, value, cancellable, fwupd_client_modify_device_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_get_remotes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_remotes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_remotes: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets the list of remotes that have been configured for the system. * * Returns: (element-type FwupdRemote) (transfer container): list of remotes, or %NULL * * Since: 0.9.3 **/ GPtrArray * fwupd_client_get_remotes(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_remotes_async(self, cancellable, fwupd_client_get_remotes_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->array); } static FwupdRemote * fwupd_client_get_remote_by_id_noref(GPtrArray *remotes, const gchar *remote_id) { for (guint i = 0; i < remotes->len; i++) { FwupdRemote *remote = g_ptr_array_index(remotes, i); if (g_strcmp0(remote_id, fwupd_remote_get_id(remote)) == 0) return remote; } return NULL; } /** * fwupd_client_get_remote_by_id: * @self: a #FwupdClient * @remote_id: the remote ID, e.g. `lvfs-testing` * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets a specific remote that has been configured for the system. * * Returns: (transfer full): a #FwupdRemote, or %NULL if not found * * Since: 0.9.3 **/ FwupdRemote * fwupd_client_get_remote_by_id(FwupdClient *self, const gchar *remote_id, GCancellable *cancellable, GError **error) { FwupdRemote *remote; g_autoptr(GPtrArray) remotes = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(remote_id != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* find remote in list */ remotes = fwupd_client_get_remotes(self, cancellable, error); if (remotes == NULL) return NULL; remote = fwupd_client_get_remote_by_id_noref(remotes, remote_id); if (remote == NULL) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "No remote '%s' found in search paths", remote_id); return NULL; } /* success */ return g_object_ref(remote); } static void fwupd_client_get_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_approved_firmware_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_approved_firmware: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets the list of approved firmware. * * Returns: (transfer full): checksums, or %NULL for error * * Since: 1.2.6 **/ gchar ** fwupd_client_get_approved_firmware(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; gchar **argv; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_approved_firmware_async(self, cancellable, fwupd_client_get_approved_firmware_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } argv = g_new0(gchar *, helper->array->len + 1); for (guint i = 0; i < helper->array->len; i++) { const gchar *tmp = g_ptr_array_index(helper->array, i); argv[i] = g_strdup(tmp); } return argv; } static void fwupd_client_set_approved_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_set_approved_firmware_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_set_approved_firmware: * @self: a #FwupdClient * @checksums: Array of checksums * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Sets the list of approved firmware. * * Returns: %TRUE for success * * Since: 1.2.6 **/ gboolean fwupd_client_set_approved_firmware(FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* convert */ for (guint i = 0; checksums[i] != NULL; i++) g_ptr_array_add(array, g_strdup(checksums[i])); /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_set_approved_firmware_async(self, array, cancellable, fwupd_client_set_approved_firmware_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_get_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->array = fwupd_client_get_blocked_firmware_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_get_blocked_firmware: * @self: a #FwupdClient * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Gets the list of blocked firmware. * * Returns: (transfer full): checksums, or %NULL for error * * Since: 1.4.6 **/ gchar ** fwupd_client_get_blocked_firmware(FwupdClient *self, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; gchar **argv; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_get_blocked_firmware_async(self, cancellable, fwupd_client_get_blocked_firmware_cb, helper); g_main_loop_run(helper->loop); if (helper->array == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } argv = g_new0(gchar *, helper->array->len + 1); for (guint i = 0; i < helper->array->len; i++) { const gchar *tmp = g_ptr_array_index(helper->array, i); argv[i] = g_strdup(tmp); } return argv; } static void fwupd_client_set_blocked_firmware_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_set_blocked_firmware_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_set_blocked_firmware: * @self: a #FwupdClient * @checksums: Array of checksums * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Sets the list of approved firmware. * * Returns: %TRUE for success * * Since: 1.4.6 **/ gboolean fwupd_client_set_blocked_firmware(FwupdClient *self, gchar **checksums, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func(g_free); g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(checksums != NULL, FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; for (guint i = 0; checksums[i] != NULL; i++) g_ptr_array_add(array, g_strdup(checksums[i])); /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_set_blocked_firmware_async(self, array, cancellable, fwupd_client_set_blocked_firmware_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_set_feature_flags_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->ret = fwupd_client_set_feature_flags_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_set_feature_flags: * @self: a #FwupdClient * @feature_flags: feature flags, e.g. %FWUPD_FEATURE_FLAG_UPDATE_TEXT * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Sets the features the client supports. This allows firmware to depend on * specific front-end features, for instance showing the user an image on * how to detach the hardware. * * Clients can call this none or multiple times. * * Returns: %TRUE for success * * Since: 1.4.5 **/ gboolean fwupd_client_set_feature_flags(FwupdClient *self, FwupdFeatureFlags feature_flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return FALSE; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_set_feature_flags_async(self, feature_flags, cancellable, fwupd_client_set_feature_flags_cb, helper); g_main_loop_run(helper->loop); if (!helper->ret) { g_propagate_error(error, g_steal_pointer(&helper->error)); return FALSE; } return TRUE; } static void fwupd_client_self_sign_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->str = fwupd_client_self_sign_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_self_sign: * @self: a #FwupdClient * @value: a string to sign, typically a JSON blob * @flags: signing flags, e.g. %FWUPD_SELF_SIGN_FLAG_ADD_TIMESTAMP * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Signs the data using the client self-signed certificate. * * Returns: a signature, or %NULL for failure * * Since: 1.2.6 **/ gchar * fwupd_client_self_sign(FwupdClient *self, const gchar *value, FwupdSelfSignFlags flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(value != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_self_sign_async(self, value, flags, cancellable, fwupd_client_self_sign_cb, helper); g_main_loop_run(helper->loop); if (helper->str == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->str); } static void fwupd_client_download_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->bytes = fwupd_client_download_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_download_bytes: * @self: a #FwupdClient * @url: the remote URL * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Downloads data from a remote server. The [method@Client.set_user_agent] function * should be called before this method is used. * * Returns: (transfer full): downloaded data, or %NULL for error * * Since: 1.4.5 **/ GBytes * fwupd_client_download_bytes(FwupdClient *self, const gchar *url, FwupdClientDownloadFlags flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(url != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); g_return_val_if_fail(fwupd_client_get_user_agent(self) != NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_download_bytes_async(self, url, flags, cancellable, fwupd_client_download_bytes_cb, helper); g_main_loop_run(helper->loop); if (helper->bytes == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->bytes); } /** * fwupd_client_download_file: * @self: a #FwupdClient * @url: the remote URL * @file: a file * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Downloads data from a remote server. The [method@Client.set_user_agent] function * should be called before this method is used. * * Returns: %TRUE if the file was written * * Since: 1.5.2 **/ gboolean fwupd_client_download_file(FwupdClient *self, const gchar *url, GFile *file, FwupdClientDownloadFlags flags, GCancellable *cancellable, GError **error) { gssize size; g_autoptr(GBytes) bytes = NULL; g_autoptr(GOutputStream) ostream = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), FALSE); g_return_val_if_fail(url != NULL, FALSE); g_return_val_if_fail(G_IS_FILE(file), FALSE); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); g_return_val_if_fail(fwupd_client_get_user_agent(self) != NULL, FALSE); /* download then write */ bytes = fwupd_client_download_bytes(self, url, flags, cancellable, error); if (bytes == NULL) return FALSE; ostream = G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error)); if (ostream == NULL) return FALSE; size = g_output_stream_write_bytes(ostream, bytes, NULL, error); if (size < 0) return FALSE; /* success */ return TRUE; } static void fwupd_client_upload_bytes_cb(GObject *source, GAsyncResult *res, gpointer user_data) { FwupdClientHelper *helper = (FwupdClientHelper *)user_data; helper->bytes = fwupd_client_upload_bytes_finish(FWUPD_CLIENT(source), res, &helper->error); g_main_loop_quit(helper->loop); } /** * fwupd_client_upload_bytes: * @self: a #FwupdClient * @url: the remote URL * @payload: payload string * @signature: (nullable): signature string * @flags: download flags, e.g. %FWUPD_CLIENT_DOWNLOAD_FLAG_NONE * @cancellable: (nullable): optional #GCancellable * @error: (nullable): optional return location for an error * * Uploads data to a remote server. The [method@Client.set_user_agent] function * should be called before this method is used. * * Returns: (transfer full): response data, or %NULL for error * * Since: 1.4.5 **/ GBytes * fwupd_client_upload_bytes(FwupdClient *self, const gchar *url, const gchar *payload, const gchar *signature, FwupdClientUploadFlags flags, GCancellable *cancellable, GError **error) { g_autoptr(FwupdClientHelper) helper = NULL; g_return_val_if_fail(FWUPD_IS_CLIENT(self), NULL); g_return_val_if_fail(url != NULL, NULL); g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* connect */ if (!fwupd_client_connect(self, cancellable, error)) return NULL; /* call async version and run loop until complete */ helper = fwupd_client_helper_new(self); fwupd_client_upload_bytes_async(self, url, payload, signature, flags, cancellable, fwupd_client_upload_bytes_cb, helper); g_main_loop_run(helper->loop); if (helper->bytes == NULL) { g_propagate_error(error, g_steal_pointer(&helper->error)); return NULL; } return g_steal_pointer(&helper->bytes); }