1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2008 David Zeuthen <zeuthen@gmail.com>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <glib/gi18n-lib.h>
29
#include <sys/types.h>
33
#include <glib-object.h>
35
#include "udiskscrypttabmonitor.h"
36
#include "udiskscrypttabentry.h"
37
#include "udisksprivate.h"
38
#include "udiskslogging.h"
41
* SECTION:udiskscrypttabmonitor
42
* @title: UDisksCrypttabMonitor
43
* @short_description: Monitors entries in the crypttab file
45
* This type is used for monitoring entries in the
46
* <filename>/etc/crypttab</filename> file.
50
* UDisksCrypttabMonitor:
52
* The #UDisksCrypttabMonitor structure contains only private data and
53
* should only be accessed using the provided API.
55
struct _UDisksCrypttabMonitor
57
GObject parent_instance;
60
GList *crypttab_entries;
62
GFileMonitor *file_monitor;
65
typedef struct _UDisksCrypttabMonitorClass UDisksCrypttabMonitorClass;
67
struct _UDisksCrypttabMonitorClass
69
GObjectClass parent_class;
71
void (*entry_added) (UDisksCrypttabMonitor *monitor,
72
UDisksCrypttabEntry *entry);
73
void (*entry_removed) (UDisksCrypttabMonitor *monitor,
74
UDisksCrypttabEntry *entry);
77
/*--------------------------------------------------------------------------------------------------------------*/
86
static guint signals[LAST_SIGNAL] = { 0 };
88
G_DEFINE_TYPE (UDisksCrypttabMonitor, udisks_crypttab_monitor, G_TYPE_OBJECT)
90
static void udisks_crypttab_monitor_ensure (UDisksCrypttabMonitor *monitor);
91
static void udisks_crypttab_monitor_invalidate (UDisksCrypttabMonitor *monitor);
92
static void udisks_crypttab_monitor_constructed (GObject *object);
95
udisks_crypttab_monitor_finalize (GObject *object)
97
UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
99
g_object_unref (monitor->file_monitor);
101
g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
102
g_list_free (monitor->crypttab_entries);
104
if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize != NULL)
105
G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize (object);
109
udisks_crypttab_monitor_init (UDisksCrypttabMonitor *monitor)
111
monitor->crypttab_entries = NULL;
115
udisks_crypttab_monitor_class_init (UDisksCrypttabMonitorClass *klass)
117
GObjectClass *gobject_class = (GObjectClass *) klass;
119
gobject_class->finalize = udisks_crypttab_monitor_finalize;
120
gobject_class->constructed = udisks_crypttab_monitor_constructed;
123
* UDisksCrypttabMonitor::entry-added
124
* @monitor: A #UDisksCrypttabMonitor.
125
* @entry: The #UDisksCrypttabEntry that was added.
127
* Emitted when a crypttab entry is added.
129
* This signal is emitted in the
130
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
131
* that @monitor was created in.
133
signals[ENTRY_ADDED_SIGNAL] = g_signal_new ("entry-added",
134
G_OBJECT_CLASS_TYPE (klass),
135
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
136
G_STRUCT_OFFSET (UDisksCrypttabMonitorClass, entry_added),
139
g_cclosure_marshal_VOID__OBJECT,
142
UDISKS_TYPE_CRYPTTAB_ENTRY);
145
* UDisksCrypttabMonitor::entry-removed
146
* @monitor: A #UDisksCrypttabMonitor.
147
* @entry: The #UDisksCrypttabEntry that was removed.
149
* Emitted when a crypttab entry is removed.
151
* This signal is emitted in the
152
* <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
153
* that @monitor was created in.
155
signals[ENTRY_REMOVED_SIGNAL] = g_signal_new ("entry-removed",
156
G_OBJECT_CLASS_TYPE (klass),
157
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
158
G_STRUCT_OFFSET (UDisksCrypttabMonitorClass, entry_removed),
161
g_cclosure_marshal_VOID__OBJECT,
164
UDISKS_TYPE_CRYPTTAB_ENTRY);
168
diff_sorted_lists (GList *list1,
170
GCompareFunc compare,
176
*added = *removed = NULL;
178
while (list1 != NULL && list2 != NULL)
180
order = (*compare) (list1->data, list2->data);
183
*removed = g_list_prepend (*removed, list1->data);
188
*added = g_list_prepend (*added, list2->data);
198
while (list1 != NULL)
200
*removed = g_list_prepend (*removed, list1->data);
203
while (list2 != NULL)
205
*added = g_list_prepend (*added, list2->data);
211
reload_crypttab_entries (UDisksCrypttabMonitor *monitor)
213
GList *old_crypttab_entries;
214
GList *cur_crypttab_entries;
219
udisks_crypttab_monitor_ensure (monitor);
221
old_crypttab_entries = g_list_copy (monitor->crypttab_entries);
222
g_list_foreach (old_crypttab_entries, (GFunc) g_object_ref, NULL);
224
udisks_crypttab_monitor_invalidate (monitor);
225
udisks_crypttab_monitor_ensure (monitor);
227
cur_crypttab_entries = g_list_copy (monitor->crypttab_entries);
229
old_crypttab_entries = g_list_sort (old_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare);
230
cur_crypttab_entries = g_list_sort (cur_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare);
231
diff_sorted_lists (old_crypttab_entries, cur_crypttab_entries, (GCompareFunc) udisks_crypttab_entry_compare, &added, &removed);
233
for (l = removed; l != NULL; l = l->next)
235
UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
236
g_signal_emit (monitor, signals[ENTRY_REMOVED_SIGNAL], 0, entry);
239
for (l = added; l != NULL; l = l->next)
241
UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
242
g_signal_emit (monitor, signals[ENTRY_ADDED_SIGNAL], 0, entry);
245
g_list_foreach (old_crypttab_entries, (GFunc) g_object_unref, NULL);
246
g_list_free (old_crypttab_entries);
247
g_list_free (cur_crypttab_entries);
248
g_list_free (removed);
253
on_file_monitor_changed (GFileMonitor *file_monitor,
256
GFileMonitorEvent event_type,
259
UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (user_data);
260
if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
261
event_type == G_FILE_MONITOR_EVENT_CREATED ||
262
event_type == G_FILE_MONITOR_EVENT_DELETED)
264
udisks_debug ("/etc/crypttab changed!");
265
reload_crypttab_entries (monitor);
270
udisks_crypttab_monitor_constructed (GObject *object)
272
UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
276
file = g_file_new_for_path ("/etc/crypttab");
278
monitor->file_monitor = g_file_monitor_file (file,
280
NULL, /* cancellable */
282
if (monitor->file_monitor == NULL)
284
udisks_error ("Error monitoring /etc/crypttab: %s (%s, %d)",
285
error->message, g_quark_to_string (error->domain), error->code);
286
g_error_free (error);
290
g_signal_connect (monitor->file_monitor,
292
G_CALLBACK (on_file_monitor_changed),
295
g_object_unref (file);
297
if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed != NULL)
298
(*G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed) (object);
302
* udisks_crypttab_monitor_new:
304
* Creates a new #UDisksCrypttabMonitor object.
306
* Signals are emitted in the <link
307
* linkend="g-main-context-push-thread-default">thread-default main
308
* loop</link> that this function is called from.
310
* Returns: A #UDisksCrypttabMonitor. Free with g_object_unref().
312
UDisksCrypttabMonitor *
313
udisks_crypttab_monitor_new (void)
315
return UDISKS_CRYPTTAB_MONITOR (g_object_new (UDISKS_TYPE_CRYPTTAB_MONITOR, NULL));
319
udisks_crypttab_monitor_invalidate (UDisksCrypttabMonitor *monitor)
321
monitor->have_data = FALSE;
323
g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
324
g_list_free (monitor->crypttab_entries);
325
monitor->crypttab_entries = NULL;
329
/* ---------------------------------------------------------------------------------------------------- */
332
have_entry (UDisksCrypttabMonitor *monitor,
333
UDisksCrypttabEntry *entry)
339
for (l = monitor->crypttab_entries; l != NULL; l = l->next)
341
UDisksCrypttabEntry *other_entry = UDISKS_CRYPTTAB_ENTRY (l->data);
342
if (udisks_crypttab_entry_compare (entry, other_entry) == 0)
353
udisks_crypttab_monitor_ensure (UDisksCrypttabMonitor *monitor)
363
if (monitor->have_data)
367
if (!g_file_get_contents ("/etc/crypttab",
372
if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
374
udisks_warning ("Error opening /etc/crypttab file: %s (%s, %d)",
375
error->message, g_quark_to_string (error->domain), error->code);
377
g_error_free (error);
381
lines = g_strsplit (contents, "\n", 0);
383
for (n = 0; lines != NULL && lines[n] != NULL; n++)
387
UDisksCrypttabEntry *entry;
389
const gchar *line = lines[n];
390
if (strlen (line) == 0)
395
tokens = g_strsplit_set (line, " \t", 0);
396
num_tokens = g_strv_length (tokens);
399
udisks_warning ("Line %d of /etc/crypttab only contains %d tokens", n, num_tokens);
403
entry = _udisks_crypttab_entry_new (tokens[0],
405
num_tokens >= 3 ? tokens[2] : NULL,
406
num_tokens >= 4 ? tokens[3] : NULL);
407
if (!have_entry (monitor, entry))
409
monitor->crypttab_entries = g_list_prepend (monitor->crypttab_entries, entry);
413
g_object_unref (entry);
420
monitor->have_data = TRUE;
428
* udisks_crypttab_monitor_get_entries:
429
* @monitor: A #UDisksCrypttabMonitor.
431
* Gets all /etc/crypttab entries
433
* Returns: (transfer full) (element-type UDisksCrypttabEntry): A list of #UDisksCrypttabEntry objects that must be freed with g_list_free() after each element has been freed with g_object_unref().
436
udisks_crypttab_monitor_get_entries (UDisksCrypttabMonitor *monitor)
440
g_return_val_if_fail (UDISKS_IS_CRYPTTAB_MONITOR (monitor), NULL);
442
udisks_crypttab_monitor_ensure (monitor);
444
ret = g_list_copy (monitor->crypttab_entries);
445
g_list_foreach (ret, (GFunc) g_object_ref, NULL);