/** * fu_provider_clear_results: **/ gboolean fu_provider_clear_results (FuProvider *provider, FuDevice *device, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); g_autoptr(GError) error_local = NULL; g_autoptr(FuDevice) device_pending = NULL; g_autoptr(FuPending) pending = NULL; /* handled by the provider */ if (klass->clear_results != NULL) return klass->clear_results (provider, device, error); /* handled using the database */ pending = fu_pending_new (); device_pending = fu_pending_get_device (pending, fu_device_get_id (device), &error_local); if (device_pending == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to find %s in pending database: %s", fu_device_get_id (device), error_local->message); return FALSE; } /* remove from pending database */ return fu_pending_remove_device (pending, device, error); }
static gboolean fu_provider_chug_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; GChecksumType checksum_type; gsize len; g_autoptr(GError) error_local = NULL; g_autofree gchar *hash = NULL; g_autofree guint8 *data = NULL; /* find item */ item = g_hash_table_lookup (priv->devices, fu_device_get_id (device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "cannot find: %s", fu_device_get_id (device)); return FALSE; } /* open */ if (!fu_provider_chug_open (item, error)) return FALSE; /* get the firmware from the device */ g_debug ("ColorHug: Verifying firmware"); ch_device_queue_read_firmware (priv->device_queue, item->usb_device, &data, &len); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to dump firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* get the checksum */ checksum_type = fu_provider_get_checksum_type (flags); hash = g_compute_checksum_for_data (checksum_type, (guchar *) data, len); fu_device_set_checksum (device, hash); fu_device_set_checksum_kind (device, checksum_type); /* we're done here */ if (!g_usb_device_close (item->usb_device, &error_local)) g_debug ("Failed to close: %s", error_local->message); return TRUE; }
/** * fu_provider_schedule_update: **/ static gboolean fu_provider_schedule_update (FuProvider *provider, FuDevice *device, GBytes *blob_cab, GError **error) { gchar tmpname[] = {"XXXXXX.cap"}; guint i; g_autofree gchar *dirname = NULL; g_autofree gchar *filename = NULL; g_autoptr(FuDevice) device_tmp = NULL; g_autoptr(FuPending) pending = NULL; g_autoptr(GFile) file = NULL; /* id already exists */ pending = fu_pending_new (); device_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL); if (device_tmp != NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_ALREADY_PENDING, "%s is already scheduled to be updated", fu_device_get_id (device)); return FALSE; } /* create directory */ dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) return FALSE; } /* get a random filename */ for (i = 0; i < 6; i++) tmpname[i] = g_random_int_range ('A', 'Z'); filename = g_build_filename (dirname, tmpname, NULL); /* just copy to the temp file */ fu_provider_set_status (provider, FWUPD_STATUS_SCHEDULING); if (!g_file_set_contents (filename, g_bytes_get_data (blob_cab, NULL), g_bytes_get_size (blob_cab), error)) return FALSE; /* schedule for next boot */ g_debug ("schedule %s to be installed to %s on next boot", filename, fu_device_get_id (device)); fu_device_set_metadata (device, FU_DEVICE_KEY_FILENAME_CAB, filename); /* add to database */ if (!fu_pending_add_device (pending, device, error)) return FALSE; /* next boot we run offline */ return fu_provider_offline_setup (error); }
/** * fu_provider_get_results: **/ gboolean fu_provider_get_results (FuProvider *provider, FuDevice *device, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); FwupdUpdateState update_state; const gchar *tmp; g_autoptr(GError) error_local = NULL; g_autoptr(FwupdResult) res_pending = NULL; g_autoptr(FuPending) pending = NULL; /* handled by the provider */ if (klass->get_results != NULL) return klass->get_results (provider, device, error); /* handled using the database */ pending = fu_pending_new (); res_pending = fu_pending_get_device (pending, fu_device_get_id (device), &error_local); if (res_pending == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Failed to find %s in pending database: %s", fu_device_get_id (device), error_local->message); return FALSE; } /* copy the important parts from the pending device to the real one */ update_state = fwupd_result_get_update_state (res_pending); if (update_state == FWUPD_UPDATE_STATE_UNKNOWN || update_state == FWUPD_UPDATE_STATE_PENDING) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Device %s has not been updated offline yet", fu_device_get_id (device)); return FALSE; } /* copy */ fu_device_set_update_state (device, update_state); tmp = fwupd_result_get_update_error (res_pending); if (tmp != NULL) fu_device_set_update_error (device, tmp); tmp = fwupd_result_get_device_version (res_pending); if (tmp != NULL) fu_device_set_version (device, tmp); tmp = fwupd_result_get_update_version (res_pending); if (tmp != NULL) fu_device_set_update_version (device, tmp); return TRUE; }
/** * fu_provider_get_results: **/ gboolean fu_provider_get_results (FuProvider *provider, FuDevice *device, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); const gchar *tmp; guint i; g_autoptr(GError) error_local = NULL; g_autoptr(FuDevice) device_pending = NULL; g_autoptr(FuPending) pending = NULL; const gchar *copy_keys[] = { FU_DEVICE_KEY_PENDING_STATE, FU_DEVICE_KEY_PENDING_ERROR, FU_DEVICE_KEY_VERSION, FU_DEVICE_KEY_UPDATE_VERSION, NULL }; /* handled by the provider */ if (klass->get_results != NULL) return klass->get_results (provider, device, error); /* handled using the database */ pending = fu_pending_new (); device_pending = fu_pending_get_device (pending, fu_device_get_id (device), &error_local); if (device_pending == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Failed to find %s in pending database: %s", fu_device_get_id (device), error_local->message); return FALSE; } /* copy the important parts from the pending device to the real one */ tmp = fu_device_get_metadata (device_pending, FU_DEVICE_KEY_PENDING_STATE); if (tmp == NULL || g_strcmp0 (tmp, "scheduled") == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "Device %s has not been updated offline yet", fu_device_get_id (device)); return FALSE; } for (i = 0; copy_keys[i] != NULL; i++) { tmp = fu_device_get_metadata (device_pending, copy_keys[i]); if (tmp != NULL) fu_device_set_metadata (device, copy_keys[i], tmp); } return TRUE; }
/** * fu_provider_unlock: **/ gboolean fu_provider_unlock (FuProvider *provider, FuDevice *device, GError **error) { guint64 flags; FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); /* final check */ flags = fu_device_get_flags (device); if ((flags & FU_DEVICE_FLAG_LOCKED) == 0) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Device %s is not locked", fu_device_get_id (device)); return FALSE; } /* run provider method */ if (klass->unlock != NULL) { if (!klass->unlock (provider, device, error)) return FALSE; } /* update with correct flags */ flags = fu_device_get_flags (device); fu_device_set_flags (device, flags &= ~FU_DEVICE_FLAG_LOCKED); fu_device_set_modified (device, g_get_real_time () / G_USEC_PER_SEC); return TRUE; }
static gboolean fu_provider_uefi_unlock (FuProvider *provider, FuDevice *device, GError **error) { #ifdef HAVE_UEFI_UNLOCK gint rc; g_debug ("unlocking UEFI device %s", fu_device_get_id (device)); rc = fwup_enable_esrt(); if (rc <= 0) { g_debug("Failed to unlock UEFI device"); return FALSE; } else if (rc == 1) g_debug("UEFI device is already unlocked"); else if (rc == 2) g_debug("Succesfully unlocked UEFI device"); else if (rc == 3) g_debug("UEFI device will be unlocked on next reboot"); return TRUE; #else g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Not supported, update libfwupdate!"); return FALSE; #endif }
/** * fu_provider_udev_unlock: **/ static gboolean fu_provider_udev_unlock (FuProvider *provider, FuDevice *device, GError **error) { const gchar *rom_fn; g_autoptr(FuRom) rom = NULL; g_autoptr(GFile) file = NULL; /* get the FW version from the rom */ g_debug ("unlocking UDev device %s", fu_device_get_id (device)); rom_fn = fu_device_get_metadata (device, "RomFilename"); if (rom_fn == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Unable to read firmware from device"); return FALSE; } file = g_file_new_for_path (rom_fn); rom = fu_rom_new (); if (!fu_rom_load_file (rom, file, FU_ROM_LOAD_FLAG_BLANK_PPID, NULL, error)) return FALSE; /* update version */ if (g_strcmp0 (fu_device_get_version (device), fu_rom_get_version (rom)) != 0) { g_debug ("changing version of %s from %s to %s", fu_device_get_id (device), fu_device_get_version (device), fu_rom_get_version (rom)); fu_device_set_version (device, fu_rom_get_version (rom)); } /* prefer the GUID from the firmware rather than the * hardware as the firmware may be more generic, which * also allows us to match the GUID when doing 'verify' * on a device with a different PID to the firmware */ if (g_strcmp0 (fu_device_get_guid (device), fu_rom_get_guid (rom)) != 0) { fu_device_set_guid (device, fu_rom_get_guid (rom)); g_debug ("changing GUID of %s from %s to %s", fu_device_get_id (device), fu_device_get_guid (device), fu_rom_get_guid (rom)); } return TRUE; }
/** * fu_provider_device_remove: **/ void fu_provider_device_remove (FuProvider *provider, FuDevice *device) { g_debug ("emit removed from %s: %s", fu_provider_get_name (provider), fu_device_get_id (device)); g_signal_emit (provider, signals[SIGNAL_DEVICE_REMOVED], 0, device); }
/** * fu_provider_device_add: **/ void fu_provider_device_add (FuProvider *provider, FuDevice *device) { g_debug ("emit added: %s", fu_device_get_id (device)); fu_device_set_metadata (device, FU_DEVICE_KEY_PROVIDER, fu_provider_get_name (provider)); g_signal_emit (provider, signals[SIGNAL_DEVICE_ADDED], 0, device); }
/** * fu_provider_device_add: **/ void fu_provider_device_add (FuProvider *provider, FuDevice *device) { g_debug ("emit added from %s: %s", fu_provider_get_name (provider), fu_device_get_id (device)); fu_device_set_created (device, g_get_real_time () / G_USEC_PER_SEC); fu_device_set_provider (device, fu_provider_get_name (provider)); g_signal_emit (provider, signals[SIGNAL_DEVICE_ADDED], 0, device); }
gboolean fu_plugin_device_removed (FuPlugin *plugin, FuDevice *device, GError **error) { const gchar *device_key = fu_device_get_id (device); FuDevice *dev; FuDevice *parent; /* only the device with bridge will be in cache */ dev = fu_plugin_cache_lookup (plugin, device_key); if (dev == NULL) return TRUE; fu_plugin_cache_remove (plugin, device_key); /* find the parent and ask daemon to remove whole chain */ parent = fu_device_get_parent (dev); if (parent != NULL && FU_IS_DELL_DOCK_EC (parent)) { g_debug ("Removing %s (%s)", fu_device_get_name (parent), fu_device_get_id (parent)); fu_plugin_device_remove (plugin, parent); } return TRUE; }
static gboolean fu_provider_chug_open (FuProviderChugItem *item, GError **error) { g_autoptr(GError) error_local = NULL; if (!ch_device_open (item->usb_device, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_READ, "failed to open %s device: %s", fu_device_get_id (item->device), error_local->message); return FALSE; } return TRUE; }
/** * fu_util_update: **/ static gboolean fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) { FuDevice *dev; GPtrArray *devices = NULL; guint i; /* apply any updates */ devices = fu_util_get_updates_internal (priv, error); if (devices == NULL) return FALSE; for (i = 0; i < devices->len; i++) { const gchar *checksum; const gchar *uri; _cleanup_free_ gchar *basename = NULL; _cleanup_free_ gchar *fn = NULL; dev = g_ptr_array_index (devices, i); /* download file */ checksum = fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_HASH); if (checksum == NULL) continue; uri = fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_URI); if (uri == NULL) continue; g_print ("Downloading %s for %s...\n", fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_VERSION), fu_device_get_display_name (dev)); basename = g_path_get_basename (uri); fn = g_build_filename (g_get_tmp_dir (), basename, NULL); if (!fu_util_download_file (priv, uri, fn, checksum, error)) return FALSE; g_print ("Updating %s on %s...\n", fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_VERSION), fu_device_get_display_name (dev)); if (!fu_util_install_with_fallback (priv, fu_device_get_id (dev), fn, error)) return FALSE; } return TRUE; }
gboolean fu_plugin_usb_device_added (FuPlugin *plugin, FuUsbDevice *device, GError **error) { g_autoptr(FuDeviceLocker) locker = NULL; g_autoptr(FuDellDockHub) hub = fu_dell_dock_hub_new (device); FuDevice *fu_device = FU_DEVICE (hub); const gchar *key = NULL; locker = fu_device_locker_new (fu_device, error); if (locker == NULL) return FALSE; fu_plugin_device_add (plugin, fu_device); if (fu_device_has_custom_flag (fu_device, "has-bridge")) { g_autoptr(GError) error_local = NULL; /* only add the device with parent to cache */ key = fu_device_get_id (fu_device); if (fu_plugin_cache_lookup (plugin, key) != NULL) { g_debug ("Ignoring already added device %s", key); return TRUE; } fu_plugin_cache_add (plugin, key, fu_device); /* probe for extended devices */ if (!fu_plugin_dell_dock_probe (plugin, fu_device, &error_local)) { g_warning ("Failed to probe bridged devices for %s: %s", key, error_local->message); } } /* clear updatable flag if parent doesn't have it */ fu_dell_dock_clone_updatable (fu_device); return TRUE; }
/** * fu_util_install_prepared: **/ static gboolean fu_util_install_prepared (FuUtilPrivate *priv, gchar **values, GError **error) { gint vercmp; guint cnt = 0; guint i; const gchar *tmp; _cleanup_ptrarray_unref_ GPtrArray *devices = NULL; _cleanup_object_unref_ FuPending *pending = NULL; /* do this first to avoid a loop if this tool segfaults */ g_unlink (FU_OFFLINE_TRIGGER_FILENAME); if (g_strv_length (values) != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "Invalid arguments: none expected"); return FALSE; } /* ensure root user */ if (getuid () != 0 || geteuid () != 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "This function can only be used as root"); return FALSE; } /* get prepared updates */ pending = fu_pending_new (); devices = fu_pending_get_devices (pending, error); if (devices == NULL) return FALSE; /* apply each update */ for (i = 0; i < devices->len; i++) { FuDevice *device; device = g_ptr_array_index (devices, i); /* check not already done */ tmp = fu_device_get_metadata (device, FU_DEVICE_KEY_PENDING_STATE); if (g_strcmp0 (tmp, "scheduled") != 0) continue; /* tell the user what's going to happen */ vercmp = as_utils_vercmp (fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_OLD), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_NEW)); if (vercmp == 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second is a version number * e.g. "1.2.3" */ g_print (_("Reinstalling %s with %s... "), fu_device_get_display_name (device), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_NEW)); } else if (vercmp > 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second and third are * version numbers e.g. "1.2.3" */ g_print (_("Downgrading %s from %s to %s... "), fu_device_get_display_name (device), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_OLD), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_NEW)); } else if (vercmp < 0) { /* TRANSLATORS: the first replacement is a display name * e.g. "ColorHugALS" and the second and third are * version numbers e.g. "1.2.3" */ g_print (_("Updating %s from %s to %s... "), fu_device_get_display_name (device), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_OLD), fu_device_get_metadata (device, FU_DEVICE_KEY_VERSION_NEW)); } if (!fu_util_install_internal (priv, fu_device_get_id (device), fu_device_get_metadata (device, FU_DEVICE_KEY_FILENAME_CAB), error)) return FALSE; cnt++; } /* nothing to do */ if (cnt == 0) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "No updates prepared"); return FALSE; } /* reboot */ fu_util_offline_update_reboot (); g_print ("%s\n", _("Done!")); return TRUE; }
/** * fu_provider_update: **/ gboolean fu_provider_update (FuProvider *provider, FuDevice *device, GBytes *blob_cab, GBytes *blob_fw, FuProviderFlags flags, GError **error) { FuProviderClass *klass = FU_PROVIDER_GET_CLASS (provider); g_autoptr(FuPending) pending = NULL; g_autoptr(FuDevice) device_pending = NULL; GError *error_update = NULL; /* schedule for next reboot, or handle in the provider */ if (flags & FU_PROVIDER_UPDATE_FLAG_OFFLINE) { if (klass->update_offline == NULL) return fu_provider_schedule_update (provider, device, blob_cab, error); return klass->update_offline (provider, device, blob_fw, flags, error); } /* cancel the pending action */ if (!fu_provider_offline_invalidate (error)) return FALSE; /* online */ if (klass->update_online == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "No online update possible"); return FALSE; } pending = fu_pending_new (); device_pending = fu_pending_get_device (pending, fu_device_get_id (device), NULL); if (!klass->update_online (provider, device, blob_fw, flags, &error_update)) { /* save the error to the database */ if (device_pending != NULL) { fu_pending_set_error_msg (pending, device, error_update->message, NULL); } g_propagate_error (error, error_update); return FALSE; } /* cleanup */ if (device_pending != NULL) { const gchar *tmp; /* update pending database */ fu_pending_set_state (pending, device, FU_PENDING_STATE_SUCCESS, NULL); /* delete cab file */ tmp = fu_device_get_metadata (device_pending, FU_DEVICE_KEY_FILENAME_CAB); if (tmp != NULL && g_str_has_prefix (tmp, LIBEXECDIR)) { g_autoptr(GError) error_local = NULL; g_autoptr(GFile) file = NULL; file = g_file_new_for_path (tmp); if (!g_file_delete (file, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INVALID_FILE, "Failed to delete %s: %s", tmp, error_local->message); return FALSE; } } } return TRUE; }
/** * fu_provider_schedule_update: **/ static gboolean fu_provider_schedule_update (FuProvider *provider, FuDevice *device, GInputStream *stream, GError **error) { gchar tmpname[] = {"XXXXXX.cap"}; guint i; _cleanup_bytes_unref_ GBytes *fwbin = NULL; _cleanup_free_ gchar *dirname = NULL; _cleanup_free_ gchar *filename = NULL; _cleanup_object_unref_ FuDevice *device_tmp = NULL; _cleanup_object_unref_ FuPending *pending = NULL; _cleanup_object_unref_ GFile *file = NULL; /* id already exists */ pending = fu_pending_new (); device_tmp = fu_pending_get_device (pending, fu_device_get_id (device), NULL); if (device_tmp != NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_ALREADY_PENDING, "%s is already scheduled to be updated", fu_device_get_id (device)); return FALSE; } /* create directory */ dirname = g_build_filename (LOCALSTATEDIR, "lib", "fwupd", NULL); file = g_file_new_for_path (dirname); if (!g_file_query_exists (file, NULL)) { if (!g_file_make_directory_with_parents (file, NULL, error)) return FALSE; } /* get a random filename */ for (i = 0; i < 6; i++) tmpname[i] = g_random_int_range ('A', 'Z'); filename = g_build_filename (dirname, tmpname, NULL); /* just copy to the temp file */ fu_provider_set_status (provider, FWUPD_STATUS_SCHEDULING); if (!g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, error)) return FALSE; fwbin = g_input_stream_read_bytes (stream, FU_PROVIDER_FIRMWARE_MAX, NULL, error); if (fwbin == NULL) return FALSE; if (!g_file_set_contents (filename, g_bytes_get_data (fwbin, NULL), g_bytes_get_size (fwbin), error)) return FALSE; /* schedule for next boot */ g_debug ("schedule %s to be installed to %s on next boot", filename, fu_device_get_id (device)); fu_device_set_metadata (device, FU_DEVICE_KEY_FILENAME_CAB, filename); /* add to database */ if (!fu_pending_add_device (pending, device, error)) return FALSE; /* next boot we run offline */ return fu_provider_offline_setup (error); }
static gboolean fu_provider_chug_update (FuProvider *provider, FuDevice *device, GBytes *blob_fw, FwupdInstallFlags flags, GError **error) { FuProviderChug *provider_chug = FU_PROVIDER_CHUG (provider); FuProviderChugPrivate *priv = GET_PRIVATE (provider_chug); FuProviderChugItem *item; g_autoptr(GError) error_local = NULL; /* find item */ item = g_hash_table_lookup (priv->devices, fu_device_get_id (device)); if (item == NULL) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "cannot find: %s", fu_device_get_id (device)); return FALSE; } /* this file is so small, just slurp it all in one go */ item->fw_bin = g_bytes_ref (blob_fw); /* check this firmware is actually for this device */ if (!ch_device_check_firmware (item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin), &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "firmware is not suitable: %s", error_local->message); return FALSE; } /* switch to bootloader mode */ if (!item->is_bootloader) { g_debug ("ColorHug: Switching to bootloader mode"); if (!fu_provider_chug_open (item, error)) return FALSE; ch_device_queue_reset (priv->device_queue, item->usb_device); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_RESTART); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to reset device: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* this device has just gone away, no error possible */ g_usb_device_close (item->usb_device, NULL); /* wait for reconnection */ g_debug ("ColorHug: Waiting for bootloader"); if (!fu_provider_chug_wait_for_connect (provider_chug, item, error)) return FALSE; } /* open the device, which is now in bootloader mode */ if (!fu_provider_chug_open (item, error)) return FALSE; /* write firmware */ g_debug ("ColorHug: Writing firmware"); ch_device_queue_write_firmware (priv->device_queue, item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin)); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_WRITE); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to write firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* verify firmware */ g_debug ("ColorHug: Veifying firmware"); ch_device_queue_verify_firmware (priv->device_queue, item->usb_device, g_bytes_get_data (item->fw_bin, NULL), g_bytes_get_size (item->fw_bin)); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_VERIFY); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to verify firmware: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* boot into the new firmware */ g_debug ("ColorHug: Booting new firmware"); ch_device_queue_boot_flash (priv->device_queue, item->usb_device); fu_provider_set_status (provider, FWUPD_STATUS_DEVICE_RESTART); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to boot flash: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* this device has just gone away, no error possible */ g_usb_device_close (item->usb_device, NULL); /* wait for firmware mode */ if (!fu_provider_chug_wait_for_connect (provider_chug, item, error)) return FALSE; if (!fu_provider_chug_open (item, error)) return FALSE; /* set flash success */ g_debug ("ColorHug: Setting flash success"); ch_device_queue_set_flash_success (priv->device_queue, item->usb_device, 1); if (!ch_device_queue_process (priv->device_queue, CH_DEVICE_QUEUE_PROCESS_FLAGS_NONE, NULL, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to set flash success: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* close, orderly */ if (!g_usb_device_close (item->usb_device, &error_local)) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_WRITE, "failed to close device: %s", error_local->message); g_usb_device_close (item->usb_device, NULL); return FALSE; } /* get the new firmware version */ g_debug ("ColorHug: Getting new firmware version"); item->got_version = FALSE; fu_provider_chug_get_firmware_version (item); if (item->got_version) g_debug ("ColorHug: DONE!"); return TRUE; }
/** * fu_util_verify_all: **/ static gboolean fu_util_verify_all (FuUtilPrivate *priv, GError **error) { AsApp *app; FuDevice *dev; const gchar *tmp; guint i; _cleanup_object_unref_ AsStore *store = NULL; _cleanup_ptrarray_unref_ GPtrArray *devices = NULL; _cleanup_ptrarray_unref_ GPtrArray *devices_tmp = NULL; /* get devices from daemon */ devices_tmp = fu_util_get_devices_internal (priv, error); if (devices_tmp == NULL) return FALSE; /* get results */ for (i = 0; i < devices_tmp->len; i++) { _cleanup_error_free_ GError *error_local = NULL; dev = g_ptr_array_index (devices_tmp, i); if (!fu_util_verify_internal (priv, fu_device_get_id (dev), &error_local)) { g_print ("Failed to verify %s: %s\n", fu_device_get_id (dev), error_local->message); } } /* only load firmware from the system */ store = as_store_new (); as_store_add_filter (store, AS_ID_KIND_FIRMWARE); if (!as_store_load (store, AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM, NULL, error)) return FALSE; /* print */ devices = fu_util_get_devices_internal (priv, error); if (devices == NULL) return FALSE; for (i = 0; i < devices->len; i++) { const gchar *hash = NULL; const gchar *ver = NULL; _cleanup_free_ gchar *status = NULL; dev = g_ptr_array_index (devices, i); hash = fu_device_get_metadata (dev, FU_DEVICE_KEY_FIRMWARE_HASH); if (hash == NULL) continue; app = as_store_get_app_by_id (store, fu_device_get_guid (dev)); if (app == NULL) { status = g_strdup ("No metadata"); } else { AsRelease *rel; ver = fu_device_get_metadata (dev, FU_DEVICE_KEY_VERSION); rel = as_app_get_release (app, ver); if (rel == NULL) { status = g_strdup_printf ("No version %s", ver); } else { tmp = as_release_get_checksum (rel, G_CHECKSUM_SHA1); if (g_strcmp0 (tmp, hash) != 0) { status = g_strdup_printf ("Failed: for v%s expected %s", ver, tmp); } else { status = g_strdup ("OK"); } } } g_print ("%s\t%s\t%s\n", fu_device_get_guid (dev), hash, status); } return TRUE; }
/** * fu_util_get_devices: **/ static gboolean fu_util_get_devices (FuUtilPrivate *priv, gchar **values, GError **error) { FuDevice *dev; _cleanup_ptrarray_unref_ GPtrArray *devices = NULL; guint i; guint j; guint k; guint f; guint64 flags; const gchar *value; const gchar *keys[] = { FU_DEVICE_KEY_DISPLAY_NAME, FU_DEVICE_KEY_PROVIDER, FU_DEVICE_KEY_GUID, FU_DEVICE_KEY_VERSION, FU_DEVICE_KEY_URL_HOMEPAGE, FU_DEVICE_KEY_NAME, FU_DEVICE_KEY_SUMMARY, FU_DEVICE_KEY_DESCRIPTION, FU_DEVICE_KEY_LICENSE, FU_DEVICE_KEY_FLAGS, FU_DEVICE_KEY_TRUSTED, FU_DEVICE_KEY_SIZE, FU_DEVICE_KEY_FIRMWARE_HASH, NULL }; const gchar *flags_str[] = { "Internal", "AllowOnline", "AllowOffline", NULL }; /* get devices from daemon */ devices = fu_util_get_devices_internal (priv, error); if (devices == NULL) return FALSE; /* print */ if (devices->len == 0) { /* TRANSLATORS: nothing attached that can be upgraded */ g_print ("%s\n", _("No hardware detected with firmware update capability")); return TRUE; } for (i = 0; i < devices->len; i++) { dev = g_ptr_array_index (devices, i); g_print ("Device: %s\n", fu_device_get_id (dev)); for (j = 0; keys[j] != NULL; j++) { if (g_strcmp0 (keys[j], FU_DEVICE_KEY_FLAGS) == 0) { flags = fu_device_get_flags (dev); for (f = 0; flags_str[f] != NULL; f++) { g_print (" %s:", flags_str[f]); for (k = strlen (flags_str[f]); k < 15; k++) g_print (" "); g_print (" %s\n", flags & (1 << f) ? "True" : "False"); } continue; } value = fu_device_get_metadata (dev, keys[j]); if (value != NULL) { g_print (" %s:", keys[j]); for (k = strlen (keys[j]); k < 15; k++) g_print (" "); g_print (" %s\n", value); } } } return TRUE; }