/** * 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; }
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); }
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); }
/** * 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; }