diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index 7e01fef08..251ca5a9f 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -364,6 +364,7 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi.so %{_libdir}/fwupd-plugins-3/libfu_plugin_uefi_recovery.so %endif +%{_libdir}/fwupd-plugins-3/libfu_plugin_logind.so %{_libdir}/fwupd-plugins-3/libfu_plugin_logitech_hidpp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_upower.so %{_libdir}/fwupd-plugins-3/libfu_plugin_vli.so diff --git a/plugins/logind/README.md b/plugins/logind/README.md new file mode 100644 index 000000000..bd66d8bba --- /dev/null +++ b/plugins/logind/README.md @@ -0,0 +1,13 @@ +logind Support +============== + +Introduction +------------ + +This plugin is used to ensure that the machine does not enter a low power mode +when updates are being performed. + +Vendor ID Security +------------------ + +This protocol does not create a device and thus requires no vendor ID set. diff --git a/plugins/logind/fu-plugin-logind.c b/plugins/logind/fu-plugin-logind.c new file mode 100644 index 000000000..67bb32fa0 --- /dev/null +++ b/plugins/logind/fu-plugin-logind.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include +#include + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + GDBusProxy *logind_proxy; + gint logind_fd; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); +} + +void +fu_plugin_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); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + 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; + } + if (g_dbus_proxy_get_name_owner (data->logind_proxy) == 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; +} + +gboolean +fu_plugin_update_prepare (FuPlugin *plugin, + FwupdInstallFlags flags, + FuDevice *device, + 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; +} + +gboolean +fu_plugin_update_cleanup (FuPlugin *plugin, + FwupdInstallFlags flags, + FuDevice *device, + 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; +} diff --git a/plugins/logind/meson.build b/plugins/logind/meson.build new file mode 100644 index 000000000..b9aea41e7 --- /dev/null +++ b/plugins/logind/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLogind"'] + +shared_module('fu_plugin_logind', + fu_hash, + sources : [ + 'fu-plugin-logind.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index 3fad95b53..00895266e 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -27,6 +27,10 @@ subdir('thelio-io') subdir('wacom-raw') endif +if get_option('systemd') +subdir('logind') +endif + # depends on dfu subdir('csr')