/** * 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_udev_verify: **/ static gboolean fu_provider_udev_verify (FuProvider *provider, FuDevice *device, FuProviderVerifyFlags flags, GError **error) { const gchar *rom_fn; g_autoptr(GFile) file = NULL; g_autoptr(FuRom) rom = NULL; /* open the file */ 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; fu_device_set_metadata (device, FU_DEVICE_KEY_FIRMWARE_HASH, fu_rom_get_checksum (rom)); 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_update_prepare (FuPlugin *plugin, FwupdInstallFlags flags, FuDevice *device, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(GUdevDevice) udevice = NULL; const gchar *devpath; /* only run for thunderbolt plugin */ if (g_strcmp0 (fu_device_get_plugin (device), "thunderbolt") != 0) return TRUE; /* reset any timers that might still be running from coldplug */ if (data->timeout_id != 0) { g_source_remove (data->timeout_id); data->timeout_id = 0; } devpath = fu_device_get_metadata (device, "sysfs-path"); udevice = g_udev_client_query_by_sysfs_path (data->udev, devpath); if (udevice != NULL) { data->needs_forcepower = FALSE; return TRUE; } data->updating = TRUE; if (!fu_plugin_thunderbolt_power_set (plugin, TRUE, error)) return FALSE; data->needs_forcepower = TRUE; /* wait for the device to come back onto the bus */ fu_device_set_status (device, FWUPD_STATUS_DEVICE_RESTART); for (guint i = 0; i < 5; i++) { g_autoptr(GUdevDevice) udevice_tmp = NULL; g_usleep (TBT_NEW_DEVICE_TIMEOUT * G_USEC_PER_SEC); udevice_tmp = g_udev_client_query_by_sysfs_path (data->udev, devpath); if (udevice_tmp != NULL) return TRUE; } /* device did not wake up */ g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "device did not wake up when required"); return FALSE; }
/** * fu_util_get_updates: **/ static gboolean fu_util_get_updates (FuUtilPrivate *priv, gchar **values, GError **error) { FuDevice *dev; GPtrArray *devices = NULL; guint i; /* print any updates */ devices = fu_util_get_updates_internal (priv, error); if (devices == NULL) return FALSE; for (i = 0; i < devices->len; i++) { dev = g_ptr_array_index (devices, i); /* TRANSLATORS: first replacement is device name */ g_print (_("%s has firmware updates:"), fu_device_get_display_name (dev)); g_print ("\n"); /* TRANSLATORS: section header for firmware version */ fu_util_print_data (_("Version"), fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_VERSION)); /* TRANSLATORS: section header for firmware SHA1 */ fu_util_print_data (_("Checksum"), fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_HASH)); /* TRANSLATORS: section header for firmware remote http:// */ fu_util_print_data (_("Location"), fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_URI)); /* TRANSLATORS: section header for long firmware desc */ fu_util_print_data (_("Description"), fu_device_get_metadata (dev, FU_DEVICE_KEY_UPDATE_DESCRIPTION)); } return TRUE; }
/** * 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_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_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_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; }
/** * 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; }