Пример #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);
}
Пример #2
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);
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
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);
}
Пример #7
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;
}