/
githubmirror
/
fwupd
Обзор
Документация
Войти
/
githubmirror
/
fwupd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/fu-plugin-list.c
377 строк
10 KB
Richard Hughes
trivial: Use dispose in more places
15 сен 2024, 17:53
15 сен 2024, 17:53
7b769c4
Код
Авторство
О чём код?
/* * Copyright 2017 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "FuPluginList" #include "config.h" #include "fu-plugin-list.h" #include "fu-plugin-private.h" /** * FuPluginList: * * This list of plugins provides a way to get the specific plugin quickly using * a hash table and also any plugin-list specific functionality such as * sorting by dependency order. * * See also: [class@FuPlugin] */ static void fu_plugin_list_finalize(GObject *obj); struct _FuPluginList { GObject parent_instance; GPtrArray *plugins; /* of FuPlugin */ GHashTable *plugins_hash; /* of name : FuPlugin */ }; G_DEFINE_TYPE(FuPluginList, fu_plugin_list, G_TYPE_OBJECT) /** * fu_plugin_list_get_all: * @self: a #FuPluginList * * Gets all the plugins that have been added. * * Returns: (transfer none) (element-type FuPlugin): the plugins * * Since: 1.0.2 **/ GPtrArray * fu_plugin_list_get_all(FuPluginList *self) { g_return_val_if_fail(FU_IS_PLUGIN_LIST(self), NULL); return self->plugins; } static void fu_plugin_list_rules_changed_cb(FuPlugin *plugin, gpointer user_data) { FuPluginList *self = FU_PLUGIN_LIST(user_data); GPtrArray *rules = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_CONFLICTS); if (rules == NULL) return; for (guint j = 0; j < rules->len; j++) { const gchar *plugin_name = g_ptr_array_index(rules, j); FuPlugin *dep = fu_plugin_list_find_by_name(self, plugin_name, NULL); if (dep == NULL) continue; if (fu_plugin_has_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; g_info("late disabling %s as conflicts with %s", fu_plugin_get_name(dep), fu_plugin_get_name(plugin)); fu_plugin_add_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED); } } /** * fu_plugin_list_add: * @self: a #FuPluginList * @plugin: a plugin * * Adds a plugin to the list. The plugin name is used for a hash key and must * be set before calling this function. * * Since: 1.0.2 **/ void fu_plugin_list_add(FuPluginList *self, FuPlugin *plugin) { g_return_if_fail(FU_IS_PLUGIN_LIST(self)); g_return_if_fail(FU_IS_PLUGIN(plugin)); g_return_if_fail(fu_plugin_get_name(plugin) != NULL); g_ptr_array_add(self->plugins, g_object_ref(plugin)); g_hash_table_insert(self->plugins_hash, g_strdup(fu_plugin_get_name(plugin)), g_object_ref(plugin)); g_signal_connect(FU_PLUGIN(plugin), "rules-changed", G_CALLBACK(fu_plugin_list_rules_changed_cb), self); } /** * fu_plugin_list_remove_all: * @self: a #FuPluginList * * Removed all the plugins from the list. * * Since: 2.0.0 **/ void fu_plugin_list_remove_all(FuPluginList *self) { g_return_if_fail(FU_IS_PLUGIN_LIST(self)); for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index(self->plugins, i); g_signal_handlers_disconnect_by_data(plugin, self); } g_ptr_array_set_size(self->plugins, 0); g_hash_table_remove_all(self->plugins_hash); } /** * fu_plugin_list_find_by_name: * @self: a #FuPluginList * @name: a plugin name, e.g. `dfu` * @error: (nullable): optional return location for an error * * Finds a specific plugin using the plugin name. * * Returns: (transfer none): a plugin, or %NULL * * Since: 1.0.2 **/ FuPlugin * fu_plugin_list_find_by_name(FuPluginList *self, const gchar *name, GError **error) { FuPlugin *plugin; g_return_val_if_fail(FU_IS_PLUGIN_LIST(self), NULL); g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); /* sanity check */ if (self->plugins->len == 0) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no plugins loaded"); return NULL; } plugin = g_hash_table_lookup(self->plugins_hash, name); if (plugin == NULL) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no plugin %s found", name); return NULL; } return plugin; } static gint fu_plugin_list_sort_cb(gconstpointer a, gconstpointer b) { FuPlugin **pa = (FuPlugin **)a; FuPlugin **pb = (FuPlugin **)b; return fu_plugin_order_compare(*pa, *pb); } /** * fu_plugin_list_depsolve: * @self: a #FuPluginList * @error: (nullable): optional return location for an error * * Depsolves the list of plugins into the correct order. Some plugin methods * are called on all plugins and for some situations the order they are called * may be important. Use fu_plugin_add_rule() to affect the depsolved order * if required. * * Returns: %TRUE for success, or %FALSE if the set could not be depsolved * * Since: 1.0.2 **/ gboolean fu_plugin_list_depsolve(FuPluginList *self, GError **error) { FuPlugin *dep; GPtrArray *deps; gboolean changes; guint dep_loop_check = 0; g_return_val_if_fail(FU_IS_PLUGIN_LIST(self), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* order by deps */ do { changes = FALSE; for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index(self->plugins, i); deps = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_RUN_AFTER); if (deps == NULL) continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index(deps, j); dep = fu_plugin_list_find_by_name(self, plugin_name, NULL); if (dep == NULL) { g_info("cannot find plugin '%s' " "requested by '%s'", plugin_name, fu_plugin_get_name(plugin)); continue; } if (fu_plugin_has_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_order(plugin) <= fu_plugin_get_order(dep)) { g_debug("%s [%u] to be ordered after %s [%u] " "so promoting to [%u]", fu_plugin_get_name(plugin), fu_plugin_get_order(plugin), fu_plugin_get_name(dep), fu_plugin_get_order(dep), fu_plugin_get_order(dep) + 1); fu_plugin_set_order(plugin, fu_plugin_get_order(dep) + 1); changes = TRUE; } } } for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index(self->plugins, i); deps = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_RUN_BEFORE); if (deps == NULL) continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index(deps, j); dep = fu_plugin_list_find_by_name(self, plugin_name, NULL); if (dep == NULL) { g_info("cannot find plugin '%s' " "requested by '%s'", plugin_name, fu_plugin_get_name(plugin)); continue; } if (fu_plugin_has_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_order(plugin) >= fu_plugin_get_order(dep)) { g_debug("%s [%u] to be ordered before %s [%u] " "so promoting to [%u]", fu_plugin_get_name(plugin), fu_plugin_get_order(plugin), fu_plugin_get_name(dep), fu_plugin_get_order(dep), fu_plugin_get_order(dep) + 1); fu_plugin_set_order(dep, fu_plugin_get_order(plugin) + 1); changes = TRUE; } } } /* set priority as well */ for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index(self->plugins, i); deps = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_BETTER_THAN); if (deps == NULL) continue; for (guint j = 0; j < deps->len && !changes; j++) { const gchar *plugin_name = g_ptr_array_index(deps, j); dep = fu_plugin_list_find_by_name(self, plugin_name, NULL); if (dep == NULL) { g_info("cannot find plugin '%s' " "referenced by '%s'", plugin_name, fu_plugin_get_name(plugin)); continue; } if (fu_plugin_has_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; if (fu_plugin_get_priority(plugin) <= fu_plugin_get_priority(dep)) { g_debug("%s [%u] better than %s [%u] " "so bumping to [%u]", fu_plugin_get_name(plugin), fu_plugin_get_priority(plugin), fu_plugin_get_name(dep), fu_plugin_get_priority(dep), fu_plugin_get_priority(dep) + 1); fu_plugin_set_priority(plugin, fu_plugin_get_priority(dep) + 1); changes = TRUE; } } } /* check we're not stuck */ if (dep_loop_check++ > 100) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "got stuck in dep loop"); return FALSE; } } while (changes); /* check for conflicts */ for (guint i = 0; i < self->plugins->len; i++) { FuPlugin *plugin = g_ptr_array_index(self->plugins, i); if (fu_plugin_has_flag(plugin, FWUPD_PLUGIN_FLAG_DISABLED)) continue; deps = fu_plugin_get_rules(plugin, FU_PLUGIN_RULE_CONFLICTS); if (deps == NULL) continue; for (guint j = 0; j < deps->len; j++) { const gchar *plugin_name = g_ptr_array_index(deps, j); dep = fu_plugin_list_find_by_name(self, plugin_name, NULL); if (dep == NULL) continue; if (fu_plugin_has_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED)) continue; g_info("disabling %s as conflicts with %s", fu_plugin_get_name(dep), fu_plugin_get_name(plugin)); fu_plugin_add_flag(dep, FWUPD_PLUGIN_FLAG_DISABLED); } } /* sort by order */ g_ptr_array_sort(self->plugins, fu_plugin_list_sort_cb); return TRUE; } static void fu_plugin_list_dispose(GObject *obj) { FuPluginList *self = FU_PLUGIN_LIST(obj); if (self->plugins != NULL) g_ptr_array_set_size(self->plugins, 0); if (self->plugins_hash != NULL) g_hash_table_remove_all(self->plugins_hash); G_OBJECT_CLASS(fu_plugin_list_parent_class)->dispose(obj); } static void fu_plugin_list_class_init(FuPluginListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->dispose = fu_plugin_list_dispose; object_class->finalize = fu_plugin_list_finalize; } static void fu_plugin_list_init(FuPluginList *self) { self->plugins = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); self->plugins_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_object_unref); } static void fu_plugin_list_finalize(GObject *obj) { FuPluginList *self = FU_PLUGIN_LIST(obj); g_ptr_array_unref(self->plugins); g_hash_table_unref(self->plugins_hash); G_OBJECT_CLASS(fu_plugin_list_parent_class)->finalize(obj); } /** * fu_plugin_list_new: * * Creates a new plugin list. * * Returns: (transfer full): a #FuPluginList * * Since: 1.0.2 **/ FuPluginList * fu_plugin_list_new(void) { FuPluginList *self; self = g_object_new(FU_TYPE_PLUGIN_LIST, NULL); return FU_PLUGIN_LIST(self); }