Richard Hughes | 02c90d8 | 2018-08-09 12:13:03 +0100 | [diff] [blame] | 1 | /* |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 2 | * Copyright (C) 2017 Richard Hughes <richard@hughsie.com> |
| 3 | * |
Mario Limonciello | 51308e6 | 2018-05-28 20:05:46 -0500 | [diff] [blame] | 4 | * SPDX-License-Identifier: LGPL-2.1+ |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 5 | */ |
| 6 | |
Richard Hughes | b08e7bc | 2018-09-11 10:51:13 +0100 | [diff] [blame] | 7 | #define G_LOG_DOMAIN "FuConfig" |
| 8 | |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 9 | #include "config.h" |
| 10 | |
| 11 | #include <glib-object.h> |
| 12 | #include <gio/gio.h> |
| 13 | |
Richard Hughes | 4be17d1 | 2018-05-30 20:36:29 +0100 | [diff] [blame] | 14 | #include "fu-common.h" |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 15 | #include "fu-config.h" |
| 16 | |
Mario Limonciello | 263cab9 | 2019-08-20 17:16:00 -0500 | [diff] [blame] | 17 | enum { |
| 18 | SIGNAL_CHANGED, |
| 19 | SIGNAL_LAST |
| 20 | }; |
| 21 | |
| 22 | static guint signals[SIGNAL_LAST] = { 0 }; |
| 23 | |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 24 | static void fu_config_finalize (GObject *obj); |
| 25 | |
| 26 | struct _FuConfig |
| 27 | { |
| 28 | GObject parent_instance; |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 29 | GFileMonitor *monitor; |
| 30 | GPtrArray *blacklist_devices; /* (element-type utf-8) */ |
| 31 | GPtrArray *blacklist_plugins; /* (element-type utf-8) */ |
| 32 | GPtrArray *approved_firmware; /* (element-type utf-8) */ |
Richard Hughes | c7bbbc2 | 2018-01-02 22:22:25 +0000 | [diff] [blame] | 33 | guint64 archive_size_max; |
Richard Hughes | 75b965d | 2018-11-15 13:51:21 +0000 | [diff] [blame] | 34 | guint idle_timeout; |
Mario Limonciello | bfcf75b | 2019-04-17 15:05:39 +0100 | [diff] [blame] | 35 | gchar *config_file; |
Mario Limonciello | d81ea2e | 2020-01-13 14:11:43 -0600 | [diff] [blame] | 36 | gboolean update_motd; |
Mario Limonciello | 4fa95a7 | 2020-03-28 10:50:57 -0500 | [diff] [blame^] | 37 | gboolean enumerate_all_devices; |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 38 | }; |
| 39 | |
| 40 | G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT) |
| 41 | |
Mario Limonciello | 263cab9 | 2019-08-20 17:16:00 -0500 | [diff] [blame] | 42 | static void |
| 43 | fu_config_emit_changed (FuConfig *self) |
| 44 | { |
| 45 | g_debug ("::configuration changed"); |
| 46 | g_signal_emit (self, signals[SIGNAL_CHANGED], 0); |
| 47 | } |
| 48 | |
Richard Hughes | 4c36970 | 2017-06-16 15:31:38 +0100 | [diff] [blame] | 49 | static gboolean |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 50 | fu_config_reload (FuConfig *self, GError **error) |
Richard Hughes | cda1cdf | 2017-06-16 21:49:35 +0100 | [diff] [blame] | 51 | { |
Richard Hughes | 321f77a | 2018-02-14 10:25:53 +0000 | [diff] [blame] | 52 | guint64 archive_size_max; |
Richard Hughes | 75b965d | 2018-11-15 13:51:21 +0000 | [diff] [blame] | 53 | guint idle_timeout; |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 54 | g_auto(GStrv) approved_firmware = NULL; |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 55 | g_auto(GStrv) devices = NULL; |
| 56 | g_auto(GStrv) plugins = NULL; |
Mario Limonciello | 38027e6 | 2019-04-17 15:16:07 +0100 | [diff] [blame] | 57 | g_autofree gchar *domains = NULL; |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 58 | g_autoptr(GKeyFile) keyfile = g_key_file_new (); |
Mario Limonciello | 4fa95a7 | 2020-03-28 10:50:57 -0500 | [diff] [blame^] | 59 | g_autoptr(GError) error_enumerate_all = NULL; |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 60 | |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 61 | g_debug ("loading config values from %s", self->config_file); |
| 62 | if (!g_key_file_load_from_file (keyfile, self->config_file, |
| 63 | G_KEY_FILE_NONE, error)) |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 64 | return FALSE; |
| 65 | |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 66 | /* get blacklisted devices */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 67 | g_ptr_array_set_size (self->blacklist_devices, 0); |
| 68 | devices = g_key_file_get_string_list (keyfile, |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 69 | "fwupd", |
| 70 | "BlacklistDevices", |
| 71 | NULL, /* length */ |
| 72 | NULL); |
| 73 | if (devices != NULL) { |
| 74 | for (guint i = 0; devices[i] != NULL; i++) { |
| 75 | g_ptr_array_add (self->blacklist_devices, |
| 76 | g_strdup (devices[i])); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /* get blacklisted plugins */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 81 | g_ptr_array_set_size (self->blacklist_plugins, 0); |
| 82 | plugins = g_key_file_get_string_list (keyfile, |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 83 | "fwupd", |
| 84 | "BlacklistPlugins", |
| 85 | NULL, /* length */ |
| 86 | NULL); |
| 87 | if (plugins != NULL) { |
| 88 | for (guint i = 0; plugins[i] != NULL; i++) { |
| 89 | g_ptr_array_add (self->blacklist_plugins, |
| 90 | g_strdup (plugins[i])); |
| 91 | } |
| 92 | } |
| 93 | |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 94 | /* get approved firmware */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 95 | g_ptr_array_set_size (self->approved_firmware, 0); |
| 96 | approved_firmware = g_key_file_get_string_list (keyfile, |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 97 | "fwupd", |
| 98 | "ApprovedFirmware", |
| 99 | NULL, /* length */ |
| 100 | NULL); |
| 101 | if (approved_firmware != NULL) { |
| 102 | for (guint i = 0; approved_firmware[i] != NULL; i++) { |
| 103 | g_ptr_array_add (self->approved_firmware, |
| 104 | g_strdup (approved_firmware[i])); |
| 105 | } |
| 106 | } |
| 107 | |
Richard Hughes | c7bbbc2 | 2018-01-02 22:22:25 +0000 | [diff] [blame] | 108 | /* get maximum archive size, defaulting to something sane */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 109 | archive_size_max = g_key_file_get_uint64 (keyfile, |
Richard Hughes | 321f77a | 2018-02-14 10:25:53 +0000 | [diff] [blame] | 110 | "fwupd", |
| 111 | "ArchiveSizeMax", |
| 112 | NULL); |
| 113 | if (archive_size_max > 0) |
| 114 | self->archive_size_max = archive_size_max *= 0x100000; |
Richard Hughes | 75b965d | 2018-11-15 13:51:21 +0000 | [diff] [blame] | 115 | |
| 116 | /* get idle timeout */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 117 | idle_timeout = g_key_file_get_uint64 (keyfile, |
Richard Hughes | 75b965d | 2018-11-15 13:51:21 +0000 | [diff] [blame] | 118 | "fwupd", |
| 119 | "IdleTimeout", |
| 120 | NULL); |
| 121 | if (idle_timeout > 0) |
| 122 | self->idle_timeout = idle_timeout; |
Mario Limonciello | 38027e6 | 2019-04-17 15:16:07 +0100 | [diff] [blame] | 123 | |
| 124 | /* get the domains to run in verbose */ |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 125 | domains = g_key_file_get_string (keyfile, |
Mario Limonciello | 38027e6 | 2019-04-17 15:16:07 +0100 | [diff] [blame] | 126 | "fwupd", |
| 127 | "VerboseDomains", |
| 128 | NULL); |
| 129 | if (domains != NULL && domains[0] != '\0') |
| 130 | g_setenv ("FWUPD_VERBOSE", domains, TRUE); |
| 131 | |
Mario Limonciello | d81ea2e | 2020-01-13 14:11:43 -0600 | [diff] [blame] | 132 | /* whether to update the motd on changes */ |
| 133 | self->update_motd = g_key_file_get_boolean (keyfile, |
| 134 | "fwupd", |
| 135 | "UpdateMotd", |
| 136 | NULL); |
| 137 | |
Mario Limonciello | 4fa95a7 | 2020-03-28 10:50:57 -0500 | [diff] [blame^] | 138 | /* whether to only show supported devices for some plugins */ |
| 139 | self->enumerate_all_devices = g_key_file_get_boolean (keyfile, |
| 140 | "fwupd", |
| 141 | "EnumerateAllDevices", |
| 142 | &error_enumerate_all); |
| 143 | /* if error parsing or missing, we want to default to true */ |
| 144 | if (!self->enumerate_all_devices && error_enumerate_all != NULL) { |
| 145 | g_debug ("failed to read EnumerateAllDevices key: %s", error_enumerate_all->message); |
| 146 | self->enumerate_all_devices = TRUE; |
| 147 | } |
| 148 | |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 149 | return TRUE; |
| 150 | } |
| 151 | |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 152 | static void |
| 153 | fu_config_monitor_changed_cb (GFileMonitor *monitor, |
| 154 | GFile *file, |
| 155 | GFile *other_file, |
| 156 | GFileMonitorEvent event_type, |
| 157 | gpointer user_data) |
Richard Hughes | 481aa2a | 2018-09-18 20:51:46 +0100 | [diff] [blame] | 158 | { |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 159 | FuConfig *self = FU_CONFIG (user_data); |
| 160 | g_autoptr(GError) error = NULL; |
| 161 | g_debug ("%s changed, reloading all configs", self->config_file); |
| 162 | if (!fu_config_reload (self, &error)) |
| 163 | g_warning ("failed to rescan daemon config: %s", error->message); |
| 164 | fu_config_emit_changed (self); |
Richard Hughes | 481aa2a | 2018-09-18 20:51:46 +0100 | [diff] [blame] | 165 | } |
| 166 | |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 167 | gboolean |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 168 | fu_config_set_key_value (FuConfig *self, const gchar *key, const gchar *value, GError **error) |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 169 | { |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 170 | g_autoptr(GKeyFile) keyfile = g_key_file_new (); |
| 171 | if (!g_key_file_load_from_file (keyfile, self->config_file, |
| 172 | G_KEY_FILE_KEEP_COMMENTS, error)) |
| 173 | return FALSE; |
| 174 | g_key_file_set_string (keyfile, "fwupd", key, value); |
| 175 | if (!g_key_file_save_to_file (keyfile, self->config_file, error)) |
| 176 | return FALSE; |
| 177 | return fu_config_reload (self, error); |
| 178 | } |
| 179 | |
| 180 | gboolean |
| 181 | fu_config_load (FuConfig *self, GError **error) |
| 182 | { |
Richard Hughes | 4be17d1 | 2018-05-30 20:36:29 +0100 | [diff] [blame] | 183 | g_autofree gchar *configdir = NULL; |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 184 | g_autoptr(GFile) file = NULL; |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 185 | |
| 186 | g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 187 | g_return_val_if_fail (self->config_file == NULL, FALSE); |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 188 | |
| 189 | /* load the main daemon config file */ |
Richard Hughes | 4be17d1 | 2018-05-30 20:36:29 +0100 | [diff] [blame] | 190 | configdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG); |
Mario Limonciello | bfcf75b | 2019-04-17 15:05:39 +0100 | [diff] [blame] | 191 | self->config_file = g_build_filename (configdir, "daemon.conf", NULL); |
| 192 | if (g_file_test (self->config_file, G_FILE_TEST_EXISTS)) { |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 193 | if (!fu_config_reload (self, error)) |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 194 | return FALSE; |
| 195 | } else { |
Mario Limonciello | bfcf75b | 2019-04-17 15:05:39 +0100 | [diff] [blame] | 196 | g_warning ("Daemon configuration %s not found", self->config_file); |
Mario Limonciello | d82e3b5 | 2018-05-22 10:18:27 -0500 | [diff] [blame] | 197 | } |
Richard Hughes | c7bbbc2 | 2018-01-02 22:22:25 +0000 | [diff] [blame] | 198 | |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 199 | /* set up a notify watch */ |
| 200 | file = g_file_new_for_path (self->config_file); |
| 201 | self->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error); |
| 202 | if (self->monitor == NULL) |
Richard Hughes | 1fd3ecf | 2018-04-16 10:53:46 +0100 | [diff] [blame] | 203 | return FALSE; |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 204 | g_signal_connect (self->monitor, "changed", |
| 205 | G_CALLBACK (fu_config_monitor_changed_cb), self); |
Richard Hughes | 4c36970 | 2017-06-16 15:31:38 +0100 | [diff] [blame] | 206 | |
| 207 | /* success */ |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 208 | return TRUE; |
| 209 | } |
| 210 | |
Richard Hughes | 75b965d | 2018-11-15 13:51:21 +0000 | [diff] [blame] | 211 | guint |
| 212 | fu_config_get_idle_timeout (FuConfig *self) |
| 213 | { |
| 214 | g_return_val_if_fail (FU_IS_CONFIG (self), 0); |
| 215 | return self->idle_timeout; |
| 216 | } |
| 217 | |
Richard Hughes | 4c36970 | 2017-06-16 15:31:38 +0100 | [diff] [blame] | 218 | GPtrArray * |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 219 | fu_config_get_blacklist_devices (FuConfig *self) |
| 220 | { |
| 221 | g_return_val_if_fail (FU_IS_CONFIG (self), NULL); |
| 222 | return self->blacklist_devices; |
| 223 | } |
| 224 | |
Richard Hughes | c7bbbc2 | 2018-01-02 22:22:25 +0000 | [diff] [blame] | 225 | guint64 |
| 226 | fu_config_get_archive_size_max (FuConfig *self) |
| 227 | { |
| 228 | g_return_val_if_fail (FU_IS_CONFIG (self), 0); |
| 229 | return self->archive_size_max; |
| 230 | } |
| 231 | |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 232 | GPtrArray * |
| 233 | fu_config_get_blacklist_plugins (FuConfig *self) |
| 234 | { |
| 235 | g_return_val_if_fail (FU_IS_CONFIG (self), NULL); |
| 236 | return self->blacklist_plugins; |
| 237 | } |
| 238 | |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 239 | GPtrArray * |
| 240 | fu_config_get_approved_firmware (FuConfig *self) |
| 241 | { |
| 242 | g_return_val_if_fail (FU_IS_CONFIG (self), NULL); |
| 243 | return self->approved_firmware; |
| 244 | } |
| 245 | |
Mario Limonciello | d81ea2e | 2020-01-13 14:11:43 -0600 | [diff] [blame] | 246 | gboolean |
| 247 | fu_config_get_update_motd (FuConfig *self) |
| 248 | { |
| 249 | g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); |
| 250 | return self->update_motd; |
| 251 | } |
| 252 | |
Mario Limonciello | 4fa95a7 | 2020-03-28 10:50:57 -0500 | [diff] [blame^] | 253 | gboolean |
| 254 | fu_config_get_enumerate_all_devices (FuConfig *self) |
| 255 | { |
| 256 | g_return_val_if_fail (FU_IS_CONFIG (self), FALSE); |
| 257 | return self->enumerate_all_devices; |
| 258 | } |
| 259 | |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 260 | static void |
| 261 | fu_config_class_init (FuConfigClass *klass) |
| 262 | { |
| 263 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
| 264 | object_class->finalize = fu_config_finalize; |
Mario Limonciello | 263cab9 | 2019-08-20 17:16:00 -0500 | [diff] [blame] | 265 | |
| 266 | signals[SIGNAL_CHANGED] = |
| 267 | g_signal_new ("changed", |
| 268 | G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, |
| 269 | 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, |
| 270 | G_TYPE_NONE, 0); |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 271 | } |
| 272 | |
| 273 | static void |
| 274 | fu_config_init (FuConfig *self) |
| 275 | { |
Richard Hughes | c7bbbc2 | 2018-01-02 22:22:25 +0000 | [diff] [blame] | 276 | self->archive_size_max = 512 * 0x100000; |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 277 | self->blacklist_devices = g_ptr_array_new_with_free_func (g_free); |
| 278 | self->blacklist_plugins = g_ptr_array_new_with_free_func (g_free); |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 279 | self->approved_firmware = g_ptr_array_new_with_free_func (g_free); |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | static void |
| 283 | fu_config_finalize (GObject *obj) |
| 284 | { |
| 285 | FuConfig *self = FU_CONFIG (obj); |
| 286 | |
Richard Hughes | d1808aa | 2019-12-10 15:20:30 +0000 | [diff] [blame] | 287 | if (self->monitor != NULL) |
| 288 | g_object_unref (self->monitor); |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 289 | g_ptr_array_unref (self->blacklist_devices); |
| 290 | g_ptr_array_unref (self->blacklist_plugins); |
Richard Hughes | 8dd4c1c | 2019-03-03 18:27:57 +0000 | [diff] [blame] | 291 | g_ptr_array_unref (self->approved_firmware); |
Mario Limonciello | bfcf75b | 2019-04-17 15:05:39 +0100 | [diff] [blame] | 292 | g_free (self->config_file); |
Richard Hughes | 980ef14 | 2017-06-16 12:45:27 +0100 | [diff] [blame] | 293 | |
| 294 | G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); |
| 295 | } |
| 296 | |
| 297 | FuConfig * |
| 298 | fu_config_new (void) |
| 299 | { |
| 300 | FuConfig *self; |
| 301 | self = g_object_new (FU_TYPE_CONFIG, NULL); |
| 302 | return FU_CONFIG (self); |
| 303 | } |