~behda/+junk/udisks2.original

« back to all changes in this revision

Viewing changes to src/udiskslinuxdriveobject.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) 2007-2010 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 <string.h>
 
25
#include <stdlib.h>
 
26
#include <stdio.h>
 
27
 
 
28
#include "udiskslogging.h"
 
29
#include "udisksdaemon.h"
 
30
#include "udisksdaemonutil.h"
 
31
#include "udiskslinuxprovider.h"
 
32
#include "udiskslinuxdriveobject.h"
 
33
#include "udiskslinuxdrive.h"
 
34
#include "udiskslinuxdriveata.h"
 
35
#include "udiskslinuxblockobject.h"
 
36
#include "udiskslinuxdevice.h"
 
37
 
 
38
/**
 
39
 * SECTION:udiskslinuxdriveobject
 
40
 * @title: UDisksLinuxDriveObject
 
41
 * @short_description: Object representing a drive on Linux
 
42
 *
 
43
 * Object corresponding to a drive on Linux.
 
44
 */
 
45
 
 
46
typedef struct _UDisksLinuxDriveObjectClass   UDisksLinuxDriveObjectClass;
 
47
 
 
48
/**
 
49
 * UDisksLinuxDriveObject:
 
50
 *
 
51
 * The #UDisksLinuxDriveObject structure contains only private data and
 
52
 * should only be accessed using the provided API.
 
53
 */
 
54
struct _UDisksLinuxDriveObject
 
55
{
 
56
  UDisksObjectSkeleton parent_instance;
 
57
 
 
58
  UDisksDaemon *daemon;
 
59
 
 
60
  /* list of UDisksLinuxDevice objects for block objects */
 
61
  GList *devices;
 
62
 
 
63
  /* interfaces */
 
64
  UDisksDrive *iface_drive;
 
65
  UDisksDriveAta *iface_drive_ata;
 
66
};
 
67
 
 
68
struct _UDisksLinuxDriveObjectClass
 
69
{
 
70
  UDisksObjectSkeletonClass parent_class;
 
71
};
 
72
 
 
73
enum
 
74
{
 
75
  PROP_0,
 
76
  PROP_DAEMON,
 
77
  PROP_DEVICE
 
78
};
 
79
 
 
80
G_DEFINE_TYPE (UDisksLinuxDriveObject, udisks_linux_drive_object, UDISKS_TYPE_OBJECT_SKELETON);
 
81
 
 
82
static void
 
83
udisks_linux_drive_object_finalize (GObject *_object)
 
84
{
 
85
  UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object);
 
86
 
 
87
  /* note: we don't hold a ref to drive_object->daemon or drive_object->mount_monitor */
 
88
  g_list_foreach (object->devices, (GFunc) g_object_unref, NULL);
 
89
  g_list_free (object->devices);
 
90
 
 
91
  if (object->iface_drive != NULL)
 
92
    g_object_unref (object->iface_drive);
 
93
  if (object->iface_drive_ata != NULL)
 
94
    g_object_unref (object->iface_drive_ata);
 
95
 
 
96
  if (G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->finalize != NULL)
 
97
    G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->finalize (_object);
 
98
}
 
99
 
 
100
static void
 
101
udisks_linux_drive_object_get_property (GObject    *__object,
 
102
                                        guint       prop_id,
 
103
                                        GValue     *value,
 
104
                                        GParamSpec *pspec)
 
105
{
 
106
  UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (__object);
 
107
 
 
108
  switch (prop_id)
 
109
    {
 
110
    case PROP_DAEMON:
 
111
      g_value_set_object (value, udisks_linux_drive_object_get_daemon (object));
 
112
      break;
 
113
 
 
114
    default:
 
115
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
116
      break;
 
117
    }
 
118
}
 
119
 
 
120
static void
 
121
udisks_linux_drive_object_set_property (GObject      *__object,
 
122
                                        guint         prop_id,
 
123
                                        const GValue *value,
 
124
                                        GParamSpec   *pspec)
 
125
{
 
126
  UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (__object);
 
127
 
 
128
  switch (prop_id)
 
129
    {
 
130
    case PROP_DAEMON:
 
131
      g_assert (object->daemon == NULL);
 
132
      /* we don't take a reference to the daemon */
 
133
      object->daemon = g_value_get_object (value);
 
134
      break;
 
135
 
 
136
    case PROP_DEVICE:
 
137
      g_assert (object->devices == NULL);
 
138
      object->devices = g_list_prepend (NULL, g_value_dup_object (value));
 
139
      break;
 
140
 
 
141
    default:
 
142
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
143
      break;
 
144
    }
 
145
}
 
146
 
 
147
 
 
148
static void
 
149
udisks_linux_drive_object_init (UDisksLinuxDriveObject *object)
 
150
{
 
151
}
 
152
 
 
153
static GObjectConstructParam *
 
154
find_construct_property (guint                  n_construct_properties,
 
155
                         GObjectConstructParam *construct_properties,
 
156
                         const gchar           *name)
 
157
{
 
158
  guint n;
 
159
  for (n = 0; n < n_construct_properties; n++)
 
160
    if (g_strcmp0 (g_param_spec_get_name (construct_properties[n].pspec), name) == 0)
 
161
      return &construct_properties[n];
 
162
  return NULL;
 
163
}
 
164
 
 
165
/* unless given, compute object path from sysfs path */
 
166
static GObject *
 
167
udisks_linux_drive_object_constructor (GType                  type,
 
168
                                       guint                  n_construct_properties,
 
169
                                       GObjectConstructParam *construct_properties)
 
170
{
 
171
  GObjectConstructParam *cp;
 
172
  UDisksDaemon *daemon;
 
173
  GUdevClient *client;
 
174
  UDisksLinuxDevice *device;
 
175
 
 
176
  cp = find_construct_property (n_construct_properties, construct_properties, "daemon");
 
177
  g_assert (cp != NULL);
 
178
  daemon = UDISKS_DAEMON (g_value_get_object (cp->value));
 
179
  g_assert (daemon != NULL);
 
180
 
 
181
  client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon));
 
182
 
 
183
  cp = find_construct_property (n_construct_properties, construct_properties, "device");
 
184
  g_assert (cp != NULL);
 
185
  device = g_value_get_object (cp->value);
 
186
  g_assert (device != NULL);
 
187
 
 
188
  if (!udisks_linux_drive_object_should_include_device (client, device, NULL))
 
189
    {
 
190
      return NULL;
 
191
    }
 
192
  else
 
193
    {
 
194
      return G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructor (type,
 
195
                                                                                   n_construct_properties,
 
196
                                                                                   construct_properties);
 
197
    }
 
198
}
 
199
 
 
200
static void
 
201
strip_and_replace_with_uscore (gchar *s)
 
202
{
 
203
  guint n;
 
204
 
 
205
  if (s == NULL)
 
206
    goto out;
 
207
 
 
208
  g_strstrip (s);
 
209
 
 
210
  for (n = 0; s != NULL && s[n] != '\0'; n++)
 
211
    {
 
212
      if (s[n] == ' ' || s[n] == '-')
 
213
        s[n] = '_';
 
214
    }
 
215
 
 
216
 out:
 
217
  ;
 
218
}
 
219
 
 
220
static void
 
221
udisks_linux_drive_object_constructed (GObject *_object)
 
222
{
 
223
  UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object);
 
224
  gchar *vendor;
 
225
  gchar *model;
 
226
  gchar *serial;
 
227
  GString *str;
 
228
 
 
229
  /* initial coldplug */
 
230
  udisks_linux_drive_object_uevent (object, "add", object->devices->data);
 
231
 
 
232
  /* compute the object path */
 
233
  vendor = g_strdup (udisks_drive_get_vendor (object->iface_drive));
 
234
  model = g_strdup (udisks_drive_get_model (object->iface_drive));
 
235
  serial = g_strdup (udisks_drive_get_serial (object->iface_drive));
 
236
  strip_and_replace_with_uscore (vendor);
 
237
  strip_and_replace_with_uscore (model);
 
238
  strip_and_replace_with_uscore (serial);
 
239
  str = g_string_new ("/org/freedesktop/UDisks2/drives/");
 
240
  if (vendor == NULL && model == NULL && serial == NULL)
 
241
    {
 
242
      g_string_append (str, "drive");
 
243
    }
 
244
  else
 
245
    {
 
246
      /* <VENDOR>_<MODEL>_<SERIAL> */
 
247
      if (vendor != NULL && strlen (vendor) > 0)
 
248
        {
 
249
          udisks_safe_append_to_object_path (str, vendor);
 
250
        }
 
251
      if (model != NULL && strlen (model) > 0)
 
252
        {
 
253
          if (str->str[str->len - 1] != '/')
 
254
            g_string_append_c (str, '_');
 
255
          udisks_safe_append_to_object_path (str, model);
 
256
        }
 
257
      if (serial != NULL && strlen (serial) > 0)
 
258
        {
 
259
          if (str->str[str->len - 1] != '/')
 
260
            g_string_append_c (str, '_');
 
261
          udisks_safe_append_to_object_path (str, serial);
 
262
        }
 
263
    }
 
264
  g_free (vendor);
 
265
  g_free (model);
 
266
  g_free (serial);
 
267
  g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), str->str);
 
268
  g_string_free (str, TRUE);
 
269
 
 
270
  if (G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructed != NULL)
 
271
    G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructed (_object);
 
272
}
 
273
 
 
274
static void
 
275
udisks_linux_drive_object_class_init (UDisksLinuxDriveObjectClass *klass)
 
276
{
 
277
  GObjectClass *gobject_class;
 
278
 
 
279
  gobject_class = G_OBJECT_CLASS (klass);
 
280
  gobject_class->constructor  = udisks_linux_drive_object_constructor;
 
281
  gobject_class->finalize     = udisks_linux_drive_object_finalize;
 
282
  gobject_class->constructed  = udisks_linux_drive_object_constructed;
 
283
  gobject_class->set_property = udisks_linux_drive_object_set_property;
 
284
  gobject_class->get_property = udisks_linux_drive_object_get_property;
 
285
 
 
286
  /**
 
287
   * UDisksLinuxDriveObject:daemon:
 
288
   *
 
289
   * The #UDisksDaemon the object is for.
 
290
   */
 
291
  g_object_class_install_property (gobject_class,
 
292
                                   PROP_DAEMON,
 
293
                                   g_param_spec_object ("daemon",
 
294
                                                        "Daemon",
 
295
                                                        "The daemon the object is for",
 
296
                                                        UDISKS_TYPE_DAEMON,
 
297
                                                        G_PARAM_READABLE |
 
298
                                                        G_PARAM_WRITABLE |
 
299
                                                        G_PARAM_CONSTRUCT_ONLY |
 
300
                                                        G_PARAM_STATIC_STRINGS));
 
301
 
 
302
  /**
 
303
   * UDisksLinuxDriveObject:device:
 
304
   *
 
305
   * The #UDisksLinuxDevice for the object. Connect to the #GObject::notify
 
306
   * signal to get notified whenever this is updated.
 
307
   */
 
308
  g_object_class_install_property (gobject_class,
 
309
                                   PROP_DEVICE,
 
310
                                   g_param_spec_object ("device",
 
311
                                                        "Device",
 
312
                                                        "The device for the object",
 
313
                                                        UDISKS_TYPE_LINUX_DEVICE,
 
314
                                                        G_PARAM_WRITABLE |
 
315
                                                        G_PARAM_CONSTRUCT_ONLY |
 
316
                                                        G_PARAM_STATIC_STRINGS));
 
317
 
 
318
}
 
319
 
 
320
/**
 
321
 * udisks_linux_drive_object_new:
 
322
 * @daemon: A #UDisksDaemon.
 
323
 * @device: The #UDisksLinuxDevice for the sysfs block device.
 
324
 *
 
325
 * Create a new drive object.
 
326
 *
 
327
 * Returns: A #UDisksLinuxDriveObject object or %NULL if @device does not represent a drive. Free with g_object_unref().
 
328
 */
 
329
UDisksLinuxDriveObject *
 
330
udisks_linux_drive_object_new (UDisksDaemon      *daemon,
 
331
                               UDisksLinuxDevice *device)
 
332
{
 
333
  GObject *object;
 
334
 
 
335
  g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
 
336
  g_return_val_if_fail (UDISKS_IS_LINUX_DEVICE (device), NULL);
 
337
 
 
338
  object = g_object_new (UDISKS_TYPE_LINUX_DRIVE_OBJECT,
 
339
                         "daemon", daemon,
 
340
                         "device", device,
 
341
                         NULL);
 
342
 
 
343
  if (object != NULL)
 
344
    return UDISKS_LINUX_DRIVE_OBJECT (object);
 
345
  else
 
346
    return NULL;
 
347
}
 
348
 
 
349
/**
 
350
 * udisks_linux_drive_object_get_daemon:
 
351
 * @object: A #UDisksLinuxDriveObject.
 
352
 *
 
353
 * Gets the daemon used by @object.
 
354
 *
 
355
 * Returns: A #UDisksDaemon. Do not free, the object is owned by @object.
 
356
 */
 
357
UDisksDaemon *
 
358
udisks_linux_drive_object_get_daemon (UDisksLinuxDriveObject *object)
 
359
{
 
360
  g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), NULL);
 
361
  return object->daemon;
 
362
}
 
363
 
 
364
/**
 
365
 * udisks_linux_drive_object_get_devices:
 
366
 * @object: A #UDisksLinuxDriveObject.
 
367
 *
 
368
 * Gets the current #UDisksLinuxDevice objects associated with @object.
 
369
 *
 
370
 * Returns: A list of #UDisksLinuxDevice objects. Free each element with
 
371
 * g_object_unref(), then free the list with g_list_free().
 
372
 */
 
373
GList *
 
374
udisks_linux_drive_object_get_devices (UDisksLinuxDriveObject *object)
 
375
{
 
376
  GList *ret;
 
377
  g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), NULL);
 
378
  ret = g_list_copy (object->devices);
 
379
  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
 
380
  return ret;
 
381
}
 
382
 
 
383
/**
 
384
 * udisks_linux_drive_object_get_device:
 
385
 * @object: A #UDisksLinuxDriveObject.
 
386
 * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device.
 
387
 *
 
388
 * Gets one of the #UDisksLinuxDevice object associated with @object.
 
389
 *
 
390
 * If @get_hw is %TRUE and @object represents a multipath device then
 
391
 * one of the paths is returned rather than the multipath device. This
 
392
 * is useful if you e.g. need to configure the physical hardware.
 
393
 *
 
394
 * Returns: A #UDisksLinuxDevice or %NULL. The returned object must be freed
 
395
 * with g_object_unref().
 
396
 */
 
397
UDisksLinuxDevice *
 
398
udisks_linux_drive_object_get_device (UDisksLinuxDriveObject   *object,
 
399
                                      gboolean                  get_hw)
 
400
{
 
401
  UDisksLinuxDevice *ret = NULL;
 
402
  /* TODO: actually look at @get_hw */
 
403
  if (object->devices != NULL)
 
404
    {
 
405
      ret = object->devices->data;
 
406
      if (ret != NULL)
 
407
        g_object_ref (ret);
 
408
    }
 
409
  return ret;
 
410
}
 
411
 
 
412
/**
 
413
 * udisks_linux_drive_object_get_block:
 
414
 * @object: A #UDisksLinuxDriveObject.
 
415
 * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device.
 
416
 *
 
417
 * Gets a #UDisksLinuxBlockObject representing a block device associated with @object.
 
418
 *
 
419
 * Returns: A #UDisksLinuxBlockObject or %NULL. The returned object
 
420
 * must be freed with g_object_unref().
 
421
 */
 
422
UDisksLinuxBlockObject *
 
423
udisks_linux_drive_object_get_block (UDisksLinuxDriveObject   *object,
 
424
                                     gboolean                  get_hw)
 
425
{
 
426
  GDBusObjectManagerServer *object_manager;
 
427
  UDisksLinuxBlockObject *ret;
 
428
  GList *objects;
 
429
  GList *l;
 
430
 
 
431
  /* TODO: actually look at @get_hw */
 
432
 
 
433
  ret = NULL;
 
434
 
 
435
  object_manager = udisks_daemon_get_object_manager (object->daemon);
 
436
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
 
437
  for (l = objects; l != NULL; l = l->next)
 
438
    {
 
439
      GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data);
 
440
      UDisksBlock *block;
 
441
      UDisksLinuxDevice *device;
 
442
      gboolean is_disk;
 
443
 
 
444
      if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object))
 
445
        continue;
 
446
 
 
447
      device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (iter_object));
 
448
      is_disk = (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") == 0);
 
449
      g_object_unref (device);
 
450
 
 
451
      if (!is_disk)
 
452
        continue;
 
453
 
 
454
      block = udisks_object_peek_block (UDISKS_OBJECT (iter_object));
 
455
      if (g_strcmp0 (udisks_block_get_drive (block),
 
456
                     g_dbus_object_get_object_path (G_DBUS_OBJECT (object))) == 0)
 
457
        {
 
458
          ret = g_object_ref (iter_object);
 
459
          goto out;
 
460
        }
 
461
    }
 
462
 
 
463
 out:
 
464
  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
 
465
  g_list_free (objects);
 
466
  return ret;
 
467
}
 
468
 
 
469
/* ---------------------------------------------------------------------------------------------------- */
 
470
 
 
471
typedef gboolean (*HasInterfaceFunc)    (UDisksLinuxDriveObject     *object);
 
472
typedef void     (*ConnectInterfaceFunc) (UDisksLinuxDriveObject    *object);
 
473
typedef gboolean (*UpdateInterfaceFunc) (UDisksLinuxDriveObject     *object,
 
474
                                         const gchar    *uevent_action,
 
475
                                         GDBusInterface *interface);
 
476
 
 
477
static gboolean
 
478
update_iface (UDisksLinuxDriveObject   *object,
 
479
              const gchar              *uevent_action,
 
480
              HasInterfaceFunc          has_func,
 
481
              ConnectInterfaceFunc      connect_func,
 
482
              UpdateInterfaceFunc       update_func,
 
483
              GType                     skeleton_type,
 
484
              gpointer                  _interface_pointer)
 
485
{
 
486
  gboolean ret = FALSE;
 
487
  gboolean has;
 
488
  gboolean add;
 
489
  GDBusInterface **interface_pointer = _interface_pointer;
 
490
 
 
491
  g_return_val_if_fail (object != NULL, FALSE);
 
492
  g_return_val_if_fail (has_func != NULL, FALSE);
 
493
  g_return_val_if_fail (update_func != NULL, FALSE);
 
494
  g_return_val_if_fail (g_type_is_a (skeleton_type, G_TYPE_OBJECT), FALSE);
 
495
  g_return_val_if_fail (g_type_is_a (skeleton_type, G_TYPE_DBUS_INTERFACE), FALSE);
 
496
  g_return_val_if_fail (interface_pointer != NULL, FALSE);
 
497
  g_return_val_if_fail (*interface_pointer == NULL || G_IS_DBUS_INTERFACE (*interface_pointer), FALSE);
 
498
 
 
499
  add = FALSE;
 
500
  has = has_func (object);
 
501
  if (*interface_pointer == NULL)
 
502
    {
 
503
      if (has)
 
504
        {
 
505
          *interface_pointer = g_object_new (skeleton_type, NULL);
 
506
          if (connect_func != NULL)
 
507
            connect_func (object);
 
508
          add = TRUE;
 
509
        }
 
510
    }
 
511
  else
 
512
    {
 
513
      if (!has)
 
514
        {
 
515
          g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (object),
 
516
                                                   G_DBUS_INTERFACE_SKELETON (*interface_pointer));
 
517
          g_object_unref (*interface_pointer);
 
518
          *interface_pointer = NULL;
 
519
        }
 
520
    }
 
521
 
 
522
  if (*interface_pointer != NULL)
 
523
    {
 
524
      if (update_func (object, uevent_action, G_DBUS_INTERFACE (*interface_pointer)))
 
525
        ret = TRUE;
 
526
      if (add)
 
527
        g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object),
 
528
                                              G_DBUS_INTERFACE_SKELETON (*interface_pointer));
 
529
    }
 
530
 
 
531
  return ret;
 
532
}
 
533
 
 
534
/* ---------------------------------------------------------------------------------------------------- */
 
535
 
 
536
static gboolean
 
537
drive_check (UDisksLinuxDriveObject *object)
 
538
{
 
539
  return TRUE;
 
540
}
 
541
 
 
542
static void
 
543
drive_connect (UDisksLinuxDriveObject *object)
 
544
{
 
545
}
 
546
 
 
547
static gboolean
 
548
drive_update (UDisksLinuxDriveObject  *object,
 
549
              const gchar             *uevent_action,
 
550
              GDBusInterface          *_iface)
 
551
{
 
552
  return udisks_linux_drive_update (UDISKS_LINUX_DRIVE (object->iface_drive), object);
 
553
}
 
554
 
 
555
/* ---------------------------------------------------------------------------------------------------- */
 
556
 
 
557
static gboolean
 
558
drive_ata_check (UDisksLinuxDriveObject *object)
 
559
{
 
560
  gboolean ret;
 
561
  UDisksLinuxDevice *device;
 
562
 
 
563
  ret = FALSE;
 
564
  if (object->devices == NULL)
 
565
    goto out;
 
566
 
 
567
  device = object->devices->data;
 
568
  if (device->ata_identify_device_data != NULL || device->ata_identify_packet_device_data != NULL)
 
569
    ret = TRUE;
 
570
 
 
571
 out:
 
572
  return ret;
 
573
}
 
574
 
 
575
static void
 
576
drive_ata_connect (UDisksLinuxDriveObject *object)
 
577
{
 
578
 
 
579
}
 
580
 
 
581
static gboolean
 
582
drive_ata_update (UDisksLinuxDriveObject  *object,
 
583
                  const gchar             *uevent_action,
 
584
                  GDBusInterface          *_iface)
 
585
{
 
586
  return udisks_linux_drive_ata_update (UDISKS_LINUX_DRIVE_ATA (object->iface_drive_ata), object);
 
587
}
 
588
 
 
589
/* ---------------------------------------------------------------------------------------------------- */
 
590
 
 
591
static void apply_configuration (UDisksLinuxDriveObject *object);
 
592
 
 
593
static GList *
 
594
find_link_for_sysfs_path (UDisksLinuxDriveObject *object,
 
595
                          const gchar            *sysfs_path)
 
596
{
 
597
  GList *l;
 
598
  GList *ret;
 
599
  ret = NULL;
 
600
  for (l = object->devices; l != NULL; l = l->next)
 
601
    {
 
602
      UDisksLinuxDevice *device = l->data;
 
603
      if (g_strcmp0 (g_udev_device_get_sysfs_path (device->udev_device), sysfs_path) == 0)
 
604
        {
 
605
          ret = l;
 
606
          goto out;
 
607
        }
 
608
    }
 
609
 out:
 
610
  return ret;
 
611
}
 
612
 
 
613
/**
 
614
 * udisks_linux_drive_object_uevent:
 
615
 * @object: A #UDisksLinuxDriveObject.
 
616
 * @action: Uevent action or %NULL
 
617
 * @device: A #UDisksLinuxDevice device object or %NULL if the device hasn't changed.
 
618
 *
 
619
 * Updates all information on interfaces on @drive.
 
620
 */
 
621
void
 
622
udisks_linux_drive_object_uevent (UDisksLinuxDriveObject *object,
 
623
                                  const gchar            *action,
 
624
                                  UDisksLinuxDevice      *device)
 
625
{
 
626
  GList *link;
 
627
  gboolean conf_changed;
 
628
 
 
629
  g_return_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object));
 
630
  g_return_if_fail (device == NULL || UDISKS_IS_LINUX_DEVICE (device));
 
631
 
 
632
  link = NULL;
 
633
  if (device != NULL)
 
634
    link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device->udev_device));
 
635
  if (g_strcmp0 (action, "remove") == 0)
 
636
    {
 
637
      if (link != NULL)
 
638
        {
 
639
          g_object_unref (UDISKS_LINUX_DEVICE (link->data));
 
640
          object->devices = g_list_delete_link (object->devices, link);
 
641
        }
 
642
      else
 
643
        {
 
644
          udisks_warning ("Drive doesn't have device with sysfs path %s on remove event",
 
645
                          g_udev_device_get_sysfs_path (device->udev_device));
 
646
        }
 
647
    }
 
648
  else
 
649
    {
 
650
      if (link != NULL)
 
651
        {
 
652
          g_object_unref (UDISKS_LINUX_DEVICE (link->data));
 
653
          link->data = g_object_ref (device);
 
654
        }
 
655
      else
 
656
        {
 
657
          if (device != NULL)
 
658
            object->devices = g_list_append (object->devices, g_object_ref (device));
 
659
        }
 
660
    }
 
661
 
 
662
  conf_changed = FALSE;
 
663
  conf_changed |= update_iface (object, action, drive_check, drive_connect, drive_update,
 
664
                                UDISKS_TYPE_LINUX_DRIVE, &object->iface_drive);
 
665
  conf_changed |= update_iface (object, action, drive_ata_check, drive_ata_connect, drive_ata_update,
 
666
                                UDISKS_TYPE_LINUX_DRIVE_ATA, &object->iface_drive_ata);
 
667
 
 
668
  if (conf_changed)
 
669
    apply_configuration (object);
 
670
}
 
671
 
 
672
/* ---------------------------------------------------------------------------------------------------- */
 
673
 
 
674
static void
 
675
apply_configuration (UDisksLinuxDriveObject *object)
 
676
{
 
677
  GVariant *configuration = NULL;
 
678
  UDisksLinuxDevice *device = NULL;
 
679
 
 
680
  if (object->iface_drive == NULL)
 
681
    goto out;
 
682
 
 
683
  configuration = udisks_drive_dup_configuration (object->iface_drive);
 
684
  if (configuration == NULL)
 
685
    goto out;
 
686
 
 
687
  device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
 
688
  if (device == NULL)
 
689
    goto out;
 
690
 
 
691
  if (object->iface_drive_ata != NULL)
 
692
    {
 
693
      udisks_linux_drive_ata_apply_configuration (UDISKS_LINUX_DRIVE_ATA (object->iface_drive_ata),
 
694
                                                  device,
 
695
                                                  configuration);
 
696
    }
 
697
 
 
698
 out:
 
699
  g_clear_object (&device);
 
700
  if (configuration != NULL)
 
701
    g_variant_unref (configuration);
 
702
}
 
703
 
 
704
/* ---------------------------------------------------------------------------------------------------- */
 
705
 
 
706
/* utility routine to blacklist WWNs that are not suitable to use
 
707
 * for identification purposes
 
708
 */
 
709
static gboolean
 
710
is_wwn_black_listed (const gchar *wwn)
 
711
{
 
712
  g_return_val_if_fail (wwn != NULL, FALSE);
 
713
 
 
714
  if (g_str_has_prefix (wwn, "0x") || g_str_has_prefix (wwn, "0X"))
 
715
    wwn += 2;
 
716
 
 
717
  if (g_ascii_strcasecmp (wwn, "50f0000000000000") == 0)
 
718
    {
 
719
      /* SAMSUNG SP1604N (PATA), see https://bugzilla.redhat.com/show_bug.cgi?id=838691#c4 */
 
720
      return TRUE;
 
721
    }
 
722
  else
 
723
    {
 
724
      return FALSE;
 
725
    }
 
726
}
 
727
 
 
728
static gchar *
 
729
check_for_vpd (GUdevDevice *device)
 
730
{
 
731
  gchar *ret = NULL;
 
732
  const gchar *serial;
 
733
  const gchar *wwn;
 
734
  const gchar *path;
 
735
 
 
736
  g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
 
737
 
 
738
  /* order of preference: WWN_serial, WWN, serial, path */
 
739
  serial = g_udev_device_get_property (device, "ID_SERIAL");
 
740
  wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION");
 
741
  path = g_udev_device_get_property (device, "ID_PATH");
 
742
  if (wwn != NULL && strlen (wwn) > 0 && !is_wwn_black_listed (wwn))
 
743
    {
 
744
      if (serial != NULL && strlen (serial) > 0)
 
745
        ret = g_strdup_printf ("%s_%s", wwn, serial);
 
746
      else
 
747
        ret = g_strdup (wwn);
 
748
    }
 
749
  else if (serial != NULL && strlen (serial) > 0)
 
750
    {
 
751
      ret = g_strdup (serial);
 
752
    }
 
753
  else if (path != NULL && strlen (path) > 0)
 
754
    {
 
755
      ret = g_strdup (path);
 
756
    }
 
757
  return ret;
 
758
}
 
759
 
 
760
/* <internal>
 
761
 * udisks_linux_drive_object_should_include_device:
 
762
 * @client: A #GUdevClient.
 
763
 * @device: A #UDisksLinuxDevice.
 
764
 * @out_vpd: Return location for unique ID or %NULL.
 
765
 *
 
766
 * Checks if we should even construct a #UDisksLinuxDriveObject for @device.
 
767
 *
 
768
 * Returns: %TRUE if we should construct an object, %FALSE otherwise.
 
769
 */
 
770
gboolean
 
771
udisks_linux_drive_object_should_include_device (GUdevClient  *client,
 
772
                                                 UDisksLinuxDevice  *device,
 
773
                                                 gchar       **out_vpd)
 
774
{
 
775
  gboolean ret;
 
776
  gchar *vpd;
 
777
 
 
778
  ret = FALSE;
 
779
  vpd = NULL;
 
780
 
 
781
  /* The 'block' subsystem encompasses several objects with varying
 
782
   * DEVTYPE including
 
783
   *
 
784
   *  - disk
 
785
   *  - partition
 
786
   *
 
787
   * and we are only interested in the first.
 
788
   */
 
789
  if (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") != 0)
 
790
    goto out;
 
791
 
 
792
  vpd = check_for_vpd (device->udev_device);
 
793
 
 
794
  if (vpd == NULL)
 
795
    {
 
796
      const gchar *name;
 
797
      const gchar *vendor;
 
798
      const gchar *model;
 
799
      const gchar *dm_name;
 
800
      GUdevDevice *parent;
 
801
 
 
802
      name = g_udev_device_get_name (device->udev_device);
 
803
 
 
804
      /* workaround for floppy devices */
 
805
      if (g_str_has_prefix (name, "fd"))
 
806
        {
 
807
          vpd = g_strdup_printf ("pcfloppy_%s", name);
 
808
          goto found;
 
809
        }
 
810
 
 
811
      /* workaround for missing serial/wwn on virtio-blk */
 
812
      if (g_str_has_prefix (name, "vd"))
 
813
        {
 
814
          vpd = g_strdup (name);
 
815
          goto found;
 
816
        }
 
817
 
 
818
      /* workaround for missing serial/wwn on VMware */
 
819
      vendor = g_udev_device_get_property (device->udev_device, "ID_VENDOR");
 
820
      model = g_udev_device_get_property (device->udev_device, "ID_MODEL");
 
821
      if (g_str_has_prefix (name, "sd") &&
 
822
          vendor != NULL && g_strcmp0 (vendor, "VMware") == 0 &&
 
823
          model != NULL && g_str_has_prefix (model, "Virtual"))
 
824
        {
 
825
          vpd = g_strdup (name);
 
826
          goto found;
 
827
        }
 
828
 
 
829
      /* workaround for missing serial/wwn on firewire devices */
 
830
      parent = g_udev_device_get_parent_with_subsystem (device->udev_device, "firewire", NULL);
 
831
      if (parent != NULL)
 
832
        {
 
833
          vpd = g_strdup (name);
 
834
          g_object_unref (parent);
 
835
          goto found;
 
836
        }
 
837
 
 
838
      /* dm-multipath */
 
839
      dm_name = g_udev_device_get_sysfs_attr (device->udev_device, "dm/name");
 
840
      if (dm_name != NULL && g_str_has_prefix (dm_name, "mpath"))
 
841
        {
 
842
          gchar **slaves;
 
843
          guint n;
 
844
          slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device->udev_device), "slaves");
 
845
          for (n = 0; slaves[n] != NULL; n++)
 
846
            {
 
847
              GUdevDevice *slave;
 
848
              slave = g_udev_client_query_by_sysfs_path (client, slaves[n]);
 
849
              if (slave != NULL)
 
850
                {
 
851
                  vpd = check_for_vpd (slave);
 
852
                  if (vpd != NULL)
 
853
                    {
 
854
                      g_object_unref (slave);
 
855
                      g_strfreev (slaves);
 
856
                      goto found;
 
857
                    }
 
858
                  g_object_unref (slave);
 
859
                }
 
860
            }
 
861
          g_strfreev (slaves);
 
862
        }
 
863
    }
 
864
 
 
865
 found:
 
866
  if (vpd != NULL)
 
867
    {
 
868
      if (out_vpd != NULL)
 
869
        {
 
870
          *out_vpd = vpd;
 
871
          vpd = NULL;
 
872
        }
 
873
      ret = TRUE;
 
874
    }
 
875
 
 
876
 out:
 
877
  g_free (vpd);
 
878
  return ret;
 
879
}
 
880
 
 
881
/* ---------------------------------------------------------------------------------------------------- */
 
882
 
 
883
/**
 
884
 * udisks_linux_drive_object_housekeeping:
 
885
 * @object: A #UDisksLinuxDriveObject.
 
886
 * @secs_since_last: Number of seconds sincex the last housekeeping or 0 if the first housekeeping ever.
 
887
 * @cancellable: A %GCancellable or %NULL.
 
888
 * @error: Return location for error or %NULL.
 
889
 *
 
890
 * Called periodically (every ten minutes or so) to perform
 
891
 * housekeeping tasks such as refreshing ATA SMART data.
 
892
 *
 
893
 * The function runs in a dedicated thread and is allowed to perform
 
894
 * blocking I/O.
 
895
 *
 
896
 * Long-running tasks should periodically check @cancellable to see if
 
897
 * they have been cancelled.
 
898
 *
 
899
 * Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
 
900
 */
 
901
gboolean
 
902
udisks_linux_drive_object_housekeeping (UDisksLinuxDriveObject  *object,
 
903
                                        guint                    secs_since_last,
 
904
                                        GCancellable            *cancellable,
 
905
                                        GError                 **error)
 
906
{
 
907
  gboolean ret;
 
908
 
 
909
  ret = FALSE;
 
910
 
 
911
  if (object->iface_drive_ata != NULL &&
 
912
      udisks_drive_ata_get_smart_supported (object->iface_drive_ata) &&
 
913
      udisks_drive_ata_get_smart_enabled (object->iface_drive_ata))
 
914
    {
 
915
      GError *local_error;
 
916
      gboolean nowakeup;
 
917
 
 
918
      /* Wake-up only on start-up */
 
919
      nowakeup = TRUE;
 
920
      if (secs_since_last == 0)
 
921
        nowakeup = FALSE;
 
922
 
 
923
      udisks_info ("Refreshing SMART data on %s (nowakeup=%d)",
 
924
                   g_dbus_object_get_object_path (G_DBUS_OBJECT (object)),
 
925
                   nowakeup);
 
926
 
 
927
      local_error = NULL;
 
928
      if (!udisks_linux_drive_ata_refresh_smart_sync (UDISKS_LINUX_DRIVE_ATA (object->iface_drive_ata),
 
929
                                                      nowakeup,
 
930
                                                      NULL, /* simulate_path */
 
931
                                                      cancellable,
 
932
                                                      &local_error))
 
933
        {
 
934
          if (nowakeup && (local_error->domain == UDISKS_ERROR &&
 
935
                           local_error->code == UDISKS_ERROR_WOULD_WAKEUP))
 
936
            {
 
937
              udisks_info ("Drive %s is in a sleep state",
 
938
                           g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
 
939
              g_error_free (local_error);
 
940
            }
 
941
          else if (nowakeup && (local_error->domain == UDISKS_ERROR &&
 
942
                                local_error->code == UDISKS_ERROR_DEVICE_BUSY))
 
943
            {
 
944
              /* typically because a "secure erase" operation is pending */
 
945
              udisks_info ("Drive %s is busy",
 
946
                           g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
 
947
              g_error_free (local_error);
 
948
            }
 
949
          else
 
950
            {
 
951
              g_propagate_prefixed_error (error, local_error, "Error updating SMART data: ");
 
952
              goto out;
 
953
            }
 
954
        }
 
955
    }
 
956
 
 
957
  ret = TRUE;
 
958
 
 
959
 out:
 
960
  return ret;
 
961
}
 
962
 
 
963
static gboolean
 
964
is_block_unlocked (GList *objects, const gchar *crypto_object_path)
 
965
{
 
966
  gboolean ret = FALSE;
 
967
  GList *l;
 
968
  for (l = objects; l != NULL; l = l->next)
 
969
    {
 
970
      UDisksObject *object = UDISKS_OBJECT (l->data);
 
971
      UDisksBlock *block;
 
972
      block = udisks_object_peek_block (object);
 
973
      if (block != NULL)
 
974
        {
 
975
          if (g_strcmp0 (udisks_block_get_crypto_backing_device (block), crypto_object_path) == 0)
 
976
            {
 
977
              ret = TRUE;
 
978
              goto out;
 
979
            }
 
980
        }
 
981
    }
 
982
 out:
 
983
  return ret;
 
984
}
 
985
 
 
986
/**
 
987
 * udisks_linux_drive_object_is_not_in_use:
 
988
 * @object: A #UDisksLinuxDriveObject.
 
989
 * @cancellable: (allow-none): A #GCancellable or %NULL.
 
990
 * @error: A #GError or %NULL.
 
991
 *
 
992
 * Checks if the drive represented by @object is in use and sets
 
993
 * @error if so.
 
994
 *
 
995
 * Returns: %TRUE if @object is not is use, %FALSE if @error is set.
 
996
 */
 
997
gboolean
 
998
udisks_linux_drive_object_is_not_in_use (UDisksLinuxDriveObject   *object,
 
999
                                         GCancellable             *cancellable,
 
1000
                                         GError                  **error)
 
1001
{
 
1002
  GDBusObjectManagerServer *object_manager;
 
1003
  const gchar *drive_object_path;
 
1004
  gboolean ret = TRUE;
 
1005
  GList *objects = NULL;
 
1006
  GList *l;
 
1007
 
 
1008
  g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), FALSE);
 
1009
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
 
1010
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1011
 
 
1012
  drive_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
 
1013
 
 
1014
  object_manager = udisks_daemon_get_object_manager (object->daemon);
 
1015
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
 
1016
 
 
1017
  /* Visit all block devices related to the drive... */
 
1018
  for (l = objects; l != NULL; l = l->next)
 
1019
    {
 
1020
      GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data);
 
1021
      UDisksBlock *block;
 
1022
      UDisksFilesystem *filesystem;
 
1023
 
 
1024
      if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object))
 
1025
        continue;
 
1026
 
 
1027
      block = udisks_object_peek_block (UDISKS_OBJECT (iter_object));
 
1028
      filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (iter_object));
 
1029
 
 
1030
      if (g_strcmp0 (udisks_block_get_drive (block), drive_object_path) != 0)
 
1031
        continue;
 
1032
 
 
1033
      /* bail if block device is mounted */
 
1034
      if (filesystem != NULL)
 
1035
        {
 
1036
          if (g_strv_length ((gchar **) udisks_filesystem_get_mount_points (filesystem)) > 0)
 
1037
            {
 
1038
              g_set_error (error,
 
1039
                           UDISKS_ERROR,
 
1040
                           UDISKS_ERROR_DEVICE_BUSY,
 
1041
                           "Device %s is mounted",
 
1042
                           udisks_block_get_preferred_device (block));
 
1043
              ret = FALSE;
 
1044
              goto out;
 
1045
            }
 
1046
        }
 
1047
 
 
1048
      /* bail if block device is unlocked (LUKS) */
 
1049
      if (is_block_unlocked (objects, g_dbus_object_get_object_path (G_DBUS_OBJECT (iter_object))))
 
1050
        {
 
1051
          g_set_error (error,
 
1052
                       UDISKS_ERROR,
 
1053
                       UDISKS_ERROR_DEVICE_BUSY,
 
1054
                       "Encrypted device %s is unlocked",
 
1055
                       udisks_block_get_preferred_device (block));
 
1056
          ret = FALSE;
 
1057
          goto out;
 
1058
        }
 
1059
    }
 
1060
 
 
1061
 out:
 
1062
  g_list_free_full (objects, g_object_unref);
 
1063
  return ret;
 
1064
}
 
1065
 
 
1066
/* ---------------------------------------------------------------------------------------------------- */
 
1067
 
 
1068
/**
 
1069
 * udisks_linux_drive_object_get_siblings:
 
1070
 * @object: A #UDisksLinuxDriveObject.
 
1071
 *
 
1072
 * Gets the siblings for @object, if any.
 
1073
 *
 
1074
 * Returns: (transfer full) (element-type UDisksLinuxDriveObject): A list of #UDisksLinuxDriveObject
 
1075
 *   instances. The returned list should be freed with g_list_free() after each element has been
 
1076
 *   freed with g_object_unref().
 
1077
 */
 
1078
GList *
 
1079
udisks_linux_drive_object_get_siblings (UDisksLinuxDriveObject *object)
 
1080
{
 
1081
  GDBusObjectManagerServer *object_manager;
 
1082
  GList *ret = NULL;
 
1083
  GList *objects = NULL;
 
1084
  GList *l;
 
1085
  gchar *sibling_id = NULL;
 
1086
 
 
1087
  if (object->iface_drive == NULL)
 
1088
    goto out;
 
1089
 
 
1090
  sibling_id = udisks_drive_dup_sibling_id (object->iface_drive);
 
1091
  if (sibling_id == NULL || strlen (sibling_id) == 0)
 
1092
    goto out;
 
1093
 
 
1094
  object_manager = udisks_daemon_get_object_manager (object->daemon);
 
1095
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
 
1096
  for (l = objects; l != NULL; l = l->next)
 
1097
    {
 
1098
      GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data);
 
1099
      UDisksLinuxDriveObject *iter_linux_drive_object;
 
1100
 
 
1101
      if (!UDISKS_IS_LINUX_DRIVE_OBJECT (iter_object))
 
1102
        continue;
 
1103
 
 
1104
      iter_linux_drive_object = UDISKS_LINUX_DRIVE_OBJECT (iter_object);
 
1105
      if (iter_linux_drive_object->iface_drive != NULL &&
 
1106
          g_strcmp0 (udisks_drive_get_sibling_id (iter_linux_drive_object->iface_drive), sibling_id) == 0)
 
1107
        {
 
1108
          ret = g_list_prepend (ret, g_object_ref (iter_object));
 
1109
        }
 
1110
    }
 
1111
 
 
1112
 out:
 
1113
  ret = g_list_reverse (ret);
 
1114
  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
 
1115
  g_list_free (objects);
 
1116
  g_free (sibling_id);
 
1117
  return ret;
 
1118
}
 
1119