/
githubmirror
/
fwupd
Обзор
Документация
Войти
/
githubmirror
/
fwupd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
2.0.21
src/fu-daemon.c
285 строк
7 KB
Richard Hughes
Refactor the hypervisor and container detection to be usable from plugins
19 ноя 2025, 17:25
19 ноя 2025, 17:25
0bf93bb
Код
Авторство
О чём код?
/* * Copyright 2022 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "FuMain" #include "config.h" #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #ifdef HAVE_MMAN_H #include <sys/mman.h> #endif #include "fu-context-private.h" #include "fu-daemon.h" typedef struct { FuEngine *engine; GMainLoop *loop; guint housekeeping_id; gboolean update_in_progress; gboolean pending_stop; guint process_quit_id; } FuDaemonPrivate; G_DEFINE_TYPE_WITH_PRIVATE(FuDaemon, fu_daemon, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fu_daemon_get_instance_private(o)) #define FU_DAEMON_HOUSEKEEPING_DELAY 10 /* seconds */ FuEngine * fu_daemon_get_engine(FuDaemon *self) { FuDaemonPrivate *priv = GET_PRIVATE(self); g_return_val_if_fail(FU_IS_DAEMON(self), NULL); return priv->engine; } void fu_daemon_set_update_in_progress(FuDaemon *self, gboolean update_in_progress) { FuDaemonPrivate *priv = GET_PRIVATE(self); g_return_if_fail(FU_IS_DAEMON(self)); priv->update_in_progress = update_in_progress; } gboolean fu_daemon_get_pending_stop(FuDaemon *self) { FuDaemonPrivate *priv = GET_PRIVATE(self); g_return_val_if_fail(FU_IS_DAEMON(self), FALSE); return priv->pending_stop; } static gboolean fu_daemon_schedule_housekeeping_cb(gpointer user_data) { FuDaemon *self = FU_DAEMON(user_data); FuDaemonPrivate *priv = GET_PRIVATE(self); FuContext *ctx = fu_engine_get_context(priv->engine); #ifdef HAVE_MALLOC_TRIM /* drop heap except one page */ malloc_trim(0); #endif /* anything that listens to the context can perform actions now */ fu_context_housekeeping(ctx); /* success */ priv->housekeeping_id = 0; return G_SOURCE_REMOVE; } void fu_daemon_schedule_housekeeping(FuDaemon *self) { FuDaemonPrivate *priv = GET_PRIVATE(self); guint delay = FU_DAEMON_HOUSEKEEPING_DELAY; if (priv->update_in_progress) return; if (priv->housekeeping_id != 0) g_source_remove(priv->housekeeping_id); if (g_getenv("CI") != NULL) delay = 1; priv->housekeeping_id = g_timeout_add_seconds(delay, fu_daemon_schedule_housekeeping_cb, self); } static gboolean fu_daemon_schedule_process_quit_cb(gpointer user_data) { FuDaemon *self = FU_DAEMON(user_data); FuDaemonPrivate *priv = GET_PRIVATE(self); g_autoptr(GError) error = NULL; g_info("daemon asked to quit, shutting down"); priv->process_quit_id = 0; if (!fu_daemon_stop(self, &error)) g_warning("failed to stop daemon, will wait: %s\n", error->message); return G_SOURCE_REMOVE; } void fu_daemon_schedule_process_quit(FuDaemon *self) { FuDaemonPrivate *priv = GET_PRIVATE(self); /* busy? */ if (priv->update_in_progress) { g_warning("asked to quit during a firmware update, ignoring"); return; } /* allow the daemon to respond to the request, then quit */ if (priv->process_quit_id != 0) g_source_remove(priv->process_quit_id); priv->process_quit_id = g_idle_add(fu_daemon_schedule_process_quit_cb, self); } static gboolean fu_daemon_check_syscall_filtering(GError **error) { #ifdef HAVE_MMAN_H if (g_getenv("FWUPD_SYSCALL_FILTER") != NULL) { const gsize bufsz = 10; g_autofree guint8 *buf = g_malloc0(bufsz); if (mlock(buf, bufsz) == 0) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_BROKEN_SYSTEM, "syscall filtering is configured but not working"); munlock(buf, bufsz); return FALSE; } g_debug("syscall filtering is working"); } #endif /* success */ return TRUE; } gboolean fu_daemon_setup(FuDaemon *self, const gchar *socket_address, GError **error) { FuDaemonClass *klass = FU_DAEMON_GET_CLASS(self); FuEngine *engine = fu_daemon_get_engine(self); guint timer_max_ms; g_autoptr(FuProgress) progress = fu_progress_new(G_STRLOC); g_autoptr(GTimer) timer = g_timer_new(); g_return_val_if_fail(FU_IS_DAEMON(self), FALSE); g_return_val_if_fail(FU_IS_ENGINE(engine), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* check that the process manager is preventing access to dangerous system calls */ if (!fu_daemon_check_syscall_filtering(error)) return FALSE; /* proxy on */ if (!klass->setup(self, socket_address, progress, error)) return FALSE; /* how did we do */ timer_max_ms = fu_config_get_value_u64(FU_CONFIG(fu_engine_get_config(engine)), "fwupd", "IdleInhibitStartupThreshold"); if (timer_max_ms > 0) { guint timer_ms = g_timer_elapsed(timer, NULL) * 1000.f; if (timer_ms > timer_max_ms) { g_autofree gchar *reason = g_strdup_printf("daemon-startup-%ums-max-%ums", timer_ms, timer_max_ms); fu_engine_idle_inhibit(engine, FU_IDLE_INHIBIT_TIMEOUT, reason); } } /* a good place to do the traceback */ if (fu_progress_get_profile(progress)) { g_autofree gchar *str = fu_progress_traceback(progress); if (str != NULL) g_print("\n%s\n", str); } /* success */ return TRUE; } gboolean fu_daemon_start(FuDaemon *self, GError **error) { FuDaemonClass *klass = FU_DAEMON_GET_CLASS(self); FuDaemonPrivate *priv = GET_PRIVATE(self); g_return_val_if_fail(FU_IS_DAEMON(self), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); /* super useful for debugging */ if (g_getenv("FWUPD_VERBOSE") != NULL) { GHashTableIter iter; const gchar *key; const gchar *value; g_autoptr(GHashTable) metadata = NULL; g_autoptr(GString) str = g_string_new("report metadata:"); metadata = fu_engine_get_report_metadata(priv->engine, error); if (metadata == NULL) return FALSE; g_hash_table_iter_init(&iter, metadata); while (g_hash_table_iter_next(&iter, (gpointer *)&key, (gpointer *)&value)) g_string_append_printf(str, "\n - %s=%s", key, value); g_debug("%s", str->str); } /* optional */ if (klass->start != NULL && !klass->start(self, error)) return FALSE; fu_daemon_schedule_housekeeping(self); g_main_loop_run(priv->loop); return TRUE; } gboolean fu_daemon_stop(FuDaemon *self, GError **error) { FuDaemonClass *klass = FU_DAEMON_GET_CLASS(self); FuDaemonPrivate *priv = GET_PRIVATE(self); g_return_val_if_fail(FU_IS_DAEMON(self), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (priv->update_in_progress) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "in a firmware update, ignoring"); priv->pending_stop = TRUE; return FALSE; } /* optional */ if (klass->stop != NULL && !klass->stop(self, error)) return FALSE; g_main_loop_quit(priv->loop); return TRUE; } static void fu_daemon_init(FuDaemon *self) { FuDaemonPrivate *priv = GET_PRIVATE(self); g_autoptr(FuContext) ctx = fu_context_new(); priv->engine = fu_engine_new(ctx); priv->loop = g_main_loop_new(NULL, FALSE); } static void fu_daemon_finalize(GObject *obj) { FuDaemon *self = FU_DAEMON(obj); FuDaemonPrivate *priv = GET_PRIVATE(self); if (priv->loop != NULL) g_main_loop_unref(priv->loop); if (priv->housekeeping_id != 0) g_source_remove(priv->housekeeping_id); if (priv->process_quit_id != 0) g_source_remove(priv->process_quit_id); if (priv->engine != NULL) g_object_unref(priv->engine); G_OBJECT_CLASS(fu_daemon_parent_class)->finalize(obj); } static void fu_daemon_class_init(FuDaemonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->finalize = fu_daemon_finalize; }