Exemple #1
0
/**
 * 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);
}
Exemple #2
0
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;
}
Exemple #3
0
/**
 * 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);
}
Exemple #4
0
/**
 * 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;
}
Exemple #5
0
/**
 * 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;
}
Exemple #6
0
/**
 * 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;
}
Exemple #7
0
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
}
Exemple #8
0
/**
 * 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;
}
Exemple #9
0
/**
 * 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);
}
Exemple #10
0
/**
 * 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);
}
Exemple #11
0
/**
 * 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);
}
Exemple #12
0
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;
}
Exemple #13
0
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;
}
Exemple #14
0
/**
 * 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;
}
Exemple #15
0
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;
}
Exemple #16
0
/**
 * 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;
}
Exemple #17
0
/**
 * 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;
}
Exemple #18
0
/**
 * 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);
}
Exemple #19
0
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;
}
Exemple #20
0
/**
 * 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;
}
Exemple #21
0
/**
 * 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;
}