~behda/+junk/udisks2.original

« back to all changes in this revision

Viewing changes to src/udiskscrypttabmonitor.c

  • Committer: behda
  • Date: 2014-05-24 15:15:11 UTC
  • Revision ID: pauvitk@gmail.com-20140524151511-3vtr0uubjewx3z2j
Initial commit of source code and Debian packaging.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
 
2
 *
 
3
 * Copyright (C) 2008 David Zeuthen <zeuthen@gmail.com>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
#include <glib/gi18n-lib.h>
 
23
 
 
24
#include <stdlib.h>
 
25
#include <stdio.h>
 
26
#include <signal.h>
 
27
#include <errno.h>
 
28
#include <string.h>
 
29
#include <sys/types.h>
 
30
#include <sys/stat.h>
 
31
 
 
32
#include <glib.h>
 
33
#include <glib-object.h>
 
34
 
 
35
#include "udiskscrypttabmonitor.h"
 
36
#include "udiskscrypttabentry.h"
 
37
#include "udisksprivate.h"
 
38
#include "udiskslogging.h"
 
39
 
 
40
/**
 
41
 * SECTION:udiskscrypttabmonitor
 
42
 * @title: UDisksCrypttabMonitor
 
43
 * @short_description: Monitors entries in the crypttab file
 
44
 *
 
45
 * This type is used for monitoring entries in the
 
46
 * <filename>/etc/crypttab</filename> file.
 
47
 */
 
48
 
 
49
/**
 
50
 * UDisksCrypttabMonitor:
 
51
 *
 
52
 * The #UDisksCrypttabMonitor structure contains only private data and
 
53
 * should only be accessed using the provided API.
 
54
 */
 
55
struct _UDisksCrypttabMonitor
 
56
{
 
57
  GObject parent_instance;
 
58
 
 
59
  gboolean have_data;
 
60
  GList *crypttab_entries;
 
61
 
 
62
  GFileMonitor *file_monitor;
 
63
};
 
64
 
 
65
typedef struct _UDisksCrypttabMonitorClass UDisksCrypttabMonitorClass;
 
66
 
 
67
struct _UDisksCrypttabMonitorClass
 
68
{
 
69
  GObjectClass parent_class;
 
70
 
 
71
  void (*entry_added)   (UDisksCrypttabMonitor  *monitor,
 
72
                         UDisksCrypttabEntry    *entry);
 
73
  void (*entry_removed) (UDisksCrypttabMonitor  *monitor,
 
74
                         UDisksCrypttabEntry    *entry);
 
75
};
 
76
 
 
77
/*--------------------------------------------------------------------------------------------------------------*/
 
78
 
 
79
enum
 
80
  {
 
81
    ENTRY_ADDED_SIGNAL,
 
82
    ENTRY_REMOVED_SIGNAL,
 
83
    LAST_SIGNAL,
 
84
  };
 
85
 
 
86
static guint signals[LAST_SIGNAL] = { 0 };
 
87
 
 
88
G_DEFINE_TYPE (UDisksCrypttabMonitor, udisks_crypttab_monitor, G_TYPE_OBJECT)
 
89
 
 
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);
 
93
 
 
94
static void
 
95
udisks_crypttab_monitor_finalize (GObject *object)
 
96
{
 
97
  UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
 
98
 
 
99
  g_object_unref (monitor->file_monitor);
 
100
 
 
101
  g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
 
102
  g_list_free (monitor->crypttab_entries);
 
103
 
 
104
  if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize != NULL)
 
105
    G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->finalize (object);
 
106
}
 
107
 
 
108
static void
 
109
udisks_crypttab_monitor_init (UDisksCrypttabMonitor *monitor)
 
110
{
 
111
  monitor->crypttab_entries = NULL;
 
112
}
 
113
 
 
114
static void
 
115
udisks_crypttab_monitor_class_init (UDisksCrypttabMonitorClass *klass)
 
116
{
 
117
  GObjectClass *gobject_class = (GObjectClass *) klass;
 
118
 
 
119
  gobject_class->finalize    = udisks_crypttab_monitor_finalize;
 
120
  gobject_class->constructed = udisks_crypttab_monitor_constructed;
 
121
 
 
122
  /**
 
123
   * UDisksCrypttabMonitor::entry-added
 
124
   * @monitor: A #UDisksCrypttabMonitor.
 
125
   * @entry: The #UDisksCrypttabEntry that was added.
 
126
   *
 
127
   * Emitted when a crypttab entry is added.
 
128
   *
 
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.
 
132
   */
 
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),
 
137
                                              NULL,
 
138
                                              NULL,
 
139
                                              g_cclosure_marshal_VOID__OBJECT,
 
140
                                              G_TYPE_NONE,
 
141
                                              1,
 
142
                                              UDISKS_TYPE_CRYPTTAB_ENTRY);
 
143
 
 
144
  /**
 
145
   * UDisksCrypttabMonitor::entry-removed
 
146
   * @monitor: A #UDisksCrypttabMonitor.
 
147
   * @entry: The #UDisksCrypttabEntry that was removed.
 
148
   *
 
149
   * Emitted when a crypttab entry is removed.
 
150
   *
 
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.
 
154
   */
 
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),
 
159
                                                NULL,
 
160
                                                NULL,
 
161
                                                g_cclosure_marshal_VOID__OBJECT,
 
162
                                                G_TYPE_NONE,
 
163
                                                1,
 
164
                                                UDISKS_TYPE_CRYPTTAB_ENTRY);
 
165
}
 
166
 
 
167
static void
 
168
diff_sorted_lists (GList *list1,
 
169
                   GList *list2,
 
170
                   GCompareFunc compare,
 
171
                   GList **added,
 
172
                   GList **removed)
 
173
{
 
174
  int order;
 
175
 
 
176
  *added = *removed = NULL;
 
177
 
 
178
  while (list1 != NULL && list2 != NULL)
 
179
    {
 
180
      order = (*compare) (list1->data, list2->data);
 
181
      if (order < 0)
 
182
        {
 
183
          *removed = g_list_prepend (*removed, list1->data);
 
184
          list1 = list1->next;
 
185
        }
 
186
      else if (order > 0)
 
187
        {
 
188
          *added = g_list_prepend (*added, list2->data);
 
189
          list2 = list2->next;
 
190
        }
 
191
      else
 
192
        { /* same item */
 
193
          list1 = list1->next;
 
194
          list2 = list2->next;
 
195
        }
 
196
    }
 
197
 
 
198
  while (list1 != NULL)
 
199
    {
 
200
      *removed = g_list_prepend (*removed, list1->data);
 
201
      list1 = list1->next;
 
202
    }
 
203
  while (list2 != NULL)
 
204
    {
 
205
      *added = g_list_prepend (*added, list2->data);
 
206
      list2 = list2->next;
 
207
    }
 
208
}
 
209
 
 
210
static void
 
211
reload_crypttab_entries (UDisksCrypttabMonitor *monitor)
 
212
{
 
213
  GList *old_crypttab_entries;
 
214
  GList *cur_crypttab_entries;
 
215
  GList *added;
 
216
  GList *removed;
 
217
  GList *l;
 
218
 
 
219
  udisks_crypttab_monitor_ensure (monitor);
 
220
 
 
221
  old_crypttab_entries = g_list_copy (monitor->crypttab_entries);
 
222
  g_list_foreach (old_crypttab_entries, (GFunc) g_object_ref, NULL);
 
223
 
 
224
  udisks_crypttab_monitor_invalidate (monitor);
 
225
  udisks_crypttab_monitor_ensure (monitor);
 
226
 
 
227
  cur_crypttab_entries = g_list_copy (monitor->crypttab_entries);
 
228
 
 
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);
 
232
 
 
233
  for (l = removed; l != NULL; l = l->next)
 
234
    {
 
235
      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
 
236
      g_signal_emit (monitor, signals[ENTRY_REMOVED_SIGNAL], 0, entry);
 
237
    }
 
238
 
 
239
  for (l = added; l != NULL; l = l->next)
 
240
    {
 
241
      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
 
242
      g_signal_emit (monitor, signals[ENTRY_ADDED_SIGNAL], 0, entry);
 
243
    }
 
244
 
 
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);
 
249
  g_list_free (added);
 
250
}
 
251
 
 
252
static void
 
253
on_file_monitor_changed (GFileMonitor      *file_monitor,
 
254
                         GFile             *file,
 
255
                         GFile             *other_file,
 
256
                         GFileMonitorEvent  event_type,
 
257
                         gpointer           user_data)
 
258
{
 
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)
 
263
    {
 
264
      udisks_debug ("/etc/crypttab changed!");
 
265
      reload_crypttab_entries (monitor);
 
266
    }
 
267
}
 
268
 
 
269
static void
 
270
udisks_crypttab_monitor_constructed (GObject *object)
 
271
{
 
272
  UDisksCrypttabMonitor *monitor = UDISKS_CRYPTTAB_MONITOR (object);
 
273
  GError *error;
 
274
  GFile *file;
 
275
 
 
276
  file = g_file_new_for_path ("/etc/crypttab");
 
277
  error = NULL;
 
278
  monitor->file_monitor = g_file_monitor_file (file,
 
279
                                               G_FILE_MONITOR_NONE,
 
280
                                               NULL, /* cancellable */
 
281
                                               &error);
 
282
  if (monitor->file_monitor == NULL)
 
283
    {
 
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);
 
287
    }
 
288
  else
 
289
    {
 
290
      g_signal_connect (monitor->file_monitor,
 
291
                        "changed",
 
292
                        G_CALLBACK (on_file_monitor_changed),
 
293
                        monitor);
 
294
    }
 
295
  g_object_unref (file);
 
296
 
 
297
  if (G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed != NULL)
 
298
    (*G_OBJECT_CLASS (udisks_crypttab_monitor_parent_class)->constructed) (object);
 
299
}
 
300
 
 
301
/**
 
302
 * udisks_crypttab_monitor_new:
 
303
 *
 
304
 * Creates a new #UDisksCrypttabMonitor object.
 
305
 *
 
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.
 
309
 *
 
310
 * Returns: A #UDisksCrypttabMonitor. Free with g_object_unref().
 
311
 */
 
312
UDisksCrypttabMonitor *
 
313
udisks_crypttab_monitor_new (void)
 
314
{
 
315
  return UDISKS_CRYPTTAB_MONITOR (g_object_new (UDISKS_TYPE_CRYPTTAB_MONITOR, NULL));
 
316
}
 
317
 
 
318
static void
 
319
udisks_crypttab_monitor_invalidate (UDisksCrypttabMonitor *monitor)
 
320
{
 
321
  monitor->have_data = FALSE;
 
322
 
 
323
  g_list_foreach (monitor->crypttab_entries, (GFunc) g_object_unref, NULL);
 
324
  g_list_free (monitor->crypttab_entries);
 
325
  monitor->crypttab_entries = NULL;
 
326
}
 
327
 
 
328
 
 
329
/* ---------------------------------------------------------------------------------------------------- */
 
330
 
 
331
static gboolean
 
332
have_entry (UDisksCrypttabMonitor *monitor,
 
333
            UDisksCrypttabEntry   *entry)
 
334
{
 
335
  GList *l;
 
336
  gboolean ret;
 
337
 
 
338
  ret = FALSE;
 
339
  for (l = monitor->crypttab_entries; l != NULL; l = l->next)
 
340
    {
 
341
      UDisksCrypttabEntry *other_entry = UDISKS_CRYPTTAB_ENTRY (l->data);
 
342
      if (udisks_crypttab_entry_compare (entry, other_entry) == 0)
 
343
        {
 
344
          ret = TRUE;
 
345
          goto out;
 
346
        }
 
347
    }
 
348
 out:
 
349
  return ret;
 
350
}
 
351
 
 
352
static void
 
353
udisks_crypttab_monitor_ensure (UDisksCrypttabMonitor *monitor)
 
354
{
 
355
  gchar *contents;
 
356
  gchar **lines;
 
357
  GError *error;
 
358
  guint n;
 
359
 
 
360
  contents = NULL;
 
361
  lines = NULL;
 
362
 
 
363
  if (monitor->have_data)
 
364
    goto out;
 
365
 
 
366
  error = NULL;
 
367
  if (!g_file_get_contents ("/etc/crypttab",
 
368
                            &contents,
 
369
                            NULL, /* size */
 
370
                            &error))
 
371
    {
 
372
      if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
 
373
        {
 
374
          udisks_warning ("Error opening /etc/crypttab file: %s (%s, %d)",
 
375
                          error->message, g_quark_to_string (error->domain), error->code);
 
376
        }
 
377
      g_error_free (error);
 
378
      goto out;
 
379
    }
 
380
 
 
381
  lines = g_strsplit (contents, "\n", 0);
 
382
 
 
383
  for (n = 0; lines != NULL && lines[n] != NULL; n++)
 
384
    {
 
385
      gchar **tokens;
 
386
      guint num_tokens;
 
387
      UDisksCrypttabEntry *entry;
 
388
 
 
389
      const gchar *line = lines[n];
 
390
      if (strlen (line) == 0)
 
391
        continue;
 
392
      if (line[0] == '#')
 
393
        continue;
 
394
 
 
395
      tokens = g_strsplit_set (line, " \t", 0);
 
396
      num_tokens = g_strv_length (tokens);
 
397
      if (num_tokens < 2)
 
398
        {
 
399
          udisks_warning ("Line %d of /etc/crypttab only contains %d tokens", n, num_tokens);
 
400
          goto continue_loop;
 
401
        }
 
402
 
 
403
      entry = _udisks_crypttab_entry_new (tokens[0],
 
404
                                          tokens[1],
 
405
                                          num_tokens >= 3 ? tokens[2] : NULL,
 
406
                                          num_tokens >= 4 ? tokens[3] : NULL);
 
407
      if (!have_entry (monitor, entry))
 
408
        {
 
409
          monitor->crypttab_entries = g_list_prepend (monitor->crypttab_entries, entry);
 
410
        }
 
411
      else
 
412
        {
 
413
          g_object_unref (entry);
 
414
        }
 
415
 
 
416
    continue_loop:
 
417
      g_strfreev (tokens);
 
418
    }
 
419
 
 
420
  monitor->have_data = TRUE;
 
421
 
 
422
 out:
 
423
  g_free (contents);
 
424
  g_strfreev (lines);
 
425
}
 
426
 
 
427
/**
 
428
 * udisks_crypttab_monitor_get_entries:
 
429
 * @monitor: A #UDisksCrypttabMonitor.
 
430
 *
 
431
 * Gets all /etc/crypttab entries
 
432
 *
 
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().
 
434
 */
 
435
GList *
 
436
udisks_crypttab_monitor_get_entries (UDisksCrypttabMonitor  *monitor)
 
437
{
 
438
  GList *ret;
 
439
 
 
440
  g_return_val_if_fail (UDISKS_IS_CRYPTTAB_MONITOR (monitor), NULL);
 
441
 
 
442
  udisks_crypttab_monitor_ensure (monitor);
 
443
 
 
444
  ret = g_list_copy (monitor->crypttab_entries);
 
445
  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
 
446
  return ret;
 
447
}
 
448