/**
 * gs_plugin_xdg_app_refine_app:
 */
static gboolean
gs_plugin_xdg_app_refine_app (GsPlugin *plugin,
			      GsApp *app,
			      GsPluginRefineFlags flags,
			      GCancellable *cancellable,
			      GError **error)
{
	g_autoptr(AsProfileTask) ptask = NULL;

	/* only process this app if was created by this plugin */
	if (g_strcmp0 (gs_app_get_management_plugin (app),
		       gs_plugin_get_name (plugin)) != 0)
		return TRUE;

	/* profile */
	ptask = as_profile_start (gs_plugin_get_profile (plugin),
				  "xdg-app::refine{%s}",
				  gs_app_get_id (app));

	/* AppStream sets the source to appname/arch/branch */
	if (!gs_plugin_refine_item_metadata (plugin, app, cancellable, error))
		return FALSE;

	/* check the installed state */
	if (!gs_plugin_refine_item_state (plugin, app, cancellable, error))
		return FALSE;

	/* version fallback */
	if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) {
		if (gs_app_get_version (app) == NULL) {
			const gchar *branch;
			branch = gs_app_get_xdgapp_branch (app);
			gs_app_set_version (app, branch);
		}
	}

	/* size */
	if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) {
		if (!gs_plugin_refine_item_size (plugin, app, cancellable, error))
			return FALSE;
	}

	/* origin */
	if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN) {
		if (!gs_plugin_refine_item_origin_ui (plugin, app, cancellable, error))
			return FALSE;
	}

	return TRUE;
}
/**
 * gs_plugin_app_upgrade_download:
 */
gboolean
gs_plugin_app_upgrade_download (GsPlugin *plugin,
				GsApp *app,
				GCancellable *cancellable,
				GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	ProgressData data;
	g_autoptr(PkResults) results = NULL;

	/* only process this app if was created by this plugin */
	if (g_strcmp0 (gs_app_get_management_plugin (app), "packagekit") != 0)
		return TRUE;

	data.app = app;
	data.plugin = plugin;

	/* check is distro-upgrade */
	if (gs_app_get_kind (app) != AS_APP_KIND_OS_UPGRADE) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_FAILED,
			     "app %s is not a distro upgrade",
			     gs_app_get_id (app));
		return FALSE;
	}

	/* ask PK to download enough packages to upgrade the system */
	gs_app_set_state (app, AS_APP_STATE_INSTALLING);
	results = pk_task_upgrade_system_sync (priv->task,
					       gs_app_get_version (app),
					       PK_UPGRADE_KIND_ENUM_COMPLETE,
					       cancellable,
					       gs_plugin_packagekit_progress_cb, &data,
					       error);
	if (!gs_plugin_packagekit_results_valid (results, error)) {
		gs_app_set_state_recover (app);
		return FALSE;
	}

	/* state is known */
	gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
	return TRUE;
}
예제 #3
0
static GPtrArray *
gs_plugin_odrs_fetch_for_app (GsPlugin *plugin, GsApp *app, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	const gchar *version;
	guint status_code;
	g_autofree gchar *cachefn_basename = NULL;
	g_autofree gchar *cachefn = NULL;
	g_autofree gchar *data = NULL;
	g_autofree gchar *uri = NULL;
	g_autoptr(GFile) cachefn_file = NULL;
	g_autoptr(GPtrArray) reviews = NULL;
	g_autoptr(JsonBuilder) builder = NULL;
	g_autoptr(JsonGenerator) json_generator = NULL;
	g_autoptr(JsonNode) json_root = NULL;
	g_autoptr(SoupMessage) msg = NULL;

	/* look in the cache */
	cachefn_basename = g_strdup_printf ("%s.json", gs_app_get_id (app));
	cachefn = gs_utils_get_cache_filename ("reviews",
					       cachefn_basename,
					       GS_UTILS_CACHE_FLAG_WRITEABLE,
					       error);
	if (cachefn == NULL)
		return NULL;
	cachefn_file = g_file_new_for_path (cachefn);
	if (gs_utils_get_file_age (cachefn_file) < ODRS_REVIEW_CACHE_AGE_MAX) {
		g_autofree gchar *json_data = NULL;
		if (!g_file_get_contents (cachefn, &json_data, NULL, error))
			return NULL;
		g_debug ("got review data for %s from %s",
			 gs_app_get_id (app), cachefn);
		return gs_plugin_odrs_parse_reviews (plugin,
						     json_data, -1,
						     error);
	}

	/* not always available */
	version = gs_app_get_version (app);
	if (version == NULL)
		version = "unknown";

	/* create object with review data */
	builder = json_builder_new ();
	json_builder_begin_object (builder);
	json_builder_set_member_name (builder, "user_hash");
	json_builder_add_string_value (builder, priv->user_hash);
	json_builder_set_member_name (builder, "app_id");
	json_builder_add_string_value (builder, gs_app_get_id (app));
	json_builder_set_member_name (builder, "locale");
	json_builder_add_string_value (builder, gs_plugin_get_locale (plugin));
	json_builder_set_member_name (builder, "distro");
	json_builder_add_string_value (builder, priv->distro);
	json_builder_set_member_name (builder, "version");
	json_builder_add_string_value (builder, version);
	json_builder_set_member_name (builder, "limit");
	json_builder_add_int_value (builder, ODRS_REVIEW_NUMBER_RESULTS_MAX);
	json_builder_end_object (builder);

	/* export as a string */
	json_root = json_builder_get_root (builder);
	json_generator = json_generator_new ();
	json_generator_set_pretty (json_generator, TRUE);
	json_generator_set_root (json_generator, json_root);
	data = json_generator_to_data (json_generator, NULL);
	if (data == NULL)
		return NULL;
	uri = g_strdup_printf ("%s/fetch", priv->review_server);
	msg = soup_message_new (SOUP_METHOD_POST, uri);
	soup_message_set_request (msg, "application/json; charset=utf-8",
				  SOUP_MEMORY_COPY, data, strlen (data));
	status_code = soup_session_send_message (gs_plugin_get_soup_session (plugin), msg);
	if (status_code != SOUP_STATUS_OK) {
		if (!gs_plugin_odrs_parse_success (msg->response_body->data,
						   msg->response_body->length,
						   error))
			return NULL;
		/* not sure what to do here */
		g_set_error_literal (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
				     "status code invalid");
		gs_utils_error_add_unique_id (error, priv->cached_origin);
		return NULL;
	}
	reviews = gs_plugin_odrs_parse_reviews (plugin,
						msg->response_body->data,
						msg->response_body->length,
						error);
	if (reviews == NULL)
		return NULL;
	g_debug ("odrs returned: %s", msg->response_body->data);

	/* save to the cache */
	if (!g_file_set_contents (cachefn,
				  msg->response_body->data,
				  msg->response_body->length,
				  error))
		return NULL;

	/* success */
	return g_steal_pointer (&reviews);
}
예제 #4
0
static GsApp *
gs_plugin_fwupd_new_app (GsPlugin *plugin, FwupdDevice *dev, GError **error)
{
	FwupdRelease *rel = fwupd_device_get_release_default (dev);
	GPtrArray *checksums;
	const gchar *update_uri;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *filename_cache = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GsApp) app = NULL;

	/* update unsupported */
	app = gs_plugin_fwupd_new_app_from_device (plugin, dev);
	if (gs_app_get_state (app) != AS_APP_STATE_UPDATABLE_LIVE) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "%s [%s] cannot be updated",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* some missing */
	if (gs_app_get_id (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No id for firmware");
		return NULL;
	}
	if (gs_app_get_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	if (gs_app_get_update_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No update-version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	checksums = fwupd_release_get_checksums (rel);
	if (checksums->len == 0) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NO_SECURITY,
			     "%s [%s] (%s) has no checksums, ignoring as unsafe",
			     gs_app_get_name (app),
			     gs_app_get_id (app),
			     gs_app_get_update_version (app));
		return NULL;
	}
	update_uri = fwupd_release_get_uri (rel);
	if (update_uri == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_INVALID_FORMAT,
			     "no location available for %s [%s]",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* does the firmware already exist in the cache? */
	basename = g_path_get_basename (update_uri);
	filename_cache = gs_utils_get_cache_filename ("fwupd",
						      basename,
						      GS_UTILS_CACHE_FLAG_NONE,
						      error);
	if (filename_cache == NULL)
		return NULL;

	/* delete the file if the checksum does not match */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS)) {
		const gchar *checksum_tmp = NULL;
		g_autofree gchar *checksum = NULL;

		/* we can migrate to something better than SHA1 when the LVFS
		 * starts producing metadata with multiple hash types */
		checksum_tmp = fwupd_checksum_get_by_kind (checksums,
							   G_CHECKSUM_SHA1);
		if (checksum_tmp == NULL) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "No valid checksum for %s",
				     filename_cache);
		}
		checksum = gs_plugin_fwupd_get_file_checksum (filename_cache,
							      G_CHECKSUM_SHA1,
							      error);
		if (checksum == NULL)
			return NULL;
		if (g_strcmp0 (checksum_tmp, checksum) != 0) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "%s does not match checksum, expected %s got %s",
				     filename_cache, checksum_tmp, checksum);
			g_unlink (filename_cache);
			return NULL;
		}
	}

	/* already downloaded, so overwrite */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS))
		gs_app_set_size_download (app, 0);

	/* actually add the application */
	file = g_file_new_for_path (filename_cache);
	gs_app_set_local_file (app, file);
	return g_steal_pointer (&app);
}
예제 #5
0
/**
 * gs_plugin_refine_app:
 */
gboolean
gs_plugin_refine_app (GsPlugin *plugin,
		      GsApp *app,
		      GsPluginRefineFlags flags,
		      GCancellable *cancellable,
		      GError **error)
{
	Header h;
	const gchar *fn;
	gint rc;
	g_auto(rpmdbMatchIterator) mi = NULL;
	g_auto(rpmts) ts = NULL;

	/* not required */
	if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) == 0 &&
	    (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) == 0 &&
	    (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE) == 0 &&
	    (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) == 0)
		return TRUE;

	/* no need to run the plugin */
	if (gs_app_get_source_default (app) != NULL &&
	    gs_app_get_source_id_default (app) != NULL)
		return TRUE;

	/* open db readonly */
	ts = rpmtsCreate();
	rpmtsSetRootDir (ts, NULL);
	rc = rpmtsOpenDB (ts, O_RDONLY);
	if (rc != 0) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_FAILED,
			     "Failed to open rpmdb: %i", rc);
		return FALSE;
	}

	/* look for a specific file */
	fn = gs_app_get_metadata_item (app, "appstream::source-file");
	if (fn == NULL)
		return TRUE;
	if (!g_str_has_prefix (fn, "/usr"))
		return TRUE;
	mi = rpmtsInitIterator (ts, RPMDBI_INSTFILENAMES, fn, 0);
	if (mi == NULL) {
		g_debug ("rpm: no search results for %s", fn);
		return TRUE;
	}

	/* on rpm-ostree this package cannot be removed 'live' */
	gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY);

	/* process any results */
	g_debug ("rpm: querying for %s with %s", gs_app_get_id (app), fn);
	while ((h = rpmdbNextIterator (mi)) != NULL) {
		guint64 epoch;
		const gchar *name;
		const gchar *version;
		const gchar *arch;
		const gchar *release;
		const gchar *license;

		/* add default source */
		name = headerGetString (h, RPMTAG_NAME);
		if (gs_app_get_source_default (app) == NULL) {
			g_debug ("rpm: setting source to %s", name);
			gs_app_add_source (app, name);
		}

		/* set size */
		if (gs_app_get_size_download (app) == 0)
			gs_app_set_size_download (app, 0);
		if (gs_app_get_size_installed (app) == 0) {
			guint64 tmp;
			tmp = headerGetNumber (h, RPMTAG_SIZE);
			gs_app_set_size_installed (app, tmp);
		}

		/* set license */
		license = headerGetString (h, RPMTAG_LICENSE);
		if (gs_app_get_license (app) == NULL && license != NULL) {
			g_autofree gchar *tmp = NULL;
			tmp = as_utils_license_to_spdx (license);
			gs_app_set_license (app, GS_APP_QUALITY_NORMAL, tmp);
		}

		/* add version */
		version = headerGetString (h, RPMTAG_VERSION);
		if (gs_app_get_version (app) == NULL) {
			g_debug ("rpm: setting version to %s", version);
			gs_app_set_version (app, version);
		}

		/* add source-id */
		if (gs_app_get_source_id_default (app) == NULL) {
			g_autofree gchar *tmp = NULL;
			release = headerGetString (h, RPMTAG_RELEASE);
			arch = headerGetString (h, RPMTAG_ARCH);
			epoch = headerGetNumber (h, RPMTAG_EPOCH);
			if (epoch > 0) {
				tmp = g_strdup_printf ("%s;%" G_GUINT64_FORMAT ":%s-%s;%s;installed",
						       name, epoch, version, release, arch);
			} else {
				tmp = g_strdup_printf ("%s;%s-%s;%s;installed",
						       name, version, release, arch);
			}
			g_debug ("rpm: setting source-id to %s", tmp);
			gs_app_add_source_id (app, tmp);
		}
	}

	return TRUE;
}