blob: 2cb2b171a4f80a9478b37176c0dbaf5190cc181e [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;
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 Hughesc7bbbc22018-01-02 22:22:25 +000033 guint64 archive_size_max;
Richard Hughes75b965d2018-11-15 13:51:21 +000034 guint idle_timeout;
Mario Limonciellobfcf75b2019-04-17 15:05:39 +010035 gchar *config_file;
Mario Limonciellod81ea2e2020-01-13 14:11:43 -060036 gboolean update_motd;
Mario Limonciello4fa95a72020-03-28 10:50:57 -050037 gboolean enumerate_all_devices;
Richard Hughes980ef142017-06-16 12:45:27 +010038};
39
40G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT)
41
Mario Limonciello263cab92019-08-20 17:16:00 -050042static void
43fu_config_emit_changed (FuConfig *self)
44{
45 g_debug ("::configuration changed");
46 g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
47}
48
Richard Hughes4c369702017-06-16 15:31:38 +010049static gboolean
Richard Hughesd1808aa2019-12-10 15:20:30 +000050fu_config_reload (FuConfig *self, GError **error)
Richard Hughescda1cdf2017-06-16 21:49:35 +010051{
Richard Hughes321f77a2018-02-14 10:25:53 +000052 guint64 archive_size_max;
Richard Hughes75b965d2018-11-15 13:51:21 +000053 guint idle_timeout;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +000054 g_auto(GStrv) approved_firmware = NULL;
Richard Hughes980ef142017-06-16 12:45:27 +010055 g_auto(GStrv) devices = NULL;
56 g_auto(GStrv) plugins = NULL;
Mario Limonciello38027e62019-04-17 15:16:07 +010057 g_autofree gchar *domains = NULL;
Richard Hughesd1808aa2019-12-10 15:20:30 +000058 g_autoptr(GKeyFile) keyfile = g_key_file_new ();
Mario Limonciello4fa95a72020-03-28 10:50:57 -050059 g_autoptr(GError) error_enumerate_all = NULL;
Richard Hughes980ef142017-06-16 12:45:27 +010060
Richard Hughesd1808aa2019-12-10 15:20:30 +000061 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 Hughes980ef142017-06-16 12:45:27 +010064 return FALSE;
65
Richard Hughes980ef142017-06-16 12:45:27 +010066 /* get blacklisted devices */
Richard Hughesd1808aa2019-12-10 15:20:30 +000067 g_ptr_array_set_size (self->blacklist_devices, 0);
68 devices = g_key_file_get_string_list (keyfile,
Richard Hughes980ef142017-06-16 12:45:27 +010069 "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 Hughesd1808aa2019-12-10 15:20:30 +000081 g_ptr_array_set_size (self->blacklist_plugins, 0);
82 plugins = g_key_file_get_string_list (keyfile,
Richard Hughes980ef142017-06-16 12:45:27 +010083 "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 Hughes8dd4c1c2019-03-03 18:27:57 +000094 /* get approved firmware */
Richard Hughesd1808aa2019-12-10 15:20:30 +000095 g_ptr_array_set_size (self->approved_firmware, 0);
96 approved_firmware = g_key_file_get_string_list (keyfile,
Richard Hughes8dd4c1c2019-03-03 18:27:57 +000097 "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 Hughesc7bbbc22018-01-02 22:22:25 +0000108 /* get maximum archive size, defaulting to something sane */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000109 archive_size_max = g_key_file_get_uint64 (keyfile,
Richard Hughes321f77a2018-02-14 10:25:53 +0000110 "fwupd",
111 "ArchiveSizeMax",
112 NULL);
113 if (archive_size_max > 0)
114 self->archive_size_max = archive_size_max *= 0x100000;
Richard Hughes75b965d2018-11-15 13:51:21 +0000115
116 /* get idle timeout */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000117 idle_timeout = g_key_file_get_uint64 (keyfile,
Richard Hughes75b965d2018-11-15 13:51:21 +0000118 "fwupd",
119 "IdleTimeout",
120 NULL);
121 if (idle_timeout > 0)
122 self->idle_timeout = idle_timeout;
Mario Limonciello38027e62019-04-17 15:16:07 +0100123
124 /* get the domains to run in verbose */
Richard Hughesd1808aa2019-12-10 15:20:30 +0000125 domains = g_key_file_get_string (keyfile,
Mario Limonciello38027e62019-04-17 15:16:07 +0100126 "fwupd",
127 "VerboseDomains",
128 NULL);
129 if (domains != NULL && domains[0] != '\0')
130 g_setenv ("FWUPD_VERBOSE", domains, TRUE);
131
Mario Limonciellod81ea2e2020-01-13 14:11:43 -0600132 /* 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 Limonciello4fa95a72020-03-28 10:50:57 -0500138 /* 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 Limonciellod82e3b52018-05-22 10:18:27 -0500149 return TRUE;
150}
151
Richard Hughesd1808aa2019-12-10 15:20:30 +0000152static void
153fu_config_monitor_changed_cb (GFileMonitor *monitor,
154 GFile *file,
155 GFile *other_file,
156 GFileMonitorEvent event_type,
157 gpointer user_data)
Richard Hughes481aa2a2018-09-18 20:51:46 +0100158{
Richard Hughesd1808aa2019-12-10 15:20:30 +0000159 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 Hughes481aa2a2018-09-18 20:51:46 +0100165}
166
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500167gboolean
Richard Hughesd1808aa2019-12-10 15:20:30 +0000168fu_config_set_key_value (FuConfig *self, const gchar *key, const gchar *value, GError **error)
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500169{
Richard Hughesd1808aa2019-12-10 15:20:30 +0000170 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
180gboolean
181fu_config_load (FuConfig *self, GError **error)
182{
Richard Hughes4be17d12018-05-30 20:36:29 +0100183 g_autofree gchar *configdir = NULL;
Richard Hughesd1808aa2019-12-10 15:20:30 +0000184 g_autoptr(GFile) file = NULL;
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500185
186 g_return_val_if_fail (FU_IS_CONFIG (self), FALSE);
Richard Hughesd1808aa2019-12-10 15:20:30 +0000187 g_return_val_if_fail (self->config_file == NULL, FALSE);
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500188
189 /* load the main daemon config file */
Richard Hughes4be17d12018-05-30 20:36:29 +0100190 configdir = fu_common_get_path (FU_PATH_KIND_SYSCONFDIR_PKG);
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100191 self->config_file = g_build_filename (configdir, "daemon.conf", NULL);
192 if (g_file_test (self->config_file, G_FILE_TEST_EXISTS)) {
Richard Hughesd1808aa2019-12-10 15:20:30 +0000193 if (!fu_config_reload (self, error))
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500194 return FALSE;
195 } else {
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100196 g_warning ("Daemon configuration %s not found", self->config_file);
Mario Limonciellod82e3b52018-05-22 10:18:27 -0500197 }
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000198
Richard Hughesd1808aa2019-12-10 15:20:30 +0000199 /* 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 Hughes1fd3ecf2018-04-16 10:53:46 +0100203 return FALSE;
Richard Hughesd1808aa2019-12-10 15:20:30 +0000204 g_signal_connect (self->monitor, "changed",
205 G_CALLBACK (fu_config_monitor_changed_cb), self);
Richard Hughes4c369702017-06-16 15:31:38 +0100206
207 /* success */
Richard Hughes980ef142017-06-16 12:45:27 +0100208 return TRUE;
209}
210
Richard Hughes75b965d2018-11-15 13:51:21 +0000211guint
212fu_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 Hughes4c369702017-06-16 15:31:38 +0100218GPtrArray *
Richard Hughes980ef142017-06-16 12:45:27 +0100219fu_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 Hughesc7bbbc22018-01-02 22:22:25 +0000225guint64
226fu_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 Hughes980ef142017-06-16 12:45:27 +0100232GPtrArray *
233fu_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 Hughes8dd4c1c2019-03-03 18:27:57 +0000239GPtrArray *
240fu_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 Limonciellod81ea2e2020-01-13 14:11:43 -0600246gboolean
247fu_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 Limonciello4fa95a72020-03-28 10:50:57 -0500253gboolean
254fu_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 Hughes980ef142017-06-16 12:45:27 +0100260static void
261fu_config_class_init (FuConfigClass *klass)
262{
263 GObjectClass *object_class = G_OBJECT_CLASS (klass);
264 object_class->finalize = fu_config_finalize;
Mario Limonciello263cab92019-08-20 17:16:00 -0500265
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 Hughes980ef142017-06-16 12:45:27 +0100271}
272
273static void
274fu_config_init (FuConfig *self)
275{
Richard Hughesc7bbbc22018-01-02 22:22:25 +0000276 self->archive_size_max = 512 * 0x100000;
Richard Hughes980ef142017-06-16 12:45:27 +0100277 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 Hughes8dd4c1c2019-03-03 18:27:57 +0000279 self->approved_firmware = g_ptr_array_new_with_free_func (g_free);
Richard Hughes980ef142017-06-16 12:45:27 +0100280}
281
282static void
283fu_config_finalize (GObject *obj)
284{
285 FuConfig *self = FU_CONFIG (obj);
286
Richard Hughesd1808aa2019-12-10 15:20:30 +0000287 if (self->monitor != NULL)
288 g_object_unref (self->monitor);
Richard Hughes980ef142017-06-16 12:45:27 +0100289 g_ptr_array_unref (self->blacklist_devices);
290 g_ptr_array_unref (self->blacklist_plugins);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000291 g_ptr_array_unref (self->approved_firmware);
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100292 g_free (self->config_file);
Richard Hughes980ef142017-06-16 12:45:27 +0100293
294 G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj);
295}
296
297FuConfig *
298fu_config_new (void)
299{
300 FuConfig *self;
301 self = g_object_new (FU_TYPE_CONFIG, NULL);
302 return FU_CONFIG (self);
303}