blob: 6dc31cc88ce7ad2b978aa4f16ad97583fd1687d4 [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughes980ef142017-06-16 12:45:27 +01002 * Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
3 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughes980ef142017-06-16 12:45:27 +01005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuConfig"
8
Richard Hughes980ef142017-06-16 12:45:27 +01009#include "config.h"
10
11#include <glib-object.h>
12#include <gio/gio.h>
13
Richard Hughes4be17d12018-05-30 20:36:29 +010014#include "fu-common.h"
Richard Hughes980ef142017-06-16 12:45:27 +010015#include "fu-config.h"
16
Mario Limonciello263cab92019-08-20 17:16:00 -050017enum {
18 SIGNAL_CHANGED,
19 SIGNAL_LAST
20};
21
22static guint signals[SIGNAL_LAST] = { 0 };
23
Richard Hughes980ef142017-06-16 12:45:27 +010024static void fu_config_finalize (GObject *obj);
25
26struct _FuConfig
27{
28 GObject parent_instance;
Richard Hughesd1808aa2019-12-10 15:20:30 +000029 GFileMonitor *monitor;
Richard Hughes85226fd2020-06-30 14:43:48 +010030 GPtrArray *disabled_devices; /* (element-type utf-8) */
31 GPtrArray *disabled_plugins; /* (element-type utf-8) */
Richard Hughesd1808aa2019-12-10 15:20:30 +000032 GPtrArray *approved_firmware; /* (element-type utf-8) */
Richard Hughes31206832020-07-27 15:31:11 +010033 GPtrArray *blocked_firmware; /* (element-type utf-8) */
Richard Hughesb856f0b2021-01-28 10:59:49 +000034 GPtrArray *uri_schemes; /* (element-type utf-8) */
Richard Hughesc7bbbc22018-01-02 22:22:25 +000035 guint64 archive_size_max;
Richard Hughes75b965d2018-11-15 13:51:21 +000036 guint idle_timeout;
Mario Limonciellobfcf75b2019-04-17 15:05:39 +010037 gchar *config_file;
Mario Limonciellod81ea2e2020-01-13 14:11:43 -060038 gboolean update_motd;
Mario Limonciello4fa95a72020-03-28 10:50:57 -050039 gboolean enumerate_all_devices;
Richard Hughes980ef142017-06-16 12:45:27 +010040};
41
42G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT)
43
Mario Limonciello263cab92019-08-20 17:16:00 -050044static void
45fu_config_emit_changed (FuConfig *self)
46{
47 g_debug ("::configuration changed");
48 g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
49}
50
Richard Hughes4c369702017-06-16 15:31:38 +010051static gboolean
Richard Hughesd1808aa2019-12-10 15:20:30 +000052fu_config_reload (FuConfig *self, GError **error)
Richard Hughescda1cdf2017-06-16 21:49:35 +010053{
Richard Hughes321f77a2018-02-14 10:25:53 +000054 guint64 archive_size_max;
Richard Hughes75b965d2018-11-15 13:51:21 +000055 guint idle_timeout;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +000056 g_auto(GStrv) approved_firmware = NULL;
Richard Hughes31206832020-07-27 15:31:11 +010057 g_auto(GStrv) blocked_firmware = NULL;
Richard Hughesb856f0b2021-01-28 10:59:49 +000058 g_auto(GStrv) uri_schemes = NULL;
Richard Hughes980ef142017-06-16 12:45:27 +010059 g_auto(GStrv) devices = NULL;
60 g_auto(GStrv) plugins = NULL;
Mario Limonciello38027e62019-04-17 15:16:07 +010061 g_autofree gchar *domains = NULL;
Richard Hughesd1808aa2019-12-10 15:20:30 +000062 g_autoptr(GKeyFile) keyfile = g_key_file_new ();
Mario Limonciello3dbb92e2020-03-30 12:07:18 -050063 g_autoptr(GError) error_update_motd = NULL;
Mario Limonciello4fa95a72020-03-28 10:50:57 -050064 g_autoptr(GError) error_enumerate_all = NULL;
Richard Hughes980ef142017-06-16 12:45:27 +010065
Richard Hughesd1808aa2019-12-10 15:20:30 +000066 g_debug ("loading config values from %s", self->config_file);
67 if (!g_key_file_load_from_file (keyfile, self->config_file,
68 G_KEY_FILE_NONE, error))
Richard Hughes980ef142017-06-16 12:45:27 +010069 return FALSE;
70
Richard Hughes85226fd2020-06-30 14:43:48 +010071 /* get disabled devices */
72 g_ptr_array_set_size (self->disabled_devices, 0);
Richard Hughesd1808aa2019-12-10 15:20:30 +000073 devices = g_key_file_get_string_list (keyfile,
Richard Hughes980ef142017-06-16 12:45:27 +010074 "fwupd",
Richard Hughes85226fd2020-06-30 14:43:48 +010075 "DisabledDevices",
Richard Hughes980ef142017-06-16 12:45:27 +010076 NULL, /* length */
77 NULL);
78 if (devices != NULL) {
79 for (guint i = 0; devices[i] != NULL; i++) {
Richard Hughes85226fd2020-06-30 14:43:48 +010080 g_ptr_array_add (self->disabled_devices,
Richard Hughes980ef142017-06-16 12:45:27 +010081 g_strdup (devices[i]));
82 }
83 }
84
Richard Hughes85226fd2020-06-30 14:43:48 +010085 /* get disabled plugins */
86 g_ptr_array_set_size (self->disabled_plugins, 0);
Richard Hughesd1808aa2019-12-10 15:20:30 +000087 plugins = g_key_file_get_string_list (keyfile,
Richard Hughes980ef142017-06-16 12:45:27 +010088 "fwupd",
Richard Hughes85226fd2020-06-30 14:43:48 +010089 "DisabledPlugins",
Richard Hughes980ef142017-06-16 12:45:27 +010090 NULL, /* length */
91 NULL);
92 if (plugins != NULL) {
93 for (guint i = 0; plugins[i] != NULL; i++) {
Richard Hughes85226fd2020-06-30 14:43:48 +010094 g_ptr_array_add (self->disabled_plugins,
Richard Hughes980ef142017-06-16 12:45:27 +010095 g_strdup (plugins[i]));
96 }
97 }
98
Richard Hughes8dd4c1c2019-03-03 18:27:57 +000099 /* get approved firmware */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000100 g_ptr_array_set_size (self->approved_firmware, 0);
101 approved_firmware = g_key_file_get_string_list (keyfile,
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000102 "fwupd",
103 "ApprovedFirmware",
104 NULL, /* length */
105 NULL);
106 if (approved_firmware != NULL) {
107 for (guint i = 0; approved_firmware[i] != NULL; i++) {
108 g_ptr_array_add (self->approved_firmware,
109 g_strdup (approved_firmware[i]));
110 }
111 }
112
Richard Hughes31206832020-07-27 15:31:11 +0100113 /* get blocked firmware */
114 g_ptr_array_set_size (self->blocked_firmware, 0);
115 blocked_firmware = g_key_file_get_string_list (keyfile,
116 "fwupd",
117 "BlockedFirmware",
118 NULL, /* length */
119 NULL);
120 if (blocked_firmware != NULL) {
121 for (guint i = 0; blocked_firmware[i] != NULL; i++) {
122 g_ptr_array_add (self->blocked_firmware,
123 g_strdup (blocked_firmware[i]));
124 }
125 }
126
Richard Hughesb856f0b2021-01-28 10:59:49 +0000127 /* get download schemes */
128 g_ptr_array_set_size (self->uri_schemes, 0);
129 uri_schemes = g_key_file_get_string_list (keyfile,
130 "fwupd",
131 "UriSchemes",
132 NULL, /* length */
133 NULL);
134 if (uri_schemes != NULL) {
135 for (guint i = 0; uri_schemes[i] != NULL; i++) {
136 g_ptr_array_add (self->uri_schemes,
137 g_strdup (uri_schemes[i]));
138 }
139 }
140 if (self->uri_schemes->len == 0) {
141 g_ptr_array_add (self->uri_schemes, g_strdup ("file"));
142 g_ptr_array_add (self->uri_schemes, g_strdup ("https"));
143 g_ptr_array_add (self->uri_schemes, g_strdup ("http"));
144 g_ptr_array_add (self->uri_schemes, g_strdup ("ipfs"));
145 }
146
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000147 /* get maximum archive size, defaulting to something sane */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000148 archive_size_max = g_key_file_get_uint64 (keyfile,
Richard Hughes321f77a2018-02-14 10:25:53 +0000149 "fwupd",
150 "ArchiveSizeMax",
151 NULL);
Richard Hughes68175e92021-01-14 09:43:33 +0000152 if (archive_size_max > 0) {
Mario Limonciello27fd95a2020-08-10 10:02:24 -0500153 self->archive_size_max = archive_size_max * 0x100000;
Richard Hughes68175e92021-01-14 09:43:33 +0000154 } else {
155 guint64 memory_size = fu_common_get_memory_size ();
156 g_autofree gchar *str = NULL;
157 if (memory_size > 0) {
158 self->archive_size_max = MAX (memory_size / 4, G_MAXSIZE);
159 str = g_format_size (self->archive_size_max);
160 g_debug ("using autodetected max archive size %s", str);
161 } else {
162 self->archive_size_max = 512 * 0x100000;
163 str = g_format_size (self->archive_size_max);
164 g_debug ("using fallback max archive size %s", str);
165 }
166 }
Richard Hughes75b965d2018-11-15 13:51:21 +0000167
168 /* get idle timeout */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000169 idle_timeout = g_key_file_get_uint64 (keyfile,
Richard Hughes75b965d2018-11-15 13:51:21 +0000170 "fwupd",
171 "IdleTimeout",
172 NULL);
173 if (idle_timeout > 0)
174 self->idle_timeout = idle_timeout;
Mario Limonciello38027e62019-04-17 15:16:07 +0100175
176 /* get the domains to run in verbose */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000177 domains = g_key_file_get_string (keyfile,
Mario Limonciello38027e62019-04-17 15:16:07 +0100178 "fwupd",
179 "VerboseDomains",
180 NULL);
181 if (domains != NULL && domains[0] != '\0')
182 g_setenv ("FWUPD_VERBOSE", domains, TRUE);
183
Mario Limonciellod81ea2e2020-01-13 14:11:43 -0600184 /* whether to update the motd on changes */
185 self->update_motd = g_key_file_get_boolean (keyfile,
186 "fwupd",
187 "UpdateMotd",
Mario Limonciello3dbb92e2020-03-30 12:07:18 -0500188 &error_update_motd);
189 if (!self->update_motd && error_update_motd != NULL) {
190 g_debug ("failed to read UpdateMotd key: %s", error_update_motd->message);
191 self->update_motd = TRUE;
192 }
Mario Limonciellod81ea2e2020-01-13 14:11:43 -0600193
Mario Limonciello4fa95a72020-03-28 10:50:57 -0500194 /* whether to only show supported devices for some plugins */
195 self->enumerate_all_devices = g_key_file_get_boolean (keyfile,
196 "fwupd",
197 "EnumerateAllDevices",
198 &error_enumerate_all);
199 /* if error parsing or missing, we want to default to true */
200 if (!self->enumerate_all_devices && error_enumerate_all != NULL) {
201 g_debug ("failed to read EnumerateAllDevices key: %s", error_enumerate_all->message);
202 self->enumerate_all_devices = TRUE;
203 }
204
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500205 return TRUE;
206}
207
Richard Hughesd1808aa2019-12-10 15:20:30 +0000208static void
209fu_config_monitor_changed_cb (GFileMonitor *monitor,
210 GFile *file,
211 GFile *other_file,
212 GFileMonitorEvent event_type,
213 gpointer user_data)
Richard Hughes481aa2a2018-09-18 20:51:46 +0100214{
Richard Hughesd1808aa2019-12-10 15:20:30 +0000215 FuConfig *self = FU_CONFIG (user_data);
216 g_autoptr(GError) error = NULL;
217 g_debug ("%s changed, reloading all configs", self->config_file);
218 if (!fu_config_reload (self, &error))
219 g_warning ("failed to rescan daemon config: %s", error->message);
220 fu_config_emit_changed (self);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100221}
222
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500223gboolean
Richard Hughesd1808aa2019-12-10 15:20:30 +0000224fu_config_set_key_value (FuConfig *self, const gchar *key, const gchar *value, GError **error)
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500225{
Richard Hughesd1808aa2019-12-10 15:20:30 +0000226 g_autoptr(GKeyFile) keyfile = g_key_file_new ();
227 if (!g_key_file_load_from_file (keyfile, self->config_file,
228 G_KEY_FILE_KEEP_COMMENTS, error))
229 return FALSE;
230 g_key_file_set_string (keyfile, "fwupd", key, value);
231 if (!g_key_file_save_to_file (keyfile, self->config_file, error))
232 return FALSE;
233 return fu_config_reload (self, error);
234}
235
236gboolean
237fu_config_load (FuConfig *self, GError **error)
238{
Richard Hughes4be17d12018-05-30 20:36:29 +0100239 g_autofree gchar *configdir = NULL;
Richard Hughesd1808aa2019-12-10 15:20:30 +0000240 g_autoptr(GFile) file = NULL;
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500241
242 g_return_val_if_fail (FU_IS_CONFIG (self), FALSE);
Richard Hughesd1808aa2019-12-10 15:20:30 +0000243 g_return_val_if_fail (self->config_file == NULL, FALSE);
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500244
245 /* load the main daemon config file */
Richard Hughes4be17d12018-05-30 20:36:29 +0100246 configdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100247 self->config_file = g_build_filename (configdir, "daemon.conf", NULL);
248 if (g_file_test (self->config_file, G_FILE_TEST_EXISTS)) {
Richard Hughesd1808aa2019-12-10 15:20:30 +0000249 if (!fu_config_reload (self, error))
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500250 return FALSE;
251 } else {
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100252 g_warning ("Daemon configuration %s not found", self->config_file);
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500253 }
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000254
Richard Hughesd1808aa2019-12-10 15:20:30 +0000255 /* set up a notify watch */
256 file = g_file_new_for_path (self->config_file);
257 self->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error);
258 if (self->monitor == NULL)
Richard Hughes1fd3ecf2018-04-16 10:53:46 +0100259 return FALSE;
Richard Hughesd1808aa2019-12-10 15:20:30 +0000260 g_signal_connect (self->monitor, "changed",
261 G_CALLBACK (fu_config_monitor_changed_cb), self);
Richard Hughes4c369702017-06-16 15:31:38 +0100262
263 /* success */
Richard Hughes980ef142017-06-16 12:45:27 +0100264 return TRUE;
265}
266
Richard Hughes75b965d2018-11-15 13:51:21 +0000267guint
268fu_config_get_idle_timeout (FuConfig *self)
269{
270 g_return_val_if_fail (FU_IS_CONFIG (self), 0);
271 return self->idle_timeout;
272}
273
Richard Hughes4c369702017-06-16 15:31:38 +0100274GPtrArray *
Richard Hughes85226fd2020-06-30 14:43:48 +0100275fu_config_get_disabled_devices (FuConfig *self)
Richard Hughes980ef142017-06-16 12:45:27 +0100276{
277 g_return_val_if_fail (FU_IS_CONFIG (self), NULL);
Richard Hughes85226fd2020-06-30 14:43:48 +0100278 return self->disabled_devices;
Richard Hughes980ef142017-06-16 12:45:27 +0100279}
280
Richard Hughes31206832020-07-27 15:31:11 +0100281GPtrArray *
282fu_config_get_blocked_firmware (FuConfig *self)
283{
284 g_return_val_if_fail (FU_IS_CONFIG (self), NULL);
285 return self->blocked_firmware;
286}
287
Richard Hughesb856f0b2021-01-28 10:59:49 +0000288guint
289fu_config_get_uri_scheme_prio (FuConfig *self, const gchar *scheme)
290{
291#if GLIB_CHECK_VERSION(2,54,0)
292 guint idx = G_MAXUINT;
293 g_ptr_array_find_with_equal_func (self->uri_schemes,
294 scheme, g_str_equal, &idx);
295 return idx;
296#else
297 for (guint i = 0; i < self->uri_schemes->len; i++)
298 const gchar *scheme_tmp = g_ptr_array_index (self->uri_schemes, i);
299 if (g_str_equal (scheme_tmp, scheme))
300 return i;
301 }
302 return G_MAXUINT;
303#endif
304}
305
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000306guint64
307fu_config_get_archive_size_max (FuConfig *self)
308{
309 g_return_val_if_fail (FU_IS_CONFIG (self), 0);
310 return self->archive_size_max;
311}
312
Richard Hughes980ef142017-06-16 12:45:27 +0100313GPtrArray *
Richard Hughes85226fd2020-06-30 14:43:48 +0100314fu_config_get_disabled_plugins (FuConfig *self)
Richard Hughes980ef142017-06-16 12:45:27 +0100315{
316 g_return_val_if_fail (FU_IS_CONFIG (self), NULL);
Richard Hughes85226fd2020-06-30 14:43:48 +0100317 return self->disabled_plugins;
Richard Hughes980ef142017-06-16 12:45:27 +0100318}
319
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000320GPtrArray *
321fu_config_get_approved_firmware (FuConfig *self)
322{
323 g_return_val_if_fail (FU_IS_CONFIG (self), NULL);
324 return self->approved_firmware;
325}
326
Mario Limonciellod81ea2e2020-01-13 14:11:43 -0600327gboolean
328fu_config_get_update_motd (FuConfig *self)
329{
330 g_return_val_if_fail (FU_IS_CONFIG (self), FALSE);
331 return self->update_motd;
332}
333
Mario Limonciello4fa95a72020-03-28 10:50:57 -0500334gboolean
335fu_config_get_enumerate_all_devices (FuConfig *self)
336{
337 g_return_val_if_fail (FU_IS_CONFIG (self), FALSE);
338 return self->enumerate_all_devices;
339}
340
Richard Hughes980ef142017-06-16 12:45:27 +0100341static void
342fu_config_class_init (FuConfigClass *klass)
343{
344 GObjectClass *object_class = G_OBJECT_CLASS (klass);
345 object_class->finalize = fu_config_finalize;
Mario Limonciello263cab92019-08-20 17:16:00 -0500346
347 signals[SIGNAL_CHANGED] =
348 g_signal_new ("changed",
349 G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
350 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
351 G_TYPE_NONE, 0);
Richard Hughes980ef142017-06-16 12:45:27 +0100352}
353
354static void
355fu_config_init (FuConfig *self)
356{
Richard Hughes85226fd2020-06-30 14:43:48 +0100357 self->disabled_devices = g_ptr_array_new_with_free_func (g_free);
358 self->disabled_plugins = g_ptr_array_new_with_free_func (g_free);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000359 self->approved_firmware = g_ptr_array_new_with_free_func (g_free);
Richard Hughes31206832020-07-27 15:31:11 +0100360 self->blocked_firmware = g_ptr_array_new_with_free_func (g_free);
Richard Hughesb856f0b2021-01-28 10:59:49 +0000361 self->uri_schemes = g_ptr_array_new_with_free_func (g_free);
Richard Hughes980ef142017-06-16 12:45:27 +0100362}
363
364static void
365fu_config_finalize (GObject *obj)
366{
367 FuConfig *self = FU_CONFIG (obj);
368
Richard Hughes0b6f5832020-09-01 20:15:02 +0100369 if (self->monitor != NULL) {
370 g_file_monitor_cancel (self->monitor);
Richard Hughesd1808aa2019-12-10 15:20:30 +0000371 g_object_unref (self->monitor);
Richard Hughes0b6f5832020-09-01 20:15:02 +0100372 }
Richard Hughes85226fd2020-06-30 14:43:48 +0100373 g_ptr_array_unref (self->disabled_devices);
374 g_ptr_array_unref (self->disabled_plugins);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000375 g_ptr_array_unref (self->approved_firmware);
Richard Hughes31206832020-07-27 15:31:11 +0100376 g_ptr_array_unref (self->blocked_firmware);
Richard Hughesb856f0b2021-01-28 10:59:49 +0000377 g_ptr_array_unref (self->uri_schemes);
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100378 g_free (self->config_file);
Richard Hughes980ef142017-06-16 12:45:27 +0100379
380 G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj);
381}
382
383FuConfig *
384fu_config_new (void)
385{
386 FuConfig *self;
387 self = g_object_new (FU_TYPE_CONFIG, NULL);
388 return FU_CONFIG (self);
389}