mirror of
https://git.proxmox.com/git/fwupd
synced 2025-11-04 22:13:50 +00:00
We were calling g_module_symbol() 2703 times, which is actually more expensive than you'd think. It also means the plugins are actually what we tell people they are: A set of vfuncs that get run. The reality before that they were dlsym'd functions that get called at pretty random times.
141 lines
3.4 KiB
C
141 lines
3.4 KiB
C
/*
|
|
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <fwupdplugin.h>
|
|
|
|
#include <gio/gunixfdlist.h>
|
|
#include <glib/gstdio.h>
|
|
|
|
struct FuPluginData {
|
|
GDBusProxy *logind_proxy;
|
|
gint logind_fd;
|
|
};
|
|
|
|
static void
|
|
fu_plugin_logind_init(FuPlugin *plugin)
|
|
{
|
|
fu_plugin_alloc_data(plugin, sizeof(FuPluginData));
|
|
}
|
|
|
|
static void
|
|
fu_plugin_logind_destroy(FuPlugin *plugin)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data(plugin);
|
|
if (data->logind_fd != 0)
|
|
g_close(data->logind_fd, NULL);
|
|
if (data->logind_proxy != NULL)
|
|
g_object_unref(data->logind_proxy);
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_logind_startup(FuPlugin *plugin, GError **error)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data(plugin);
|
|
g_autofree gchar *name_owner = NULL;
|
|
|
|
data->logind_proxy = g_dbus_proxy_new_for_bus_sync(
|
|
G_BUS_TYPE_SYSTEM,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
|
NULL,
|
|
"org.freedesktop.login1",
|
|
"/org/freedesktop/login1",
|
|
"org.freedesktop.login1.Manager",
|
|
NULL,
|
|
error);
|
|
if (data->logind_proxy == NULL) {
|
|
g_prefix_error(error, "failed to connect to logind: ");
|
|
return FALSE;
|
|
}
|
|
name_owner = g_dbus_proxy_get_name_owner(data->logind_proxy);
|
|
if (name_owner == NULL) {
|
|
g_set_error(error,
|
|
FWUPD_ERROR,
|
|
FWUPD_ERROR_NOT_SUPPORTED,
|
|
"no owner for %s",
|
|
g_dbus_proxy_get_name(data->logind_proxy));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_logind_prepare(FuPlugin *plugin,
|
|
FuDevice *device,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data(plugin);
|
|
g_autoptr(GError) error_local = NULL;
|
|
g_autoptr(GUnixFDList) out_fd_list = NULL;
|
|
g_autoptr(GVariant) res = NULL;
|
|
const gchar *what = "shutdown:sleep:idle:handle-power-key:handle-suspend-key:"
|
|
"handle-hibernate-key:handle-lid-switch";
|
|
|
|
/* already inhibited */
|
|
if (data->logind_fd != 0)
|
|
return TRUE;
|
|
|
|
/* not yet connected */
|
|
if (data->logind_proxy == NULL) {
|
|
g_warning("no logind connection to use");
|
|
return TRUE;
|
|
}
|
|
|
|
/* block shutdown and idle */
|
|
res = g_dbus_proxy_call_with_unix_fd_list_sync(
|
|
data->logind_proxy,
|
|
"Inhibit",
|
|
g_variant_new("(ssss)", what, PACKAGE_NAME, "Firmware Update in Progress", "block"),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
NULL, /* fd_list */
|
|
&out_fd_list,
|
|
NULL, /* GCancellable */
|
|
&error_local);
|
|
if (res == NULL) {
|
|
g_warning("failed to Inhibit using logind: %s", error_local->message);
|
|
return TRUE;
|
|
}
|
|
|
|
/* keep fd as cookie */
|
|
if (g_unix_fd_list_get_length(out_fd_list) != 1) {
|
|
g_warning("invalid response from logind");
|
|
return TRUE;
|
|
}
|
|
data->logind_fd = g_unix_fd_list_get(out_fd_list, 0, NULL);
|
|
g_debug("opened logind fd %i", data->logind_fd);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
fu_plugin_logind_cleanup(FuPlugin *plugin,
|
|
FuDevice *device,
|
|
FwupdInstallFlags flags,
|
|
GError **error)
|
|
{
|
|
FuPluginData *data = fu_plugin_get_data(plugin);
|
|
if (data->logind_fd == 0)
|
|
return TRUE;
|
|
g_debug("closed logind fd %i", data->logind_fd);
|
|
if (!g_close(data->logind_fd, error))
|
|
return FALSE;
|
|
data->logind_fd = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
fu_plugin_init_vfuncs(FuPluginVfuncs *vfuncs)
|
|
{
|
|
vfuncs->build_hash = FU_BUILD_HASH;
|
|
vfuncs->init = fu_plugin_logind_init;
|
|
vfuncs->destroy = fu_plugin_logind_destroy;
|
|
vfuncs->startup = fu_plugin_logind_startup;
|
|
vfuncs->cleanup = fu_plugin_logind_cleanup;
|
|
vfuncs->prepare = fu_plugin_logind_prepare;
|
|
}
|