diff --git a/data/bash-completion/fwupdmgr.in b/data/bash-completion/fwupdmgr.in index 0f569ec74..ffab18214 100644 --- a/data/bash-completion/fwupdmgr.in +++ b/data/bash-completion/fwupdmgr.in @@ -46,7 +46,6 @@ _fwupdmgr_opts=( '--show-all-devices' '--sign' '--filter' - '--log' '--disable-ssl-strict' ) diff --git a/data/daemon.conf b/data/daemon.conf index 9be2843d6..8b472b9ef 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -22,3 +22,6 @@ IdleTimeout=7200 # If set to FuValue, FuValue domain (same as --domain-verbose=FuValue) # If set to *, all domains (same as --verbose) VerboseDomains= + +# Update the message of the day (MOTD) on device and metadata changes +UpdateMotd=true diff --git a/data/fwupd.service.in b/data/fwupd.service.in index 4085632e5..8fdb9cc65 100644 --- a/data/fwupd.service.in +++ b/data/fwupd.service.in @@ -6,6 +6,8 @@ Before=display-manager.service [Service] Type=dbus +RuntimeDirectory=@motd_dir@ +RuntimeDirectoryPreserve=yes BusName=org.freedesktop.fwupd ExecStart=@libexecdir@/fwupd/fwupd StateDirectory=@package_name@ diff --git a/data/meson.build b/data/meson.build index 25db95097..37bb001e8 100644 --- a/data/meson.build +++ b/data/meson.build @@ -91,6 +91,7 @@ endif if (get_option('systemd') or get_option('elogind')) and build_daemon con2 = configuration_data() con2.set('libexecdir', libexecdir) + con2.set('motd_dir', motd_dir) # replace @libexecdir@ configure_file( diff --git a/data/motd/fwupd-refresh.service.in b/data/motd/fwupd-refresh.service similarity index 87% rename from data/motd/fwupd-refresh.service.in rename to data/motd/fwupd-refresh.service index 2264eb07b..8a67a3fd3 100644 --- a/data/motd/fwupd-refresh.service.in +++ b/data/motd/fwupd-refresh.service @@ -5,9 +5,7 @@ After=network.target network-online.target systemd-networkd.service NetworkManag [Service] Type=oneshot -RuntimeDirectory=@motd_dir@ CacheDirectory=fwupdmgr -RuntimeDirectoryPreserve=yes StandardError=null DynamicUser=yes RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET AF_INET6 @@ -17,4 +15,3 @@ ProtectControlGroups=yes RestrictRealtime=yes SuccessExitStatus=2 ExecStart=@bindir@/fwupdmgr refresh --no-metadata-check -@dynamic_options@ diff --git a/data/motd/meson.build b/data/motd/meson.build index b583fb7f7..fb8d352f9 100644 --- a/data/motd/meson.build +++ b/data/motd/meson.build @@ -1,35 +1,20 @@ -motd_file = '85-fwupd' -motd_dir = 'motd.d' -fwupdmgr_path = join_paths (bindir, 'fwupdmgr') -motd_fullpath = join_paths ('/run', motd_dir, motd_file) -con2 = configuration_data() -con2.set('bindir', bindir) -con2.set('motd_file', motd_file) -con2.set('motd_dir', motd_dir) -con2.set('motd_fullpath', motd_fullpath) if get_option('systemd') install_data(['fwupd-refresh.timer'], install_dir: systemdunitdir) install_data(['fwupd-refresh.preset'], install_dir: systemdsystempresetdir) - - dynamic_options = [] - if systemd.version().version_compare('>= 243') - dynamic_options += 'ExecStart=' + fwupdmgr_path + ' get-updates --log ' + motd_file - else - dynamic_options += '# motd population disabled; requires systemd v243 or later' - endif - con2.set('dynamic_options', '\n'.join(dynamic_options)) - - configure_file( - input : 'fwupd-refresh.service.in', - output : 'fwupd-refresh.service', - configuration : con2, - install: true, + install_data(['fwupd-refresh.service'], install_dir: systemdunitdir) + motd_fullpath = join_paths ('/run', motd_dir, motd_file) +else + motd_fullpath = join_paths (localstatedir, motd_dir, motd_file) endif +con2 = configuration_data() +con2.set('motd_fullpath', motd_fullpath) + + # This file is only used in Ubuntu, which chooses to use update-motd instead # of sourcing /run/motd.d/* # See https://bugs.launchpad.net/ubuntu/+source/pam/+bug/399071 diff --git a/meson.build b/meson.build index 1e9b8a4cc..63f2797ff 100644 --- a/meson.build +++ b/meson.build @@ -397,6 +397,12 @@ endif conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set_quoted('VERSION', meson.project_version()) + +motd_file = '85-fwupd' +motd_dir = 'motd.d' +conf.set_quoted('MOTD_FILE', motd_file) +conf.set_quoted('MOTD_DIR', motd_dir) + configure_file( output : 'config.h', configuration : conf diff --git a/po/POTFILES.in b/po/POTFILES.in index c459d7eb4..ff7003b3f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,6 +7,7 @@ plugins/uefi/fu-plugin-uefi.c plugins/uefi/fu-uefi-tool.c src/fu-agent.c src/fu-debug.c +src/fu-engine-helper.c src/fu-main.c src/fu-offline.c src/fu-progressbar.c diff --git a/src/fu-config.c b/src/fu-config.c index ec3f54ef5..50ed6b199 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -33,6 +33,7 @@ struct _FuConfig guint64 archive_size_max; guint idle_timeout; gchar *config_file; + gboolean update_motd; }; G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT) @@ -126,6 +127,12 @@ fu_config_reload (FuConfig *self, GError **error) if (domains != NULL && domains[0] != '\0') g_setenv ("FWUPD_VERBOSE", domains, TRUE); + /* whether to update the motd on changes */ + self->update_motd = g_key_file_get_boolean (keyfile, + "fwupd", + "UpdateMotd", + NULL); + return TRUE; } @@ -223,6 +230,13 @@ fu_config_get_approved_firmware (FuConfig *self) return self->approved_firmware; } +gboolean +fu_config_get_update_motd (FuConfig *self) +{ + g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); + return self->update_motd; +} + static void fu_config_class_init (FuConfigClass *klass) { diff --git a/src/fu-config.h b/src/fu-config.h index 845baa425..a6bd85f3b 100644 --- a/src/fu-config.h +++ b/src/fu-config.h @@ -26,3 +26,4 @@ guint fu_config_get_idle_timeout (FuConfig *self); GPtrArray *fu_config_get_blacklist_devices (FuConfig *self); GPtrArray *fu_config_get_blacklist_plugins (FuConfig *self); GPtrArray *fu_config_get_approved_firmware (FuConfig *self); +gboolean fu_config_get_update_motd (FuConfig *self); diff --git a/src/fu-engine-helper.c b/src/fu-engine-helper.c new file mode 100644 index 000000000..4d403d0c4 --- /dev/null +++ b/src/fu-engine-helper.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuEngine" + +#include "config.h" + +#include + +#include "fu-engine.h" +#include "fu-engine-helper.h" + +gboolean +fu_engine_update_motd (FuEngine *self, GError **error) +{ + guint upgrade_count = 0; + g_autoptr(GPtrArray) devices = NULL; + g_autoptr(GString) str = NULL; + g_autofree gchar *target = NULL; + + /* get devices from daemon, we even want to know if it's nothing */ + devices = fu_engine_get_devices (self, NULL); + if (devices != NULL) { + for (guint i = 0; i < devices->len; i++) { + FwupdDevice *dev = g_ptr_array_index (devices, i); + g_autoptr(GPtrArray) rels = NULL; + + /* get the releases for this device */ + rels = fu_engine_get_upgrades (self, + fwupd_device_get_id (dev), + NULL); + if (rels == NULL) + continue; + upgrade_count++; + } + } + + /* If running under systemd unit, use the directory as a base */ + if (g_getenv ("RUNTIME_DIRECTORY") != NULL) { + target = g_build_filename (g_getenv ("RUNTIME_DIRECTORY"), + PACKAGE_NAME, + MOTD_FILE, + NULL); + /* otherwise use the cache directory */ + } else { + g_autofree gchar *directory = fu_common_get_path (FU_PATH_KIND_CACHEDIR_PKG); + target = g_build_filename (directory, MOTD_DIR, MOTD_FILE, NULL); + } + + /* create the directory and file, even if zero devices; we want an empty file then */ + if (!fu_common_mkdir_parent (target, error)) + return FALSE; + + if (upgrade_count == 0) { + g_autoptr(GFile) file = g_file_new_for_path (target); + g_autoptr(GFileOutputStream) output = NULL; + output = g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, + NULL, error); + return output != NULL; + } + + str = g_string_new (""); + if (upgrade_count == 1) { + g_string_append_printf (str, + _("%u device has a firmware upgrade available."), + upgrade_count); + } else { + g_string_append_printf (str, + _("%u devices have a firmware upgrade available."), + upgrade_count); + } + g_string_append_printf (str, + "\n%s\n", + _("Run `fwupdmgr get-upgrades` for more information.")); + return g_file_set_contents (target, str->str, str->len, error); +} + diff --git a/src/fu-engine-helper.h b/src/fu-engine-helper.h new file mode 100644 index 000000000..9491ca9de --- /dev/null +++ b/src/fu-engine-helper.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2020 Mario Limonciello + * + * SPDX-License-Identifier: LGPL-2.1+ + */ +#pragma once + +#include "fu-engine.h" + +gboolean fu_engine_update_motd (FuEngine *self, + GError **error); diff --git a/src/fu-engine.c b/src/fu-engine.c index 5df9f0547..0c8c40387 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -36,6 +36,7 @@ #include "fu-device-list.h" #include "fu-device-private.h" #include "fu-engine.h" +#include "fu-engine-helper.h" #include "fu-hwids.h" #include "fu-idle.h" #include "fu-keyring-utils.h" @@ -117,6 +118,14 @@ fu_engine_emit_changed (FuEngine *self) { g_signal_emit (self, signals[SIGNAL_CHANGED], 0); fu_engine_idle_reset (self); + + /* update the motd */ + if (self->loaded && + fu_config_get_update_motd (self->config)) { + g_autoptr(GError) error_local = NULL; + if (!fu_engine_update_motd (self, &error_local)) + g_debug ("%s", error_local->message); + } } static void @@ -551,6 +560,7 @@ fu_engine_modify_config (FuEngine *self, const gchar *key, const gchar *value, G "BlacklistPlugins", "IdleTimeout", "VerboseDomains", + "UpdateMotd", NULL }; g_return_val_if_fail (FU_IS_ENGINE (self), FALSE); @@ -1913,6 +1923,10 @@ fu_engine_install_release (FuEngine *self, if ((flags & FWUPD_INSTALL_FLAG_NO_HISTORY) == 0 && !fu_history_modify_device (self->history, device, error)) return FALSE; + + /* make the UI update */ + fu_engine_emit_changed (self); + return TRUE; } @@ -2531,7 +2545,6 @@ fu_engine_install_blob (FuEngine *self, /* make the UI update */ fu_engine_set_status (self, FWUPD_STATUS_IDLE); - fu_engine_emit_changed (self); g_debug ("Updating %s took %f seconds", fu_device_get_name (device), g_timer_elapsed (timer, NULL)); return TRUE; @@ -2867,6 +2880,9 @@ fu_engine_remote_list_changed_cb (FuRemoteList *remote_list, FuEngine *self) &error_local)) g_warning ("Failed to reload metadata store: %s", error_local->message); + + /* make the UI update */ + fu_engine_emit_changed (self); } #ifdef HAVE_GIO_UNIX @@ -3021,7 +3037,11 @@ fu_engine_update_metadata (FuEngine *self, const gchar *remote_id, bytes_sig, error)) return FALSE; } - return fu_engine_load_metadata_store (self, FU_ENGINE_LOAD_FLAG_NONE, error); + if (!fu_engine_load_metadata_store (self, FU_ENGINE_LOAD_FLAG_NONE, error)) + return FALSE; + fu_engine_emit_changed (self); + return TRUE; + #else g_set_error (error, FWUPD_ERROR, @@ -4310,6 +4330,8 @@ fu_engine_add_device (FuEngine *self, FuDevice *device) /* sometimes inherit flags from recent history */ fu_engine_device_inherit_history (self, device); + + fu_engine_emit_changed (self); } static void @@ -5233,6 +5255,9 @@ fu_engine_load (FuEngine *self, FuEngineLoadFlags flags, GError **error) fu_engine_set_status (self, FWUPD_STATUS_IDLE); self->loaded = TRUE; + /* let clients know engine finished starting up */ + fu_engine_emit_changed (self); + /* success */ return TRUE; } diff --git a/src/fu-util.c b/src/fu-util.c index 4babd22f3..4a3d94b46 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -77,8 +77,6 @@ struct FuUtilPrivate { FwupdDeviceFlags filter_exclude; }; -static GFileOutputStream *log_output = NULL; - static gboolean fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error); static gboolean fu_util_download_file (FuUtilPrivate *priv, SoupURI *uri, @@ -2384,33 +2382,6 @@ fu_util_check_polkit_actions (GError **error) return TRUE; } -static void -fu_util_log_output (const gchar *str) -{ - if (log_output != NULL) { - g_autoptr(GError) error_local = NULL; - if (g_output_stream_write (G_OUTPUT_STREAM (log_output), - str, strlen(str), - NULL, &error_local) <0) - g_printerr ("%s\n", error_local->message); - } -} - -static void -fu_util_close_log (void) -{ - if (log_output != NULL) { - g_autoptr(GError) error_local = NULL; - if (!g_output_stream_close (G_OUTPUT_STREAM (log_output), - NULL, - &error_local)) { - g_printerr ("%s\n", error_local->message); - return; - } - g_object_unref (log_output); - } -} - static void fu_util_display_help (FuUtilPrivate *priv) { @@ -2463,9 +2434,6 @@ main (int argc, char *argv[]) { "assume-yes", 'y', 0, G_OPTION_ARG_NONE, &priv->assume_yes, /* TRANSLATORS: command line option */ _("Answer yes to all questions"), NULL }, - { "log", '\0', 0, G_OPTION_ARG_STRING, &log, - /* TRANSLATORS: command line option */ - _("Log output to FILE (typically for scripting use)"), NULL }, { "sign", '\0', 0, G_OPTION_ARG_NONE, &priv->sign, /* TRANSLATORS: command line option */ _("Sign the uploaded data with the client certificate"), NULL }, @@ -2710,8 +2678,7 @@ main (int argc, char *argv[]) } /* non-TTY consoles cannot answer questions */ - if (log != NULL || - isatty (fileno (stdout)) == 0) { + if (isatty (fileno (stdout)) == 0) { priv->no_unreported_check = TRUE; priv->no_metadata_check = TRUE; priv->no_reboot_check = TRUE; @@ -2808,27 +2775,6 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } - /* configure stdout redirection */ - if (log != NULL) { - g_autoptr(GFile) file = NULL; - g_autofree gchar *target_fname = NULL; - /* If running under systemd unit, use the directory as a base */ - if (g_getenv ("RUNTIME_DIRECTORY") != NULL) { - target_fname = g_build_filename (g_getenv ("RUNTIME_DIRECTORY"), - log, - NULL); - } else { - target_fname = g_steal_pointer (&log); - } - file = g_file_new_for_commandline_arg (target_fname); - log_output = g_file_append_to (file, G_FILE_CREATE_NONE, NULL, &error); - if (log_output == NULL) { - g_printerr ("%s\n", error->message); - return EXIT_FAILURE; - } - g_set_print_handler (fu_util_log_output); - } - /* run the specified command */ ret = fu_util_cmd_array_run (cmd_array, priv, argv[1], (gchar**) &argv[2], &error); if (!ret) { @@ -2841,7 +2787,6 @@ main (int argc, char *argv[]) } else { ret = EXIT_SUCCESS; } - fu_util_close_log (); return ret; } diff --git a/src/meson.build b/src/meson.build index f3747dca8..8140ddd38 100644 --- a/src/meson.build +++ b/src/meson.build @@ -137,6 +137,7 @@ fwupdtool = executable( 'fu-debug.c', 'fu-device-list.c', 'fu-engine.c', + 'fu-engine-helper.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', @@ -205,6 +206,7 @@ executable( 'fu-debug.c', 'fu-device-list.c', 'fu-engine.c', + 'fu-engine-helper.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c', @@ -263,6 +265,7 @@ if get_option('tests') 'fu-config.c', 'fu-device-list.c', 'fu-engine.c', + 'fu-engine-helper.c', 'fu-history.c', 'fu-idle.c', 'fu-install-task.c',