/
githubmirror
/
fwupd
Обзор
Документация
Войти
/
githubmirror
/
fwupd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/fu-idle.c
236 строк
5 KB
Richard Hughes
Use a cryptographically secure RNG when building the idle ID
03 июн 2026, 18:10
03 июн 2026, 18:10
b7c8c33
Код
Авторство
О чём код?
/* * Copyright 2018 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "FuIdle" #include "config.h" #include "fu-idle.h" static void fu_idle_finalize(GObject *obj); struct _FuIdle { GObject parent_instance; GPtrArray *items; /* of FuIdleItem */ guint idle_id; guint timeout; FuIdleInhibit inhibit_old; }; enum { SIGNAL_INHIBIT_CHANGED, SIGNAL_TIMEOUT, SIGNAL_LAST }; static guint signals[SIGNAL_LAST] = {0}; typedef struct { FuIdleInhibit inhibit; gchar *reason; guint32 token; } FuIdleItem; G_DEFINE_TYPE(FuIdle, fu_idle, G_TYPE_OBJECT) static gboolean fu_idle_check_cb(gpointer user_data) { FuIdle *self = FU_IDLE(user_data); g_signal_emit(self, signals[SIGNAL_TIMEOUT], 0); return G_SOURCE_CONTINUE; } static void fu_idle_start(FuIdle *self) { if (self->idle_id != 0) return; if (self->timeout == 0) return; self->idle_id = g_timeout_add_seconds(self->timeout, fu_idle_check_cb, self); } static void fu_idle_stop(FuIdle *self) { if (self->idle_id == 0) return; g_clear_handle_id(&self->idle_id, g_source_remove); } static void fu_idle_emit_inhibit_changed(FuIdle *self) { FuIdleInhibit inhibit_global = FU_IDLE_INHIBIT_NONE; fu_idle_reset(self); for (guint i = 0; i < self->items->len; i++) { FuIdleItem *item = g_ptr_array_index(self->items, i); inhibit_global |= item->inhibit; } if (self->inhibit_old != inhibit_global) { g_autofree gchar *inhibit_str = fu_idle_inhibit_to_string(inhibit_global); g_debug("now inhibited: %s", inhibit_str); g_signal_emit(self, signals[SIGNAL_INHIBIT_CHANGED], 0, inhibit_global); self->inhibit_old = inhibit_global; } } void fu_idle_reset(FuIdle *self) { g_return_if_fail(FU_IS_IDLE(self)); fu_idle_stop(self); if (!fu_idle_has_inhibit(self, FU_IDLE_INHIBIT_TIMEOUT)) fu_idle_start(self); } void fu_idle_uninhibit(FuIdle *self, guint32 token) { g_return_if_fail(FU_IS_IDLE(self)); g_return_if_fail(token != 0); for (guint i = 0; i < self->items->len; i++) { FuIdleItem *item = g_ptr_array_index(self->items, i); if (item->token == token) { g_autofree gchar *inhibit_str = fu_idle_inhibit_to_string(item->inhibit); g_debug("uninhibiting: %s by %s", inhibit_str, item->reason); g_ptr_array_remove_index(self->items, i); break; } } fu_idle_emit_inhibit_changed(self); } guint32 fu_idle_inhibit(FuIdle *self, FuIdleInhibit inhibit, const gchar *reason) { FuIdleItem *item; g_autofree gchar *inhibit_str = fu_idle_inhibit_to_string(inhibit); g_autoptr(GByteArray) buf = NULL; g_return_val_if_fail(FU_IS_IDLE(self), 0); g_return_val_if_fail(inhibit != FU_IDLE_INHIBIT_NONE, 0); g_debug("inhibiting: %s by %s", inhibit_str, reason); item = g_new0(FuIdleItem, 1); item->inhibit = inhibit; item->reason = g_strdup(reason); /* prefer a cryptographically secure RNG, fall back if not available */ buf = fu_common_get_random(sizeof(guint32), NULL); if (buf != NULL) item->token = fu_memread_uint32(buf->data, G_LITTLE_ENDIAN); if (item->token == 0) { /* nocheck:blocked */ item->token = g_random_int_range(1, G_MAXINT); } g_ptr_array_add(self->items, item); fu_idle_emit_inhibit_changed(self); return item->token; } gboolean fu_idle_has_inhibit(FuIdle *self, FuIdleInhibit inhibit) { g_return_val_if_fail(FU_IS_IDLE(self), FALSE); g_return_val_if_fail(inhibit != FU_IDLE_INHIBIT_NONE, FALSE); for (guint i = 0; i < self->items->len; i++) { FuIdleItem *item = g_ptr_array_index(self->items, i); if (item->inhibit & inhibit) return TRUE; } return FALSE; } void fu_idle_set_timeout(FuIdle *self, guint timeout) { g_return_if_fail(FU_IS_IDLE(self)); g_debug("setting timeout to %us", timeout); self->timeout = timeout; fu_idle_reset(self); } static void fu_idle_item_free(FuIdleItem *item) { g_free(item->reason); g_free(item); } FuIdleLocker * fu_idle_locker_new(FuIdle *self, FuIdleInhibit inhibit, const gchar *reason) { FuIdleLocker *locker = g_new0(FuIdleLocker, 1); locker->idle = g_object_ref(self); locker->token = fu_idle_inhibit(self, inhibit, reason); return locker; } void fu_idle_locker_free(FuIdleLocker *locker) { g_return_if_fail(locker != NULL); fu_idle_uninhibit(locker->idle, locker->token); g_object_unref(locker->idle); g_free(locker); } static void fu_idle_class_init(FuIdleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = fu_idle_finalize; signals[SIGNAL_INHIBIT_CHANGED] = g_signal_new("inhibit-changed", G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals[SIGNAL_TIMEOUT] = g_signal_new("timeout", G_TYPE_FROM_CLASS(object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void fu_idle_init(FuIdle *self) { self->items = g_ptr_array_new_with_free_func((GDestroyNotify)fu_idle_item_free); } static void fu_idle_finalize(GObject *obj) { FuIdle *self = FU_IDLE(obj); fu_idle_stop(self); g_ptr_array_unref(self->items); G_OBJECT_CLASS(fu_idle_parent_class)->finalize(obj); } FuIdle * fu_idle_new(void) { FuIdle *self; self = g_object_new(FU_TYPE_IDLE, NULL); return FU_IDLE(self); }